}
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];
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);
}
G3D_LIGHT3 = 0x0040,
G3D_TEXTURE = 0x0080,
G3D_BLEND = 0x0100,
+ G3D_TEXTURE_GEN = 0x0200,
G3D_ALL = 0x7fffffff
};
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);
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "demo.h"
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",
};
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) {
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;
}
{
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);
static void draw(void)
{
+ float t = (float)time_msec / 16.0f;
update();
g3d_matrix_mode(G3D_MODELVIEW);
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;
+}
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;
{
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");
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");
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;
int i, j;
int nfaces, uverts, vverts;
struct g3d_vertex *vptr;
- int16_t *iptr;
+ uint16_t *iptr;
mesh->prim = G3D_QUADS;
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);
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);
#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);
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))) {
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;
goto err;
}
} else {
- uint16_t idx = dynarr_size(mesh->varr);
+ uint16_t newidx = dynarr_size(mesh->varr);
struct g3d_vertex v;
struct facevertex *newfv;
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;
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;
}
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;
}
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;