From: John Tsiombikas Date: Sun, 18 Jun 2023 21:37:52 +0000 (+0300) Subject: first render X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=commitdiff_plain;h=81dffafe4b045c854d8a97f9c6c41877ee7669ca;p=retroray first render --- diff --git a/Makefile b/Makefile index 87a5ebe..94e655d 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,9 @@ dosobj = src/dos/djdpmi.obj src/dos/gfx.obj src/dos/keyb.obj src/dos/main.obj & src/dos/mouse.obj src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj appobj = src/app.obj src/cmesh.obj src/darray.obj src/font.obj src/logger.obj & - src/meshgen.obj src/meshload.obj src/options.obj src/rbtree.obj src/rt.obj & + src/meshgen.obj src/meshload.obj src/options.obj src/rbtree.obj src/geom.obj & src/rend.obj src/rtk.obj src/scene.obj src/scr_mod.obj src/scr_rend.obj & + src/texture.obj src/material.obj & src/util.obj src/util_s.obj src/cpuid.obj src/cpuid_s.obj gawobj = src/gaw/gaw_sw.obj src/gaw/gawswtnl.obj src/gaw/polyclip.obj src/gaw/polyfill.obj @@ -13,8 +14,9 @@ libpath = libpath libs/dos dosobj = src\dos\djdpmi.obj src\dos\gfx.obj src\dos\keyb.obj src\dos\main.obj & src\dos\mouse.obj src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj appobj = src\app.obj src\cmesh.obj src\darray.obj src\font.obj src\logger.obj & - src\meshgen.obj src\meshload.obj src\options.obj src\rbtree.obj src\rt.obj & + src\meshgen.obj src\meshload.obj src\options.obj src\rbtree.obj src\geom.obj & src\rend.obj src\rtk.obj src\scene.obj src\scr_mod.obj src\scr_rend.obj & + src\texture.obj src\material.obj & src\util.obj src\util_s.obj src\cpuid.obj src\cpuid_s.obj gawobj = src\gaw\gaw_sw.obj src\gaw\gawswtnl.obj src\gaw\polyclip.obj src\gaw\polyfill.obj diff --git a/libs/cgmath/cgmath.h b/libs/cgmath/cgmath.h index 9f99361..b343c73 100644 --- a/libs/cgmath/cgmath.h +++ b/libs/cgmath/cgmath.h @@ -77,6 +77,7 @@ extern "C" { static CGM_INLINE void cgm_vcons(cgm_vec3 *v, float x, float y, float z); static CGM_INLINE cgm_vec3 cgm_vvec(float x, float y, float z); +static CGM_INLINE void cgm_vneg(cgm_vec3 *v); static CGM_INLINE void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b); static CGM_INLINE void cgm_vadd_scaled(cgm_vec3 *a, const cgm_vec3 *b, float s); /* a+b*s */ static CGM_INLINE void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b); diff --git a/libs/cgmath/cgmvec3.inl b/libs/cgmath/cgmvec3.inl index 874d0fc..8191c63 100644 --- a/libs/cgmath/cgmvec3.inl +++ b/libs/cgmath/cgmvec3.inl @@ -22,6 +22,13 @@ static CGM_INLINE cgm_vec3 cgm_vvec(float x, float y, float z) return v; } +static CGM_INLINE void cgm_vneg(cgm_vec3 *v) +{ + v->x = -v->x; + v->y = -v->y; + v->z = -v->z; +} + static CGM_INLINE void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b) { a->x += b->x; diff --git a/src/geom.c b/src/geom.c index 1a89ccd..3be5e07 100644 --- a/src/geom.c +++ b/src/geom.c @@ -39,7 +39,7 @@ int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit * switch(obj->type) { case OBJ_SPHERE: - res = ray_sphere(ray, (const struct sphere*)obj, hit); + res = ray_sphere(&localray, (const struct sphere*)obj, hit); break; default: @@ -57,6 +57,8 @@ int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit * return res; } +#define EPSILON 1e-5 + int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit) { int i; @@ -64,11 +66,10 @@ int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit) struct rayhit *rhptr; a = cgm_vdot(&ray->dir, &ray->dir); - b = 2.0f * ray->dir.x * (ray->origin.x - sph->pos.x) + - 2.0f * ray->dir.y * (ray->origin.y - sph->pos.y) + - 2.0f * ray->dir.z * (ray->origin.z - sph->pos.z); - c = cgm_vdot(&sph->pos, &sph->pos) + cgm_vdot(&ray->origin, &ray->origin) + - cgm_vdot(&sph->pos, &ray->origin) * -2.0f - sph->rad * sph->rad; + b = 2.0f * ray->dir.x * ray->origin.x + + 2.0f * ray->dir.y * ray->origin.y + + 2.0f * ray->dir.z * ray->origin.z; + c = cgm_vdot(&ray->origin, &ray->origin) - sph->rad * sph->rad; if((d = b * b - 4.0 * a * c) < 0.0) return 0; @@ -76,14 +77,14 @@ int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit) t1 = (-b + sqrt_d) / (2.0 * a); t2 = (-b - sqrt_d) / (2.0 * a); - if((t1 < 1e-6f && t2 < 1e-6f) || (t1 > 1.0f && t2 > 1.0f)) { + if((t1 < EPSILON && t2 < EPSILON) || (t1 > 1.0f && t2 > 1.0f)) { return 0; } if(hit) { - if(t1 < 1e-6f || t1 > 1.0f) { + if(t1 < EPSILON || t1 > 1.0f) { t1 = t2; - } else if(t2 < 1e-6f || t2 > 1.0f) { + } else if(t2 < EPSILON || t2 > 1.0f) { t2 = t1; } if(t2 < t1) { diff --git a/src/material.c b/src/material.c new file mode 100644 index 0000000..177ac68 --- /dev/null +++ b/src/material.c @@ -0,0 +1,50 @@ +/* +RetroRay - integrated standalone vintage modeller/renderer +Copyright (C) 2023 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include "material.h" + +void mtl_init(struct material *mtl) +{ + static int mtlidx; + char namebuf[64]; + + cgm_vcons(&mtl->kd, 0.7, 0.7, 0.7); + cgm_vcons(&mtl->ks, 0.5, 0.5, 0.5); + cgm_vcons(&mtl->ke, 0, 0, 0); + mtl->shin = 50.0f; + mtl->refl = mtl->trans = 0.0f; + mtl->ior = 1.3333333; + mtl->texmap = 0; + + sprintf(namebuf, "material%03d", mtlidx++); + mtl_set_name(mtl, namebuf); +} + +void mtl_destroy(struct material *mtl) +{ + if(!mtl) return; + free(mtl->name); +} + +void mtl_set_name(struct material *mtl, const char *name) +{ + char *tmp = strdup(name); + if(!tmp) return; + free(mtl->name); + mtl->name = tmp; +} diff --git a/src/material.h b/src/material.h new file mode 100644 index 0000000..15bccd3 --- /dev/null +++ b/src/material.h @@ -0,0 +1,38 @@ +/* +RetroRay - integrated standalone vintage modeller/renderer +Copyright (C) 2023 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef MATERIAL_H_ +#define MATERIAL_H_ + +#include "cgmath/cgmath.h" +#include "texture.h" + +struct material { + char *name; + cgm_vec3 kd, ks, ke; + float shin; + float refl, trans, ior; + + struct texture *texmap; +}; + +void mtl_init(struct material *mtl); +void mtl_destroy(struct material *mtl); + +void mtl_set_name(struct material *mtl, const char *name); + +#endif /* MATERIAL_H_ */ diff --git a/src/rend.c b/src/rend.c index c88277f..8547ca6 100644 --- a/src/rend.c +++ b/src/rend.c @@ -22,19 +22,30 @@ along with this program. If not, see . #include "gfxutil.h" #include "scene.h" +static int calc_light(const struct rayhit *hit, const struct light *lt, + const cgm_vec3 *vdir, cgm_vec3 *dcol, cgm_vec3 *scol); + struct img_pixmap renderbuf; int max_ray_depth; +cgm_vec3 ambient; static int rx, ry, rwidth, rheight; static int roffs; static int xstep, ystep; +static int pan_x, pan_y; + +static struct light def_light = {0, {0, 0, 0}, {1, 1, 1}}; + int rend_init(void) { img_init(&renderbuf); + cgm_vcons(&ambient, 0.05, 0.05, 0.05); + rx = ry = rwidth = rheight = roffs = 0; + pan_x = pan_y = 0; max_ray_depth = 6; return 0; @@ -52,6 +63,12 @@ void rend_size(int xsz, int ysz) } } +void rend_pan(int xoffs, int yoffs) +{ + pan_x = xoffs; + pan_y = yoffs; +} + void rend_begin(int x, int y, int w, int h) { int i; @@ -100,27 +117,32 @@ int render(uint32_t *fb) cgm_ray ray; dest = (uint32_t*)renderbuf.pixels + roffs; - if(fb) fb += roffs; + if(fb) { + fb += roffs; + } if(xstep < 1) xstep = 1; if(ystep < 1) ystep = 1; + if(scn_num_lights(scn) == 0) { + primray(&ray, renderbuf.width / 2, renderbuf.height / 2); + def_light.pos = ray.origin; + } + for(i=0; i rheight) h = rheight - i; for(j=0; j 1.0f) color.x = 1.0f; + if(color.y > 1.0f) color.y = 1.0f; + if(color.z > 1.0f) color.z = 1.0f; r = cround64(color.x * 255.0f); g = cround64(color.y * 255.0f); b = cround64(color.z * 255.0f); - - if(r > 255) r = 255; - if(g > 255) g = 255; - if(b > 255) b = 255; - pcol = PACK_RGB32(r, g, b); offs = i * renderbuf.width + j; @@ -164,5 +186,76 @@ cgm_vec3 bgcolor(const cgm_ray *ray) cgm_vec3 shade(const cgm_ray *ray, const struct rayhit *hit, int maxiter) { - return cgm_vvec(1, 0, 0); + int i, num_lights; + cgm_vec3 color, dcol, scol, texel, vdir; + struct material *mtl; + struct light *lt; + + dcol = ambient; + cgm_vcons(&scol, 0, 0, 0); + + mtl = hit->obj->mtl; + + vdir = ray->dir; + cgm_vneg(&vdir); + cgm_vnormalize(&vdir); + + if(!(num_lights = scn_num_lights(scn))) { + calc_light(hit, &def_light, &vdir, &dcol, &scol); + } + for(i=0; ilights[i]; + calc_light(hit, lt, &vdir, &dcol, &scol); + } + + if(mtl->texmap) { + texel = mtl->texmap->lookup(mtl->texmap, hit); + cgm_vmul(&dcol, &texel); + } + + color = dcol; + cgm_vadd(&color, &scol); + return color; +} + +static int calc_light(const struct rayhit *hit, const struct light *lt, + const cgm_vec3 *vdir, cgm_vec3 *dcol, cgm_vec3 *scol) +{ + float ndotl, ndoth, spec; + cgm_vec3 ldir, hdir; + cgm_ray ray; + struct material *mtl = hit->obj->mtl; + + ldir = lt->pos; + cgm_vsub(&ldir, &hit->pos); + + ray.origin = hit->pos; + ray.dir = ldir; + + if(scn_intersect(scn, &ray, 0)) { + return 0; /* in shadow */ + } + + cgm_vnormalize(&ldir); + + hdir = *vdir; + cgm_vadd(&hdir, &ldir); + cgm_vnormalize(&hdir); + + ndotl = cgm_vdot(&hit->norm, &ldir); + if(ndotl < 0.0f) ndotl = 0.0f; + ndoth = cgm_vdot(&hit->norm, &hdir); + if(ndoth < 0.0f) ndoth = 0.0f; + + spec = pow(ndoth, mtl->shin); + + dcol->x += mtl->kd.x * ndotl * lt->color.x; + dcol->y += mtl->kd.y * ndotl * lt->color.y; + dcol->z += mtl->kd.z * ndotl * lt->color.z; + + scol->x += mtl->ks.x * spec * lt->color.x; + scol->y += mtl->ks.y * spec * lt->color.y; + scol->z += mtl->ks.z * spec * lt->color.z; + + return 1; } diff --git a/src/rend.h b/src/rend.h index 61d5b5f..33c5963 100644 --- a/src/rend.h +++ b/src/rend.h @@ -25,11 +25,13 @@ along with this program. If not, see . extern struct img_pixmap renderbuf; extern int max_ray_depth; +extern cgm_vec3 ambient; struct scene; int rend_init(void); void rend_size(int xsz, int ysz); +void rend_pan(int xoffs, int yoffs); void rend_begin(int x, int y, int w, int h); int render(uint32_t *fb); diff --git a/src/scene.c b/src/scene.c index 48279cc..36c9fba 100644 --- a/src/scene.c +++ b/src/scene.c @@ -22,6 +22,8 @@ along with this program. If not, see . #include "darray.h" #include "logger.h" +static struct material *default_material(void); + struct scene *create_scene(void) { struct scene *scn; @@ -31,7 +33,8 @@ struct scene *create_scene(void) return 0; } scn->objects = darr_alloc(0, sizeof *scn->objects); - + scn->lights = darr_alloc(0, sizeof *scn->lights); + scn->mtl = darr_alloc(0, sizeof *scn->mtl); return scn; } @@ -45,6 +48,18 @@ void free_scene(struct scene *scn) free_object(scn->objects[i]); } darr_free(scn->objects); + + for(i=0; ilights); i++) { + free_light(scn->lights[i]); + } + darr_free(scn->lights); + + for(i=0; imtl); i++) { + mtl_destroy(scn->mtl[i]); + free(scn->mtl[i]); + } + darr_free(scn->mtl); + free(scn); } @@ -87,6 +102,119 @@ int scn_object_index(const struct scene *scn, const struct object *obj) return -1; } + + +int scn_add_material(struct scene *scn, struct material *mtl) +{ + darr_push(scn->mtl, &mtl); + return 0; +} + +int scn_rm_material(struct scene *scn, struct material *mtl) +{ + int idx, num_mtl; + + if((idx = scn_material_index(scn, mtl)) == -1) { + return -1; + } + + num_mtl = darr_size(scn->mtl); + + if(idx < num_mtl - 1) { + scn->mtl[idx] = scn->mtl[num_mtl - 1]; + } + darr_pop(scn->mtl); + return 0; +} + +int scn_num_materials(const struct scene *scn) +{ + return darr_size(scn->mtl); +} + +int scn_material_index(const struct scene *scn, const struct material *mtl) +{ + int i, num_mtl; + + num_mtl = darr_size(scn->mtl); + for(i=0; imtl[i] == mtl) { + return i; + } + } + return -1; +} + +struct material *scn_find_material(const struct scene *scn, const char *mname) +{ + int i, num_mtl; + + num_mtl = darr_size(scn->mtl); + for(i=0; imtl[i]->name, mname) == 0) { + return scn->mtl[i]; + } + } + return 0; +} + +/* manage lights */ + +int scn_add_light(struct scene *scn, struct light *light) +{ + darr_push(scn->lights, &light); + return 0; +} + +int scn_rm_light(struct scene *scn, struct light *light) +{ + int idx, num_lights; + + if((idx = scn_light_index(scn, light)) == -1) { + return -1; + } + + num_lights = darr_size(scn->lights); + + if(idx < num_lights - 1) { + scn->lights[idx] = scn->lights[num_lights - 1]; + } + darr_pop(scn->lights); + return 0; +} + +int scn_num_lights(const struct scene *scn) +{ + return darr_size(scn->lights); +} + +int scn_light_index(const struct scene *scn, const struct light *light) +{ + int i, num_lights; + + num_lights = darr_size(scn->lights); + for(i=0; ilights[i] == light) { + return i; + } + } + return -1; +} + +struct light *scn_find_light(const struct scene *scn, const char *mname) +{ + int i, num_lights; + + num_lights = darr_size(scn->lights); + for(i=0; ilights[i]->name, mname) == 0) { + return scn->lights[i]; + } + } + return 0; +} + + int scn_intersect(const struct scene *scn, const cgm_ray *ray, struct rayhit *hit) { int i, numobj; @@ -109,6 +237,9 @@ int scn_intersect(const struct scene *scn, const cgm_ray *ray, struct rayhit *hi return 0; } + +/* --- object functions --- */ + struct object *create_object(int type) { struct object *obj; @@ -143,6 +274,7 @@ struct object *create_object(int type) cgm_midentity(obj->xform); cgm_midentity(obj->inv_xform); obj->xform_valid = 1; + obj->mtl = default_material(); set_object_name(obj, buf); objid++; @@ -198,3 +330,65 @@ void calc_object_matrix(struct object *obj) obj->xform_valid = 1; } + +/* --- lights --- */ +struct light *create_light(void) +{ + struct light *lt; + static int ltidx; + char buf[64]; + + if(!(lt = malloc(sizeof *lt))) { + return 0; + } + cgm_vcons(<->pos, 0, 0, 0); + + set_light_color(lt, 1, 1, 1); + set_light_energy(lt, 1); + + sprintf(buf, "light%03d", ltidx++); + set_light_name(lt, buf); + + return lt; +} + +void free_light(struct light *lt) +{ + if(!lt) return; + free(lt->name); + free(lt); +} + +int set_light_name(struct light *lt, const char *name) +{ + char *tmp = strdup(name); + if(!tmp) return -1; + free(lt->name); + lt->name = tmp; + return 0; +} + +void set_light_color(struct light *lt, float r, float g, float b) +{ + cgm_vcons(<->orig_color, r, g, b); + lt->color = lt->orig_color; + cgm_vscale(<->color, lt->energy); +} + +void set_light_energy(struct light *lt, float e) +{ + lt->energy = e; + lt->color = lt->orig_color; + cgm_vscale(<->color, e); +} + +static struct material *default_material(void) +{ + static struct material defmtl; + + if(!defmtl.name) { + mtl_init(&defmtl); + mtl_set_name(&defmtl, "default_mtl"); + } + return &defmtl; +} diff --git a/src/scene.h b/src/scene.h index 7d4cd22..ce11dd5 100644 --- a/src/scene.h +++ b/src/scene.h @@ -19,6 +19,7 @@ along with this program. If not, see . #define SCENE_H_ #include "cgmath/cgmath.h" +#include "material.h" enum { OBJ_NULL, @@ -32,7 +33,8 @@ enum { cgm_vec3 pos, scale, pivot; \ cgm_quat rot; \ float xform[16], inv_xform[16]; \ - int xform_valid + int xform_valid; \ + struct material *mtl struct object { OBJ_COMMON_ATTR; @@ -49,8 +51,17 @@ struct csgnode { struct object *subobj; /* darr */ }; +struct light { + char *name; + cgm_vec3 pos; + cgm_vec3 color, orig_color; + float energy; +}; + struct scene { struct object **objects; /* darr */ + struct light **lights; + struct material **mtl; /* darr */ }; struct rayhit; /* declared in rt.h */ @@ -63,8 +74,21 @@ int scn_rm_object(struct scene *scn, int idx); int scn_num_objects(const struct scene *scn); int scn_object_index(const struct scene *scn, const struct object *obj); +int scn_add_material(struct scene *scn, struct material *mtl); +int scn_rm_material(struct scene *scn, struct material *mtl); +int scn_num_materials(const struct scene *scn); +int scn_material_index(const struct scene *scn, const struct material *mtl); +struct material *scn_find_material(const struct scene *scn, const char *mname); + +int scn_add_light(struct scene *scn, struct light *mtl); +int scn_rm_light(struct scene *scn, struct light *mtl); +int scn_num_lights(const struct scene *scn); +int scn_light_index(const struct scene *scn, const struct light *mtl); +struct light *scn_find_light(const struct scene *scn, const char *mname); + int scn_intersect(const struct scene *scn, const cgm_ray *ray, struct rayhit *hit); +/* --- objects --- */ struct object *create_object(int type); void free_object(struct object *obj); @@ -72,4 +96,12 @@ int set_object_name(struct object *obj, const char *name); void calc_object_matrix(struct object *obj); +/* --- lights --- */ +struct light *create_light(void); +void free_light(struct light *lt); + +int set_light_name(struct light *lt, const char *name); +void set_light_color(struct light *lt, float r, float g, float b); +void set_light_energy(struct light *lt, float e); + #endif /* SCENE_H_ */ diff --git a/src/scr_mod.c b/src/scr_mod.c index 65c6384..d3cbb40 100644 --- a/src/scr_mod.c +++ b/src/scr_mod.c @@ -80,6 +80,7 @@ static void mdl_mouse(int bn, int press, int x, int y); static void mdl_motion(int x, int y); static void draw_object(struct object *obj); +static void setup_material(struct material *mtl); static void draw_grid(void); static void tbn_callback(rtk_widget *w, void *cls); @@ -87,6 +88,7 @@ static void act_settool(int tidx); static void act_addobj(void); static void act_rmobj(void); +static void fix_rect(rtk_rect *rect); static void draw_rband(void); static void moveobj(struct object *obj, int px0, int py0, int px1, int py1); @@ -185,6 +187,8 @@ static int mdl_start(void) gaw_enable(GAW_CULL_FACE); gaw_enable(GAW_LIGHTING); gaw_enable(GAW_LIGHT0); + + rend_pan(0, -TOOLBAR_HEIGHT); return 0; } @@ -212,10 +216,10 @@ static void mdl_display(void) draw_grid(); - gaw_mtl_diffuse(0.5, 0.5, 0.5, 1); - num = scn_num_objects(scn); for(i=0; iobjects[i]->mtl); + if(i == selobj) { gaw_zoffset(1); gaw_enable(GAW_POLYGON_OFFSET); @@ -276,6 +280,13 @@ static void draw_object(struct object *obj) gaw_pop_matrix(); } +static void setup_material(struct material *mtl) +{ + gaw_mtl_diffuse(mtl->kd.x, mtl->kd.y, mtl->kd.z, 1.0f); + gaw_mtl_specular(mtl->ks.x, mtl->ks.y, mtl->ks.z, mtl->shin); + gaw_mtl_emission(mtl->ke.x, mtl->ke.y, mtl->ke.z); +} + static void draw_grid(void) { gaw_save(); @@ -376,6 +387,7 @@ static void mdl_mouse(int bn, int press, int x, int y) } rendering = 1; rend_size(win_width, win_height); + fix_rect(&rband); rend_begin(rband.x, rband.y, rband.width, rband.height); } @@ -521,10 +533,9 @@ static void act_rmobj(void) } } -static void draw_rband(void) +static void fix_rect(rtk_rect *rect) { - int i, x, y, w, h; - uint32_t *fbptr, *bptr; + int x, y, w, h; x = rband.x; y = rband.y; @@ -542,17 +553,32 @@ static void draw_rband(void) h = rband.height; } - fbptr = framebuf + y * win_width + x; - bptr = fbptr + win_width * (h - 1); + rect->x = x; + rect->y = y; + rect->width = w; + rect->height = h; +} + +static void draw_rband(void) +{ + int i; + rtk_rect rect; + uint32_t *fbptr, *bptr; + + rect = rband; + fix_rect(&rect); + + fbptr = framebuf + rect.y * win_width + rect.x; + bptr = fbptr + win_width * (rect.height - 1); - for(i=0; i + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include "texture.h" +#include "geom.h" +#include "imago2.h" +#include "logger.h" +#include "sizeint.h" +#include "util.h" + +static cgm_vec3 lookup_pixmap(const struct texture *btex, const struct rayhit *hit); +static cgm_vec3 lookup_chess(const struct texture *btex, const struct rayhit *hit); +static cgm_vec3 lookup_fbm2d(const struct texture *btex, const struct rayhit *hit); +static cgm_vec3 lookup_fbm3d(const struct texture *btex, const struct rayhit *hit); +static cgm_vec3 lookup_marble2d(const struct texture *btex, const struct rayhit *hit); +static cgm_vec3 lookup_marble3d(const struct texture *btex, const struct rayhit *hit); + +static const cgm_vec3 (*lookup[])(const struct texture*, const struct rayhit*) = { + lookup_pixmap, + lookup_chess, + lookup_fbm2d, + lookup_fbm3d, + lookup_marble2d, + lookup_marble3d +}; + +static const char *defname_fmt[] = { + "pixmap%03d", "chess%03d", + "fbm%03d", "sfbm%03d", + "marble%03d", "smarble%03d" +}; + +struct texture *create_texture(int type) +{ + struct texture *tex; + struct tex_pixmap *tpix; + struct tex_chess *tchess; + struct tex_fbm *tfbm; + static int texidx; + char namebuf[64]; + + switch(type) { + case TEX_PIXMAP: + if(!(tpix = malloc(sizeof *tpix))) { + goto fail; + } + tex = (struct texture*)tpix; + tpix->img = 0; + break; + + case TEX_CHESS: + if(!(tchess = malloc(sizeof *tchess))) { + goto fail; + } + tex = (struct texture*)tchess; + cgm_vcons(tchess->color, 0, 0, 0); + cgm_vcons(tchess->color + 1, 1, 1, 1); + break; + + case TEX_FBM2D: + case TEX_FBM3D: + if(!(tfbm = malloc(sizeof *tfbm))) { + goto fail; + } + tex = (struct texture*)tfbm; + tfbm->octaves = 1; + cgm_vcons(tfbm->color, 0, 0, 0); + cgm_vcons(tfbm->color + 1, 1, 1, 1); + break; + + default: + errormsg("tried to allocate invalid texture type (%d)\n", type); + return 0; + } + + tex->type = type; + tex->name = 0; + cgm_vcons(&tex->offs, 0, 0, 0); + cgm_vcons(&tex->scale, 1, 1, 1); + tex->lookup = lookup[type]; + + sprintf(namebuf, defname_fmt[type], texidx++); + tex_set_name(tex, namebuf); + return tex; + +fail: + errormsg("failed to allocate texture\n"); + return 0; +} + +void free_texture(struct texture *tex) +{ + if(!tex) return; + free(tex->name); + free(tex); +} + +void tex_set_name(struct texture *tex, const char *name) +{ + char *tmp = strdup(name); + if(!tmp) return; + free(tex->name); + tex->name = tmp; +} + +#define XFORM_UV(tex, u, v) \ + do { \ + u *= (tex)->scale.x + (tex)->offs.x; \ + v *= (tex)->scale.y + (tex)->offs.y; \ + } while(0) + +#define XFORM_UVW(tex, u, v, w) \ + do { \ + u *= (tex)->scale.x + (tex)->offs.x; \ + v *= (tex)->scale.y + (tex)->offs.y; \ + w *= (tex)->scale.z * (tex)->offs.z; \ + } while(0) + +static cgm_vec3 lookup_pixmap(const struct texture *btex, const struct rayhit *hit) +{ + struct tex_pixmap *tex = (struct tex_pixmap*)btex; + int px, py, twidth, theight; + int r, g, b; + uint32_t texel; + float u = hit->uv.x; + float v = hit->uv.y; + + twidth = tex->img->width; + theight = tex->img->height; + + XFORM_UV(tex, u, v); + + px = cround64((float)twidth * u) % twidth; + py = cround64((float)theight * v) % theight; + if(px < 0) px += twidth; + if(py < 0) py += theight; + + texel = ((uint32_t*)tex->img->pixels)[py * twidth + px]; + r = texel & 0xff; + g = (texel >> 8) & 0xff; + b = (texel >> 16) & 0xff; + + return cgm_vvec(r / 255.0f, g / 255.0f, b / 255.0f); +} + +static cgm_vec3 lookup_chess(const struct texture *btex, const struct rayhit *hit) +{ + struct tex_chess *tex = (struct tex_chess*)btex; + int cx, cy, chess; + float u = hit->uv.x; + float v = hit->uv.y; + + XFORM_UV(tex, u, v); + + cx = cround64(u) & 1; + cy = cround64(v) & 1; + chess = cx ^ cy; + return tex->color[chess]; +} + +static cgm_vec3 lookup_fbm2d(const struct texture *btex, const struct rayhit *hit) +{ + return cgm_vvec(1, 0, 0); /* TODO */ +} + +static cgm_vec3 lookup_fbm3d(const struct texture *btex, const struct rayhit *hit) +{ + return cgm_vvec(1, 0, 0); /* TODO */ +} + +static cgm_vec3 lookup_marble2d(const struct texture *btex, const struct rayhit *hit) +{ + return cgm_vvec(1, 0, 0); /* TODO */ +} + +static cgm_vec3 lookup_marble3d(const struct texture *btex, const struct rayhit *hit) +{ + return cgm_vvec(1, 0, 0); /* TODO */ +} diff --git a/src/texture.h b/src/texture.h new file mode 100644 index 0000000..3ceefc7 --- /dev/null +++ b/src/texture.h @@ -0,0 +1,66 @@ +/* +RetroRay - integrated standalone vintage modeller/renderer +Copyright (C) 2023 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef TEXTURE_H_ +#define TEXTURE_H_ + +#include "cgmath/cgmath.h" +#include "imago2.h" + +struct rayhit; + +enum { + TEX_PIXMAP, + TEX_CHESS, + TEX_FBM2D, + TEX_FBM3D, + TEX_MARBLE2D, + TEX_MARBLE3D +}; + +#define TEX_COMMON_ATTR \ + int type; \ + char *name; \ + cgm_vec3 offs, scale; \ + cgm_vec3 (*lookup)(const struct texture*, const struct rayhit*) + +struct texture { + TEX_COMMON_ATTR; +}; + +struct tex_pixmap { + TEX_COMMON_ATTR; + struct img_pixmap *img; +}; + +struct tex_chess { + TEX_COMMON_ATTR; + cgm_vec3 color[2]; +}; + +struct tex_fbm { + TEX_COMMON_ATTR; + int octaves; + cgm_vec3 color[2]; +}; + +struct texture *create_texture(int type); +void free_texture(struct texture *tex); + +void tex_set_name(struct texture *tex, const char *name); + +#endif /* TEXTURE_H_ */