first render
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 18 Jun 2023 21:37:52 +0000 (00:37 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 18 Jun 2023 21:37:52 +0000 (00:37 +0300)
13 files changed:
Makefile
libs/cgmath/cgmath.h
libs/cgmath/cgmvec3.inl
src/geom.c
src/material.c [new file with mode: 0644]
src/material.h [new file with mode: 0644]
src/rend.c
src/rend.h
src/scene.c
src/scene.h
src/scr_mod.c
src/texture.c [new file with mode: 0644]
src/texture.h [new file with mode: 0644]

index 87a5ebe..94e655d 100644 (file)
--- 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
 
index 9f99361..b343c73 100644 (file)
@@ -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);
index 874d0fc..8191c63 100644 (file)
@@ -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;
index 1a89ccd..3be5e07 100644 (file)
@@ -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 (file)
index 0000000..177ac68
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+#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 (file)
index 0000000..15bccd3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#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_ */
index c88277f..8547ca6 100644 (file)
@@ -22,19 +22,30 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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; i+=ystep) {
                h = ystep;
                if(i + h > rheight) h = rheight - i;
 
                for(j=0; j<rwidth; j+=xstep) {
-                       primray(&ray, rx + j, ry + i);
+                       primray(&ray, rx + j + pan_x, ry + i + pan_y);
                        ray_trace(&ray, max_ray_depth, &color);
 
+                       if(color.x > 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; i<num_lights; i++) {
+               lt = scn->lights[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;
 }
index 61d5b5f..33c5963 100644 (file)
@@ -25,11 +25,13 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 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);
 
index 48279cc..36c9fba 100644 (file)
@@ -22,6 +22,8 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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; i<darr_size(scn->lights); i++) {
+               free_light(scn->lights[i]);
+       }
+       darr_free(scn->lights);
+
+       for(i=0; i<darr_size(scn->mtl); 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; i<num_mtl; i++) {
+               if(scn->mtl[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; i<num_mtl; i++) {
+               if(strcmp(scn->mtl[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; i<num_lights; i++) {
+               if(scn->lights[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; i<num_lights; i++) {
+               if(strcmp(scn->lights[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(&lt->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(&lt->orig_color, r, g, b);
+       lt->color = lt->orig_color;
+       cgm_vscale(&lt->color, lt->energy);
+}
+
+void set_light_energy(struct light *lt, float e)
+{
+       lt->energy = e;
+       lt->color = lt->orig_color;
+       cgm_vscale(&lt->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;
+}
index 7d4cd22..ce11dd5 100644 (file)
@@ -19,6 +19,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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_ */
index 65c6384..d3cbb40 100644 (file)
@@ -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; i<num; i++) {
+               setup_material(scn->objects[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<w; i++) {
+       for(i=0; i<rect.width; i++) {
                fbptr[i] ^= 0xffffff;
                bptr[i] ^= 0xffffff;
        }
        fbptr += win_width;
-       for(i=0; i<h-2; i++) {
+       for(i=0; i<rect.height-2; i++) {
                fbptr[0] ^= 0xffffff;
-               fbptr[w - 1] ^= 0xffffff;
+               fbptr[rect.width - 1] ^= 0xffffff;
                fbptr += win_width;
        }
 }
diff --git a/src/texture.c b/src/texture.c
new file mode 100644 (file)
index 0000000..93d4b2f
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#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 (file)
index 0000000..3ceefc7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#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_ */