envmap, fake phong texture generation, and more
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 17 Feb 2018 08:08:42 +0000 (10:08 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 17 Feb 2018 08:08:42 +0000 (10:08 +0200)
src/3dgfx.c
src/3dgfx.h
src/infcubes.c
src/mesh.c
src/mesh.h
src/meshload.c

index 673122d..3999747 100644 (file)
@@ -396,7 +396,7 @@ void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size)
 }
 
 void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
-               const int16_t *iarr, int iarr_size)
+               const uint16_t *iarr, int iarr_size)
 {
        int i, j, nfaces;
        struct pvertex pv[16];
@@ -423,6 +423,10 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
                        if(st->opt & G3D_LIGHTING) {
                                shade(v + i);
                        }
+                       if(st->opt & G3D_TEXTURE_GEN) {
+                               v[i].u = v[i].nx * 0.5 + 0.5;
+                               v[i].v = v[i].ny * 0.5 + 0.5;
+                       }
                        xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x);
                }
 
index 94884ca..fd7f625 100644 (file)
@@ -28,6 +28,7 @@ enum {
        G3D_LIGHT3              = 0x0040,
        G3D_TEXTURE             = 0x0080,
        G3D_BLEND               = 0x0100,
+       G3D_TEXTURE_GEN = 0x0200,
 
        G3D_ALL = 0x7fffffff
 };
@@ -96,7 +97,7 @@ void g3d_set_texture(int xsz, int ysz, void *pixels);
 
 void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size);
 void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
-               const int16_t *iarr, int iarr_size);
+               const uint16_t *iarr, int iarr_size);
 
 void g3d_begin(int prim);
 void g3d_end(void);
index 36225f9..6ce74af 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <math.h>
 #include "demo.h"
@@ -14,7 +15,8 @@ static int init(void);
 static void destroy(void);
 static void start(long trans_time);
 static void draw(void);
-static void draw_cube(float sz);
+static int gen_phong_tex(struct pimage *img, int xsz, int ysz, float sexp,
+               int dr, int dg, int db, int sr, int sg, int sb);
 
 static struct screen scr = {
        "infcubes",
@@ -25,31 +27,37 @@ static struct screen scr = {
 };
 
 static float cam_theta = -29, cam_phi = 35;
-static float cam_dist = 5;
+static float cam_dist = 6;
 static struct pimage tex_inner, tex_outer;
-static struct g3d_mesh mesh_cube;
+static struct g3d_mesh mesh_cube, mesh_cube2;
 
 struct screen *infcubes_screen(void)
 {
        return &scr;
 }
 
+#define PHONG_TEX_SZ   128
 
 static int init(void)
 {
+       static const float scalemat[16] = {-6, 0, 0, 0, 0, -6, 0, 0, 0, 0, -6, 0, 0, 0, 0, 1};
+       /*
        if(!(tex_inner.pixels = img_load_pixels("data/crate.jpg", &tex_inner.width,
                                        &tex_inner.height, IMG_FMT_RGB24))) {
                fprintf(stderr, "infcubes: failed to load crate texture\n");
                return -1;
        }
        convimg_rgb24_rgb16(tex_inner.pixels, (unsigned char*)tex_inner.pixels, tex_inner.width, tex_inner.height);
+       */
+       gen_phong_tex(&tex_inner, PHONG_TEX_SZ, PHONG_TEX_SZ, 5.0f, 10, 50, 92, 192, 192, 192);
 
-       if(!(tex_outer.pixels = img_load_pixels("data/steelfrm.jpg", &tex_outer.width,
+       if(!(tex_outer.pixels = img_load_pixels("data/refmap1.jpg", &tex_outer.width,
                                        &tex_outer.height, IMG_FMT_RGB24))) {
-               fprintf(stderr, "infcubes: failed to load ornamental texture\n");
+               fprintf(stderr, "infcubes: failed to load outer texture\n");
                return -1;
        }
        convimg_rgb24_rgb16(tex_outer.pixels, (unsigned char*)tex_outer.pixels, tex_outer.width, tex_outer.height);
+       /*gen_phong_tex(&tex_outer, PHONG_TEX_SZ, PHONG_TEX_SZ, 5.0f, 50, 50, 50, 255, 255, 255);*/
 
        /*
        if(gen_cube_mesh(&mesh_cube, 1.0f, 3) == -1) {
@@ -59,6 +67,11 @@ static int init(void)
        if(load_mesh(&mesh_cube, "data/bevelbox.obj") == -1) {
                return -1;
        }
+       if(load_mesh(&mesh_cube2, "data/bevelbox.obj") == -1) {
+               return -1;
+       }
+       apply_mesh_xform(&mesh_cube2, scalemat);
+       normalize_mesh_normals(&mesh_cube2);
        return 0;
 }
 
@@ -71,7 +84,7 @@ static void start(long trans_time)
 {
        g3d_matrix_mode(G3D_PROJECTION);
        g3d_load_identity();
-       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
+       g3d_perspective(70.0, 1.3333333, 0.5, 100.0);
 
        g3d_enable(G3D_CULL_FACE);
        g3d_disable(G3D_LIGHTING);
@@ -85,6 +98,7 @@ static void update(void)
 
 static void draw(void)
 {
+       float t = (float)time_msec / 16.0f;
        update();
 
        g3d_matrix_mode(G3D_MODELVIEW);
@@ -99,15 +113,61 @@ static void draw(void)
        memset(fb_pixels, 0, fb_width * fb_height * 2);
 
        g3d_polygon_mode(G3D_TEX);
+       g3d_enable(G3D_TEXTURE_GEN);
 
        g3d_push_matrix();
-       g3d_scale(-6, -6, -6);
+       g3d_rotate(t, 1, 0, 0);
+       g3d_rotate(t, 0, 1, 0);
        g3d_set_texture(tex_outer.width, tex_outer.height, tex_outer.pixels);
-       draw_mesh(&mesh_cube);
+       draw_mesh(&mesh_cube2);
        g3d_pop_matrix();
 
        g3d_set_texture(tex_inner.width, tex_inner.height, tex_inner.pixels);
        draw_mesh(&mesh_cube);
+       g3d_disable(G3D_TEXTURE_GEN);
 
        swap_buffers(fb_pixels);
 }
+
+static int gen_phong_tex(struct pimage *img, int xsz, int ysz, float sexp,
+               int dr, int dg, int db, int sr, int sg, int sb)
+{
+       int i, j;
+       float u, v, du, dv;
+       uint16_t *pix;
+
+       if(!(img->pixels = malloc(xsz * ysz * sizeof *pix))) {
+               return -1;
+       }
+       pix = img->pixels;
+
+       du = 2.0f / (float)(xsz - 1);
+       dv = 2.0f / (float)(ysz - 1);
+
+       v = -1.0f;
+       for(i=0; i<ysz; i++) {
+               u = -1.0f;
+               for(j=0; j<xsz; j++) {
+                       float d = sqrt(u * u + v * v);
+                       float val = pow(cos(d * M_PI / 2.0f), sexp);
+                       int ival = abs(val * 255.0f);
+
+                       int r = dr + ival * sr / 256;
+                       int g = dg + ival * sg / 256;
+                       int b = db + ival * sb / 256;
+
+                       if(r > 255) r = 255;
+                       if(g > 255) g = 255;
+                       if(b > 255) b = 255;
+
+                       *pix++ = PACK_RGB16(r, g, b);
+
+                       u += du;
+               }
+               v += dv;
+       }
+
+       img->width = xsz;
+       img->height = ysz;
+       return 0;
+}
index c4c8a87..bde8266 100644 (file)
@@ -31,8 +31,8 @@ static int zsort_cmp(const void *aptr, const void *bptr)
 
 static int zsort_indexed_cmp(const void *aptr, const void *bptr)
 {
-       const int16_t *a = (const int16_t*)aptr;
-       const int16_t *b = (const int16_t*)bptr;
+       const uint16_t *a = (const uint16_t*)aptr;
+       const uint16_t *b = (const uint16_t*)bptr;
 
        const float *m = zsort_cls.xform;
 
@@ -100,7 +100,7 @@ int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb)
 {
        int i, new_vcount, new_icount;
        void *tmp;
-       int16_t *iptr;
+       uint16_t *iptr;
 
        if(ma->prim != mb->prim) {
                fprintf(stderr, "append_mesh failed, primitive mismatch\n");
@@ -173,7 +173,7 @@ int indexify_mesh(struct g3d_mesh *mesh)
        int i, j, nfaces, max_icount, idx;
        int out_vcount = 0;
        struct g3d_vertex *vin, *vout;
-       int16_t *iout;
+       uint16_t *iout;
 
        if(mesh->iarr) {
                fprintf(stderr, "indexify_mesh failed: already indexed\n");
@@ -209,13 +209,28 @@ int indexify_mesh(struct g3d_mesh *mesh)
        return 0;
 }
 
+void normalize_mesh_normals(struct g3d_mesh *mesh)
+{
+       int i;
+       struct g3d_vertex *v = mesh->varr;
+
+       for(i=0; i<mesh->vcount; i++) {
+               float mag = sqrt(v->nx * v->nx + v->ny * v->ny + v->nz * v->nz);
+               float s = (mag == 0.0f) ? 1.0f : 1.0f / mag;
+               v->nx *= s;
+               v->ny *= s;
+               v->nz *= s;
+               ++v;
+       }
+}
+
 int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int vsub)
 {
        int i, j;
        int nfaces, nverts, nidx, uverts, vverts;
        float x, y, u, v, du, dv;
        struct g3d_vertex *vptr;
-       int16_t *iptr;
+       uint16_t *iptr;
 
        if(usub < 1) usub = 1;
        if(vsub < 1) vsub = 1;
@@ -341,7 +356,7 @@ int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, in
        int i, j;
        int nfaces, uverts, vverts;
        struct g3d_vertex *vptr;
-       int16_t *iptr;
+       uint16_t *iptr;
 
        mesh->prim = G3D_QUADS;
 
index 704c492..eb0256d 100644 (file)
@@ -6,11 +6,12 @@
 struct g3d_mesh {
        int prim;
        struct g3d_vertex *varr;
-       int16_t *iarr;
+       uint16_t *iarr;
        int vcount, icount;
 };
 
 int load_mesh(struct g3d_mesh *mesh, const char *fname);
+int save_mesh(struct g3d_mesh *mesh, const char *fname);
 
 void zsort_mesh(struct g3d_mesh *mesh);
 void draw_mesh(struct g3d_mesh *mesh);
@@ -19,6 +20,8 @@ void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform);
 int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb);
 int indexify_mesh(struct g3d_mesh *mesh);
 
+void normalize_mesh_normals(struct g3d_mesh *mesh);
+
 int gen_plane_mesh(struct g3d_mesh *mesh, float width, float height, int usub, int vsub);
 int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub);
 int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub);
index 61cf128..7e3bd29 100644 (file)
@@ -1,16 +1,21 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <assert.h>
 #include "mesh.h"
 #include "dynarr.h"
 #include "rbtree.h"
 #include "vmath.h"
 #include "3dgfx.h"
+#include "util.h"
 
+struct vertex_pos_color {
+       float x, y, z;
+       float r, g, b, a;
+};
 
 struct facevertex {
        int vidx, tidx, nidx;
-       int myidx;
 };
 
 static char *clean_line(char *s);
@@ -18,20 +23,31 @@ static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int num
 static int cmp_facevert(const void *ap, const void *bp);
 static void free_rbnode_key(struct rbnode *n, void *cls);
 
-
+/* merge of different indices per attribute happens during face processing.
+ *
+ * A triplet of (vertex index/texcoord index/normal index) is used as the key
+ * to search in a balanced binary search tree for vertex buffer index assigned
+ * to the same triplet if it has been encountered before. That index is
+ * appended to the index buffer.
+ *
+ * If a particular triplet has not been encountered before, a new g3d_vertex is
+ * appended to the vertex buffer. The index of this new vertex is appended to
+ * the index buffer, and also inserted into the tree for future searches.
+ */
 int load_mesh(struct g3d_mesh *mesh, const char *fname)
 {
        int i, line_num = 0, result = -1;
        int found_quad = 0;
-       FILE *fp;
+       FILE *fp = 0;
        char buf[256];
-       vec3_t *varr = 0, *narr = 0;
+       struct vertex_pos_color *varr = 0;
+       vec3_t *narr = 0;
        vec2_t *tarr = 0;
-       struct rbtree *rbtree;
+       struct rbtree *rbtree = 0;
 
        if(!(fp = fopen(fname, "rb"))) {
                fprintf(stderr, "load_mesh: failed to open file: %s\n", fname);
-               return -1;
+               goto err;
        }
 
        if(!(rbtree = rb_create(cmp_facevert))) {
@@ -62,11 +78,24 @@ int load_mesh(struct g3d_mesh *mesh, const char *fname)
                case 'v':
                        if(isspace(line[1])) {
                                /* vertex */
-                               vec3_t v;
-                               if(sscanf(line + 2, "%f %f %f", &v.x, &v.y, &v.z) != 3) {
+                               struct vertex_pos_color v;
+                               int num;
+
+                               num = sscanf(line + 2, "%f %f %f %f %f %f %f", &v.x, &v.y, &v.z, &v.x, &v.y, &v.z, &v.a);
+                               if(num < 3) {
                                        fprintf(stderr, "%s:%d: invalid vertex definition: \"%s\"\n", fname, line_num, line);
                                        goto err;
                                }
+                               switch(num) {
+                               case 3:
+                                       v.r = 1.0f;
+                               case 4:
+                                       v.g = 1.0f;
+                               case 5:
+                                       v.b = 1.0f;
+                               case 6:
+                                       v.a = 1.0f;
+                               }
                                if(!(varr = dynarr_push(varr, &v))) {
                                        fprintf(stderr, "load_mesh: failed to resize vertex buffer\n");
                                        goto err;
@@ -125,7 +154,7 @@ int load_mesh(struct g3d_mesh *mesh, const char *fname)
                                                        goto err;
                                                }
                                        } else {
-                                               uint16_t idx = dynarr_size(mesh->varr);
+                                               uint16_t newidx = dynarr_size(mesh->varr);
                                                struct g3d_vertex v;
                                                struct facevertex *newfv;
 
@@ -133,6 +162,10 @@ int load_mesh(struct g3d_mesh *mesh, const char *fname)
                                                v.y = varr[fv.vidx].y;
                                                v.z = varr[fv.vidx].z;
                                                v.w = 1.0f;
+                                               v.r = cround64(varr[fv.vidx].r * 255.0);
+                                               v.g = cround64(varr[fv.vidx].g * 255.0);
+                                               v.b = cround64(varr[fv.vidx].b * 255.0);
+                                               v.a = cround64(varr[fv.vidx].a * 255.0);
                                                if(fv.tidx >= 0) {
                                                        v.u = tarr[fv.tidx].x;
                                                        v.v = tarr[fv.tidx].y;
@@ -148,13 +181,12 @@ int load_mesh(struct g3d_mesh *mesh, const char *fname)
                                                        v.nx = v.ny = 0.0f;
                                                        v.nz = 1.0f;
                                                }
-                                               v.r = v.g = v.b = v.a = 255;
 
                                                if(!(mesh->varr = dynarr_push(mesh->varr, &v))) {
                                                        fprintf(stderr, "load_mesh: failed to resize combined vertex array\n");
                                                        goto err;
                                                }
-                                               if(!(mesh->iarr = dynarr_push(mesh->iarr, &idx))) {
+                                               if(!(mesh->iarr = dynarr_push(mesh->iarr, &newidx))) {
                                                        fprintf(stderr, "load_mesh: failed to resize index array\n");
                                                        goto err;
                                                }
@@ -162,7 +194,7 @@ int load_mesh(struct g3d_mesh *mesh, const char *fname)
                                                if((newfv = malloc(sizeof *newfv))) {
                                                        *newfv = fv;
                                                }
-                                               if(!newfv || rb_insert(rbtree, newfv, &idx) == -1) {
+                                               if(!newfv || rb_insert(rbtree, newfv, (void*)(intptr_t)newidx) == -1) {
                                                        fprintf(stderr, "load_mesh: failed to insert facevertex to the binary search tree\n");
                                                        goto err;
                                                }
@@ -200,6 +232,46 @@ err:
        return result;
 }
 
+int save_mesh(struct g3d_mesh *mesh, const char *fname)
+{
+       int i, fvcount;
+       FILE *fp;
+
+       if(!(fp = fopen(fname, "wb"))) {
+               fprintf(stderr, "save_mesh: failed to open %s for writing\n", fname);
+               return -1;
+       }
+       fprintf(fp, "# Wavefront OBJ file shoved in your FACE by Mindlapse. Deal with it\n");
+
+       for(i=0; i<mesh->vcount; i++) {
+               struct g3d_vertex *v = mesh->varr + i;
+               fprintf(fp, "v %f %f %f %f %f %f %f\n", v->x, v->y, v->z, v->r / 255.0f, v->g / 255.0f,
+                               v->b / 255.0f, v->a / 255.0f);
+       }
+       for(i=0; i<mesh->vcount; i++) {
+               fprintf(fp, "vn %f %f %f\n", mesh->varr[i].nx, mesh->varr[i].ny, mesh->varr[i].nz);
+       }
+       for(i=0; i<mesh->vcount; i++) {
+               fprintf(fp, "vt %f %f\n", mesh->varr[i].u, mesh->varr[i].v);
+       }
+
+       fvcount = mesh->prim;
+       for(i=0; i<mesh->icount; i++) {
+               int idx = mesh->iarr[i] + 1;
+
+               if(fvcount == mesh->prim) {
+                       fprintf(fp, "\nf");
+                       fvcount = 0;
+               }
+               fprintf(fp, " %d/%d/%d", idx, idx, idx);
+               ++fvcount;
+       }
+       fprintf(fp, "\n");
+
+       fclose(fp);
+       return 0;
+}
+
 static char *clean_line(char *s)
 {
        char *end;