dbf_amiga

changeset 0:87dfe0e10235 tip

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 31 Aug 2015 07:38:37 +0300
parents
children
files .hgignore Makefile sdr/shadow-notex.p.glsl sdr/shadow.p.glsl sdr/shadow.v.glsl src/game.cc src/game.h src/geom.cc src/geom.h src/light.cc src/light.h src/main.cc src/mesh.cc src/mesh.h src/meshgen.cc src/meshgen.h src/object.cc src/object.h src/opengl.c src/opengl.h src/opt.cc src/opt.h src/pnoise.cc src/pnoise.h src/revol.cc src/revol.h src/room.cc src/room.h src/scene.cc src/scene.h src/scnload.h src/scnload_obj.cc src/sdr.c src/sdr.h src/shader.cc src/shader.h src/shadow.cc src/shadow.h src/snode.cc src/snode.h
diffstat 40 files changed, 5310 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Mon Aug 31 07:38:37 2015 +0300
     1.3 @@ -0,0 +1,5 @@
     1.4 +^amiga$
     1.5 +\.o$
     1.6 +\.swp$
     1.7 +\.d$
     1.8 +^data/
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Mon Aug 31 07:38:37 2015 +0300
     2.3 @@ -0,0 +1,45 @@
     2.4 +ccsrc = $(wildcard src/*.cc)
     2.5 +csrc = $(wildcard src/*.c)
     2.6 +obj = $(csrc:.c=.o) $(ccsrc:.cc=.o)
     2.7 +dep = $(obj:.o=.d)
     2.8 +
     2.9 +bin = amiga
    2.10 +
    2.11 +sys = $(shell uname -s)
    2.12 +
    2.13 +warn = -pedantic -Wall -Wno-format-extra-args
    2.14 +dbg = -g
    2.15 +opt = -O0
    2.16 +
    2.17 +CFLAGS = $(warn) $(dbg) $(opt)
    2.18 +CXXFLAGS = $(CFLAGS)
    2.19 +LDFLAGS = $(libgl) -lvmath -limago -lpsys -lanim -lm
    2.20 +
    2.21 +ifeq ($(sys), Darwin)
    2.22 +	libgl = -framework OpenGL -framework GLUT -lGLEW
    2.23 +	warn += -Wno-deprecated-declarations
    2.24 +else
    2.25 +	libgl = -lGL -lGLU -lglut -lGLEW
    2.26 +endif
    2.27 +
    2.28 +.PHONY: all
    2.29 +all: $(bin)
    2.30 +
    2.31 +$(bin): $(obj)
    2.32 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    2.33 +
    2.34 +-include $(dep)
    2.35 +
    2.36 +%.d: %.c
    2.37 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.38 +
    2.39 +%.d: %.cc
    2.40 +	@$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.41 +
    2.42 +.PHONY: clean
    2.43 +clean:
    2.44 +	rm -f $(obj) $(bin)
    2.45 +
    2.46 +.PHONY: cleandep
    2.47 +cleandep:
    2.48 +	rm -f $(dep)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/sdr/shadow-notex.p.glsl	Mon Aug 31 07:38:37 2015 +0300
     3.3 @@ -0,0 +1,30 @@
     3.4 +/* vi: set ft=glsl */
     3.5 +uniform sampler2DShadow shadowmap;
     3.6 +
     3.7 +varying vec3 vdir, ldir, normal;
     3.8 +varying vec4 shadow_tc;
     3.9 +
    3.10 +#define KD gl_FrontMaterial.diffuse.rgb
    3.11 +#define KS gl_FrontMaterial.specular.rgb
    3.12 +#define SPOW gl_FrontMaterial.shininess
    3.13 +
    3.14 +void main()
    3.15 +{
    3.16 +	float shadow = shadow2DProj(shadowmap, shadow_tc).x;
    3.17 +	shadow = min(shadow + 1.0 - step(0.0, shadow_tc.w), 1.0);
    3.18 +
    3.19 +	vec3 n = normalize(normal);
    3.20 +	vec3 v = normalize(vdir);
    3.21 +	vec3 l = normalize(ldir);
    3.22 +	vec3 h = normalize(l + v);
    3.23 +
    3.24 +	float ndotl = max(dot(n, l), 0.0);
    3.25 +	float ndoth = max(dot(n, h), 0.0);
    3.26 +
    3.27 +	vec3 diffuse = KD * gl_LightSource[0].diffuse.rgb * ndotl;
    3.28 +	vec3 specular = KS * gl_LightSource[0].specular.rgb * pow(ndoth, SPOW);
    3.29 +
    3.30 +	vec3 ambient = gl_LightModel.ambient.rgb * KD;
    3.31 +	gl_FragColor.rgb = ambient + (diffuse + specular) * shadow;
    3.32 +	gl_FragColor.a = gl_FrontMaterial.diffuse.a;
    3.33 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/sdr/shadow.p.glsl	Mon Aug 31 07:38:37 2015 +0300
     4.3 @@ -0,0 +1,32 @@
     4.4 +/* vi: set ft=glsl */
     4.5 +uniform sampler2D tex;
     4.6 +uniform sampler2DShadow shadowmap;
     4.7 +
     4.8 +varying vec3 vdir, ldir, normal;
     4.9 +varying vec4 shadow_tc;
    4.10 +
    4.11 +#define KD gl_FrontMaterial.diffuse.rgb
    4.12 +#define KS gl_FrontMaterial.specular.rgb
    4.13 +#define SPOW gl_FrontMaterial.shininess
    4.14 +
    4.15 +void main()
    4.16 +{
    4.17 +	float shadow = shadow2DProj(shadowmap, shadow_tc).x;
    4.18 +	vec4 texel = texture2D(tex, gl_TexCoord[0].st);
    4.19 +
    4.20 +	vec3 n = normalize(normal);
    4.21 +	vec3 v = normalize(vdir);
    4.22 +	vec3 l = normalize(ldir);
    4.23 +	vec3 h = normalize(l + v);
    4.24 +
    4.25 +	float ndotl = max(dot(n, l), 0.0);
    4.26 +	float ndoth = max(dot(n, h), 0.0);
    4.27 +
    4.28 +	vec3 albedo = KD * texel.rgb;
    4.29 +	vec3 diffuse = albedo * gl_LightSource[0].diffuse.rgb * ndotl;
    4.30 +	vec3 specular = KS * gl_LightSource[0].specular.rgb * pow(ndoth, SPOW);
    4.31 +
    4.32 +	vec3 ambient = gl_LightModel.ambient.rgb * albedo;
    4.33 +	gl_FragColor.rgb = ambient + (diffuse + specular) * shadow;
    4.34 +	gl_FragColor.a = gl_FrontMaterial.diffuse.a * texel.a;
    4.35 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/sdr/shadow.v.glsl	Mon Aug 31 07:38:37 2015 +0300
     5.3 @@ -0,0 +1,21 @@
     5.4 +varying vec3 vdir, ldir, normal;
     5.5 +varying vec4 shadow_tc;
     5.6 +
     5.7 +void main()
     5.8 +{
     5.9 +	gl_Position = ftransform();
    5.10 +
    5.11 +	vec3 vpos = (gl_ModelViewMatrix * gl_Vertex).xyz;
    5.12 +	normal = normalize(gl_NormalMatrix * gl_Normal);
    5.13 +	vdir = -vpos;
    5.14 +	ldir = gl_LightSource[0].position.xyz - vpos;
    5.15 +	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
    5.16 +
    5.17 +	mat4 offmat = mat4(0.5, 0.0, 0.0, 0.0,
    5.18 +			0.0, 0.5, 0.0, 0.0,
    5.19 +			0.0, 0.0, 0.5, 0.0,
    5.20 +			0.5, 0.5, 0.5, 1.0);
    5.21 +	mat4 tex_matrix = offmat * gl_TextureMatrix[1];
    5.22 +
    5.23 +	shadow_tc = tex_matrix * vec4(vpos, 1.0);
    5.24 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/game.cc	Mon Aug 31 07:38:37 2015 +0300
     6.3 @@ -0,0 +1,254 @@
     6.4 +#include <stdio.h>
     6.5 +#include <assert.h>
     6.6 +#include "opengl.h"
     6.7 +#include "game.h"
     6.8 +#include "sdr.h"
     6.9 +#include "shader.h"
    6.10 +#include "shadow.h"
    6.11 +#include "opt.h"
    6.12 +#include "mesh.h"
    6.13 +#include "scene.h"
    6.14 +
    6.15 +static void draw_scene();
    6.16 +
    6.17 +int win_width, win_height;
    6.18 +unsigned long cur_time;
    6.19 +bool dbg_wireframe;
    6.20 +int dbg_int;
    6.21 +
    6.22 +unsigned int sdr_shadow, sdr_shadow_notex;
    6.23 +
    6.24 +static float cam_theta, cam_phi = 23, cam_dist = 10;
    6.25 +static float cam_x, cam_y, cam_z;
    6.26 +static bool bnstate[8];
    6.27 +static int prev_x, prev_y;
    6.28 +
    6.29 +static unsigned int modkeys;
    6.30 +
    6.31 +static Scene *scn;
    6.32 +
    6.33 +
    6.34 +bool game_init()
    6.35 +{
    6.36 +	if(init_opengl() == -1) {
    6.37 +		return false;
    6.38 +	}
    6.39 +
    6.40 +	glEnable(GL_DEPTH_TEST);
    6.41 +	glEnable(GL_CULL_FACE);
    6.42 +	glEnable(GL_NORMALIZE);
    6.43 +	glEnable(GL_LIGHTING);
    6.44 +	glEnable(GL_LIGHT0);
    6.45 +
    6.46 +	float amb[] = {0.1, 0.1, 0.1, 1.0};
    6.47 +	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
    6.48 +
    6.49 +	if(glcaps.sep_spec) {
    6.50 +		glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
    6.51 +	}
    6.52 +	glEnable(GL_MULTISAMPLE);
    6.53 +
    6.54 +	if(!init_shadow(4096)) {
    6.55 +		fprintf(stderr, "failed to initialize shadowmaps\n");
    6.56 +		return false;
    6.57 +	}
    6.58 +	if(!(sdr_shadow = create_program_load("sdr/shadow.v.glsl", "sdr/shadow.p.glsl"))) {
    6.59 +		return false;
    6.60 +	}
    6.61 +	set_uniform_int(sdr_shadow, "tex", 0);
    6.62 +	set_uniform_int(sdr_shadow, "shadowmap", 1);
    6.63 +
    6.64 +	if(!(sdr_shadow_notex = create_program_load("sdr/shadow.v.glsl", "sdr/shadow-notex.p.glsl"))) {
    6.65 +		return false;
    6.66 +	}
    6.67 +	set_uniform_int(sdr_shadow_notex, "shadowmap", 1);
    6.68 +
    6.69 +	scn = new Scene;
    6.70 +	if(!scn->load("data/amiga.obj")) {
    6.71 +		return false;
    6.72 +	}
    6.73 +
    6.74 +	Mesh::use_custom_sdr_attr = false;
    6.75 +	assert(glGetError() == GL_NO_ERROR);
    6.76 +	return true;
    6.77 +}
    6.78 +
    6.79 +void game_cleanup()
    6.80 +{
    6.81 +	delete scn;
    6.82 +}
    6.83 +
    6.84 +void game_update(unsigned long time_msec)
    6.85 +{
    6.86 +	cur_time = time_msec;
    6.87 +}
    6.88 +
    6.89 +void game_display()
    6.90 +{
    6.91 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    6.92 +
    6.93 +	glMatrixMode(GL_MODELVIEW);
    6.94 +	glLoadIdentity();
    6.95 +	glTranslatef(0, 0.1, -cam_dist);
    6.96 +	glRotatef(cam_phi, 1, 0, 0);
    6.97 +	glRotatef(cam_theta, 0, 1, 0);
    6.98 +	glTranslatef(-cam_x, -cam_y, -cam_z);
    6.99 +
   6.100 +	float lpos[] = {-5, 10, 5, 1};
   6.101 +	glLightfv(GL_LIGHT0, GL_POSITION, lpos);
   6.102 +
   6.103 +	if(opt.shadows && sdr_shadow) {
   6.104 +		begin_shadow_pass(Vector3(lpos[0], lpos[1], lpos[2]), Vector3(0, 0, 0), 45);
   6.105 +		draw_scene();
   6.106 +		end_shadow_pass();
   6.107 +
   6.108 +		glActiveTexture(GL_TEXTURE1);
   6.109 +		glBindTexture(GL_TEXTURE_2D, get_shadow_tex());
   6.110 +
   6.111 +		glMatrixMode(GL_TEXTURE);
   6.112 +		Matrix4x4 shadow_matrix = get_shadow_matrix();
   6.113 +		glLoadTransposeMatrixf(shadow_matrix[0]);
   6.114 +
   6.115 +		glActiveTexture(GL_TEXTURE0);
   6.116 +		glMatrixMode(GL_MODELVIEW);
   6.117 +
   6.118 +		override_shader(sdr_shadow_notex);
   6.119 +		draw_scene();
   6.120 +		override_shader(0);
   6.121 +
   6.122 +		glActiveTexture(GL_TEXTURE1);
   6.123 +		glBindTexture(GL_TEXTURE_2D, 0);
   6.124 +		glActiveTexture(GL_TEXTURE0);
   6.125 +		glBindTexture(GL_TEXTURE_2D, 0);
   6.126 +	} else {
   6.127 +		draw_scene();
   6.128 +	}
   6.129 +}
   6.130 +
   6.131 +static void glmaterial(float r, float g, float b, float spec, float shin)
   6.132 +{
   6.133 +	float color[] = {r, g, b, 1};
   6.134 +	float scolor[] = {spec, spec, spec, 1};
   6.135 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
   6.136 +	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scolor);
   6.137 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shin);
   6.138 +}
   6.139 +
   6.140 +static void draw_scene()
   6.141 +{
   6.142 +	glmaterial(0.2, 0.2, 0.4, 0.0, 60.0);
   6.143 +	glBegin(GL_QUADS);
   6.144 +	glNormal3f(0, 1, 0);
   6.145 +	glVertex3f(-5, 0, 5);
   6.146 +	glVertex3f(5, 0, 5);
   6.147 +	glVertex3f(5, 0, -5);
   6.148 +	glVertex3f(-5, 0, -5);
   6.149 +	glEnd();
   6.150 +
   6.151 +	glPushMatrix();
   6.152 +	glTranslatef(0, 0.75, 0);
   6.153 +
   6.154 +	glmaterial(1.0, 0.4, 0.3, 0.8, 60.0);
   6.155 +	draw_teapot();
   6.156 +
   6.157 +	glPopMatrix();
   6.158 +
   6.159 +	scn->draw();
   6.160 +}
   6.161 +
   6.162 +
   6.163 +void game_reshape(int x, int y)
   6.164 +{
   6.165 +	glMatrixMode(GL_PROJECTION);
   6.166 +	glLoadIdentity();
   6.167 +	gluPerspective(45, (float)x / (float)y, 0.2, 200.0);
   6.168 +
   6.169 +	glViewport(0, 0, x, y);
   6.170 +}
   6.171 +
   6.172 +void game_keyboard(int bn, bool press)
   6.173 +{
   6.174 +	if(press) {
   6.175 +		switch(bn) {
   6.176 +		case 27:
   6.177 +			quit();
   6.178 +
   6.179 +		case 'd':
   6.180 +			scn->dump(stdout);
   6.181 +			break;
   6.182 +
   6.183 +		case 'w':
   6.184 +			dbg_wireframe = !dbg_wireframe;
   6.185 +			redisplay();
   6.186 +			break;
   6.187 +
   6.188 +		case 's':
   6.189 +			opt.shadows = !opt.shadows;
   6.190 +			redisplay();
   6.191 +			break;
   6.192 +
   6.193 +		case 'p':
   6.194 +			printf("camera pos(%g %g %g) rot(%g %g) d(%g)\n",
   6.195 +					cam_x, cam_y, cam_z, cam_theta, cam_phi, cam_dist);
   6.196 +			break;
   6.197 +		}
   6.198 +	}
   6.199 +}
   6.200 +
   6.201 +void game_modifier_key(int key, bool press)
   6.202 +{
   6.203 +	if(press) {
   6.204 +		modkeys |= (1 << key);
   6.205 +	} else {
   6.206 +		modkeys &= ~(1 << key);
   6.207 +	}
   6.208 +}
   6.209 +
   6.210 +void game_mbutton(int bn, bool press, int x, int y)
   6.211 +{
   6.212 +	bnstate[bn] = press;
   6.213 +	prev_x = x;
   6.214 +	prev_y = y;
   6.215 +
   6.216 +	if(modkeys) {
   6.217 +		return;
   6.218 +	}
   6.219 +
   6.220 +	if(bn == 0) {
   6.221 +	}
   6.222 +}
   6.223 +
   6.224 +void game_mmotion(int x, int y)
   6.225 +{
   6.226 +	int dx = x - prev_x;
   6.227 +	int dy = y - prev_y;
   6.228 +	prev_x = x;
   6.229 +	prev_y = y;
   6.230 +
   6.231 +	if(modkeys) {
   6.232 +		if(bnstate[0]) {
   6.233 +			cam_theta += dx * 0.5;
   6.234 +			cam_phi += dy * 0.5;
   6.235 +
   6.236 +			if(cam_phi < -90) cam_phi = -90;
   6.237 +			if(cam_phi > 90) cam_phi = 90;
   6.238 +		}
   6.239 +		if(bnstate[1]) {
   6.240 +			float theta = DEG_TO_RAD(cam_theta);
   6.241 +
   6.242 +			float dxp = dx * 0.1;
   6.243 +			float dyp = dy * 0.1;
   6.244 +
   6.245 +			cam_x += cos(theta) * dxp - sin(theta) * dyp;
   6.246 +			if(modkeys & (1 << MOD_SHIFT)) {
   6.247 +				cam_y -= sin(theta) * dxp + cos(theta) * dyp;
   6.248 +			} else {
   6.249 +				cam_z += sin(theta) * dxp + cos(theta) * dyp;
   6.250 +			}
   6.251 +		}
   6.252 +		if(bnstate[2]) {
   6.253 +			cam_dist += dy * 0.1;
   6.254 +			if(cam_dist < 0.0) cam_dist = 0.0;
   6.255 +		}
   6.256 +	}
   6.257 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/game.h	Mon Aug 31 07:38:37 2015 +0300
     7.3 @@ -0,0 +1,30 @@
     7.4 +#ifndef GAME_H_
     7.5 +#define GAME_H_
     7.6 +
     7.7 +#include "vmath/vmath.h"
     7.8 +
     7.9 +extern int win_width, win_height;
    7.10 +extern unsigned long cur_time;
    7.11 +
    7.12 +extern bool dbg_wireframe;
    7.13 +extern int dbg_int;
    7.14 +
    7.15 +enum { MOD_ALT, MOD_CTL, MOD_SHIFT };
    7.16 +
    7.17 +bool game_init();
    7.18 +void game_cleanup();
    7.19 +void game_update(unsigned long time_msec);
    7.20 +void game_display();
    7.21 +void game_reshape(int x, int y);
    7.22 +void game_keyboard(int key, bool press);
    7.23 +void game_modifier_key(int key, bool press);
    7.24 +void game_mbutton(int bn, bool press, int x, int y);
    7.25 +void game_mmotion(int x, int y);
    7.26 +
    7.27 +void set_fullscreen(bool fs);
    7.28 +void redisplay();
    7.29 +void quit();
    7.30 +
    7.31 +void draw_teapot();
    7.32 +
    7.33 +#endif	/* GAME_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/geom.cc	Mon Aug 31 07:38:37 2015 +0300
     8.3 @@ -0,0 +1,334 @@
     8.4 +#include <assert.h>
     8.5 +#include <float.h>
     8.6 +#include <algorithm>
     8.7 +#include "geom.h"
     8.8 +
     8.9 +GeomObject::~GeomObject()
    8.10 +{
    8.11 +}
    8.12 +
    8.13 +
    8.14 +Sphere::Sphere()
    8.15 +{
    8.16 +	radius = 1.0;
    8.17 +}
    8.18 +
    8.19 +Sphere::Sphere(const Vector3 &cent, float radius)
    8.20 +	: center(cent)
    8.21 +{
    8.22 +	this->radius = radius;
    8.23 +}
    8.24 +
    8.25 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
    8.26 +{
    8.27 +	const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
    8.28 +	const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
    8.29 +
    8.30 +	if(!sph1 || !sph2) {
    8.31 +		fprintf(stderr, "Sphere::set_union: arguments must be spheres");
    8.32 +		return;
    8.33 +	}
    8.34 +
    8.35 +	float dist = (sph1->center - sph2->center).length();
    8.36 +	float surf_dist = dist - (sph1->radius + sph2->radius);
    8.37 +	float d1 = sph1->radius + surf_dist / 2.0;
    8.38 +	float d2 = sph2->radius + surf_dist / 2.0;
    8.39 +	float t = d1 / (d1 + d2);
    8.40 +
    8.41 +	if(t < 0.0) t = 0.0;
    8.42 +	if(t > 1.0) t = 1.0;
    8.43 +
    8.44 +	center = sph1->center * t + sph2->center * (1.0 - t);
    8.45 +	radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
    8.46 +}
    8.47 +
    8.48 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
    8.49 +{
    8.50 +	fprintf(stderr, "Sphere::intersection undefined\n");
    8.51 +}
    8.52 +
    8.53 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
    8.54 +{
    8.55 +	float a = dot_product(ray.dir, ray.dir);
    8.56 +	float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
    8.57 +		2.0 * ray.dir.y * (ray.origin.y - center.y) +
    8.58 +		2.0 * ray.dir.z * (ray.origin.z - center.z);
    8.59 +	float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
    8.60 +		2.0 * dot_product(ray.origin, center) - radius * radius;
    8.61 +
    8.62 +	float discr = b * b - 4.0 * a * c;
    8.63 +	if(discr < 1e-4) {
    8.64 +		return false;
    8.65 +	}
    8.66 +
    8.67 +	float sqrt_discr = sqrt(discr);
    8.68 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
    8.69 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
    8.70 +
    8.71 +	if(t0 < 1e-4)
    8.72 +		t0 = t1;
    8.73 +	if(t1 < 1e-4)
    8.74 +		t1 = t0;
    8.75 +
    8.76 +	float t = t0 < t1 ? t0 : t1;
    8.77 +	if(t < 1e-4) {
    8.78 +		return false;
    8.79 +	}
    8.80 +
    8.81 +	// fill the HitPoint structure
    8.82 +	if(hit) {
    8.83 +		hit->obj = this;
    8.84 +		hit->dist = t;
    8.85 +		hit->pos = ray.origin + ray.dir * t;
    8.86 +		hit->normal = (hit->pos - center) / radius;
    8.87 +	}
    8.88 +	return true;
    8.89 +}
    8.90 +
    8.91 +
    8.92 +AABox::AABox()
    8.93 +{
    8.94 +}
    8.95 +
    8.96 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
    8.97 +	: min(vmin), max(vmax)
    8.98 +{
    8.99 +}
   8.100 +
   8.101 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
   8.102 +{
   8.103 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   8.104 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   8.105 +
   8.106 +	if(!box1 || !box2) {
   8.107 +		fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n");
   8.108 +		return;
   8.109 +	}
   8.110 +
   8.111 +	min.x = std::min(box1->min.x, box2->min.x);
   8.112 +	min.y = std::min(box1->min.y, box2->min.y);
   8.113 +	min.z = std::min(box1->min.z, box2->min.z);
   8.114 +
   8.115 +	max.x = std::max(box1->max.x, box2->max.x);
   8.116 +	max.y = std::max(box1->max.y, box2->max.y);
   8.117 +	max.z = std::max(box1->max.z, box2->max.z);
   8.118 +}
   8.119 +
   8.120 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   8.121 +{
   8.122 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   8.123 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   8.124 +
   8.125 +	if(!box1 || !box2) {
   8.126 +		fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n");
   8.127 +		return;
   8.128 +	}
   8.129 +
   8.130 +	for(int i=0; i<3; i++) {
   8.131 +		min[i] = std::max(box1->min[i], box2->min[i]);
   8.132 +		max[i] = std::min(box1->max[i], box2->max[i]);
   8.133 +
   8.134 +		if(max[i] < min[i]) {
   8.135 +			max[i] = min[i];
   8.136 +		}
   8.137 +	}
   8.138 +}
   8.139 +
   8.140 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const
   8.141 +{
   8.142 +	Vector3 param[2] = {min, max};
   8.143 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
   8.144 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
   8.145 +
   8.146 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
   8.147 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
   8.148 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
   8.149 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
   8.150 +
   8.151 +	if(tmin > tymax || tymin > tmax) {
   8.152 +		return false;
   8.153 +	}
   8.154 +	if(tymin > tmin) {
   8.155 +		tmin = tymin;
   8.156 +	}
   8.157 +	if(tymax < tmax) {
   8.158 +		tmax = tymax;
   8.159 +	}
   8.160 +
   8.161 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
   8.162 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
   8.163 +
   8.164 +	if(tmin > tzmax || tzmin > tmax) {
   8.165 +		return false;
   8.166 +	}
   8.167 +	if(tzmin > tmin) {
   8.168 +		tmin = tzmin;
   8.169 +	}
   8.170 +	if(tzmax < tmax) {
   8.171 +		tmax = tzmax;
   8.172 +	}
   8.173 +
   8.174 +	float t = tmin < 1e-4 ? tmax : tmin;
   8.175 +	if(t >= 1e-4) {
   8.176 +
   8.177 +		if(hit) {
   8.178 +			hit->obj = this;
   8.179 +			hit->dist = t;
   8.180 +			hit->pos = ray.origin + ray.dir * t;
   8.181 +
   8.182 +			float min_dist = FLT_MAX;
   8.183 +			Vector3 offs = min + (max - min) / 2.0;
   8.184 +			Vector3 local_hit = hit->pos - offs;
   8.185 +
   8.186 +			static const Vector3 axis[] = {
   8.187 +				Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
   8.188 +			};
   8.189 +			//int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
   8.190 +
   8.191 +			for(int i=0; i<3; i++) {
   8.192 +				float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
   8.193 +				if(dist < min_dist) {
   8.194 +					min_dist = dist;
   8.195 +					hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
   8.196 +					//hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
   8.197 +				}
   8.198 +			}
   8.199 +		}
   8.200 +		return true;
   8.201 +	}
   8.202 +	return false;
   8.203 +
   8.204 +}
   8.205 +
   8.206 +Plane::Plane()
   8.207 +	: normal(0.0, 1.0, 0.0)
   8.208 +{
   8.209 +}
   8.210 +
   8.211 +Plane::Plane(const Vector3 &p, const Vector3 &norm)
   8.212 +	: pt(p)
   8.213 +{
   8.214 +	normal = norm.normalized();
   8.215 +}
   8.216 +
   8.217 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
   8.218 +	: pt(p1)
   8.219 +{
   8.220 +	normal = cross_product(p2 - p1, p3 - p1).normalized();
   8.221 +}
   8.222 +
   8.223 +Plane::Plane(const Vector3 &normal, float dist)
   8.224 +{
   8.225 +	this->normal = normal.normalized();
   8.226 +	pt = this->normal * dist;
   8.227 +}
   8.228 +
   8.229 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
   8.230 +{
   8.231 +	fprintf(stderr, "Plane::set_union undefined\n");
   8.232 +}
   8.233 +
   8.234 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   8.235 +{
   8.236 +	fprintf(stderr, "Plane::set_intersection undefined\n");
   8.237 +}
   8.238 +
   8.239 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const
   8.240 +{
   8.241 +	float ndotdir = dot_product(normal, ray.dir);
   8.242 +	if(fabs(ndotdir) < 1e-4) {
   8.243 +		return false;
   8.244 +	}
   8.245 +
   8.246 +	if(hit) {
   8.247 +		Vector3 ptdir = pt - ray.origin;
   8.248 +		float t = dot_product(normal, ptdir) / ndotdir;
   8.249 +
   8.250 +		hit->pos = ray.origin + ray.dir * t;
   8.251 +		hit->normal = normal;
   8.252 +		hit->obj = this;
   8.253 +	}
   8.254 +	return true;
   8.255 +}
   8.256 +
   8.257 +float sphere_distance(const Vector3 &cent, float rad, const Vector3 &pt)
   8.258 +{
   8.259 +	return (pt - cent).length() - rad;
   8.260 +}
   8.261 +
   8.262 +// TODO version which takes both radii into account
   8.263 +float capsule_distance(const Vector3 &a, float ra, const Vector3 &b, float rb, const Vector3 &pt)
   8.264 +{
   8.265 +	Vector3 ab_dir = b - a;
   8.266 +	float ab_len_sq = ab_dir.length_sq();
   8.267 +
   8.268 +	if(fabs(ab_len_sq) < 1e-5) {
   8.269 +		// if a == b, the capsule is a sphere with radius the maximum of the capsule radii
   8.270 +		return sphere_distance(a, std::max(ra, rb), pt);
   8.271 +	}
   8.272 +	float ab_len = sqrt(ab_len_sq);
   8.273 +
   8.274 +	Vector3 ap_dir = pt - a;
   8.275 +
   8.276 +	float t = dot_product(ap_dir, ab_dir / ab_len) / ab_len;
   8.277 +	if(t < 0.0) {
   8.278 +		return sphere_distance(a, ra, pt);
   8.279 +	}
   8.280 +	if(t >= 1.0) {
   8.281 +		return sphere_distance(b, rb, pt);
   8.282 +	}
   8.283 +
   8.284 +	Vector3 pproj = a + ab_dir * t;
   8.285 +	return (pproj - pt).length() - ra;
   8.286 +}
   8.287 +
   8.288 +#if 0
   8.289 +float capsule_distance(const Vector3 &a, float ra, const Vector3 &b, float rb, const Vector3 &pt)
   8.290 +{
   8.291 +	Vector3 ab_dir = b - a;
   8.292 +
   8.293 +	if(fabs(ab_dir.length_sq()) < 1e-5) {
   8.294 +		// if a == b, the capsule is a sphere with radius the maximum of the capsule radii
   8.295 +		return sphere_distance(a, std::max(ra, rb), pt);
   8.296 +	}
   8.297 +	float ab_len = ab_dir.length();
   8.298 +
   8.299 +	Vector3 ap_dir = pt - a;
   8.300 +	Vector3 rotaxis = cross_product(ab_dir, ap_dir).normalized();
   8.301 +
   8.302 +	Matrix4x4 rmat;
   8.303 +	rmat.set_rotation(rotaxis, M_PI / 2.0);
   8.304 +	Vector3 right = ab_dir.transformed(rmat) / ab_len;
   8.305 +
   8.306 +	// XXX I think this check is redundant, always false, due to the cross product order
   8.307 +	//assert(dot_product(right, ab_dir) >= 0.0);
   8.308 +	if(dot_product(right, ab_dir) < 0.0) {
   8.309 +		right = -right;
   8.310 +	}
   8.311 +	Vector3 aa = a + right * ra;
   8.312 +	Vector3 bb = b + right * rb;
   8.313 +
   8.314 +	// project pt to the line segment bb-aa, see if the projection lies within the interval [0, 1)
   8.315 +	Vector3 aabb_dir = bb - aa;
   8.316 +	float aabb_len = aabb_dir.length();
   8.317 +	Vector3 aap_dir = pt - aa;
   8.318 +
   8.319 +	float t = dot_product(aap_dir, aabb_dir / aabb_len) / aabb_len;
   8.320 +	if(t < 0.0) {
   8.321 +		return sphere_distance(a, ra, pt);
   8.322 +	}
   8.323 +	if(t >= 1.0) {
   8.324 +		return sphere_distance(b, rb, pt);
   8.325 +	}
   8.326 +
   8.327 +	Vector3 ppt = aa + aabb_dir * t;
   8.328 +	Vector3 norm = ppt - pt;
   8.329 +	float dist = norm.length();
   8.330 +
   8.331 +	if(dot_product(norm, right) < 0.0) {
   8.332 +		// inside the cone
   8.333 +		dist = -dist;
   8.334 +	}
   8.335 +	return dist;
   8.336 +}
   8.337 +#endif
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/geom.h	Mon Aug 31 07:38:37 2015 +0300
     9.3 @@ -0,0 +1,73 @@
     9.4 +#ifndef GEOMOBJ_H_
     9.5 +#define GEOMOBJ_H_
     9.6 +
     9.7 +#include "vmath/vmath.h"
     9.8 +
     9.9 +class GeomObject;
    9.10 +class SceneNode;
    9.11 +
    9.12 +struct HitPoint {
    9.13 +	float dist;				//< parametric distance along the ray
    9.14 +	Vector3 pos;			//< position of intersection (orig + dir * dist)
    9.15 +	Vector3 normal;			//< normal at the point of intersection
    9.16 +	const void *obj;		//< pointer to the intersected object
    9.17 +	const SceneNode *node;
    9.18 +	Ray ray;
    9.19 +};
    9.20 +
    9.21 +class GeomObject {
    9.22 +public:
    9.23 +	virtual ~GeomObject();
    9.24 +
    9.25 +	virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0;
    9.26 +	virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0;
    9.27 +
    9.28 +	virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0;
    9.29 +};
    9.30 +
    9.31 +class Sphere : public GeomObject {
    9.32 +public:
    9.33 +	Vector3 center;
    9.34 +	float radius;
    9.35 +
    9.36 +	Sphere();
    9.37 +	Sphere(const Vector3 &center, float radius);
    9.38 +
    9.39 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
    9.40 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
    9.41 +
    9.42 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    9.43 +};
    9.44 +
    9.45 +class AABox : public GeomObject {
    9.46 +public:
    9.47 +	Vector3 min, max;
    9.48 +
    9.49 +	AABox();
    9.50 +	AABox(const Vector3 &min, const Vector3 &max);
    9.51 +
    9.52 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
    9.53 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
    9.54 +
    9.55 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    9.56 +};
    9.57 +
    9.58 +class Plane : public GeomObject {
    9.59 +public:
    9.60 +	Vector3 pt, normal;
    9.61 +
    9.62 +	Plane();
    9.63 +	Plane(const Vector3 &pt, const Vector3 &normal);
    9.64 +	Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3);
    9.65 +	Plane(const Vector3 &normal, float dist);
    9.66 +
    9.67 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
    9.68 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
    9.69 +
    9.70 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    9.71 +};
    9.72 +
    9.73 +float sphere_distance(const Vector3 &cent, float rad, const Vector3 &pt);
    9.74 +float capsule_distance(const Vector3 &a, float ra, const Vector3 &b, float rb, const Vector3 &pt);
    9.75 +
    9.76 +#endif	// GEOMOBJ_H_
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/light.cc	Mon Aug 31 07:38:37 2015 +0300
    10.3 @@ -0,0 +1,17 @@
    10.4 +#include "light.h"
    10.5 +#include "opengl.h"
    10.6 +
    10.7 +Light::Light()
    10.8 +	: color(1, 1, 1)
    10.9 +{
   10.10 +}
   10.11 +
   10.12 +void Light::setup(int idx) const
   10.13 +{
   10.14 +	float lpos[] = {pos.x, pos.y, pos.z, 1.0};
   10.15 +	float col[] = {color.x, color.y, color.z, 1.0};
   10.16 +
   10.17 +	glLightfv(GL_LIGHT0 + idx, GL_POSITION, lpos);
   10.18 +	glLightfv(GL_LIGHT0 + idx, GL_DIFFUSE, col);
   10.19 +	glLightfv(GL_LIGHT0 + idx, GL_SPECULAR, col);
   10.20 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/light.h	Mon Aug 31 07:38:37 2015 +0300
    11.3 @@ -0,0 +1,16 @@
    11.4 +#ifndef LIGHT_H_
    11.5 +#define LIGHT_H_
    11.6 +
    11.7 +#include "vmath/vmath.h"
    11.8 +
    11.9 +class Light {
   11.10 +public:
   11.11 +	Vector3 pos;
   11.12 +	Vector3 color;
   11.13 +
   11.14 +	Light();
   11.15 +
   11.16 +	void setup(int idx = 0) const;
   11.17 +};
   11.18 +
   11.19 +#endif	// LIGHT_H_
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/main.cc	Mon Aug 31 07:38:37 2015 +0300
    12.3 @@ -0,0 +1,148 @@
    12.4 +#include <stdio.h>
    12.5 +#include <stdlib.h>
    12.6 +#include <assert.h>
    12.7 +#ifdef __APPLE__
    12.8 +#include <GLUT/glut.h>
    12.9 +#else
   12.10 +#include <GL/glut.h>
   12.11 +#endif
   12.12 +#include "game.h"
   12.13 +#include "opt.h"
   12.14 +
   12.15 +static void display();
   12.16 +static void idle();
   12.17 +static void reshape(int x, int y);
   12.18 +static void keydown(unsigned char key, int x, int y);
   12.19 +static void keyup(unsigned char key, int x, int y);
   12.20 +static void mouse(int bn, int st, int x, int y);
   12.21 +static void motion(int x, int y);
   12.22 +static void update_modifiers();
   12.23 +
   12.24 +static unsigned int start_time;
   12.25 +
   12.26 +int main(int argc, char **argv)
   12.27 +{
   12.28 +	glutInit(&argc, argv);
   12.29 +	if(!init_options(argc, argv)) {
   12.30 +		return 1;
   12.31 +	}
   12.32 +	glutInitWindowSize(opt.xres, opt.yres);
   12.33 +	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | GLUT_MULTISAMPLE);
   12.34 +	glutCreateWindow("umonster");
   12.35 +
   12.36 +	if(opt.fullscreen) {
   12.37 +		set_fullscreen(true);
   12.38 +	}
   12.39 +
   12.40 +	glutDisplayFunc(display);
   12.41 +	glutIdleFunc(idle);
   12.42 +	glutReshapeFunc(reshape);
   12.43 +	glutKeyboardFunc(keydown);
   12.44 +	glutKeyboardUpFunc(keyup);
   12.45 +	glutMouseFunc(mouse);
   12.46 +	glutMotionFunc(motion);
   12.47 +	glutPassiveMotionFunc(motion);
   12.48 +
   12.49 +	if(!game_init()) {
   12.50 +		return 1;
   12.51 +	}
   12.52 +	atexit(game_cleanup);
   12.53 +
   12.54 +	start_time = glutGet(GLUT_ELAPSED_TIME);
   12.55 +	glutMainLoop();
   12.56 +	return 0;
   12.57 +}
   12.58 +
   12.59 +void set_fullscreen(bool fs)
   12.60 +{
   12.61 +	if(fs) {
   12.62 +		glutFullScreen();
   12.63 +	} else {
   12.64 +		glutReshapeWindow(opt.xres, opt.yres);
   12.65 +	}
   12.66 +}
   12.67 +
   12.68 +void redisplay()
   12.69 +{
   12.70 +	glutPostRedisplay();
   12.71 +}
   12.72 +
   12.73 +void quit()
   12.74 +{
   12.75 +	exit(0);
   12.76 +}
   12.77 +
   12.78 +void draw_teapot()
   12.79 +{
   12.80 +	glFrontFace(GL_CW);
   12.81 +	glutSolidTeapot(1.0);
   12.82 +	glFrontFace(GL_CCW);
   12.83 +}
   12.84 +
   12.85 +static void display()
   12.86 +{
   12.87 +	unsigned int msec = glutGet(GLUT_ELAPSED_TIME) - start_time;
   12.88 +	game_update(msec);
   12.89 +
   12.90 +	game_display();
   12.91 +
   12.92 +	glutSwapBuffers();
   12.93 +	assert(glGetError() == GL_NO_ERROR);
   12.94 +}
   12.95 +
   12.96 +static void idle()
   12.97 +{
   12.98 +	glutPostRedisplay();
   12.99 +}
  12.100 +
  12.101 +static void reshape(int x, int y)
  12.102 +{
  12.103 +	win_width = x;
  12.104 +	win_height = y;
  12.105 +	game_reshape(x, y);
  12.106 +}
  12.107 +
  12.108 +static void keydown(unsigned char key, int x, int y)
  12.109 +{
  12.110 +	update_modifiers();
  12.111 +	game_keyboard(key, true);
  12.112 +}
  12.113 +
  12.114 +static void keyup(unsigned char key, int x, int y)
  12.115 +{
  12.116 +	update_modifiers();
  12.117 +	game_keyboard(key, false);
  12.118 +}
  12.119 +
  12.120 +static void mouse(int bn, int st, int x, int y)
  12.121 +{
  12.122 +	update_modifiers();
  12.123 +	game_mbutton(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y);
  12.124 +}
  12.125 +
  12.126 +static void motion(int x, int y)
  12.127 +{
  12.128 +	game_mmotion(x, y);
  12.129 +}
  12.130 +
  12.131 +static void update_modifiers()
  12.132 +{
  12.133 +	static unsigned int prev_mod;
  12.134 +	unsigned int mod = glutGetModifiers();
  12.135 +	unsigned int delta = mod ^ prev_mod;
  12.136 +
  12.137 +	if(delta & GLUT_ACTIVE_SHIFT) {
  12.138 +		bool press = (mod & GLUT_ACTIVE_SHIFT) != 0;
  12.139 +		game_modifier_key(MOD_SHIFT, press);
  12.140 +	}
  12.141 +	if(delta & GLUT_ACTIVE_CTRL) {
  12.142 +		bool press = (mod & GLUT_ACTIVE_CTRL) != 0;
  12.143 +		game_modifier_key(MOD_CTL, press);
  12.144 +	}
  12.145 +	if(delta & GLUT_ACTIVE_ALT) {
  12.146 +		bool press = (mod & GLUT_ACTIVE_ALT) != 0;
  12.147 +		game_modifier_key(MOD_ALT, press);
  12.148 +	}
  12.149 +
  12.150 +	prev_mod = mod;
  12.151 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/mesh.cc	Mon Aug 31 07:38:37 2015 +0300
    13.3 @@ -0,0 +1,1297 @@
    13.4 +#include <stdio.h>
    13.5 +#include <stdlib.h>
    13.6 +#include <float.h>
    13.7 +#include <assert.h>
    13.8 +#include "opengl.h"
    13.9 +#include "mesh.h"
   13.10 +//#include "xform_node.h"
   13.11 +
   13.12 +#define USE_OLDGL
   13.13 +
   13.14 +bool Mesh::use_custom_sdr_attr = true;
   13.15 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
   13.16 +/*
   13.17 +	(int)SDR_ATTR_VERTEX,
   13.18 +	(int)SDR_ATTR_NORMAL,
   13.19 +	(int)SDR_ATTR_TANGENT,
   13.20 +	(int)SDR_ATTR_TEXCOORD,
   13.21 +	(int)SDR_ATTR_COLOR,
   13.22 +	-1, -1};
   13.23 +*/
   13.24 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
   13.25 +float Mesh::vertex_sel_dist = 0.01;
   13.26 +float Mesh::vis_vecsize = 1.0;
   13.27 +
   13.28 +Mesh::Mesh()
   13.29 +{
   13.30 +	clear();
   13.31 +
   13.32 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   13.33 +
   13.34 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   13.35 +		vattr[i].vbo = buffer_objects[i];
   13.36 +	}
   13.37 +	ibo = buffer_objects[NUM_MESH_ATTR];
   13.38 +	wire_ibo = 0;
   13.39 +}
   13.40 +
   13.41 +Mesh::~Mesh()
   13.42 +{
   13.43 +	glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   13.44 +
   13.45 +	if(wire_ibo) {
   13.46 +		glDeleteBuffers(1, &wire_ibo);
   13.47 +	}
   13.48 +}
   13.49 +
   13.50 +Mesh::Mesh(const Mesh &rhs)
   13.51 +{
   13.52 +	clear();
   13.53 +
   13.54 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   13.55 +
   13.56 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   13.57 +		vattr[i].vbo = buffer_objects[i];
   13.58 +	}
   13.59 +	ibo = buffer_objects[NUM_MESH_ATTR];
   13.60 +	wire_ibo = 0;
   13.61 +
   13.62 +	clone(rhs);
   13.63 +}
   13.64 +
   13.65 +Mesh &Mesh::operator =(const Mesh &rhs)
   13.66 +{
   13.67 +	if(&rhs != this) {
   13.68 +		clone(rhs);
   13.69 +	}
   13.70 +	return *this;
   13.71 +}
   13.72 +
   13.73 +bool Mesh::clone(const Mesh &m)
   13.74 +{
   13.75 +	clear();
   13.76 +
   13.77 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   13.78 +		if(m.has_attrib(i)) {
   13.79 +			m.get_attrib_data(i);	// force validation of the actual data on the source mesh
   13.80 +
   13.81 +			vattr[i].nelem = m.vattr[i].nelem;
   13.82 +			vattr[i].data = m.vattr[i].data;	// copy the actual data
   13.83 +			vattr[i].data_valid = true;
   13.84 +		}
   13.85 +	}
   13.86 +
   13.87 +	if(m.is_indexed()) {
   13.88 +		m.get_index_data();		// again, force validation
   13.89 +
   13.90 +		// copy the index data
   13.91 +		idata = m.idata;
   13.92 +		idata_valid = true;
   13.93 +	}
   13.94 +
   13.95 +	name = m.name;
   13.96 +	nverts = m.nverts;
   13.97 +	nfaces = m.nfaces;
   13.98 +
   13.99 +	//bones = m.bones;
  13.100 +
  13.101 +	memcpy(cur_val, m.cur_val, sizeof cur_val);
  13.102 +
  13.103 +	aabb = m.aabb;
  13.104 +	aabb_valid = m.aabb_valid;
  13.105 +	bsph = m.bsph;
  13.106 +	bsph_valid = m.bsph_valid;
  13.107 +
  13.108 +	hitface = m.hitface;
  13.109 +	hitvert = m.hitvert;
  13.110 +
  13.111 +	intersect_mode = m.intersect_mode;
  13.112 +	vertex_sel_dist = m.vertex_sel_dist;
  13.113 +	vis_vecsize = m.vis_vecsize;
  13.114 +
  13.115 +	return true;
  13.116 +}
  13.117 +
  13.118 +void Mesh::set_name(const char *name)
  13.119 +{
  13.120 +	this->name = name;
  13.121 +}
  13.122 +
  13.123 +const char *Mesh::get_name() const
  13.124 +{
  13.125 +	return name.c_str();
  13.126 +}
  13.127 +
  13.128 +bool Mesh::has_attrib(int attr) const
  13.129 +{
  13.130 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  13.131 +		return false;
  13.132 +	}
  13.133 +
  13.134 +	// if neither of these is valid, then nobody has set this attribute
  13.135 +	return vattr[attr].vbo_valid || vattr[attr].data_valid;
  13.136 +}
  13.137 +
  13.138 +bool Mesh::is_indexed() const
  13.139 +{
  13.140 +	return ibo_valid || idata_valid;
  13.141 +}
  13.142 +
  13.143 +void Mesh::clear()
  13.144 +{
  13.145 +	//bones.clear();
  13.146 +
  13.147 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  13.148 +		vattr[i].nelem = 0;
  13.149 +		vattr[i].vbo_valid = false;
  13.150 +		vattr[i].data_valid = false;
  13.151 +		//vattr[i].sdr_loc = -1;
  13.152 +		vattr[i].data.clear();
  13.153 +	}
  13.154 +	ibo_valid = idata_valid = false;
  13.155 +	idata.clear();
  13.156 +
  13.157 +	wire_ibo_valid = false;
  13.158 +
  13.159 +	nverts = nfaces = 0;
  13.160 +
  13.161 +	bsph_valid = false;
  13.162 +	aabb_valid = false;
  13.163 +}
  13.164 +
  13.165 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
  13.166 +{
  13.167 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  13.168 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  13.169 +		return 0;
  13.170 +	}
  13.171 +
  13.172 +	if(nverts && num != nverts) {
  13.173 +		fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
  13.174 +		return 0;
  13.175 +	}
  13.176 +	nverts = num;
  13.177 +
  13.178 +	vattr[attrib].data.clear();
  13.179 +	vattr[attrib].nelem = nelem;
  13.180 +	vattr[attrib].data.resize(num * nelem);
  13.181 +
  13.182 +	if(data) {
  13.183 +		memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
  13.184 +	}
  13.185 +
  13.186 +	vattr[attrib].data_valid = true;
  13.187 +	vattr[attrib].vbo_valid = false;
  13.188 +	return &vattr[attrib].data[0];
  13.189 +}
  13.190 +
  13.191 +float *Mesh::get_attrib_data(int attrib)
  13.192 +{
  13.193 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  13.194 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  13.195 +		return 0;
  13.196 +	}
  13.197 +
  13.198 +	vattr[attrib].vbo_valid = false;
  13.199 +	return (float*)((const Mesh*)this)->get_attrib_data(attrib);
  13.200 +}
  13.201 +
  13.202 +const float *Mesh::get_attrib_data(int attrib) const
  13.203 +{
  13.204 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  13.205 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  13.206 +		return 0;
  13.207 +	}
  13.208 +
  13.209 +	if(!vattr[attrib].data_valid) {
  13.210 +#if GL_ES_VERSION_2_0
  13.211 +		fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
  13.212 +		return 0;
  13.213 +#else
  13.214 +		if(!vattr[attrib].vbo_valid) {
  13.215 +			fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
  13.216 +			return 0;
  13.217 +		}
  13.218 +
  13.219 +		// local data copy is unavailable, grab the data from the vbo
  13.220 +		Mesh *m = (Mesh*)this;
  13.221 +		m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
  13.222 +
  13.223 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
  13.224 +		void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
  13.225 +		memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
  13.226 +		glUnmapBuffer(GL_ARRAY_BUFFER);
  13.227 +
  13.228 +		vattr[attrib].data_valid = true;
  13.229 +#endif
  13.230 +	}
  13.231 +
  13.232 +	return &vattr[attrib].data[0];
  13.233 +}
  13.234 +
  13.235 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
  13.236 +{
  13.237 +	float *data = get_attrib_data(attrib);
  13.238 +	if(data) {
  13.239 +		data += idx * vattr[attrib].nelem;
  13.240 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  13.241 +			data[i] = v[i];
  13.242 +		}
  13.243 +	}
  13.244 +}
  13.245 +
  13.246 +Vector4 Mesh::get_attrib(int attrib, int idx) const
  13.247 +{
  13.248 +	Vector4 v(0.0, 0.0, 0.0, 1.0);
  13.249 +	const float *data = get_attrib_data(attrib);
  13.250 +	if(data) {
  13.251 +		data += idx * vattr[attrib].nelem;
  13.252 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  13.253 +			v[i] = data[i];
  13.254 +		}
  13.255 +	}
  13.256 +	return v;
  13.257 +}
  13.258 +
  13.259 +int Mesh::get_attrib_count(int attrib) const
  13.260 +{
  13.261 +	return has_attrib(attrib) ? nverts : 0;
  13.262 +}
  13.263 +
  13.264 +
  13.265 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
  13.266 +{
  13.267 +	int nidx = nfaces * 3;
  13.268 +	if(nidx && num != nidx) {
  13.269 +		fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
  13.270 +		return 0;
  13.271 +	}
  13.272 +	nfaces = num / 3;
  13.273 +
  13.274 +	idata.clear();
  13.275 +	idata.resize(num);
  13.276 +
  13.277 +	if(indices) {
  13.278 +		memcpy(&idata[0], indices, num * sizeof *indices);
  13.279 +	}
  13.280 +
  13.281 +	idata_valid = true;
  13.282 +	ibo_valid = false;
  13.283 +
  13.284 +	return &idata[0];
  13.285 +}
  13.286 +
  13.287 +unsigned int *Mesh::get_index_data()
  13.288 +{
  13.289 +	ibo_valid = false;
  13.290 +	return (unsigned int*)((const Mesh*)this)->get_index_data();
  13.291 +}
  13.292 +
  13.293 +const unsigned int *Mesh::get_index_data() const
  13.294 +{
  13.295 +	if(!idata_valid) {
  13.296 +#if GL_ES_VERSION_2_0
  13.297 +		fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
  13.298 +		return 0;
  13.299 +#else
  13.300 +		if(!ibo_valid) {
  13.301 +			fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
  13.302 +			return 0;
  13.303 +		}
  13.304 +
  13.305 +		// local data copy is unavailable, gram the data from the ibo
  13.306 +		Mesh *m = (Mesh*)this;
  13.307 +		int nidx = nfaces * 3;
  13.308 +		m->idata.resize(nidx);
  13.309 +
  13.310 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  13.311 +		void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
  13.312 +		memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
  13.313 +		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
  13.314 +
  13.315 +		idata_valid = true;
  13.316 +#endif
  13.317 +	}
  13.318 +
  13.319 +	return &idata[0];
  13.320 +}
  13.321 +
  13.322 +int Mesh::get_index_count() const
  13.323 +{
  13.324 +	return nfaces * 3;
  13.325 +}
  13.326 +
  13.327 +void Mesh::append(const Mesh &mesh)
  13.328 +{
  13.329 +	unsigned int idxoffs = nverts;
  13.330 +
  13.331 +	if(!nverts) {
  13.332 +		clone(mesh);
  13.333 +		return;
  13.334 +	}
  13.335 +
  13.336 +	nverts += mesh.nverts;
  13.337 +	nfaces += mesh.nfaces;
  13.338 +
  13.339 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  13.340 +		if(has_attrib(i) && mesh.has_attrib(i)) {
  13.341 +			// force validating the data arrays
  13.342 +			get_attrib_data(i);
  13.343 +			mesh.get_attrib_data(i);
  13.344 +
  13.345 +			// append the mesh data
  13.346 +			vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
  13.347 +		}
  13.348 +	}
  13.349 +
  13.350 +	if(ibo_valid || idata_valid) {
  13.351 +		// make index arrays valid
  13.352 +		get_index_data();
  13.353 +		mesh.get_index_data();
  13.354 +
  13.355 +		size_t orig_sz = idata.size();
  13.356 +
  13.357 +		idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
  13.358 +
  13.359 +		// fixup all the new indices
  13.360 +		for(size_t i=orig_sz; i<idata.size(); i++) {
  13.361 +			idata[i] += idxoffs;
  13.362 +		}
  13.363 +	}
  13.364 +
  13.365 +	// fuck everything
  13.366 +	wire_ibo_valid = false;
  13.367 +	aabb_valid = false;
  13.368 +	bsph_valid = false;
  13.369 +}
  13.370 +
  13.371 +// assemble a complete vertex by adding all the useful attributes
  13.372 +void Mesh::vertex(float x, float y, float z)
  13.373 +{
  13.374 +	cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
  13.375 +	vattr[MESH_ATTR_VERTEX].data_valid = true;
  13.376 +	vattr[MESH_ATTR_VERTEX].nelem = 3;
  13.377 +
  13.378 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  13.379 +		if(vattr[i].data_valid) {
  13.380 +			for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
  13.381 +				vattr[i].data.push_back(cur_val[i][j]);
  13.382 +			}
  13.383 +		}
  13.384 +		vattr[i].vbo_valid = false;
  13.385 +	}
  13.386 +
  13.387 +	if(idata_valid) {
  13.388 +		idata.clear();
  13.389 +	}
  13.390 +	ibo_valid = idata_valid = false;
  13.391 +}
  13.392 +
  13.393 +void Mesh::normal(float nx, float ny, float nz)
  13.394 +{
  13.395 +	cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
  13.396 +	vattr[MESH_ATTR_NORMAL].data_valid = true;
  13.397 +	vattr[MESH_ATTR_NORMAL].nelem = 3;
  13.398 +}
  13.399 +
  13.400 +void Mesh::tangent(float tx, float ty, float tz)
  13.401 +{
  13.402 +	cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
  13.403 +	vattr[MESH_ATTR_TANGENT].data_valid = true;
  13.404 +	vattr[MESH_ATTR_TANGENT].nelem = 3;
  13.405 +}
  13.406 +
  13.407 +void Mesh::texcoord(float u, float v, float w)
  13.408 +{
  13.409 +	cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
  13.410 +	vattr[MESH_ATTR_TEXCOORD].data_valid = true;
  13.411 +	vattr[MESH_ATTR_TEXCOORD].nelem = 3;
  13.412 +}
  13.413 +
  13.414 +void Mesh::boneweights(float w1, float w2, float w3, float w4)
  13.415 +{
  13.416 +	cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
  13.417 +	vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
  13.418 +	vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
  13.419 +}
  13.420 +
  13.421 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
  13.422 +{
  13.423 +	cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
  13.424 +	vattr[MESH_ATTR_BONEIDX].data_valid = true;
  13.425 +	vattr[MESH_ATTR_BONEIDX].nelem = 4;
  13.426 +}
  13.427 +
  13.428 +int Mesh::get_poly_count() const
  13.429 +{
  13.430 +	if(nfaces) {
  13.431 +		return nfaces;
  13.432 +	}
  13.433 +	if(nverts) {
  13.434 +		return nverts / 3;
  13.435 +	}
  13.436 +	return 0;
  13.437 +}
  13.438 +
  13.439 +/// static function
  13.440 +void Mesh::set_attrib_location(int attr, int loc)
  13.441 +{
  13.442 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  13.443 +		return;
  13.444 +	}
  13.445 +	Mesh::global_sdr_loc[attr] = loc;
  13.446 +}
  13.447 +
  13.448 +/// static function
  13.449 +int Mesh::get_attrib_location(int attr)
  13.450 +{
  13.451 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  13.452 +		return -1;
  13.453 +	}
  13.454 +	return Mesh::global_sdr_loc[attr];
  13.455 +}
  13.456 +
  13.457 +/// static function
  13.458 +void Mesh::clear_attrib_locations()
  13.459 +{
  13.460 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  13.461 +		Mesh::global_sdr_loc[i] = -1;
  13.462 +	}
  13.463 +}
  13.464 +
  13.465 +/// static function
  13.466 +void Mesh::set_vis_vecsize(float sz)
  13.467 +{
  13.468 +	Mesh::vis_vecsize = sz;
  13.469 +}
  13.470 +
  13.471 +float Mesh::get_vis_vecsize()
  13.472 +{
  13.473 +	return Mesh::vis_vecsize;
  13.474 +}
  13.475 +
  13.476 +void Mesh::apply_xform(const Matrix4x4 &xform)
  13.477 +{
  13.478 +	Matrix4x4 dir_xform;// = xform.inverse().transposed();
  13.479 +	dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
  13.480 +	dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
  13.481 +	dir_xform[3][3] = 1.0f;
  13.482 +
  13.483 +	apply_xform(xform, dir_xform);
  13.484 +}
  13.485 +
  13.486 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
  13.487 +{
  13.488 +	for(unsigned int i=0; i<nverts; i++) {
  13.489 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  13.490 +		set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
  13.491 +
  13.492 +		if(has_attrib(MESH_ATTR_NORMAL)) {
  13.493 +			Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
  13.494 +			set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
  13.495 +		}
  13.496 +		if(has_attrib(MESH_ATTR_TANGENT)) {
  13.497 +			Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
  13.498 +			set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
  13.499 +		}
  13.500 +	}
  13.501 +}
  13.502 +
  13.503 +void Mesh::flip()
  13.504 +{
  13.505 +	flip_faces();
  13.506 +	flip_normals();
  13.507 +}
  13.508 +
  13.509 +void Mesh::flip_faces()
  13.510 +{
  13.511 +	if(is_indexed()) {
  13.512 +		unsigned int *indices = get_index_data();
  13.513 +		if(!indices) return;
  13.514 +
  13.515 +		int idxnum = get_index_count();
  13.516 +		for(int i=0; i<idxnum; i+=3) {
  13.517 +			unsigned int tmp = indices[i + 2];
  13.518 +			indices[i + 2] = indices[i + 1];
  13.519 +			indices[i + 1] = tmp;
  13.520 +		}
  13.521 +
  13.522 +	} else {
  13.523 +		Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  13.524 +		if(!verts) return;
  13.525 +
  13.526 +		int vnum = get_attrib_count(MESH_ATTR_VERTEX);
  13.527 +		for(int i=0; i<vnum; i+=3) {
  13.528 +			Vector3 tmp = verts[i + 2];
  13.529 +			verts[i + 2] = verts[i + 1];
  13.530 +			verts[i + 1] = tmp;
  13.531 +		}
  13.532 +	}
  13.533 +}
  13.534 +
  13.535 +void Mesh::flip_normals()
  13.536 +{
  13.537 +	Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  13.538 +	if(!normals) return;
  13.539 +
  13.540 +	int num = get_attrib_count(MESH_ATTR_NORMAL);
  13.541 +	for(int i=0; i<num; i++) {
  13.542 +		normals[i] = -normals[i];
  13.543 +	}
  13.544 +}
  13.545 +
  13.546 +/*
  13.547 +int Mesh::add_bone(XFormNode *bone)
  13.548 +{
  13.549 +	int idx = bones.size();
  13.550 +	bones.push_back(bone);
  13.551 +	return idx;
  13.552 +}
  13.553 +
  13.554 +const XFormNode *Mesh::get_bone(int idx) const
  13.555 +{
  13.556 +	if(idx < 0 || idx >= (int)bones.size()) {
  13.557 +		return 0;
  13.558 +	}
  13.559 +	return bones[idx];
  13.560 +}
  13.561 +
  13.562 +int Mesh::get_bones_count() const
  13.563 +{
  13.564 +	return (int)bones.size();
  13.565 +}
  13.566 +*/
  13.567 +
  13.568 +bool Mesh::pre_draw() const
  13.569 +{
  13.570 +	cur_sdr = 0;
  13.571 +	if(glcaps.shaders) {
  13.572 +		glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
  13.573 +	}
  13.574 +
  13.575 +	((Mesh*)this)->update_buffers();
  13.576 +
  13.577 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  13.578 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  13.579 +		return false;
  13.580 +	}
  13.581 +
  13.582 +	if(cur_sdr && use_custom_sdr_attr) {
  13.583 +		// rendering with shaders
  13.584 +		if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  13.585 +			fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  13.586 +			return false;
  13.587 +		}
  13.588 +
  13.589 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  13.590 +			int loc = global_sdr_loc[i];
  13.591 +			if(loc >= 0 && vattr[i].vbo_valid) {
  13.592 +				glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  13.593 +				glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  13.594 +				glEnableVertexAttribArray(loc);
  13.595 +			}
  13.596 +		}
  13.597 +	} else {
  13.598 +#ifndef GL_ES_VERSION_2_0
  13.599 +		// rendering with fixed-function (not available in GLES2)
  13.600 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
  13.601 +		glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
  13.602 +		glEnableClientState(GL_VERTEX_ARRAY);
  13.603 +
  13.604 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  13.605 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
  13.606 +			glNormalPointer(GL_FLOAT, 0, 0);
  13.607 +			glEnableClientState(GL_NORMAL_ARRAY);
  13.608 +		}
  13.609 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  13.610 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
  13.611 +			glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
  13.612 +			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  13.613 +		}
  13.614 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  13.615 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
  13.616 +			glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
  13.617 +			glEnableClientState(GL_COLOR_ARRAY);
  13.618 +		}
  13.619 +#endif
  13.620 +	}
  13.621 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  13.622 +
  13.623 +	return true;
  13.624 +}
  13.625 +
  13.626 +void Mesh::draw() const
  13.627 +{
  13.628 +	if(!pre_draw()) return;
  13.629 +
  13.630 +	if(ibo_valid) {
  13.631 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  13.632 +		glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
  13.633 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  13.634 +	} else {
  13.635 +		glDrawArrays(GL_TRIANGLES, 0, nverts);
  13.636 +	}
  13.637 +
  13.638 +	post_draw();
  13.639 +}
  13.640 +
  13.641 +void Mesh::post_draw() const
  13.642 +{
  13.643 +	if(cur_sdr && use_custom_sdr_attr) {
  13.644 +		// rendered with shaders
  13.645 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  13.646 +			int loc = global_sdr_loc[i];
  13.647 +			if(loc >= 0 && vattr[i].vbo_valid) {
  13.648 +				glDisableVertexAttribArray(loc);
  13.649 +			}
  13.650 +		}
  13.651 +	} else {
  13.652 +#ifndef GL_ES_VERSION_2_0
  13.653 +		// rendered with fixed-function
  13.654 +		glDisableClientState(GL_VERTEX_ARRAY);
  13.655 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  13.656 +			glDisableClientState(GL_NORMAL_ARRAY);
  13.657 +		}
  13.658 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  13.659 +			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  13.660 +		}
  13.661 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  13.662 +			glDisableClientState(GL_COLOR_ARRAY);
  13.663 +		}
  13.664 +#endif
  13.665 +	}
  13.666 +}
  13.667 +
  13.668 +void Mesh::draw_wire() const
  13.669 +{
  13.670 +	if(!pre_draw()) return;
  13.671 +
  13.672 +	((Mesh*)this)->update_wire_ibo();
  13.673 +
  13.674 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  13.675 +	glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
  13.676 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  13.677 +
  13.678 +	post_draw();
  13.679 +}
  13.680 +
  13.681 +void Mesh::draw_vertices() const
  13.682 +{
  13.683 +	if(!pre_draw()) return;
  13.684 +
  13.685 +	glDrawArrays(GL_POINTS, 0, nverts);
  13.686 +
  13.687 +	post_draw();
  13.688 +}
  13.689 +
  13.690 +void Mesh::draw_normals() const
  13.691 +{
  13.692 +#ifdef USE_OLDGL
  13.693 +	int cur_sdr = 0;
  13.694 +	if(glcaps.shaders) {
  13.695 +		glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
  13.696 +	}
  13.697 +
  13.698 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  13.699 +	Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  13.700 +	if(!varr || !norm) {
  13.701 +		return;
  13.702 +	}
  13.703 +
  13.704 +	glBegin(GL_LINES);
  13.705 +	if(cur_sdr && use_custom_sdr_attr) {
  13.706 +		int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  13.707 +		if(vert_loc < 0) {
  13.708 +			glEnd();
  13.709 +			return;
  13.710 +		}
  13.711 +
  13.712 +		for(size_t i=0; i<nverts; i++) {
  13.713 +			glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  13.714 +			Vector3 end = varr[i] + norm[i] * vis_vecsize;
  13.715 +			glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  13.716 +		}
  13.717 +	} else {
  13.718 +		for(size_t i=0; i<nverts; i++) {
  13.719 +			glVertex3f(varr[i].x, varr[i].y, varr[i].z);
  13.720 +			Vector3 end = varr[i] + norm[i] * vis_vecsize;
  13.721 +			glVertex3f(end.x, end.y, end.z);
  13.722 +		}
  13.723 +	}
  13.724 +	glEnd();
  13.725 +#endif	// USE_OLDGL
  13.726 +}
  13.727 +
  13.728 +void Mesh::draw_tangents() const
  13.729 +{
  13.730 +#ifdef USE_OLDGL
  13.731 +	int cur_sdr = 0;
  13.732 +	if(glcaps.shaders) {
  13.733 +		glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
  13.734 +	}
  13.735 +
  13.736 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  13.737 +	Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
  13.738 +	if(!varr || !tang) {
  13.739 +		return;
  13.740 +	}
  13.741 +
  13.742 +	glBegin(GL_LINES);
  13.743 +	if(cur_sdr && use_custom_sdr_attr) {
  13.744 +		int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  13.745 +		if(vert_loc < 0) {
  13.746 +			glEnd();
  13.747 +			return;
  13.748 +		}
  13.749 +
  13.750 +		for(size_t i=0; i<nverts; i++) {
  13.751 +			glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  13.752 +			Vector3 end = varr[i] + tang[i] * vis_vecsize;
  13.753 +			glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  13.754 +		}
  13.755 +	} else {
  13.756 +		for(size_t i=0; i<nverts; i++) {
  13.757 +			glVertex3f(varr[i].x, varr[i].y, varr[i].z);
  13.758 +			Vector3 end = varr[i] + tang[i] * vis_vecsize;
  13.759 +			glVertex3f(end.x, end.y, end.z);
  13.760 +		}
  13.761 +	}
  13.762 +	glEnd();
  13.763 +#endif	// USE_OLDGL
  13.764 +}
  13.765 +
  13.766 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
  13.767 +{
  13.768 +	if(!aabb_valid) {
  13.769 +		((Mesh*)this)->calc_aabb();
  13.770 +	}
  13.771 +	*vmin = aabb.min;
  13.772 +	*vmax = aabb.max;
  13.773 +}
  13.774 +
  13.775 +const AABox &Mesh::get_aabbox() const
  13.776 +{
  13.777 +	if(!aabb_valid) {
  13.778 +		((Mesh*)this)->calc_aabb();
  13.779 +	}
  13.780 +	return aabb;
  13.781 +}
  13.782 +
  13.783 +float Mesh::get_bsphere(Vector3 *center, float *rad) const
  13.784 +{
  13.785 +	if(!bsph_valid) {
  13.786 +		((Mesh*)this)->calc_bsph();
  13.787 +	}
  13.788 +	*center = bsph.center;
  13.789 +	*rad = bsph.radius;
  13.790 +	return bsph.radius;
  13.791 +}
  13.792 +
  13.793 +const Sphere &Mesh::get_bsphere() const
  13.794 +{
  13.795 +	if(!bsph_valid) {
  13.796 +		((Mesh*)this)->calc_bsph();
  13.797 +	}
  13.798 +	return bsph;
  13.799 +}
  13.800 +
  13.801 +/// static function
  13.802 +void Mesh::set_intersect_mode(unsigned int mode)
  13.803 +{
  13.804 +	Mesh::intersect_mode = mode;
  13.805 +}
  13.806 +
  13.807 +/// static function
  13.808 +unsigned int Mesh::get_intersect_mode()
  13.809 +{
  13.810 +	return Mesh::intersect_mode;
  13.811 +}
  13.812 +
  13.813 +/// static function
  13.814 +void Mesh::set_vertex_select_distance(float dist)
  13.815 +{
  13.816 +	Mesh::vertex_sel_dist = dist;
  13.817 +}
  13.818 +
  13.819 +/// static function
  13.820 +float Mesh::get_vertex_select_distance()
  13.821 +{
  13.822 +	return Mesh::vertex_sel_dist;
  13.823 +}
  13.824 +
  13.825 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
  13.826 +{
  13.827 +	assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
  13.828 +
  13.829 +	const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  13.830 +	const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  13.831 +	if(!varr) {
  13.832 +		return false;
  13.833 +	}
  13.834 +	const unsigned int *idxarr = get_index_data();
  13.835 +
  13.836 +	// first test with the bounding box
  13.837 +	AABox box;
  13.838 +	get_aabbox(&box.min, &box.max);
  13.839 +	if(!box.intersect(ray)) {
  13.840 +		return false;
  13.841 +	}
  13.842 +
  13.843 +	HitPoint nearest_hit;
  13.844 +	nearest_hit.dist = FLT_MAX;
  13.845 +	nearest_hit.obj = 0;
  13.846 +
  13.847 +	if(Mesh::intersect_mode & ISECT_VERTICES) {
  13.848 +		// we asked for "intersections" with the vertices of the mesh
  13.849 +		long nearest_vidx = -1;
  13.850 +		float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
  13.851 +
  13.852 +		for(unsigned int i=0; i<nverts; i++) {
  13.853 +
  13.854 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
  13.855 +				continue;
  13.856 +			}
  13.857 +
  13.858 +			// project the vertex onto the ray line
  13.859 +			float t = dot_product(varr[i] - ray.origin, ray.dir);
  13.860 +			Vector3 vproj = ray.origin + ray.dir * t;
  13.861 +
  13.862 +			float dist_sq = (vproj - varr[i]).length_sq();
  13.863 +			if(dist_sq < thres_sq) {
  13.864 +				if(!hit) {
  13.865 +					return true;
  13.866 +				}
  13.867 +				if(t < nearest_hit.dist) {
  13.868 +					nearest_hit.dist = t;
  13.869 +					nearest_vidx = i;
  13.870 +				}
  13.871 +			}
  13.872 +		}
  13.873 +
  13.874 +		if(nearest_vidx != -1) {
  13.875 +			hitvert = varr[nearest_vidx];
  13.876 +			nearest_hit.obj = &hitvert;
  13.877 +		}
  13.878 +
  13.879 +	} else {
  13.880 +		// regular intersection test with polygons
  13.881 +
  13.882 +		for(unsigned int i=0; i<nfaces; i++) {
  13.883 +			Triangle face(i, varr, idxarr);
  13.884 +
  13.885 +			// ignore back-facing polygons if the mode flags include ISECT_FRONT
  13.886 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
  13.887 +				continue;
  13.888 +			}
  13.889 +
  13.890 +			HitPoint fhit;
  13.891 +			if(face.intersect(ray, hit ? &fhit : 0)) {
  13.892 +				if(!hit) {
  13.893 +					return true;
  13.894 +				}
  13.895 +				if(fhit.dist < nearest_hit.dist) {
  13.896 +					nearest_hit = fhit;
  13.897 +					hitface = face;
  13.898 +				}
  13.899 +			}
  13.900 +		}
  13.901 +	}
  13.902 +
  13.903 +	if(nearest_hit.obj) {
  13.904 +		if(hit) {
  13.905 +			*hit = nearest_hit;
  13.906 +
  13.907 +			// if we are interested in the mesh and not the faces set obj to this
  13.908 +			if(Mesh::intersect_mode & ISECT_FACE) {
  13.909 +				hit->obj = &hitface;
  13.910 +			} else if(Mesh::intersect_mode & ISECT_VERTICES) {
  13.911 +				hit->obj = &hitvert;
  13.912 +			} else {
  13.913 +				hit->obj = this;
  13.914 +			}
  13.915 +		}
  13.916 +		return true;
  13.917 +	}
  13.918 +	return false;
  13.919 +}
  13.920 +
  13.921 +
  13.922 +// texture coordinate manipulation
  13.923 +void Mesh::texcoord_apply_xform(const Matrix4x4 &xform)
  13.924 +{
  13.925 +	if(!has_attrib(MESH_ATTR_TEXCOORD)) {
  13.926 +		return;
  13.927 +	}
  13.928 +
  13.929 +	for(unsigned int i=0; i<nverts; i++) {
  13.930 +		Vector4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
  13.931 +		set_attrib(MESH_ATTR_TEXCOORD, i, tc.transformed(xform));
  13.932 +	}
  13.933 +}
  13.934 +
  13.935 +void Mesh::texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang)
  13.936 +{
  13.937 +	if(!nverts) return;
  13.938 +
  13.939 +	if(!has_attrib(MESH_ATTR_TEXCOORD)) {
  13.940 +		// allocate texture coordinate attribute array
  13.941 +		set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
  13.942 +	}
  13.943 +
  13.944 +	Vector3 n = norm.normalized();
  13.945 +	Vector3 b = cross_product(n, tang).normalized();
  13.946 +	Vector3 t = cross_product(b, n);
  13.947 +
  13.948 +	for(unsigned int i=0; i<nverts; i++) {
  13.949 +		Vector3 pos = get_attrib(MESH_ATTR_VERTEX, i);
  13.950 +
  13.951 +		// distance along the tangent direction
  13.952 +		float u = dot_product(pos, t);
  13.953 +		// distance along the bitangent direction
  13.954 +		float v = dot_product(pos, b);
  13.955 +
  13.956 +		set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(u, v, 0, 1));
  13.957 +	}
  13.958 +}
  13.959 +
  13.960 +void Mesh::texcoord_gen_box()
  13.961 +{
  13.962 +	if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
  13.963 +
  13.964 +	if(!has_attrib(MESH_ATTR_TEXCOORD)) {
  13.965 +		// allocate texture coordinate attribute array
  13.966 +		set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
  13.967 +	}
  13.968 +
  13.969 +	for(unsigned int i=0; i<nverts; i++) {
  13.970 +		Vector3 pos = Vector3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vector3(0.5, 0.5, 0.5);
  13.971 +		Vector3 norm = get_attrib(MESH_ATTR_NORMAL, i);
  13.972 +
  13.973 +		float abs_nx = fabs(norm.x);
  13.974 +		float abs_ny = fabs(norm.y);
  13.975 +		float abs_nz = fabs(norm.z);
  13.976 +		int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
  13.977 +
  13.978 +		float uv[2], *uvptr = uv;
  13.979 +		for(int j=0; j<3; j++) {
  13.980 +			if(j == dom) continue;	// skip dominant axis
  13.981 +
  13.982 +			*uvptr++ = pos[j];
  13.983 +		}
  13.984 +		set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(uv[0], uv[1], 0, 1));
  13.985 +	}
  13.986 +}
  13.987 +
  13.988 +void Mesh::texcoord_gen_cylinder()
  13.989 +{
  13.990 +	if(!nverts) return;
  13.991 +
  13.992 +	if(!has_attrib(MESH_ATTR_TEXCOORD)) {
  13.993 +		// allocate texture coordinate attribute array
  13.994 +		set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
  13.995 +	}
  13.996 +
  13.997 +	for(unsigned int i=0; i<nverts; i++) {
  13.998 +		Vector3 pos = get_attrib(MESH_ATTR_VERTEX, i);
  13.999 +
 13.1000 +		float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
 13.1001 +		float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
 13.1002 +
 13.1003 +		float u = theta / (2.0 * M_PI) + 0.5;
 13.1004 +		float v = pos.y;
 13.1005 +
 13.1006 +		set_attrib(MESH_ATTR_TEXCOORD, i, Vector4(u, v, 0, 1));
 13.1007 +	}
 13.1008 +}
 13.1009 +
 13.1010 +
 13.1011 +void Mesh::dump(FILE *fp) const
 13.1012 +{
 13.1013 +	if(!has_attrib(MESH_ATTR_VERTEX)) {
 13.1014 +		return;
 13.1015 +	}
 13.1016 +
 13.1017 +	fprintf(fp, "VERTEX ATTRIBUTES\n");
 13.1018 +	static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" };
 13.1019 +	static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
 13.1020 +
 13.1021 +	for(int i=0; i<(int)nverts; i++) {
 13.1022 +		fprintf(fp, "%5u:", i);
 13.1023 +		for(int j=0; j<NUM_MESH_ATTR; j++) {
 13.1024 +			if(has_attrib(j)) {
 13.1025 +				Vector4 v = get_attrib(j, i);
 13.1026 +				int nelem = vattr[j].nelem;
 13.1027 +				fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
 13.1028 +			}
 13.1029 +		}
 13.1030 +		fputc('\n', fp);
 13.1031 +	}
 13.1032 +
 13.1033 +	if(is_indexed()) {
 13.1034 +		const unsigned int *idx = get_index_data();
 13.1035 +		int numidx = get_index_count();
 13.1036 +		int numtri = numidx / 3;
 13.1037 +		assert(numidx % 3 == 0);
 13.1038 +
 13.1039 +		fprintf(fp, "FACES\n");
 13.1040 +
 13.1041 +		for(int i=0; i<numtri; i++) {
 13.1042 +			fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
 13.1043 +			idx += 3;
 13.1044 +		}
 13.1045 +	}
 13.1046 +}
 13.1047 +
 13.1048 +// ------ private member functions ------
 13.1049 +
 13.1050 +void Mesh::calc_aabb()
 13.1051 +{
 13.1052 +	// the cast is to force calling the const version which doesn't invalidate
 13.1053 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
 13.1054 +		return;
 13.1055 +	}
 13.1056 +
 13.1057 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
 13.1058 +	aabb.max = -aabb.min;
 13.1059 +
 13.1060 +	for(unsigned int i=0; i<nverts; i++) {
 13.1061 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
 13.1062 +		for(int j=0; j<3; j++) {
 13.1063 +			if(v[j] < aabb.min[j]) {
 13.1064 +				aabb.min[j] = v[j];
 13.1065 +			}
 13.1066 +			if(v[j] > aabb.max[j]) {
 13.1067 +				aabb.max[j] = v[j];
 13.1068 +			}
 13.1069 +		}
 13.1070 +	}
 13.1071 +	aabb_valid = true;
 13.1072 +}
 13.1073 +
 13.1074 +void Mesh::calc_bsph()
 13.1075 +{
 13.1076 +	// the cast is to force calling the const version which doesn't invalidate
 13.1077 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
 13.1078 +		return;
 13.1079 +	}
 13.1080 +
 13.1081 +	Vector3 v;
 13.1082 +	bsph.center = Vector3(0, 0, 0);
 13.1083 +
 13.1084 +	// first find the center
 13.1085 +	for(unsigned int i=0; i<nverts; i++) {
 13.1086 +		v = get_attrib(MESH_ATTR_VERTEX, i);
 13.1087 +		bsph.center += v;
 13.1088 +	}
 13.1089 +	bsph.center /= (float)nverts;
 13.1090 +
 13.1091 +	bsph.radius = 0.0f;
 13.1092 +	for(unsigned int i=0; i<nverts; i++) {
 13.1093 +		v = get_attrib(MESH_ATTR_VERTEX, i);
 13.1094 +		float dist_sq = (v - bsph.center).length_sq();
 13.1095 +		if(dist_sq > bsph.radius) {
 13.1096 +			bsph.radius = dist_sq;
 13.1097 +		}
 13.1098 +	}
 13.1099 +	bsph.radius = sqrt(bsph.radius);
 13.1100 +
 13.1101 +	bsph_valid = true;
 13.1102 +}
 13.1103 +
 13.1104 +void Mesh::update_buffers()
 13.1105 +{
 13.1106 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
 13.1107 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
 13.1108 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
 13.1109 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
 13.1110 +			vattr[i].vbo_valid = true;
 13.1111 +		}
 13.1112 +	}
 13.1113 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
 13.1114 +
 13.1115 +	if(idata_valid && !ibo_valid) {
 13.1116 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
 13.1117 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
 13.1118 +		ibo_valid = true;
 13.1119 +	}
 13.1120 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 13.1121 +}
 13.1122 +
 13.1123 +void Mesh::update_wire_ibo()
 13.1124 +{
 13.1125 +	update_buffers();
 13.1126 +
 13.1127 +	if(wire_ibo_valid) {
 13.1128 +		return;
 13.1129 +	}
 13.1130 +
 13.1131 +	if(!wire_ibo) {
 13.1132 +		glGenBuffers(1, &wire_ibo);
 13.1133 +	}
 13.1134 +
 13.1135 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
 13.1136 +	unsigned int *dest = wire_idxarr;
 13.1137 +
 13.1138 +	if(ibo_valid) {
 13.1139 +		// we're dealing with an indexed mesh
 13.1140 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
 13.1141 +
 13.1142 +		for(unsigned int i=0; i<nfaces; i++) {
 13.1143 +			*dest++ = idxarr[0];
 13.1144 +			*dest++ = idxarr[1];
 13.1145 +			*dest++ = idxarr[1];
 13.1146 +			*dest++ = idxarr[2];
 13.1147 +			*dest++ = idxarr[2];
 13.1148 +			*dest++ = idxarr[0];
 13.1149 +			idxarr += 3;
 13.1150 +		}
 13.1151 +	} else {
 13.1152 +		// not an indexed mesh ...
 13.1153 +		for(unsigned int i=0; i<nfaces; i++) {
 13.1154 +			int vidx = i * 3;
 13.1155 +			*dest++ = vidx;
 13.1156 +			*dest++ = vidx + 1;
 13.1157 +			*dest++ = vidx + 1;
 13.1158 +			*dest++ = vidx + 2;
 13.1159 +			*dest++ = vidx + 2;
 13.1160 +			*dest++ = vidx;
 13.1161 +		}
 13.1162 +	}
 13.1163 +
 13.1164 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
 13.1165 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
 13.1166 +	delete [] wire_idxarr;
 13.1167 +	wire_ibo_valid = true;
 13.1168 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 13.1169 +}
 13.1170 +
 13.1171 +
 13.1172 +// ------ class Triangle ------
 13.1173 +Triangle::Triangle()
 13.1174 +{
 13.1175 +	normal_valid = false;
 13.1176 +	id = -1;
 13.1177 +}
 13.1178 +
 13.1179 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
 13.1180 +{
 13.1181 +	v[0] = v0;
 13.1182 +	v[1] = v1;
 13.1183 +	v[2] = v2;
 13.1184 +	normal_valid = false;
 13.1185 +	id = -1;
 13.1186 +}
 13.1187 +
 13.1188 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
 13.1189 +{
 13.1190 +	if(idxarr) {
 13.1191 +		v[0] = varr[idxarr[n * 3]];
 13.1192 +		v[1] = varr[idxarr[n * 3 + 1]];
 13.1193 +		v[2] = varr[idxarr[n * 3 + 2]];
 13.1194 +	} else {
 13.1195 +		v[0] = varr[n * 3];
 13.1196 +		v[1] = varr[n * 3 + 1];
 13.1197 +		v[2] = varr[n * 3 + 2];
 13.1198 +	}
 13.1199 +	normal_valid = false;
 13.1200 +	id = n;
 13.1201 +}
 13.1202 +
 13.1203 +void Triangle::calc_normal()
 13.1204 +{
 13.1205 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
 13.1206 +	normal_valid = true;
 13.1207 +}
 13.1208 +
 13.1209 +const Vector3 &Triangle::get_normal() const
 13.1210 +{
 13.1211 +	if(!normal_valid) {
 13.1212 +		((Triangle*)this)->calc_normal();
 13.1213 +	}
 13.1214 +	return normal;
 13.1215 +}
 13.1216 +
 13.1217 +void Triangle::transform(const Matrix4x4 &xform)
 13.1218 +{
 13.1219 +	v[0].transform(xform);
 13.1220 +	v[1].transform(xform);
 13.1221 +	v[2].transform(xform);
 13.1222 +	normal_valid = false;
 13.1223 +}
 13.1224 +
 13.1225 +void Triangle::draw() const
 13.1226 +{
 13.1227 +	Vector3 n[3];
 13.1228 +	n[0] = get_normal();
 13.1229 +	n[1] = get_normal();
 13.1230 +	n[2] = get_normal();
 13.1231 +
 13.1232 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 13.1233 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
 13.1234 +
 13.1235 +	glEnableVertexAttribArray(vloc);
 13.1236 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 13.1237 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
 13.1238 +
 13.1239 +	glDrawArrays(GL_TRIANGLES, 0, 3);
 13.1240 +
 13.1241 +	glDisableVertexAttribArray(vloc);
 13.1242 +	glDisableVertexAttribArray(nloc);
 13.1243 +}
 13.1244 +
 13.1245 +void Triangle::draw_wire() const
 13.1246 +{
 13.1247 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
 13.1248 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 13.1249 +
 13.1250 +	glEnableVertexAttribArray(vloc);
 13.1251 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 13.1252 +
 13.1253 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
 13.1254 +
 13.1255 +	glDisableVertexAttribArray(vloc);
 13.1256 +}
 13.1257 +
 13.1258 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
 13.1259 +{
 13.1260 +	Vector3 norm = get_normal();
 13.1261 +
 13.1262 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
 13.1263 +	if(area_sq < 1e-5) {
 13.1264 +		return Vector3(0, 0, 0);
 13.1265 +	}
 13.1266 +
 13.1267 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
 13.1268 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
 13.1269 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
 13.1270 +
 13.1271 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
 13.1272 +}
 13.1273 +
 13.1274 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
 13.1275 +{
 13.1276 +	Vector3 normal = get_normal();
 13.1277 +
 13.1278 +	float ndotdir = dot_product(ray.dir, normal);
 13.1279 +	if(fabs(ndotdir) < 1e-4) {
 13.1280 +		return false;
 13.1281 +	}
 13.1282 +
 13.1283 +	Vector3 vertdir = v[0] - ray.origin;
 13.1284 +	float t = dot_product(normal, vertdir) / ndotdir;
 13.1285 +
 13.1286 +	Vector3 pos = ray.origin + ray.dir * t;
 13.1287 +	Vector3 bary = calc_barycentric(pos);
 13.1288 +
 13.1289 +	if(bary.x + bary.y + bary.z > 1.00001) {
 13.1290 +		return false;
 13.1291 +	}
 13.1292 +
 13.1293 +	if(hit) {
 13.1294 +		hit->dist = t;
 13.1295 +		hit->pos = ray.origin + ray.dir * t;
 13.1296 +		hit->normal = normal;
 13.1297 +		hit->obj = this;
 13.1298 +	}
 13.1299 +	return true;
 13.1300 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/mesh.h	Mon Aug 31 07:38:37 2015 +0300
    14.3 @@ -0,0 +1,240 @@
    14.4 +#ifndef MESH_H_
    14.5 +#define MESH_H_
    14.6 +
    14.7 +#include <stdio.h>
    14.8 +#include <string>
    14.9 +#include <vector>
   14.10 +#include "vmath/vmath.h"
   14.11 +#include "geom.h"
   14.12 +
   14.13 +enum {
   14.14 +	MESH_ATTR_VERTEX,
   14.15 +	MESH_ATTR_NORMAL,
   14.16 +	MESH_ATTR_TANGENT,
   14.17 +	MESH_ATTR_TEXCOORD,
   14.18 +	MESH_ATTR_COLOR,
   14.19 +	MESH_ATTR_BONEWEIGHTS,
   14.20 +	MESH_ATTR_BONEIDX,
   14.21 +
   14.22 +	NUM_MESH_ATTR
   14.23 +};
   14.24 +
   14.25 +// intersection mode flags
   14.26 +enum {
   14.27 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
   14.28 +	ISECT_FRONT		= 1,	// front-faces only
   14.29 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
   14.30 +	ISECT_VERTICES	= 4		// return (?) TODO
   14.31 +};
   14.32 +
   14.33 +//class XFormNode;
   14.34 +
   14.35 +
   14.36 +class Triangle {
   14.37 +public:
   14.38 +	Vector3 v[3];
   14.39 +	Vector3 normal;
   14.40 +	bool normal_valid;
   14.41 +	int id;
   14.42 +
   14.43 +	Triangle();
   14.44 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
   14.45 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
   14.46 +
   14.47 +	/// calculate normal (quite expensive)
   14.48 +	void calc_normal();
   14.49 +	const Vector3 &get_normal() const;
   14.50 +
   14.51 +	void transform(const Matrix4x4 &xform);
   14.52 +
   14.53 +	void draw() const;
   14.54 +	void draw_wire() const;
   14.55 +
   14.56 +	/// calculate barycentric coordinates of a point
   14.57 +	Vector3 calc_barycentric(const Vector3 &pos) const;
   14.58 +
   14.59 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   14.60 +};
   14.61 +
   14.62 +
   14.63 +class Mesh {
   14.64 +private:
   14.65 +	std::string name;
   14.66 +	unsigned int nverts, nfaces;
   14.67 +
   14.68 +	// current value for each attribute for the immedate mode
   14.69 +	// interface.
   14.70 +	Vector4 cur_val[NUM_MESH_ATTR];
   14.71 +
   14.72 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
   14.73 +
   14.74 +	// vertex attribute data and buffer objects
   14.75 +	struct {
   14.76 +		int nelem;					// number of elements per attribute range: [1, 4]
   14.77 +		std::vector<float> data;
   14.78 +		unsigned int vbo;
   14.79 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
   14.80 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
   14.81 +		//int sdr_loc;
   14.82 +	} vattr[NUM_MESH_ATTR];
   14.83 +
   14.84 +	static int global_sdr_loc[NUM_MESH_ATTR];
   14.85 +
   14.86 +	//std::vector<XFormNode*> bones;	// bones affecting this mesh
   14.87 +
   14.88 +	// index data and buffer object
   14.89 +	std::vector<unsigned int> idata;
   14.90 +	unsigned int ibo;
   14.91 +	mutable bool ibo_valid;
   14.92 +	mutable bool idata_valid;
   14.93 +
   14.94 +	// index buffer object for wireframe rendering (constructed on demand)
   14.95 +	unsigned int wire_ibo;
   14.96 +	mutable bool wire_ibo_valid;
   14.97 +
   14.98 +	// axis-aligned bounding box
   14.99 +	mutable AABox aabb;
  14.100 +	mutable bool aabb_valid;
  14.101 +
  14.102 +	// bounding sphere
  14.103 +	mutable Sphere bsph;
  14.104 +	mutable bool bsph_valid;
  14.105 +
  14.106 +	// keeps the last intersected face
  14.107 +	mutable Triangle hitface;
  14.108 +	// keeps the last intersected vertex position
  14.109 +	mutable Vector3 hitvert;
  14.110 +
  14.111 +	void calc_aabb();
  14.112 +	void calc_bsph();
  14.113 +
  14.114 +	static unsigned int intersect_mode;
  14.115 +	static float vertex_sel_dist;
  14.116 +
  14.117 +	static float vis_vecsize;
  14.118 +
  14.119 +	/// update the VBOs after data has changed (invalid vbo/ibo)
  14.120 +	void update_buffers();
  14.121 +	/// construct/update the wireframe index buffer (called from draw_wire).
  14.122 +	void update_wire_ibo();
  14.123 +
  14.124 +	mutable int cur_sdr;
  14.125 +	bool pre_draw() const;
  14.126 +	void post_draw() const;
  14.127 +
  14.128 +
  14.129 +public:
  14.130 +	static bool use_custom_sdr_attr;
  14.131 +
  14.132 +	Mesh();
  14.133 +	~Mesh();
  14.134 +
  14.135 +	Mesh(const Mesh &rhs);
  14.136 +	Mesh &operator =(const Mesh &rhs);
  14.137 +	bool clone(const Mesh &m);
  14.138 +
  14.139 +	void set_name(const char *name);
  14.140 +	const char *get_name() const;
  14.141 +
  14.142 +	bool has_attrib(int attr) const;
  14.143 +	bool is_indexed() const;
  14.144 +
  14.145 +	// clears everything about this mesh, and returns to the newly constructed state
  14.146 +	void clear();
  14.147 +
  14.148 +	// access the vertex attribute data
  14.149 +	// if vdata == 0, space is just allocated
  14.150 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
  14.151 +	float *get_attrib_data(int attrib);	// invalidates vbo
  14.152 +	const float *get_attrib_data(int attrib) const;
  14.153 +
  14.154 +	// simple access to any particular attribute
  14.155 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
  14.156 +	Vector4 get_attrib(int attrib, int idx) const;
  14.157 +
  14.158 +	int get_attrib_count(int attrib) const;
  14.159 +
  14.160 +	// ... same for index data
  14.161 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
  14.162 +	unsigned int *get_index_data();	// invalidates ibo
  14.163 +	const unsigned int *get_index_data() const;
  14.164 +
  14.165 +	int get_index_count() const;
  14.166 +
  14.167 +	void append(const Mesh &mesh);
  14.168 +
  14.169 +	// immediate-mode style mesh construction interface
  14.170 +	void vertex(float x, float y, float z);
  14.171 +	void normal(float nx, float ny, float nz);
  14.172 +	void tangent(float tx, float ty, float tz);
  14.173 +	void texcoord(float u, float v, float w);
  14.174 +	void boneweights(float w1, float w2, float w3, float w4);
  14.175 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
  14.176 +
  14.177 +	int get_poly_count() const;
  14.178 +
  14.179 +	/* apply a transformation to the vertices and its inverse-transpose
  14.180 +	 * to the normals and tangents.
  14.181 +	 */
  14.182 +	void apply_xform(const Matrix4x4 &xform);
  14.183 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
  14.184 +
  14.185 +	void flip();	// both faces and normals
  14.186 +	void flip_faces();
  14.187 +	void flip_normals();
  14.188 +
  14.189 +	// adds a bone and returns its index
  14.190 +	/*int add_bone(XFormNode *bone);
  14.191 +	const XFormNode *get_bone(int idx) const;
  14.192 +	int get_bones_count() const;*/
  14.193 +
  14.194 +	// access the shader attribute locations
  14.195 +	static void set_attrib_location(int attr, int loc);
  14.196 +	static int get_attrib_location(int attr);
  14.197 +	static void clear_attrib_locations();
  14.198 +
  14.199 +	static void set_vis_vecsize(float sz);
  14.200 +	static float get_vis_vecsize();
  14.201 +
  14.202 +	void draw() const;
  14.203 +	void draw_wire() const;
  14.204 +	void draw_vertices() const;
  14.205 +	void draw_normals() const;
  14.206 +	void draw_tangents() const;
  14.207 +
  14.208 +	/** get the bounding box in local space. The result will be cached, and subsequent
  14.209 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  14.210 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  14.211 +	 * @{ */
  14.212 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
  14.213 +	const AABox &get_aabbox() const;
  14.214 +	/// @}
  14.215 +
  14.216 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
  14.217 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  14.218 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  14.219 +	 * @{ */
  14.220 +	float get_bsphere(Vector3 *center, float *rad) const;
  14.221 +	const Sphere &get_bsphere() const;
  14.222 +
  14.223 +	static void set_intersect_mode(unsigned int mode);
  14.224 +	static unsigned int get_intersect_mode();
  14.225 +	static void set_vertex_select_distance(float dist);
  14.226 +	static float get_vertex_select_distance();
  14.227 +
  14.228 +	/** Find the intersection between the mesh and a ray.
  14.229 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
  14.230 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
  14.231 +	 */
  14.232 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
  14.233 +
  14.234 +	// texture coordinate manipulation
  14.235 +	void texcoord_apply_xform(const Matrix4x4 &xform);
  14.236 +	void texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang);
  14.237 +	void texcoord_gen_box();
  14.238 +	void texcoord_gen_cylinder();
  14.239 +
  14.240 +	void dump(FILE *fp) const;
  14.241 +};
  14.242 +
  14.243 +#endif	// MESH_H_
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/meshgen.cc	Mon Aug 31 07:38:37 2015 +0300
    15.3 @@ -0,0 +1,775 @@
    15.4 +#include <stdio.h>
    15.5 +#include "meshgen.h"
    15.6 +#include "mesh.h"
    15.7 +
    15.8 +// -------- sphere --------
    15.9 +
   15.10 +#define SURAD(u)	((u) * 2.0 * M_PI)
   15.11 +#define SVRAD(v)	((v) * M_PI)
   15.12 +
   15.13 +static Vector3 sphvec(float theta, float phi)
   15.14 +{
   15.15 +	return Vector3(sin(theta) * sin(phi),
   15.16 +			cos(phi),
   15.17 +			cos(theta) * sin(phi));
   15.18 +}
   15.19 +
   15.20 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
   15.21 +{
   15.22 +	if(usub < 4) usub = 4;
   15.23 +	if(vsub < 2) vsub = 2;
   15.24 +
   15.25 +	int uverts = usub + 1;
   15.26 +	int vverts = vsub + 1;
   15.27 +
   15.28 +	int num_verts = uverts * vverts;
   15.29 +	int num_quads = usub * vsub;
   15.30 +	int num_tri = num_quads * 2;
   15.31 +
   15.32 +	mesh->clear();
   15.33 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
   15.34 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
   15.35 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
   15.36 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
   15.37 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
   15.38 +
   15.39 +	float du = urange / (float)(uverts - 1);
   15.40 +	float dv = vrange / (float)(vverts - 1);
   15.41 +
   15.42 +	float u = 0.0;
   15.43 +	for(int i=0; i<uverts; i++) {
   15.44 +		float theta = u * 2.0 * M_PI;
   15.45 +
   15.46 +		float v = 0.0;
   15.47 +		for(int j=0; j<vverts; j++) {
   15.48 +			float phi = v * M_PI;
   15.49 +
   15.50 +			Vector3 pos = sphvec(theta, phi);
   15.51 +
   15.52 +			*varr++ = pos * rad;
   15.53 +			*narr++ = pos;
   15.54 +			*tarr++ = (sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f)).normalized();
   15.55 +			*uvarr++ = Vector2(u * urange, v * vrange);
   15.56 +
   15.57 +			if(i < usub && j < vsub) {
   15.58 +				int idx = i * vverts + j;
   15.59 +				*idxarr++ = idx;
   15.60 +				*idxarr++ = idx + 1;
   15.61 +				*idxarr++ = idx + vverts + 1;
   15.62 +
   15.63 +				*idxarr++ = idx;
   15.64 +				*idxarr++ = idx + vverts + 1;
   15.65 +				*idxarr++ = idx + vverts;
   15.66 +			}
   15.67 +
   15.68 +			v += dv;
   15.69 +		}
   15.70 +		u += du;
   15.71 +	}
   15.72 +}
   15.73 +
   15.74 +// -------- torus -----------
   15.75 +static Vector3 torusvec(float theta, float phi, float mr, float rr)
   15.76 +{
   15.77 +	theta = -theta;
   15.78 +
   15.79 +	float rx = -cos(phi) * rr + mr;
   15.80 +	float ry = sin(phi) * rr;
   15.81 +	float rz = 0.0;
   15.82 +
   15.83 +	float x = rx * sin(theta) + rz * cos(theta);
   15.84 +	float y = ry;
   15.85 +	float z = -rx * cos(theta) + rz * sin(theta);
   15.86 +
   15.87 +	return Vector3(x, y, z);
   15.88 +}
   15.89 +
   15.90 +void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange)
   15.91 +{
   15.92 +	if(usub < 4) usub = 4;
   15.93 +	if(vsub < 2) vsub = 2;
   15.94 +
   15.95 +	int uverts = usub + 1;
   15.96 +	int vverts = vsub + 1;
   15.97 +
   15.98 +	int num_verts = uverts * vverts;
   15.99 +	int num_quads = usub * vsub;
  15.100 +	int num_tri = num_quads * 2;
  15.101 +
  15.102 +	mesh->clear();
  15.103 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.104 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.105 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.106 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.107 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.108 +
  15.109 +	float du = urange / (float)(uverts - 1);
  15.110 +	float dv = vrange / (float)(vverts - 1);
  15.111 +
  15.112 +	float u = 0.0;
  15.113 +	for(int i=0; i<uverts; i++) {
  15.114 +		float theta = u * 2.0 * M_PI;
  15.115 +
  15.116 +		float v = 0.0;
  15.117 +		for(int j=0; j<vverts; j++) {
  15.118 +			float phi = v * 2.0 * M_PI;
  15.119 +
  15.120 +			Vector3 pos = torusvec(theta, phi, mainrad, ringrad);
  15.121 +			Vector3 cent = torusvec(theta, phi, mainrad, 0.0);
  15.122 +
  15.123 +			*varr++ = pos;
  15.124 +			*narr++ = (pos - cent) / ringrad;
  15.125 +
  15.126 +			Vector3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad);
  15.127 +			Vector3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad);
  15.128 +
  15.129 +			*tarr++ = (pnext - pprev).normalized();
  15.130 +			*uvarr++ = Vector2(u * urange, v * vrange);
  15.131 +
  15.132 +			if(i < usub && j < vsub) {
  15.133 +				int idx = i * vverts + j;
  15.134 +				*idxarr++ = idx;
  15.135 +				*idxarr++ = idx + 1;
  15.136 +				*idxarr++ = idx + vverts + 1;
  15.137 +
  15.138 +				*idxarr++ = idx;
  15.139 +				*idxarr++ = idx + vverts + 1;
  15.140 +				*idxarr++ = idx + vverts;
  15.141 +			}
  15.142 +
  15.143 +			v += dv;
  15.144 +		}
  15.145 +		u += du;
  15.146 +	}
  15.147 +}
  15.148 +
  15.149 +
  15.150 +// -------- cylinder --------
  15.151 +
  15.152 +static Vector3 cylvec(float theta, float height)
  15.153 +{
  15.154 +	return Vector3(sin(theta), height, cos(theta));
  15.155 +}
  15.156 +
  15.157 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
  15.158 +{
  15.159 +	if(usub < 4) usub = 4;
  15.160 +	if(vsub < 1) vsub = 1;
  15.161 +
  15.162 +	int uverts = usub + 1;
  15.163 +	int vverts = vsub + 1;
  15.164 +
  15.165 +	int num_body_verts = uverts * vverts;
  15.166 +	int num_body_quads = usub * vsub;
  15.167 +	int num_body_tri = num_body_quads * 2;
  15.168 +
  15.169 +	int capvverts = capsub ? capsub + 1 : 0;
  15.170 +	int num_cap_verts = uverts * capvverts;
  15.171 +	int num_cap_quads = usub * capsub;
  15.172 +	int num_cap_tri = num_cap_quads * 2;
  15.173 +
  15.174 +	int num_verts = num_body_verts + num_cap_verts * 2;
  15.175 +	int num_tri = num_body_tri + num_cap_tri * 2;
  15.176 +
  15.177 +	mesh->clear();
  15.178 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.179 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.180 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.181 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.182 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.183 +
  15.184 +	float du = urange / (float)(uverts - 1);
  15.185 +	float dv = vrange / (float)(vverts - 1);
  15.186 +
  15.187 +	float u = 0.0;
  15.188 +	for(int i=0; i<uverts; i++) {
  15.189 +		float theta = SURAD(u);
  15.190 +
  15.191 +		float v = 0.0;
  15.192 +		for(int j=0; j<vverts; j++) {
  15.193 +			float y = (v - 0.5) * height;
  15.194 +			Vector3 pos = cylvec(theta, y);
  15.195 +
  15.196 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  15.197 +			*narr++ = Vector3(pos.x, 0.0, pos.z);
  15.198 +			*tarr++ = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  15.199 +			*uvarr++ = Vector2(u * urange, v * vrange);
  15.200 +
  15.201 +			if(i < usub && j < vsub) {
  15.202 +				int idx = i * vverts + j;
  15.203 +
  15.204 +				*idxarr++ = idx;
  15.205 +				*idxarr++ = idx + vverts + 1;
  15.206 +				*idxarr++ = idx + 1;
  15.207 +
  15.208 +				*idxarr++ = idx;
  15.209 +				*idxarr++ = idx + vverts;
  15.210 +				*idxarr++ = idx + vverts + 1;
  15.211 +			}
  15.212 +
  15.213 +			v += dv;
  15.214 +		}
  15.215 +		u += du;
  15.216 +	}
  15.217 +
  15.218 +
  15.219 +	// now the cap!
  15.220 +	if(!capsub) {
  15.221 +		return;
  15.222 +	}
  15.223 +
  15.224 +	dv = 1.0 / (float)(capvverts - 1);
  15.225 +
  15.226 +	u = 0.0;
  15.227 +	for(int i=0; i<uverts; i++) {
  15.228 +		float theta = SURAD(u);
  15.229 +
  15.230 +		float v = 0.0;
  15.231 +		for(int j=0; j<capvverts; j++) {
  15.232 +			float r = v * rad;
  15.233 +
  15.234 +			Vector3 pos = cylvec(theta, height / 2.0) * r;
  15.235 +			pos.y = height / 2.0;
  15.236 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  15.237 +
  15.238 +			*varr++ = pos;
  15.239 +			*narr++ = Vector3(0, 1, 0);
  15.240 +			*tarr++ = tang;
  15.241 +			*uvarr++ = Vector2(u * urange, v);
  15.242 +
  15.243 +			pos.y = -height / 2.0;
  15.244 +			*varr++ = pos;
  15.245 +			*narr++ = Vector3(0, -1, 0);
  15.246 +			*tarr++ = -tang;
  15.247 +			*uvarr++ = Vector2(u * urange, v);
  15.248 +
  15.249 +			if(i < usub && j < capsub) {
  15.250 +				unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
  15.251 +
  15.252 +				unsigned int vidx[4] = {
  15.253 +					idx,
  15.254 +					idx + capvverts * 2,
  15.255 +					idx + (capvverts + 1) * 2,
  15.256 +					idx + 2
  15.257 +				};
  15.258 +
  15.259 +				*idxarr++ = vidx[0];
  15.260 +				*idxarr++ = vidx[2];
  15.261 +				*idxarr++ = vidx[1];
  15.262 +				*idxarr++ = vidx[0];
  15.263 +				*idxarr++ = vidx[3];
  15.264 +				*idxarr++ = vidx[2];
  15.265 +
  15.266 +				*idxarr++ = vidx[0] + 1;
  15.267 +				*idxarr++ = vidx[1] + 1;
  15.268 +				*idxarr++ = vidx[2] + 1;
  15.269 +				*idxarr++ = vidx[0] + 1;
  15.270 +				*idxarr++ = vidx[2] + 1;
  15.271 +				*idxarr++ = vidx[3] + 1;
  15.272 +			}
  15.273 +
  15.274 +			v += dv;
  15.275 +		}
  15.276 +		u += du;
  15.277 +	}
  15.278 +}
  15.279 +
  15.280 +// -------- cone --------
  15.281 +
  15.282 +static Vector3 conevec(float theta, float y, float height)
  15.283 +{
  15.284 +	float scale = 1.0 - y / height;
  15.285 +	return Vector3(sin(theta) * scale, y, cos(theta) * scale);
  15.286 +}
  15.287 +
  15.288 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
  15.289 +{
  15.290 +	if(usub < 4) usub = 4;
  15.291 +	if(vsub < 1) vsub = 1;
  15.292 +
  15.293 +	int uverts = usub + 1;
  15.294 +	int vverts = vsub + 1;
  15.295 +
  15.296 +	int num_body_verts = uverts * vverts;
  15.297 +	int num_body_quads = usub * vsub;
  15.298 +	int num_body_tri = num_body_quads * 2;
  15.299 +
  15.300 +	int capvverts = capsub ? capsub + 1 : 0;
  15.301 +	int num_cap_verts = uverts * capvverts;
  15.302 +	int num_cap_quads = usub * capsub;
  15.303 +	int num_cap_tri = num_cap_quads * 2;
  15.304 +
  15.305 +	int num_verts = num_body_verts + num_cap_verts;
  15.306 +	int num_tri = num_body_tri + num_cap_tri;
  15.307 +
  15.308 +	mesh->clear();
  15.309 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.310 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.311 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.312 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.313 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.314 +
  15.315 +	float du = urange / (float)(uverts - 1);
  15.316 +	float dv = vrange / (float)(vverts - 1);
  15.317 +
  15.318 +	float u = 0.0;
  15.319 +	for(int i=0; i<uverts; i++) {
  15.320 +		float theta = SURAD(u);
  15.321 +
  15.322 +		float v = 0.0;
  15.323 +		for(int j=0; j<vverts; j++) {
  15.324 +			float y = v * height;
  15.325 +			Vector3 pos = conevec(theta, y, height);
  15.326 +
  15.327 +			Vector3 tang = (conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height)).normalized();
  15.328 +			Vector3 bitang = (conevec(theta, y + 0.1, height) - pos).normalized();
  15.329 +
  15.330 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  15.331 +			*narr++ = cross_product(tang, bitang);
  15.332 +			*tarr++ = tang;
  15.333 +			*uvarr++ = Vector2(u * urange, v * vrange);
  15.334 +
  15.335 +			if(i < usub && j < vsub) {
  15.336 +				int idx = i * vverts + j;
  15.337 +
  15.338 +				*idxarr++ = idx;
  15.339 +				*idxarr++ = idx + vverts + 1;
  15.340 +				*idxarr++ = idx + 1;
  15.341 +
  15.342 +				*idxarr++ = idx;
  15.343 +				*idxarr++ = idx + vverts;
  15.344 +				*idxarr++ = idx + vverts + 1;
  15.345 +			}
  15.346 +
  15.347 +			v += dv;
  15.348 +		}
  15.349 +		u += du;
  15.350 +	}
  15.351 +
  15.352 +
  15.353 +	// now the bottom cap!
  15.354 +	if(!capsub) {
  15.355 +		return;
  15.356 +	}
  15.357 +
  15.358 +	dv = 1.0 / (float)(capvverts - 1);
  15.359 +
  15.360 +	u = 0.0;
  15.361 +	for(int i=0; i<uverts; i++) {
  15.362 +		float theta = SURAD(u);
  15.363 +
  15.364 +		float v = 0.0;
  15.365 +		for(int j=0; j<capvverts; j++) {
  15.366 +			float r = v * rad;
  15.367 +
  15.368 +			Vector3 pos = conevec(theta, 0.0, height) * r;
  15.369 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  15.370 +
  15.371 +			*varr++ = pos;
  15.372 +			*narr++ = Vector3(0, -1, 0);
  15.373 +			*tarr++ = tang;
  15.374 +			*uvarr++ = Vector2(u * urange, v);
  15.375 +
  15.376 +			if(i < usub && j < capsub) {
  15.377 +				unsigned int idx = num_body_verts + i * capvverts + j;
  15.378 +
  15.379 +				unsigned int vidx[4] = {
  15.380 +					idx,
  15.381 +					idx + capvverts,
  15.382 +					idx + (capvverts + 1),
  15.383 +					idx + 1
  15.384 +				};
  15.385 +
  15.386 +				*idxarr++ = vidx[0];
  15.387 +				*idxarr++ = vidx[1];
  15.388 +				*idxarr++ = vidx[2];
  15.389 +				*idxarr++ = vidx[0];
  15.390 +				*idxarr++ = vidx[2];
  15.391 +				*idxarr++ = vidx[3];
  15.392 +			}
  15.393 +
  15.394 +			v += dv;
  15.395 +		}
  15.396 +		u += du;
  15.397 +	}
  15.398 +}
  15.399 +
  15.400 +
  15.401 +// -------- plane --------
  15.402 +
  15.403 +void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
  15.404 +{
  15.405 +	gen_heightmap(mesh, width, height, usub, vsub, 0);
  15.406 +}
  15.407 +
  15.408 +
  15.409 +// ----- heightmap ------
  15.410 +
  15.411 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
  15.412 +{
  15.413 +	if(usub < 1) usub = 1;
  15.414 +	if(vsub < 1) vsub = 1;
  15.415 +
  15.416 +	mesh->clear();
  15.417 +
  15.418 +	int uverts = usub + 1;
  15.419 +	int vverts = vsub + 1;
  15.420 +	int num_verts = uverts * vverts;
  15.421 +
  15.422 +	int num_quads = usub * vsub;
  15.423 +	int num_tri = num_quads * 2;
  15.424 +
  15.425 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.426 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.427 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.428 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.429 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.430 +
  15.431 +	float du = 1.0 / (float)usub;
  15.432 +	float dv = 1.0 / (float)vsub;
  15.433 +
  15.434 +	float u = 0.0;
  15.435 +	for(int i=0; i<uverts; i++) {
  15.436 +		float v = 0.0;
  15.437 +		for(int j=0; j<vverts; j++) {
  15.438 +			float x = (u - 0.5) * width;
  15.439 +			float y = (v - 0.5) * height;
  15.440 +			float z = hf ? hf(u, v, hfdata) : 0.0;
  15.441 +
  15.442 +			Vector3 normal = Vector3(0, 0, 1);
  15.443 +			if(hf) {
  15.444 +				float u1z = hf(u + du, v, hfdata);
  15.445 +				float v1z = hf(u, v + dv, hfdata);
  15.446 +
  15.447 +				Vector3 tang = Vector3(du * width, 0, u1z - z);
  15.448 +				Vector3 bitan = Vector3(0, dv * height, v1z - z);
  15.449 +				normal = cross_product(tang, bitan).normalized();
  15.450 +			}
  15.451 +
  15.452 +			*varr++ = Vector3(x, y, z);
  15.453 +			*narr++ = normal;
  15.454 +			*tarr++ = Vector3(1, 0, 0);
  15.455 +			*uvarr++ = Vector2(u, v);
  15.456 +
  15.457 +			if(i < usub && j < vsub) {
  15.458 +				int idx = i * vverts + j;
  15.459 +
  15.460 +				*idxarr++ = idx;
  15.461 +				*idxarr++ = idx + vverts + 1;
  15.462 +				*idxarr++ = idx + 1;
  15.463 +
  15.464 +				*idxarr++ = idx;
  15.465 +				*idxarr++ = idx + vverts;
  15.466 +				*idxarr++ = idx + vverts + 1;
  15.467 +			}
  15.468 +
  15.469 +			v += dv;
  15.470 +		}
  15.471 +		u += du;
  15.472 +	}
  15.473 +}
  15.474 +
  15.475 +// ----- box ------
  15.476 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub)
  15.477 +{
  15.478 +	static const float face_angles[][2] = {
  15.479 +		{0, 0},
  15.480 +		{M_PI / 2.0, 0},
  15.481 +		{M_PI, 0},
  15.482 +		{3.0 * M_PI / 2.0, 0},
  15.483 +		{0, M_PI / 2.0},
  15.484 +		{0, -M_PI / 2.0}
  15.485 +	};
  15.486 +
  15.487 +	if(usub < 1) usub = 1;
  15.488 +	if(vsub < 1) vsub = 1;
  15.489 +
  15.490 +	mesh->clear();
  15.491 +
  15.492 +	for(int i=0; i<6; i++) {
  15.493 +		Matrix4x4 xform, dir_xform;
  15.494 +		Mesh m;
  15.495 +
  15.496 +		gen_plane(&m, 1, 1, usub, vsub);
  15.497 +		xform.rotate(Vector3(face_angles[i][1], face_angles[i][0], 0));
  15.498 +		dir_xform = xform;
  15.499 +		xform.translate(Vector3(0, 0, 0.5));
  15.500 +		m.apply_xform(xform, dir_xform);
  15.501 +
  15.502 +		mesh->append(m);
  15.503 +	}
  15.504 +
  15.505 +	Matrix4x4 scale;
  15.506 +	scale.set_scaling(Vector3(xsz, ysz, zsz));
  15.507 +	mesh->apply_xform(scale, Matrix4x4::identity);
  15.508 +}
  15.509 +
  15.510 +/*
  15.511 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz)
  15.512 +{
  15.513 +	mesh->clear();
  15.514 +
  15.515 +	const int num_faces = 6;
  15.516 +	int num_verts = num_faces * 4;
  15.517 +	int num_tri = num_faces * 2;
  15.518 +
  15.519 +	float x = xsz / 2.0;
  15.520 +	float y = ysz / 2.0;
  15.521 +	float z = zsz / 2.0;
  15.522 +
  15.523 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.524 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.525 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.526 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.527 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.528 +
  15.529 +	static const Vector2 uv[] = { Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(0, 1) };
  15.530 +
  15.531 +	// front
  15.532 +	for(int i=0; i<4; i++) {
  15.533 +		*narr++ = Vector3(0, 0, 1);
  15.534 +		*tarr++ = Vector3(1, 0, 0);
  15.535 +		*uvarr++ = uv[i];
  15.536 +	}
  15.537 +	*varr++ = Vector3(-x, -y, z);
  15.538 +	*varr++ = Vector3(x, -y, z);
  15.539 +	*varr++ = Vector3(x, y, z);
  15.540 +	*varr++ = Vector3(-x, y, z);
  15.541 +	// right
  15.542 +	for(int i=0; i<4; i++) {
  15.543 +		*narr++ = Vector3(1, 0, 0);
  15.544 +		*tarr++ = Vector3(0, 0, -1);
  15.545 +		*uvarr++ = uv[i];
  15.546 +	}
  15.547 +	*varr++ = Vector3(x, -y, z);
  15.548 +	*varr++ = Vector3(x, -y, -z);
  15.549 +	*varr++ = Vector3(x, y, -z);
  15.550 +	*varr++ = Vector3(x, y, z);
  15.551 +	// back
  15.552 +	for(int i=0; i<4; i++) {
  15.553 +		*narr++ = Vector3(0, 0, -1);
  15.554 +		*tarr++ = Vector3(-1, 0, 0);
  15.555 +		*uvarr++ = uv[i];
  15.556 +	}
  15.557 +	*varr++ = Vector3(x, -y, -z);
  15.558 +	*varr++ = Vector3(-x, -y, -z);
  15.559 +	*varr++ = Vector3(-x, y, -z);
  15.560 +	*varr++ = Vector3(x, y, -z);
  15.561 +	// left
  15.562 +	for(int i=0; i<4; i++) {
  15.563 +		*narr++ = Vector3(-1, 0, 0);
  15.564 +		*tarr++ = Vector3(0, 0, 1);
  15.565 +		*uvarr++ = uv[i];
  15.566 +	}
  15.567 +	*varr++ = Vector3(-x, -y, -z);
  15.568 +	*varr++ = Vector3(-x, -y, z);
  15.569 +	*varr++ = Vector3(-x, y, z);
  15.570 +	*varr++ = Vector3(-x, y, -z);
  15.571 +	// top
  15.572 +	for(int i=0; i<4; i++) {
  15.573 +		*narr++ = Vector3(0, 1, 0);
  15.574 +		*tarr++ = Vector3(1, 0, 0);
  15.575 +		*uvarr++ = uv[i];
  15.576 +	}
  15.577 +	*varr++ = Vector3(-x, y, z);
  15.578 +	*varr++ = Vector3(x, y, z);
  15.579 +	*varr++ = Vector3(x, y, -z);
  15.580 +	*varr++ = Vector3(-x, y, -z);
  15.581 +	// bottom
  15.582 +	for(int i=0; i<4; i++) {
  15.583 +		*narr++ = Vector3(0, -1, 0);
  15.584 +		*tarr++ = Vector3(1, 0, 0);
  15.585 +		*uvarr++ = uv[i];
  15.586 +	}
  15.587 +	*varr++ = Vector3(-x, -y, -z);
  15.588 +	*varr++ = Vector3(x, -y, -z);
  15.589 +	*varr++ = Vector3(x, -y, z);
  15.590 +	*varr++ = Vector3(-x, -y, z);
  15.591 +
  15.592 +	// index array
  15.593 +	static const int faceidx[] = {0, 1, 2, 0, 2, 3};
  15.594 +	for(int i=0; i<num_faces; i++) {
  15.595 +		for(int j=0; j<6; j++) {
  15.596 +			*idxarr++ = faceidx[j] + i * 4;
  15.597 +		}
  15.598 +	}
  15.599 +}
  15.600 +*/
  15.601 +
  15.602 +static inline Vector3 rev_vert(float u, float v, Vector2 (*rf)(float, float, void*), void *cls)
  15.603 +{
  15.604 +	Vector2 pos = rf(u, v, cls);
  15.605 +
  15.606 +	float angle = u * 2.0 * M_PI;
  15.607 +	float x = pos.x * cos(angle);
  15.608 +	float y = pos.y;
  15.609 +	float z = pos.x * sin(angle);
  15.610 +
  15.611 +	return Vector3(x, y, z);
  15.612 +}
  15.613 +
  15.614 +// ------ surface of revolution -------
  15.615 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), void *cls)
  15.616 +{
  15.617 +	gen_revol(mesh, usub, vsub, rfunc, 0, cls);
  15.618 +}
  15.619 +
  15.620 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*),
  15.621 +		Vector2 (*nfunc)(float, float, void*), void *cls)
  15.622 +{
  15.623 +	if(!rfunc) return;
  15.624 +	if(usub < 3) usub = 3;
  15.625 +	if(vsub < 1) vsub = 1;
  15.626 +
  15.627 +	mesh->clear();
  15.628 +
  15.629 +	int uverts = usub + 1;
  15.630 +	int vverts = vsub + 1;
  15.631 +	int num_verts = uverts * vverts;
  15.632 +
  15.633 +	int num_quads = usub * vsub;
  15.634 +	int num_tri = num_quads * 2;
  15.635 +
  15.636 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.637 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.638 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.639 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.640 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.641 +
  15.642 +	float du = 1.0 / (float)(uverts - 1);
  15.643 +	float dv = 1.0 / (float)(vverts - 1);
  15.644 +
  15.645 +	float u = 0.0;
  15.646 +	for(int i=0; i<uverts; i++) {
  15.647 +		float v = 0.0;
  15.648 +		for(int j=0; j<vverts; j++) {
  15.649 +			Vector3 pos = rev_vert(u, v, rfunc, cls);
  15.650 +
  15.651 +			Vector3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls);
  15.652 +			Vector3 tang = nextu - pos;
  15.653 +			if(tang.length_sq() < 1e-6) {
  15.654 +				float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
  15.655 +				nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls);
  15.656 +				tang = nextu - pos;
  15.657 +			}
  15.658 +
  15.659 +			Vector3 normal;
  15.660 +			if(nfunc) {
  15.661 +				normal = rev_vert(u, v, nfunc, cls);
  15.662 +			} else {
  15.663 +				Vector3 nextv = rev_vert(u, v + dv, rfunc, cls);
  15.664 +				Vector3 bitan = nextv - pos;
  15.665 +				if(bitan.length_sq() < 1e-6) {
  15.666 +					nextv = rev_vert(u, v - dv, rfunc, cls);
  15.667 +					bitan = pos - nextv;
  15.668 +				}
  15.669 +
  15.670 +				normal = cross_product(tang, bitan);
  15.671 +			}
  15.672 +
  15.673 +			*varr++ = pos;
  15.674 +			*narr++ = normal.normalized();
  15.675 +			*tarr++ = tang.normalized();
  15.676 +			*uvarr++ = Vector2(u, v);
  15.677 +
  15.678 +			if(i < usub && j < vsub) {
  15.679 +				int idx = i * vverts + j;
  15.680 +
  15.681 +				*idxarr++ = idx;
  15.682 +				*idxarr++ = idx + vverts + 1;
  15.683 +				*idxarr++ = idx + 1;
  15.684 +
  15.685 +				*idxarr++ = idx;
  15.686 +				*idxarr++ = idx + vverts;
  15.687 +				*idxarr++ = idx + vverts + 1;
  15.688 +			}
  15.689 +
  15.690 +			v += dv;
  15.691 +		}
  15.692 +		u += du;
  15.693 +	}
  15.694 +}
  15.695 +
  15.696 +
  15.697 +static inline Vector3 sweep_vert(float u, float v, float height, Vector2 (*sf)(float, float, void*), void *cls)
  15.698 +{
  15.699 +	Vector2 pos = sf(u, v, cls);
  15.700 +
  15.701 +	float x = pos.x;
  15.702 +	float y = v * height;
  15.703 +	float z = pos.y;
  15.704 +
  15.705 +	return Vector3(x, y, z);
  15.706 +}
  15.707 +
  15.708 +// ---- sweep shape along a path ----
  15.709 +void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vector2 (*sfunc)(float, float, void*), void *cls)
  15.710 +{
  15.711 +	if(!sfunc) return;
  15.712 +	if(usub < 3) usub = 3;
  15.713 +	if(vsub < 1) vsub = 1;
  15.714 +
  15.715 +	mesh->clear();
  15.716 +
  15.717 +	int uverts = usub + 1;
  15.718 +	int vverts = vsub + 1;
  15.719 +	int num_verts = uverts * vverts;
  15.720 +
  15.721 +	int num_quads = usub * vsub;
  15.722 +	int num_tri = num_quads * 2;
  15.723 +
  15.724 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.725 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.726 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.727 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.728 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.729 +
  15.730 +	float du = 1.0 / (float)(uverts - 1);
  15.731 +	float dv = 1.0 / (float)(vverts - 1);
  15.732 +
  15.733 +	float u = 0.0;
  15.734 +	for(int i=0; i<uverts; i++) {
  15.735 +		float v = 0.0;
  15.736 +		for(int j=0; j<vverts; j++) {
  15.737 +			Vector3 pos = sweep_vert(u, v, height, sfunc, cls);
  15.738 +
  15.739 +			Vector3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls);
  15.740 +			Vector3 tang = nextu - pos;
  15.741 +			if(tang.length_sq() < 1e-6) {
  15.742 +				float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
  15.743 +				nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls);
  15.744 +				tang = nextu - pos;
  15.745 +			}
  15.746 +
  15.747 +			Vector3 normal;
  15.748 +			Vector3 nextv = sweep_vert(u, v + dv, height, sfunc, cls);
  15.749 +			Vector3 bitan = nextv - pos;
  15.750 +			if(bitan.length_sq() < 1e-6) {
  15.751 +				nextv = sweep_vert(u, v - dv, height, sfunc, cls);
  15.752 +				bitan = pos - nextv;
  15.753 +			}
  15.754 +
  15.755 +			normal = cross_product(tang, bitan);
  15.756 +
  15.757 +			*varr++ = pos;
  15.758 +			*narr++ = normal.normalized();
  15.759 +			*tarr++ = tang.normalized();
  15.760 +			*uvarr++ = Vector2(u, v);
  15.761 +
  15.762 +			if(i < usub && j < vsub) {
  15.763 +				int idx = i * vverts + j;
  15.764 +
  15.765 +				*idxarr++ = idx;
  15.766 +				*idxarr++ = idx + vverts + 1;
  15.767 +				*idxarr++ = idx + 1;
  15.768 +
  15.769 +				*idxarr++ = idx;
  15.770 +				*idxarr++ = idx + vverts;
  15.771 +				*idxarr++ = idx + vverts + 1;
  15.772 +			}
  15.773 +
  15.774 +			v += dv;
  15.775 +		}
  15.776 +		u += du;
  15.777 +	}
  15.778 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/meshgen.h	Mon Aug 31 07:38:37 2015 +0300
    16.3 @@ -0,0 +1,22 @@
    16.4 +#ifndef MESHGEN_H_
    16.5 +#define MESHGEN_H_
    16.6 +
    16.7 +#include "vmath/vmath.h"
    16.8 +
    16.9 +class Mesh;
   16.10 +
   16.11 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange = 1.0, float vrange = 1.0);
   16.12 +void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange = 1.0, float vrange = 1.0);
   16.13 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   16.14 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   16.15 +void gen_plane(Mesh *mesh, float width, float height, int usub = 1, int vsub = 1);
   16.16 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata = 0);
   16.17 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub = 1, int vsub = 1);
   16.18 +
   16.19 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), void *cls = 0);
   16.20 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), Vector2 (*nfunc)(float, float, void*), void *cls);
   16.21 +
   16.22 +/* callback args: (float u, float v, void *cls) -> Vector2 XZ offset u,v in [0, 1] */
   16.23 +void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vector2 (*sfunc)(float, float, void*), void *cls = 0);
   16.24 +
   16.25 +#endif	// MESHGEN_H_
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/object.cc	Mon Aug 31 07:38:37 2015 +0300
    17.3 @@ -0,0 +1,232 @@
    17.4 +#include "object.h"
    17.5 +#include "opengl.h"
    17.6 +#include "shadow.h"
    17.7 +#include "shader.h"
    17.8 +
    17.9 +Material::Material()
   17.10 +	: diffuse(1, 1, 1), specular(0, 0, 0)
   17.11 +{
   17.12 +	shininess = 60.0;
   17.13 +	alpha = 1.0;
   17.14 +}
   17.15 +
   17.16 +RenderOps::RenderOps()
   17.17 +{
   17.18 +	zwrite = true;
   17.19 +	cast_shadows = true;
   17.20 +	transparent = false;
   17.21 +}
   17.22 +
   17.23 +void RenderOps::setup() const
   17.24 +{
   17.25 +	if(!zwrite) {
   17.26 +		glDepthMask(0);
   17.27 +	}
   17.28 +	if(transparent) {
   17.29 +		glEnable(GL_BLEND);
   17.30 +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   17.31 +	} else {
   17.32 +		glDisable(GL_BLEND);
   17.33 +	}
   17.34 +}
   17.35 +
   17.36 +Object::Object()
   17.37 +{
   17.38 +	mesh = 0;
   17.39 +	tex = 0;
   17.40 +	sdr = 0;
   17.41 +}
   17.42 +
   17.43 +Object::~Object()
   17.44 +{
   17.45 +	delete mesh;
   17.46 +}
   17.47 +
   17.48 +Matrix4x4 &Object::xform()
   17.49 +{
   17.50 +	return matrix;
   17.51 +}
   17.52 +
   17.53 +const Matrix4x4 &Object::xform() const
   17.54 +{
   17.55 +	return matrix;
   17.56 +}
   17.57 +
   17.58 +Matrix4x4 &Object::tex_xform()
   17.59 +{
   17.60 +	return tex_matrix;
   17.61 +}
   17.62 +
   17.63 +const Matrix4x4 &Object::tex_xform() const
   17.64 +{
   17.65 +	return tex_matrix;
   17.66 +}
   17.67 +
   17.68 +void Object::set_mesh(Mesh *m)
   17.69 +{
   17.70 +	this->mesh = m;
   17.71 +}
   17.72 +
   17.73 +Mesh *Object::get_mesh() const
   17.74 +{
   17.75 +	return mesh;
   17.76 +}
   17.77 +
   17.78 +void Object::set_texture(unsigned int tex)
   17.79 +{
   17.80 +	this->tex = tex;
   17.81 +}
   17.82 +
   17.83 +void Object::set_shader(unsigned int sdr)
   17.84 +{
   17.85 +	if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader) {
   17.86 +		this->sdr = sdr;
   17.87 +	}
   17.88 +}
   17.89 +
   17.90 +unsigned int Object::get_shader() const
   17.91 +{
   17.92 +	return sdr;
   17.93 +}
   17.94 +
   17.95 +void Object::draw() const
   17.96 +{
   17.97 +	if(!mesh) return;
   17.98 +
   17.99 +	if(shadow_pass && !rop.cast_shadows) {
  17.100 +		return;
  17.101 +	}
  17.102 +
  17.103 +	glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
  17.104 +	rop.setup();
  17.105 +
  17.106 +	if(glcaps.shaders) {
  17.107 +		if(sdr) {
  17.108 +			if(!shadow_pass) {
  17.109 +				::set_shader(sdr);
  17.110 +			}
  17.111 +		} else {
  17.112 +			::set_shader(0);
  17.113 +		}
  17.114 +	}
  17.115 +
  17.116 +	if(tex) {
  17.117 +		glBindTexture(GL_TEXTURE_2D, tex);
  17.118 +		glEnable(GL_TEXTURE_2D);
  17.119 +
  17.120 +		glMatrixMode(GL_TEXTURE);
  17.121 +		glPushMatrix();
  17.122 +		glLoadTransposeMatrixf(tex_matrix[0]);
  17.123 +	} else {
  17.124 +		glDisable(GL_TEXTURE_2D);
  17.125 +	}
  17.126 +
  17.127 +	glMatrixMode(GL_MODELVIEW);
  17.128 +	glPushMatrix();
  17.129 +	glMultTransposeMatrixf(matrix[0]);
  17.130 +
  17.131 +	float dcol[] = {mtl.diffuse.x, mtl.diffuse.y, mtl.diffuse.z, mtl.alpha};
  17.132 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dcol);
  17.133 +	float scol[] = {mtl.specular.x, mtl.specular.y, mtl.specular.z, 1.0f};
  17.134 +	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol);
  17.135 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mtl.shininess);
  17.136 +
  17.137 +	mesh->draw();
  17.138 +
  17.139 +	if(tex) {
  17.140 +		glDisable(GL_TEXTURE_2D);
  17.141 +
  17.142 +		glMatrixMode(GL_TEXTURE);
  17.143 +		glPopMatrix();
  17.144 +	}
  17.145 +
  17.146 +	if(sdr) {
  17.147 +		::set_shader(0);
  17.148 +	}
  17.149 +
  17.150 +	glMatrixMode(GL_MODELVIEW);
  17.151 +	glPopMatrix();
  17.152 +
  17.153 +	glPopAttrib();
  17.154 +}
  17.155 +
  17.156 +void Object::draw_wire(const Vector4 &col) const
  17.157 +{
  17.158 +	if(shadow_pass) return;
  17.159 +
  17.160 +	glPushAttrib(GL_ENABLE_BIT);
  17.161 +	glDisable(GL_LIGHTING);
  17.162 +	glUseProgram(0);
  17.163 +
  17.164 +	glMatrixMode(GL_MODELVIEW);
  17.165 +	glPushMatrix();
  17.166 +	glMultTransposeMatrixf(matrix[0]);
  17.167 +
  17.168 +	glColor4f(col.x, col.y, col.z, col.w);
  17.169 +	mesh->draw_wire();
  17.170 +
  17.171 +	glPopMatrix();
  17.172 +	glPopAttrib();
  17.173 +}
  17.174 +
  17.175 +void Object::draw_vertices(const Vector4 &col) const
  17.176 +{
  17.177 +	glPushAttrib(GL_ENABLE_BIT);
  17.178 +	glDisable(GL_LIGHTING);
  17.179 +	glUseProgram(0);
  17.180 +
  17.181 +	glMatrixMode(GL_MODELVIEW);
  17.182 +	glPushMatrix();
  17.183 +	glMultTransposeMatrixf(matrix[0]);
  17.184 +
  17.185 +	glColor4f(col.x, col.y, col.z, col.w);
  17.186 +	mesh->draw_vertices();
  17.187 +
  17.188 +	glPopMatrix();
  17.189 +	glPopAttrib();
  17.190 +}
  17.191 +
  17.192 +void Object::draw_normals(float len, const Vector4 &col) const
  17.193 +{
  17.194 +	int cur_sdr;
  17.195 +	glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
  17.196 +	glUseProgram(0);
  17.197 +
  17.198 +	glPushAttrib(GL_ENABLE_BIT);
  17.199 +	glDisable(GL_LIGHTING);
  17.200 +
  17.201 +	glMatrixMode(GL_MODELVIEW);
  17.202 +	glPushMatrix();
  17.203 +	glMultTransposeMatrixf(matrix[0]);
  17.204 +
  17.205 +	glColor4f(col.x, col.y, col.z, col.w);
  17.206 +	mesh->set_vis_vecsize(len);
  17.207 +	mesh->draw_normals();
  17.208 +
  17.209 +	glPopMatrix();
  17.210 +	glPopAttrib();
  17.211 +
  17.212 +	glUseProgram(cur_sdr);
  17.213 +}
  17.214 +
  17.215 +void Object::draw_tangents(float len, const Vector4 &col) const
  17.216 +{
  17.217 +	glPushAttrib(GL_ENABLE_BIT);
  17.218 +	glDisable(GL_LIGHTING);
  17.219 +
  17.220 +	glMatrixMode(GL_MODELVIEW);
  17.221 +	glPushMatrix();
  17.222 +	glMultTransposeMatrixf(matrix[0]);
  17.223 +
  17.224 +	glColor4f(col.x, col.y, col.z, col.w);
  17.225 +	mesh->set_vis_vecsize(len);
  17.226 +	mesh->draw_tangents();
  17.227 +
  17.228 +	glPopMatrix();
  17.229 +	glPopAttrib();
  17.230 +}
  17.231 +
  17.232 +bool Object::intersect(const Ray &ray, HitPoint *hit) const
  17.233 +{
  17.234 +	return false;	// TODO
  17.235 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/object.h	Mon Aug 31 07:38:37 2015 +0300
    18.3 @@ -0,0 +1,63 @@
    18.4 +#ifndef OBJECT_H_
    18.5 +#define OBJECT_H_
    18.6 +
    18.7 +#include "mesh.h"
    18.8 +#include "geom.h"
    18.9 +#include "vmath/vmath.h"
   18.10 +
   18.11 +struct Material {
   18.12 +	Vector3 diffuse;
   18.13 +	Vector3 specular;
   18.14 +	float shininess;
   18.15 +	float alpha;
   18.16 +
   18.17 +	Material();
   18.18 +};
   18.19 +
   18.20 +struct RenderOps {
   18.21 +	bool zwrite;
   18.22 +	bool cast_shadows;
   18.23 +	bool transparent;
   18.24 +
   18.25 +	RenderOps();
   18.26 +	void setup() const;
   18.27 +};
   18.28 +
   18.29 +class Object {
   18.30 +private:
   18.31 +	Mesh *mesh;
   18.32 +	Matrix4x4 matrix;
   18.33 +	unsigned int tex;
   18.34 +	Matrix4x4 tex_matrix;
   18.35 +	unsigned int sdr;
   18.36 +
   18.37 +public:
   18.38 +	Material mtl;
   18.39 +	RenderOps rop;
   18.40 +
   18.41 +	Object();
   18.42 +	~Object();
   18.43 +
   18.44 +	Matrix4x4 &xform();
   18.45 +	const Matrix4x4 &xform() const;
   18.46 +
   18.47 +	Matrix4x4 &tex_xform();
   18.48 +	const Matrix4x4 &tex_xform() const;
   18.49 +
   18.50 +	void set_mesh(Mesh *m);
   18.51 +	Mesh *get_mesh() const;
   18.52 +
   18.53 +	void set_texture(unsigned int tex);
   18.54 +	void set_shader(unsigned int sdr);
   18.55 +	unsigned int get_shader() const;
   18.56 +
   18.57 +	void draw() const;
   18.58 +	void draw_wire(const Vector4 &col = Vector4(1, 1, 1, 1)) const;
   18.59 +	void draw_vertices(const Vector4 &col = Vector4(1, 0.3, 0.2, 1)) const;
   18.60 +	void draw_normals(float len = 1.0, const Vector4 &col = Vector4(0.1, 0.2, 1.0, 1)) const;
   18.61 +	void draw_tangents(float len = 1.0, const Vector4 &col = Vector4(0.1, 1.0, 0.2, 1)) const;
   18.62 +
   18.63 +	bool intersect(const Ray &ray, HitPoint *hit) const;
   18.64 +};
   18.65 +
   18.66 +#endif	// OBJECT_H_
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/opengl.c	Mon Aug 31 07:38:37 2015 +0300
    19.3 @@ -0,0 +1,16 @@
    19.4 +#include "opengl.h"
    19.5 +
    19.6 +struct GLCaps glcaps;
    19.7 +
    19.8 +int init_opengl()
    19.9 +{
   19.10 +	glewInit();
   19.11 +
   19.12 +	glcaps.shaders = GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader;
   19.13 +	glcaps.fsaa = GLEW_ARB_multisample;
   19.14 +	glcaps.sep_spec = GLEW_EXT_separate_specular_color;
   19.15 +	glcaps.fbo = GLEW_ARB_framebuffer_object;
   19.16 +	glcaps.shadow = GLEW_ARB_shadow | GLEW_SGIX_shadow;
   19.17 +
   19.18 +	return 0;
   19.19 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/opengl.h	Mon Aug 31 07:38:37 2015 +0300
    20.3 @@ -0,0 +1,25 @@
    20.4 +#ifndef OPENGL_H_
    20.5 +#define OPENGL_H_
    20.6 +
    20.7 +#include <GL/glew.h>
    20.8 +
    20.9 +struct GLCaps {
   20.10 +	int shaders;
   20.11 +	int fsaa;
   20.12 +	int sep_spec;
   20.13 +	int fbo;
   20.14 +	int shadow;
   20.15 +};
   20.16 +extern struct GLCaps glcaps;
   20.17 +
   20.18 +#ifdef __cplusplus
   20.19 +extern "C" {
   20.20 +#endif
   20.21 +
   20.22 +int init_opengl();
   20.23 +
   20.24 +#ifdef __cplusplus
   20.25 +}
   20.26 +#endif
   20.27 +
   20.28 +#endif	/* OPENGL_H_ */
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/opt.cc	Mon Aug 31 07:38:37 2015 +0300
    21.3 @@ -0,0 +1,31 @@
    21.4 +#include <stdio.h>
    21.5 +#include "opt.h"
    21.6 +
    21.7 +Options opt;
    21.8 +
    21.9 +bool init_options(int argc, char **argv)
   21.10 +{
   21.11 +	opt.xres = 1280;
   21.12 +	opt.yres = 800;
   21.13 +	opt.fullscreen = false;
   21.14 +	opt.shadows = true;
   21.15 +	opt.reflections = true;
   21.16 +
   21.17 +	for(int i=1; i<argc; i++) {
   21.18 +		if(argv[i][0] == '-') {
   21.19 +			if(strcmp(argv[i], "-noshadows") == 0) {
   21.20 +				opt.shadows = false;
   21.21 +			} else if(strcmp(argv[i], "-fullscreen") == 0) {
   21.22 +				opt.fullscreen = true;
   21.23 +			} else {
   21.24 +				fprintf(stderr, "invalid option: %s\n", argv[i]);
   21.25 +				return false;
   21.26 +			}
   21.27 +		} else {
   21.28 +			fprintf(stderr, "unexpected argument: %s\n", argv[i]);
   21.29 +			return false;
   21.30 +		}
   21.31 +	}
   21.32 +
   21.33 +	return true;
   21.34 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/opt.h	Mon Aug 31 07:38:37 2015 +0300
    22.3 @@ -0,0 +1,16 @@
    22.4 +#ifndef OPT_H_
    22.5 +#define OPT_H_
    22.6 +
    22.7 +#include "vmath/vmath.h"
    22.8 +
    22.9 +struct Options {
   22.10 +	int xres, yres;
   22.11 +	bool fullscreen;
   22.12 +	bool shadows, reflections;
   22.13 +};
   22.14 +
   22.15 +extern Options opt;
   22.16 +
   22.17 +bool init_options(int argc, char **argv);
   22.18 +
   22.19 +#endif	/* OPT_H_ */
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/pnoise.cc	Mon Aug 31 07:38:37 2015 +0300
    23.3 @@ -0,0 +1,149 @@
    23.4 +#include <stdlib.h>
    23.5 +#include "pnoise.h"
    23.6 +#include "vmath/vmath.h"
    23.7 +
    23.8 +#define B	0x100
    23.9 +#define BM	0xff
   23.10 +#define N	0x1000
   23.11 +#define NP	12
   23.12 +#define NM	0xfff
   23.13 +
   23.14 +#define s_curve(t)	((t) * (t) * (3.0f - 2.0f * (t)))
   23.15 +#define setup(elem, b0, b1, r0, r1) \
   23.16 +	do {							\
   23.17 +		float t = elem + N;		\
   23.18 +		b0 = ((int)t) & BM;			\
   23.19 +		b1 = (b0 + 1) & BM;			\
   23.20 +		r0 = t - (int)t;			\
   23.21 +		r1 = r0 - 1.0f;				\
   23.22 +	} while(0)
   23.23 +
   23.24 +#define setup_p(elem, b0, b1, r0, r1, p) \
   23.25 +	do {							\
   23.26 +		float t = elem + N;		\
   23.27 +		b0 = (((int)t) & BM) % p;	\
   23.28 +		b1 = ((b0 + 1) & BM) % p;	\
   23.29 +		r0 = t - (int)t;			\
   23.30 +		r1 = r0 - 1.0f;				\
   23.31 +	} while(0)
   23.32 +
   23.33 +static int perm[B + B + 2];
   23.34 +static vec2_t grad2[B + B + 2];
   23.35 +static bool tables_valid;
   23.36 +
   23.37 +static void init_noise()
   23.38 +{
   23.39 +	for(int i=0; i<B; i++) {
   23.40 +		perm[i] = i;
   23.41 +
   23.42 +		grad2[i].x = (float)((rand() % (B + B)) - B) / B;
   23.43 +		grad2[i].y = (float)((rand() % (B + B)) - B) / B;
   23.44 +		grad2[i] = v2_normalize(grad2[i]);
   23.45 +	}
   23.46 +
   23.47 +	for(int i=0; i<B; i++) {
   23.48 +		int rand_idx = rand() % B;
   23.49 +
   23.50 +		int tmp = perm[i];
   23.51 +		perm[i] = perm[rand_idx];
   23.52 +		perm[rand_idx] = tmp;
   23.53 +	}
   23.54 +
   23.55 +	for(int i=0; i<B+2; i++) {
   23.56 +		perm[B + i] = perm[i];
   23.57 +		grad2[B + i] = grad2[i];
   23.58 +	}
   23.59 +}
   23.60 +
   23.61 +#define lerp(a, b, t)	((a) + ((b) - (a)) * t)
   23.62 +
   23.63 +float dbg_noise2(float x, float y)
   23.64 +{
   23.65 +	if(!tables_valid) {
   23.66 +		init_noise();
   23.67 +		tables_valid = true;
   23.68 +	}
   23.69 +
   23.70 +	int bx0, bx1, by0, by1;
   23.71 +	float rx0, rx1, ry0, ry1;
   23.72 +	setup(x, bx0, bx1, rx0, rx1);
   23.73 +	setup(y, by0, by1, ry0, ry1);
   23.74 +
   23.75 +	int i = perm[bx0];
   23.76 +	int j = perm[bx1];
   23.77 +
   23.78 +	int b00 = perm[i + by0];
   23.79 +	int b10 = perm[j + by0];
   23.80 +	int b01 = perm[i + by1];
   23.81 +	int b11 = perm[j + by1];
   23.82 +
   23.83 +	float sx = s_curve(rx0);
   23.84 +	float sy = s_curve(ry0);
   23.85 +
   23.86 +	vec2_t g00 = grad2[b00];
   23.87 +	vec2_t g10 = grad2[b10];
   23.88 +	vec2_t g01 = grad2[b01];
   23.89 +	vec2_t g11 = grad2[b11];
   23.90 +
   23.91 +	float u = g00.x * rx0 + g00.y * ry0;
   23.92 +	float v = g10.x * rx1 + g10.y * ry0;
   23.93 +	float a = lerp(u, v, sx);
   23.94 +
   23.95 +	u = g01.x * rx0 + g01.y * ry1;
   23.96 +	v = g11.x * rx1 + g11.y * ry1;
   23.97 +	float b = lerp(u, v, sx);
   23.98 +
   23.99 +	return lerp(a, b, sy);
  23.100 +}
  23.101 +
  23.102 +float pnoise2(float x, float y, int periodx, int periody)
  23.103 +{
  23.104 +	if(!tables_valid) {
  23.105 +		init_noise();
  23.106 +		tables_valid = true;
  23.107 +	}
  23.108 +
  23.109 +	int bx0, bx1, by0, by1;
  23.110 +	float rx0, rx1, ry0, ry1;
  23.111 +	setup_p(x, bx0, bx1, rx0, rx1, periodx);
  23.112 +	setup_p(y, by0, by1, ry0, ry1, periody);
  23.113 +
  23.114 +	int i = perm[bx0];
  23.115 +	int j = perm[bx1];
  23.116 +
  23.117 +	int b00 = perm[i + by0];
  23.118 +	int b10 = perm[j + by0];
  23.119 +	int b01 = perm[i + by1];
  23.120 +	int b11 = perm[j + by1];
  23.121 +
  23.122 +	float sx = s_curve(rx0);
  23.123 +	float sy = s_curve(ry0);
  23.124 +
  23.125 +	vec2_t g00 = grad2[b00];
  23.126 +	vec2_t g10 = grad2[b10];
  23.127 +	vec2_t g01 = grad2[b01];
  23.128 +	vec2_t g11 = grad2[b11];
  23.129 +
  23.130 +	float u = g00.x * rx0 + g00.y * ry0;
  23.131 +	float v = g10.x * rx1 + g10.y * ry0;
  23.132 +	float a = lerp(u, v, sx);
  23.133 +
  23.134 +	u = g01.x * rx0 + g01.y * ry1;
  23.135 +	v = g11.x * rx1 + g11.y * ry1;
  23.136 +	float b = lerp(u, v, sx);
  23.137 +
  23.138 +	return lerp(a, b, sy);
  23.139 +}
  23.140 +
  23.141 +float pturbulence2(float x, float y, int periodx, int periody, int octaves)
  23.142 +{
  23.143 +	int i;
  23.144 +	float res = 0.0f, freq = 1.0f;
  23.145 +	for(i=0; i<octaves; i++) {
  23.146 +		res += fabs(pnoise2(x * freq, y * freq, periodx, periody) / freq);
  23.147 +		freq *= 2.0f;
  23.148 +		periodx *= 2;
  23.149 +		periody *= 2;
  23.150 +	}
  23.151 +	return res;
  23.152 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/pnoise.h	Mon Aug 31 07:38:37 2015 +0300
    24.3 @@ -0,0 +1,8 @@
    24.4 +#ifndef PNOISE_H_
    24.5 +#define PNOISE_H_
    24.6 +
    24.7 +float dbg_noise2(float x, float y);
    24.8 +float pnoise2(float x, float y, int periodx, int periody);
    24.9 +float pturbulence2(float x, float y, int periodx, int periody, int octaves);
   24.10 +
   24.11 +#endif	// PNOISE_H_
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/revol.cc	Mon Aug 31 07:38:37 2015 +0300
    25.3 @@ -0,0 +1,44 @@
    25.4 +#include <algorithm>
    25.5 +#include "revol.h"
    25.6 +
    25.7 +Vector2 bezier_revol(float u, float v, void *cls)
    25.8 +{
    25.9 +	BezCurve *curve = (BezCurve*)cls;
   25.10 +	int nseg = (curve->numcp - 1) / 2;
   25.11 +
   25.12 +	if(v >= 1.0) v = 1.0 - 1e-6;
   25.13 +	int cidx = std::min((int)(v * nseg), nseg - 1);
   25.14 +	float t = fmod(v * (float)nseg, 1.0);
   25.15 +
   25.16 +	const vec2_t *cp = curve->cp + cidx * 2;
   25.17 +
   25.18 +	float resx = bezier(cp[0].x, cp[1].x, cp[1].x, cp[2].x, t);
   25.19 +	float resy = bezier(cp[0].y, cp[1].y, cp[1].y, cp[2].y, t);
   25.20 +	return Vector2(resx * curve->scale, resy * curve->scale);
   25.21 +}
   25.22 +
   25.23 +Vector2 bezier_revol_normal(float u, float v, void *cls)
   25.24 +{
   25.25 +	BezCurve *curve = (BezCurve*)cls;
   25.26 +	int nseg = (curve->numcp - 1) / 2;
   25.27 +
   25.28 +	if(v >= 1.0) v = 1.0 - 1e-6;
   25.29 +	int cidx = std::min((int)(v * nseg), nseg - 1);
   25.30 +	float t = fmod(v * (float)nseg, 1.0);
   25.31 +
   25.32 +	const vec2_t *cp = curve->cp + cidx * 2;
   25.33 +	Vector2 cp0 = cp[0];
   25.34 +	Vector2 cp1 = cp[1];
   25.35 +	Vector2 cp2 = cp[2];
   25.36 +
   25.37 +	Vector2 pprev, pnext;
   25.38 +	for(int i=0; i<2; i++) {
   25.39 +		pprev[i] = bezier(cp0[i], cp1[i], cp1[i], cp2[i], t - 0.05);
   25.40 +		pnext[i] = bezier(cp0[i], cp1[i], cp1[i], cp2[i], t + 0.05);
   25.41 +	}
   25.42 +
   25.43 +	float tx = pnext.x - pprev.x;
   25.44 +	float ty = pnext.y - pprev.y;
   25.45 +
   25.46 +	return Vector2(-ty, tx);
   25.47 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/revol.h	Mon Aug 31 07:38:37 2015 +0300
    26.3 @@ -0,0 +1,15 @@
    26.4 +#ifndef REVOL_H_
    26.5 +#define REVOL_H_
    26.6 +
    26.7 +#include "vmath/vmath.h"
    26.8 +
    26.9 +struct BezCurve {
   26.10 +	int numcp;
   26.11 +	vec2_t *cp;
   26.12 +	float scale;
   26.13 +};
   26.14 +
   26.15 +Vector2 bezier_revol(float u, float v, void *cls);
   26.16 +Vector2 bezier_revol_normal(float u, float v, void *cls);
   26.17 +
   26.18 +#endif	// REVOL_H_
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/room.cc	Mon Aug 31 07:38:37 2015 +0300
    27.3 @@ -0,0 +1,73 @@
    27.4 +#include <stdio.h>
    27.5 +#include "opengl.h"
    27.6 +#include "room.h"
    27.7 +#include "game.h"
    27.8 +#include "object.h"
    27.9 +#include "scene.h"
   27.10 +#include "meshgen.h"
   27.11 +#include "revol.h"
   27.12 +
   27.13 +static Scene scn;
   27.14 +
   27.15 +static const vec2_t pillar_cp[] = {
   27.16 +	{0.8, 10},
   27.17 +	{1.2, 5.5},
   27.18 +	{1, 0}
   27.19 +};
   27.20 +static const BezCurve pillar_curve = {
   27.21 +	sizeof pillar_cp / sizeof *pillar_cp,
   27.22 +	(vec2_t*)pillar_cp, 1.0
   27.23 +};
   27.24 +
   27.25 +bool init_room()
   27.26 +{
   27.27 +	Matrix4x4 xform;
   27.28 +
   27.29 +	// generate room
   27.30 +	Mesh *mroom = new Mesh;
   27.31 +	gen_box(mroom, ROOM_WIDTH, ROOM_HEIGHT, ROOM_LENGTH);
   27.32 +	xform.set_translation(Vector3(0, ROOM_HEIGHT / 2.0, 0));
   27.33 +	mroom->apply_xform(xform);
   27.34 +	mroom->flip();
   27.35 +
   27.36 +	Object *oroom = new Object;
   27.37 +	oroom->set_mesh(mroom);
   27.38 +	oroom->mtl.diffuse = Vector3(0.5, 0.5, 0.5);
   27.39 +	oroom->rop.cast_shadows = false;
   27.40 +	scn.add_object(oroom);
   27.41 +
   27.42 +	for(int i=0; i<8; i++) {
   27.43 +		float x = (i < 4 ? -1.0 : 1.0) * ROOM_WIDTH * 0.3;
   27.44 +		float z = (float)(i % 4) * 12.5 - 12.5;
   27.45 +
   27.46 +		Mesh *mpillar = new Mesh;
   27.47 +		gen_revol(mpillar, 16, 3, bezier_revol, bezier_revol_normal, (void*)&pillar_curve);
   27.48 +
   27.49 +		Mesh mtorus;
   27.50 +		gen_torus(&mtorus, 1.0, 0.25, 16, 8);
   27.51 +		Matrix4x4 xform;
   27.52 +		xform.set_translation(Vector3(0, 0.1, 0));
   27.53 +		mtorus.apply_xform(xform, Matrix4x4::identity);
   27.54 +		mpillar->append(mtorus);
   27.55 +
   27.56 +		mpillar->texcoord_gen_cylinder();
   27.57 +
   27.58 +		Object *opillar = new Object;
   27.59 +		opillar->set_mesh(mpillar);
   27.60 +		opillar->mtl.diffuse = Vector3(0.6, 0.6, 0.6);
   27.61 +		opillar->xform().set_translation(Vector3(x, 0.0, z));
   27.62 +
   27.63 +		scn.add_object(opillar);
   27.64 +	}
   27.65 +	return true;
   27.66 +}
   27.67 +
   27.68 +void cleanup_room()
   27.69 +{
   27.70 +	scn.clear();
   27.71 +}
   27.72 +
   27.73 +void draw_room()
   27.74 +{
   27.75 +	scn.draw();
   27.76 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/room.h	Mon Aug 31 07:38:37 2015 +0300
    28.3 @@ -0,0 +1,14 @@
    28.4 +#ifndef ROOM_H_
    28.5 +#define ROOM_H_
    28.6 +
    28.7 +
    28.8 +#define ROOM_WIDTH	30.0f
    28.9 +#define ROOM_HEIGHT	10.0f
   28.10 +#define ROOM_LENGTH	50.0f
   28.11 +
   28.12 +
   28.13 +bool init_room();
   28.14 +void cleanup_room();
   28.15 +void draw_room();
   28.16 +
   28.17 +#endif	// ROOM_H_
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/scene.cc	Mon Aug 31 07:38:37 2015 +0300
    29.3 @@ -0,0 +1,79 @@
    29.4 +#include "scene.h"
    29.5 +#include "opengl.h"
    29.6 +#include "opt.h"
    29.7 +#include "game.h"
    29.8 +#include "scnload.h"
    29.9 +
   29.10 +static int max_lights = -1;
   29.11 +
   29.12 +Scene::~Scene()
   29.13 +{
   29.14 +	clear();
   29.15 +}
   29.16 +
   29.17 +void Scene::clear()
   29.18 +{
   29.19 +	for(size_t i=0; i<objects.size(); i++) {
   29.20 +		delete objects[i];
   29.21 +	}
   29.22 +	objects.clear();
   29.23 +
   29.24 +	for(size_t i=0; i<lights.size(); i++) {
   29.25 +		delete lights[i];
   29.26 +	}
   29.27 +	lights.clear();
   29.28 +}
   29.29 +
   29.30 +void Scene::add_object(Object *obj)
   29.31 +{
   29.32 +	objects.push_back(obj);
   29.33 +}
   29.34 +
   29.35 +void Scene::add_lights(Light *lt)
   29.36 +{
   29.37 +	lights.push_back(lt);
   29.38 +}
   29.39 +
   29.40 +bool Scene::load(const char *fname)
   29.41 +{
   29.42 +	if(load_obj(this, fname)) {
   29.43 +		return true;
   29.44 +	}
   29.45 +
   29.46 +	fprintf(stderr, "failed to load scene file: %s\n", fname);
   29.47 +	return false;
   29.48 +}
   29.49 +
   29.50 +void Scene::dump(FILE *fp)
   29.51 +{
   29.52 +	fprintf(fp, "SCENE DUMP\n");
   29.53 +	fprintf(fp, "%d objects, %d lights\n", (int)objects.size(), (int)lights.size());
   29.54 +
   29.55 +	for(size_t i=0; i<objects.size(); i++) {
   29.56 +		fprintf(fp, "OBJECT %d:\n", (int)i);
   29.57 +		objects[i]->get_mesh()->dump(fp);
   29.58 +	}
   29.59 +}
   29.60 +
   29.61 +void Scene::draw(unsigned int flags) const
   29.62 +{
   29.63 +	if(max_lights == -1) {
   29.64 +		glGetIntegerv(GL_MAX_LIGHTS, &max_lights);
   29.65 +		printf("max lights: %d\n", max_lights);
   29.66 +	}
   29.67 +
   29.68 +	for(size_t i=0; i<lights.size(); i++) {
   29.69 +		lights[i]->setup(i);
   29.70 +	}
   29.71 +
   29.72 +	for(size_t i=0; i<objects.size(); i++) {
   29.73 +		unsigned int mask = objects[i]->rop.transparent ? DRAW_TRANSPARENT : DRAW_SOLID;
   29.74 +		if(mask & flags) {
   29.75 +			if(dbg_wireframe) {
   29.76 +				objects[i]->draw_wire();
   29.77 +			} else {
   29.78 +				objects[i]->draw();
   29.79 +			}
   29.80 +		}
   29.81 +	}
   29.82 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/scene.h	Mon Aug 31 07:38:37 2015 +0300
    30.3 @@ -0,0 +1,33 @@
    30.4 +#ifndef SCENE_H_
    30.5 +#define SCENE_H_
    30.6 +
    30.7 +#include <stdio.h>
    30.8 +#include <vector>
    30.9 +#include "object.h"
   30.10 +#include "light.h"
   30.11 +
   30.12 +enum {
   30.13 +	DRAW_SOLID = 1,
   30.14 +	DRAW_TRANSPARENT = 2,
   30.15 +	DRAW_ALL = 0x7fffffff
   30.16 +};
   30.17 +
   30.18 +class Scene {
   30.19 +public:
   30.20 +	std::vector<Object*> objects;
   30.21 +	std::vector<Light*> lights;
   30.22 +
   30.23 +	~Scene();
   30.24 +
   30.25 +	void clear();
   30.26 +
   30.27 +	void add_object(Object *obj);
   30.28 +	void add_lights(Light *lt);
   30.29 +
   30.30 +	bool load(const char *fname);
   30.31 +	void dump(FILE *fp);
   30.32 +
   30.33 +	void draw(unsigned int flags = DRAW_ALL) const;
   30.34 +};
   30.35 +
   30.36 +#endif	// SCENE_H_
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/scnload.h	Mon Aug 31 07:38:37 2015 +0300
    31.3 @@ -0,0 +1,9 @@
    31.4 +#ifndef SCNLOAD_H_
    31.5 +#define SCNLOAD_H_
    31.6 +
    31.7 +class Scene;
    31.8 +
    31.9 +bool load_obj(Scene *scn, const char *fname);
   31.10 +bool load_obj(Scene *scn, FILE *fp);
   31.11 +
   31.12 +#endif	/* SCNLOAD_H_ */
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/scnload_obj.cc	Mon Aug 31 07:38:37 2015 +0300
    32.3 @@ -0,0 +1,263 @@
    32.4 +#include <stdio.h>
    32.5 +#include <string.h>
    32.6 +#include <ctype.h>
    32.7 +#include <limits.h>
    32.8 +#include <errno.h>
    32.9 +#include <vector>
   32.10 +#include "mesh.h"
   32.11 +#include "scene.h"
   32.12 +#include "scnload.h"
   32.13 +
   32.14 +enum {
   32.15 +	CMD_VERTEX,
   32.16 +	CMD_NORMAL,
   32.17 +	CMD_TEXCOORD,
   32.18 +	CMD_FACE,
   32.19 +	CMD_OBJECT,
   32.20 +	CMD_GROUP,
   32.21 +	CMD_MTLLIB
   32.22 +};
   32.23 +
   32.24 +static struct {
   32.25 +	const char *s;
   32.26 +	int cmd;
   32.27 +} commands[] = {
   32.28 +	{"v", CMD_VERTEX},
   32.29 +	{"vn", CMD_NORMAL},
   32.30 +	{"vt", CMD_TEXCOORD},
   32.31 +	{"f", CMD_FACE},
   32.32 +	{"o", CMD_OBJECT},
   32.33 +	{"g", CMD_GROUP},
   32.34 +	{"mtllib", CMD_MTLLIB},
   32.35 +	{0, -1}
   32.36 +};
   32.37 +
   32.38 +struct Face {
   32.39 +	int vnum;
   32.40 +	int vidx[4];
   32.41 +	int nidx[4];
   32.42 +	int tidx[4];
   32.43 +};
   32.44 +
   32.45 +struct ObjMesh {
   32.46 +	std::vector<Vector3> varr;
   32.47 +	std::vector<Vector3> narr;
   32.48 +	std::vector<Vector2> tarr;
   32.49 +	std::vector<Face> faces;
   32.50 +};
   32.51 +
   32.52 +struct ParserState {
   32.53 +	FILE *fp;
   32.54 +	Scene *scn;
   32.55 +	const char *fname;
   32.56 +
   32.57 +	unsigned int voffs, noffs, toffs;
   32.58 +	ObjMesh omesh;
   32.59 +};
   32.60 +
   32.61 +static bool parse_line(ParserState *ps, char *line);
   32.62 +static void flush_mesh(ParserState *ps);
   32.63 +static char *clean_input(char *s);
   32.64 +
   32.65 +bool load_obj(Scene *scn, const char *fname)
   32.66 +{
   32.67 +	FILE *fp;
   32.68 +	char buf[256];
   32.69 +	bool result = false;
   32.70 +	ParserState ps;
   32.71 +
   32.72 +	if(!(fp = fopen(fname, "r"))) {
   32.73 +		fprintf(stderr, "failed to open obj file: %s: %s\n", fname, strerror(errno));
   32.74 +		return false;
   32.75 +	}
   32.76 +	ps.fp = fp;
   32.77 +	ps.scn = scn;
   32.78 +	ps.fname = fname;
   32.79 +	ps.voffs = ps.noffs = ps.toffs = 0;
   32.80 +
   32.81 +	int nline = 0;
   32.82 +	while(fgets(buf, sizeof buf, fp)) {
   32.83 +		++nline;
   32.84 +		char *line = clean_input(buf);
   32.85 +		if(!*line) continue;
   32.86 +
   32.87 +		if(!parse_line(&ps, line)) {
   32.88 +			fprintf(stderr, "[obj] %s:%d: failed to parse\n", fname, nline);
   32.89 +			goto done;
   32.90 +		}
   32.91 +	}
   32.92 +	flush_mesh(&ps);
   32.93 +	result = true;
   32.94 +
   32.95 +done:
   32.96 +	fclose(fp);
   32.97 +	return result;
   32.98 +}
   32.99 +
  32.100 +static int parse_cmd(char *line, char **endp)
  32.101 +{
  32.102 +	char *end = line;
  32.103 +	while(*end && !isspace(*end)) end++;
  32.104 +	*end = 0;
  32.105 +	*endp = end;
  32.106 +
  32.107 +	for(int i=0; commands[i].s; i++) {
  32.108 +		if(strcmp(commands[i].s, line) == 0) {
  32.109 +			return commands[i].cmd;
  32.110 +		}
  32.111 +	}
  32.112 +	return -1;
  32.113 +}
  32.114 +
  32.115 +static bool parse_vec3(Vector3 *vp, char *line)
  32.116 +{
  32.117 +	return sscanf(line, "%f %f %f", &vp->x, &vp->y, &vp->z) == 3;
  32.118 +}
  32.119 +
  32.120 +static bool parse_vec2(Vector2 *vp, char *line)
  32.121 +{
  32.122 +	return sscanf(line, "%f %f", &vp->x, &vp->y) == 2;
  32.123 +}
  32.124 +
  32.125 +#define INVAL_IDX	INT_MIN
  32.126 +
  32.127 +static bool parse_face(Face *fp, char *line)
  32.128 +{
  32.129 +	fp->vnum = 0;
  32.130 +
  32.131 +	int res;
  32.132 +	char *tok, *ptr = line;
  32.133 +	for(int i=0; i<4; i++) {
  32.134 +		while(*ptr && isspace(*ptr)) ptr++;
  32.135 +		if(!*ptr) break;
  32.136 +		tok = ptr;
  32.137 +
  32.138 +		fp->vnum++;
  32.139 +
  32.140 +		while(*ptr && !isspace(*ptr)) ptr++;
  32.141 +		if(*ptr) *ptr++ = 0;
  32.142 +
  32.143 +		// parse the index descriptor vidx[/[tidx]/[nidx]]
  32.144 +		if(sscanf(tok, "%d//%d", &fp->vidx[i], &fp->nidx[i]) == 2) {
  32.145 +			fp->tidx[i] = INVAL_IDX;
  32.146 +			continue;
  32.147 +		}
  32.148 +		res = sscanf(tok, "%d/%d/%d", &fp->vidx[i], &fp->tidx[i], &fp->nidx[i]);
  32.149 +		if(res > 2) {
  32.150 +			if(res != 3) {
  32.151 +				fp->nidx[i] = INVAL_IDX;
  32.152 +			}
  32.153 +			continue;
  32.154 +		}
  32.155 +		char *endp;
  32.156 +		fp->vidx[i] = strtol(tok, &endp, 10);
  32.157 +		if(endp == tok) {
  32.158 +			return false;
  32.159 +		}
  32.160 +		fp->nidx[i] = fp->tidx[i] = INVAL_IDX;
  32.161 +	}
  32.162 +	return fp->vnum >= 3 ? true : false;
  32.163 +}
  32.164 +
  32.165 +static bool parse_line(ParserState *ps, char *line)
  32.166 +{
  32.167 +	char *endp;
  32.168 +	int cmd = parse_cmd(line, &endp);
  32.169 +	if(cmd == -1) return true;	// ignore unknown commands
  32.170 +	line = endp + 1;
  32.171 +	while(*line && isspace(*line)) line++;
  32.172 +
  32.173 +	Vector3 v;
  32.174 +	Vector2 v2;
  32.175 +	Face f;
  32.176 +
  32.177 +	switch(cmd) {
  32.178 +	case CMD_VERTEX:
  32.179 +		if(!parse_vec3(&v, line)) return false;
  32.180 +		ps->omesh.varr.push_back(v);
  32.181 +		break;
  32.182 +
  32.183 +	case CMD_NORMAL:
  32.184 +		if(!parse_vec3(&v, line)) return false;
  32.185 +		ps->omesh.narr.push_back(v);
  32.186 +		break;
  32.187 +
  32.188 +	case CMD_TEXCOORD:
  32.189 +		if(!parse_vec2(&v2, line)) return false;
  32.190 +		ps->omesh.tarr.push_back(v2);
  32.191 +		break;
  32.192 +
  32.193 +	case CMD_FACE:
  32.194 +		if(!parse_face(&f, line)) return false;
  32.195 +		ps->omesh.faces.push_back(f);
  32.196 +		break;
  32.197 +
  32.198 +	case CMD_OBJECT:
  32.199 +	case CMD_GROUP:
  32.200 +		flush_mesh(ps);
  32.201 +		break;
  32.202 +
  32.203 +	default:
  32.204 +		break;
  32.205 +	}
  32.206 +	return true;
  32.207 +}
  32.208 +
  32.209 +static void flush_mesh(ParserState *ps)
  32.210 +{
  32.211 +	if(!ps->omesh.varr.empty() && !ps->omesh.faces.empty()) {
  32.212 +		int num_verts = (int)ps->omesh.varr.size();
  32.213 +		int num_faces = (int)ps->omesh.faces.size();
  32.214 +
  32.215 +		Mesh *m = new Mesh;
  32.216 +		m->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)&ps->omesh.varr[0]);
  32.217 +
  32.218 +		if(!ps->omesh.narr.empty()) {
  32.219 +			m->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)&ps->omesh.narr[0]);
  32.220 +		}
  32.221 +		if(!ps->omesh.tarr.empty()) {
  32.222 +			m->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, (float*)&ps->omesh.tarr[0]);
  32.223 +		}
  32.224 +
  32.225 +		unsigned int *idxarr = m->set_index_data(num_faces * 3);
  32.226 +		for(int i=0; i<num_faces; i++) {
  32.227 +			for(int j=0; j<3; j++) {
  32.228 +				int idx = ps->omesh.faces[i].vidx[j] - ps->voffs - 1;	// TODO normalize indices
  32.229 +				*idxarr++ = idx;
  32.230 +			}
  32.231 +		}
  32.232 +
  32.233 +		Object *o = new Object;
  32.234 +		o->set_mesh(m);
  32.235 +
  32.236 +		// TODO material & textures
  32.237 +
  32.238 +		ps->scn->add_object(o);
  32.239 +
  32.240 +		printf("added object with %d vertices and %d faces\n", num_verts, num_faces);
  32.241 +	}
  32.242 +
  32.243 +	ps->voffs += ps->omesh.varr.size();
  32.244 +	ps->noffs += ps->omesh.narr.size();
  32.245 +	ps->toffs += ps->omesh.tarr.size();
  32.246 +
  32.247 +	ps->omesh.varr.clear();
  32.248 +	ps->omesh.narr.clear();
  32.249 +	ps->omesh.tarr.clear();
  32.250 +	ps->omesh.faces.clear();
  32.251 +}
  32.252 +
  32.253 +static char *clean_input(char *s)
  32.254 +{
  32.255 +	while(*s && isspace(*s)) s++;
  32.256 +	if(!*s) return s;
  32.257 +
  32.258 +	char *end = strchr(s, '#');
  32.259 +	if(end) *end = 0;
  32.260 +
  32.261 +	end = s + strlen(s) - 1;
  32.262 +	while(end > s && isspace(*end)) end--;
  32.263 +	end[1] = 0;
  32.264 +
  32.265 +	return s;
  32.266 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/sdr.c	Mon Aug 31 07:38:37 2015 +0300
    33.3 @@ -0,0 +1,407 @@
    33.4 +#include <stdio.h>
    33.5 +#include <stdlib.h>
    33.6 +#include <string.h>
    33.7 +#include <errno.h>
    33.8 +#include <stdarg.h>
    33.9 +#include <assert.h>
   33.10 +#include "opengl.h"
   33.11 +
   33.12 +#if defined(unix) || defined(__unix__)
   33.13 +#include <unistd.h>
   33.14 +#include <sys/stat.h>
   33.15 +#endif	/* unix */
   33.16 +
   33.17 +#include "sdr.h"
   33.18 +
   33.19 +static const char *sdrtypestr(unsigned int sdrtype);
   33.20 +
   33.21 +unsigned int create_vertex_shader(const char *src)
   33.22 +{
   33.23 +	return create_shader(src, GL_VERTEX_SHADER);
   33.24 +}
   33.25 +
   33.26 +unsigned int create_pixel_shader(const char *src)
   33.27 +{
   33.28 +	return create_shader(src, GL_FRAGMENT_SHADER);
   33.29 +}
   33.30 +
   33.31 +unsigned int create_tessctl_shader(const char *src)
   33.32 +{
   33.33 +#ifdef GL_TESS_CONTROL_SHADER
   33.34 +	return create_shader(src, GL_TESS_CONTROL_SHADER);
   33.35 +#else
   33.36 +	return 0;
   33.37 +#endif
   33.38 +}
   33.39 +
   33.40 +unsigned int create_tesseval_shader(const char *src)
   33.41 +{
   33.42 +#ifdef GL_TESS_EVALUATION_SHADER
   33.43 +	return create_shader(src, GL_TESS_EVALUATION_SHADER);
   33.44 +#else
   33.45 +	return 0;
   33.46 +#endif
   33.47 +}
   33.48 +
   33.49 +unsigned int create_geometry_shader(const char *src)
   33.50 +{
   33.51 +#ifdef GL_GEOMETRY_SHADER
   33.52 +	return create_shader(src, GL_GEOMETRY_SHADER);
   33.53 +#else
   33.54 +	return 0;
   33.55 +#endif
   33.56 +}
   33.57 +
   33.58 +unsigned int create_shader(const char *src, unsigned int sdr_type)
   33.59 +{
   33.60 +	unsigned int sdr;
   33.61 +	int success, info_len;
   33.62 +	char *info_str = 0;
   33.63 +	GLenum err;
   33.64 +
   33.65 +	sdr = glCreateShader(sdr_type);
   33.66 +	assert(glGetError() == GL_NO_ERROR);
   33.67 +	glShaderSource(sdr, 1, &src, 0);
   33.68 +	err = glGetError();
   33.69 +	assert(err == GL_NO_ERROR);
   33.70 +	glCompileShader(sdr);
   33.71 +	assert(glGetError() == GL_NO_ERROR);
   33.72 +
   33.73 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
   33.74 +	assert(glGetError() == GL_NO_ERROR);
   33.75 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
   33.76 +	assert(glGetError() == GL_NO_ERROR);
   33.77 +
   33.78 +	if(info_len) {
   33.79 +		if((info_str = malloc(info_len + 1))) {
   33.80 +			glGetShaderInfoLog(sdr, info_len, 0, info_str);
   33.81 +			assert(glGetError() == GL_NO_ERROR);
   33.82 +			info_str[info_len] = 0;
   33.83 +		}
   33.84 +	}
   33.85 +
   33.86 +	if(success) {
   33.87 +		fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
   33.88 +	} else {
   33.89 +		fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
   33.90 +		glDeleteShader(sdr);
   33.91 +		sdr = 0;
   33.92 +	}
   33.93 +
   33.94 +	free(info_str);
   33.95 +	return sdr;
   33.96 +}
   33.97 +
   33.98 +void free_shader(unsigned int sdr)
   33.99 +{
  33.100 +	glDeleteShader(sdr);
  33.101 +}
  33.102 +
  33.103 +unsigned int load_vertex_shader(const char *fname)
  33.104 +{
  33.105 +	return load_shader(fname, GL_VERTEX_SHADER);
  33.106 +}
  33.107 +
  33.108 +unsigned int load_pixel_shader(const char *fname)
  33.109 +{
  33.110 +	return load_shader(fname, GL_FRAGMENT_SHADER);
  33.111 +}
  33.112 +
  33.113 +unsigned int load_tessctl_shader(const char *fname)
  33.114 +{
  33.115 +#ifdef GL_TESS_CONTROL_SHADER
  33.116 +	return load_shader(fname, GL_TESS_CONTROL_SHADER);
  33.117 +#else
  33.118 +	return 0;
  33.119 +#endif
  33.120 +}
  33.121 +
  33.122 +unsigned int load_tesseval_shader(const char *fname)
  33.123 +{
  33.124 +#ifdef GL_TESS_EVALUATION_SHADER
  33.125 +	return load_shader(fname, GL_TESS_EVALUATION_SHADER);
  33.126 +#else
  33.127 +	return 0;
  33.128 +#endif
  33.129 +}
  33.130 +
  33.131 +unsigned int load_geometry_shader(const char *fname)
  33.132 +{
  33.133 +#ifdef GL_GEOMETRY_SHADER
  33.134 +	return load_shader(fname, GL_GEOMETRY_SHADER);
  33.135 +#else
  33.136 +	return 0;
  33.137 +#endif
  33.138 +}
  33.139 +
  33.140 +unsigned int load_shader(const char *fname, unsigned int sdr_type)
  33.141 +{
  33.142 +	unsigned int sdr;
  33.143 +	size_t filesize;
  33.144 +	FILE *fp;
  33.145 +	char *src;
  33.146 +
  33.147 +	if(!(fp = fopen(fname, "rb"))) {
  33.148 +		fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
  33.149 +		return 0;
  33.150 +	}
  33.151 +
  33.152 +	fseek(fp, 0, SEEK_END);
  33.153 +	filesize = ftell(fp);
  33.154 +	fseek(fp, 0, SEEK_SET);
  33.155 +
  33.156 +	if(!(src = malloc(filesize + 1))) {
  33.157 +		fclose(fp);
  33.158 +		return 0;
  33.159 +	}
  33.160 +	fread(src, 1, filesize, fp);
  33.161 +	src[filesize] = 0;
  33.162 +	fclose(fp);
  33.163 +
  33.164 +	fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
  33.165 +	sdr = create_shader(src, sdr_type);
  33.166 +
  33.167 +	free(src);
  33.168 +	return sdr;
  33.169 +}
  33.170 +
  33.171 +
  33.172 +/* ---- gpu programs ---- */
  33.173 +
  33.174 +unsigned int create_program(void)
  33.175 +{
  33.176 +	unsigned int prog = glCreateProgram();
  33.177 +	assert(glGetError() == GL_NO_ERROR);
  33.178 +	return prog;
  33.179 +}
  33.180 +
  33.181 +unsigned int create_program_link(unsigned int sdr0, ...)
  33.182 +{
  33.183 +	unsigned int prog, sdr;
  33.184 +	va_list ap;
  33.185 +
  33.186 +	if(!(prog = create_program())) {
  33.187 +		return 0;
  33.188 +	}
  33.189 +
  33.190 +	attach_shader(prog, sdr0);
  33.191 +	if(glGetError()) {
  33.192 +		return 0;
  33.193 +	}
  33.194 +
  33.195 +	va_start(ap, sdr0);
  33.196 +	while((sdr = va_arg(ap, unsigned int))) {
  33.197 +		attach_shader(prog, sdr);
  33.198 +		if(glGetError()) {
  33.199 +			return 0;
  33.200 +		}
  33.201 +	}
  33.202 +	va_end(ap);
  33.203 +
  33.204 +	if(link_program(prog) == -1) {
  33.205 +		free_program(prog);
  33.206 +		return 0;
  33.207 +	}
  33.208 +	return prog;
  33.209 +}
  33.210 +
  33.211 +unsigned int create_program_load(const char *vfile, const char *pfile)
  33.212 +{
  33.213 +	unsigned int vs = 0, ps = 0;
  33.214 +
  33.215 +	if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
  33.216 +		return 0;
  33.217 +	}
  33.218 +	if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
  33.219 +		return 0;
  33.220 +	}
  33.221 +	return create_program_link(vs, ps, 0);
  33.222 +}
  33.223 +
  33.224 +void free_program(unsigned int sdr)
  33.225 +{
  33.226 +	glDeleteProgram(sdr);
  33.227 +}
  33.228 +
  33.229 +void attach_shader(unsigned int prog, unsigned int sdr)
  33.230 +{
  33.231 +	int err;
  33.232 +
  33.233 +	if(prog && sdr) {
  33.234 +		assert(glGetError() == GL_NO_ERROR);
  33.235 +		glAttachShader(prog, sdr);
  33.236 +		if((err = glGetError()) != GL_NO_ERROR) {
  33.237 +			fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
  33.238 +			abort();
  33.239 +		}
  33.240 +	}
  33.241 +}
  33.242 +
  33.243 +int link_program(unsigned int prog)
  33.244 +{
  33.245 +	int linked, info_len, retval = 0;
  33.246 +	char *info_str = 0;
  33.247 +
  33.248 +	glLinkProgram(prog);
  33.249 +	assert(glGetError() == GL_NO_ERROR);
  33.250 +	glGetProgramiv(prog, GL_LINK_STATUS, &linked);
  33.251 +	assert(glGetError() == GL_NO_ERROR);
  33.252 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
  33.253 +	assert(glGetError() == GL_NO_ERROR);
  33.254 +
  33.255 +	if(info_len) {
  33.256 +		if((info_str = malloc(info_len + 1))) {
  33.257 +			glGetProgramInfoLog(prog, info_len, 0, info_str);
  33.258 +			assert(glGetError() == GL_NO_ERROR);
  33.259 +			info_str[info_len] = 0;
  33.260 +		}
  33.261 +	}
  33.262 +
  33.263 +	if(linked) {
  33.264 +		fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
  33.265 +	} else {
  33.266 +		fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
  33.267 +		retval = -1;
  33.268 +	}
  33.269 +
  33.270 +	free(info_str);
  33.271 +	return retval;
  33.272 +}
  33.273 +
  33.274 +int bind_program(unsigned int prog)
  33.275 +{
  33.276 +	GLenum err;
  33.277 +
  33.278 +	glUseProgram(prog);
  33.279 +	if(prog && (err = glGetError()) != GL_NO_ERROR) {
  33.280 +		/* maybe the program is not linked, try linking first */
  33.281 +		if(err == GL_INVALID_OPERATION) {
  33.282 +			if(link_program(prog) == -1) {
  33.283 +				return -1;
  33.284 +			}
  33.285 +			glUseProgram(prog);
  33.286 +			return glGetError() == GL_NO_ERROR ? 0 : -1;
  33.287 +		}
  33.288 +		return -1;
  33.289 +	}
  33.290 +	return 0;
  33.291 +}
  33.292 +
  33.293 +/* ugly but I'm not going to write the same bloody code over and over */
  33.294 +#define BEGIN_UNIFORM_CODE \
  33.295 +	int loc, curr_prog; \
  33.296 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
  33.297 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
  33.298 +		return -1; \
  33.299 +	} \
  33.300 +	if((loc = glGetUniformLocation(prog, name)) != -1)
  33.301 +
  33.302 +#define END_UNIFORM_CODE \
  33.303 +	if((unsigned int)curr_prog != prog) { \
  33.304 +		bind_program(curr_prog); \
  33.305 +	} \
  33.306 +	return loc == -1 ? -1 : 0
  33.307 +
  33.308 +int set_uniform_int(unsigned int prog, const char *name, int val)
  33.309 +{
  33.310 +	BEGIN_UNIFORM_CODE {
  33.311 +		glUniform1i(loc, val);
  33.312 +	}
  33.313 +	END_UNIFORM_CODE;
  33.314 +}
  33.315 +
  33.316 +int set_uniform_float(unsigned int prog, const char *name, float val)
  33.317 +{
  33.318 +	BEGIN_UNIFORM_CODE {
  33.319 +		glUniform1f(loc, val);
  33.320 +	}
  33.321 +	END_UNIFORM_CODE;
  33.322 +}
  33.323 +
  33.324 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
  33.325 +{
  33.326 +	BEGIN_UNIFORM_CODE {
  33.327 +		glUniform2f(loc, x, y);
  33.328 +	}
  33.329 +	END_UNIFORM_CODE;
  33.330 +}
  33.331 +
  33.332 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
  33.333 +{
  33.334 +	BEGIN_UNIFORM_CODE {
  33.335 +		glUniform3f(loc, x, y, z);
  33.336 +	}
  33.337 +	END_UNIFORM_CODE;
  33.338 +}
  33.339 +
  33.340 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
  33.341 +{
  33.342 +	BEGIN_UNIFORM_CODE {
  33.343 +		glUniform4f(loc, x, y, z, w);
  33.344 +	}
  33.345 +	END_UNIFORM_CODE;
  33.346 +}
  33.347 +
  33.348 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat)
  33.349 +{
  33.350 +	BEGIN_UNIFORM_CODE {
  33.351 +		glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
  33.352 +	}
  33.353 +	END_UNIFORM_CODE;
  33.354 +}
  33.355 +
  33.356 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat)
  33.357 +{
  33.358 +	BEGIN_UNIFORM_CODE {
  33.359 +		glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
  33.360 +	}
  33.361 +	END_UNIFORM_CODE;
  33.362 +}
  33.363 +
  33.364 +int get_attrib_loc(unsigned int prog, const char *name)
  33.365 +{
  33.366 +	int loc, curr_prog;
  33.367 +
  33.368 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
  33.369 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
  33.370 +		return -1;
  33.371 +	}
  33.372 +
  33.373 +	loc = glGetAttribLocation(prog, (char*)name);
  33.374 +
  33.375 +	if((unsigned int)curr_prog != prog) {
  33.376 +		bind_program(curr_prog);
  33.377 +	}
  33.378 +	return loc;
  33.379 +}
  33.380 +
  33.381 +void set_attrib_float3(int attr_loc, float x, float y, float z)
  33.382 +{
  33.383 +	glVertexAttrib3f(attr_loc, x, y, z);
  33.384 +}
  33.385 +
  33.386 +static const char *sdrtypestr(unsigned int sdrtype)
  33.387 +{
  33.388 +	switch(sdrtype) {
  33.389 +	case GL_VERTEX_SHADER:
  33.390 +		return "vertex";
  33.391 +	case GL_FRAGMENT_SHADER:
  33.392 +		return "pixel";
  33.393 +#ifdef GL_TESS_CONTROL_SHADER
  33.394 +	case GL_TESS_CONTROL_SHADER:
  33.395 +		return "tessellation control";
  33.396 +#endif
  33.397 +#ifdef GL_TESS_EVALUATION_SHADER
  33.398 +	case GL_TESS_EVALUATION_SHADER:
  33.399 +		return "tessellation evaluation";
  33.400 +#endif
  33.401 +#ifdef GL_GEOMETRY_SHADER
  33.402 +	case GL_GEOMETRY_SHADER:
  33.403 +		return "geometry";
  33.404 +#endif
  33.405 +
  33.406 +	default:
  33.407 +		break;
  33.408 +	}
  33.409 +	return "<unknown>";
  33.410 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/sdr.h	Mon Aug 31 07:38:37 2015 +0300
    34.3 @@ -0,0 +1,52 @@
    34.4 +#ifndef SDR_H_
    34.5 +#define SDR_H_
    34.6 +
    34.7 +#ifdef __cplusplus
    34.8 +extern "C" {
    34.9 +#endif	/* __cplusplus */
   34.10 +
   34.11 +/* ---- shaders ---- */
   34.12 +unsigned int create_vertex_shader(const char *src);
   34.13 +unsigned int create_pixel_shader(const char *src);
   34.14 +unsigned int create_tessctl_shader(const char *src);
   34.15 +unsigned int create_tesseval_shader(const char *src);
   34.16 +unsigned int create_geometry_shader(const char *src);
   34.17 +unsigned int create_shader(const char *src, unsigned int sdr_type);
   34.18 +void free_shader(unsigned int sdr);
   34.19 +
   34.20 +unsigned int load_vertex_shader(const char *fname);
   34.21 +unsigned int load_pixel_shader(const char *fname);
   34.22 +unsigned int load_tessctl_shader(const char *fname);
   34.23 +unsigned int load_tesseval_shader(const char *fname);
   34.24 +unsigned int load_geometry_shader(const char *fname);
   34.25 +unsigned int load_shader(const char *src, unsigned int sdr_type);
   34.26 +
   34.27 +int add_shader(const char *fname, unsigned int sdr);
   34.28 +int remove_shader(const char *fname);
   34.29 +
   34.30 +/* ---- gpu programs ---- */
   34.31 +unsigned int create_program(void);
   34.32 +unsigned int create_program_link(unsigned int sdr0, ...);
   34.33 +unsigned int create_program_load(const char *vfile, const char *pfile);
   34.34 +void free_program(unsigned int sdr);
   34.35 +
   34.36 +void attach_shader(unsigned int prog, unsigned int sdr);
   34.37 +int link_program(unsigned int prog);
   34.38 +int bind_program(unsigned int prog);
   34.39 +
   34.40 +int set_uniform_int(unsigned int prog, const char *name, int val);
   34.41 +int set_uniform_float(unsigned int prog, const char *name, float val);
   34.42 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y);
   34.43 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z);
   34.44 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w);
   34.45 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat);
   34.46 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat);
   34.47 +
   34.48 +int get_attrib_loc(unsigned int prog, const char *name);
   34.49 +void set_attrib_float3(int attr_loc, float x, float y, float z);
   34.50 +
   34.51 +#ifdef __cplusplus
   34.52 +}
   34.53 +#endif	/* __cplusplus */
   34.54 +
   34.55 +#endif	/* SDR_H_ */
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/src/shader.cc	Mon Aug 31 07:38:37 2015 +0300
    35.3 @@ -0,0 +1,28 @@
    35.4 +#include "shader.h"
    35.5 +#include "sdr.h"
    35.6 +
    35.7 +static unsigned int cur_sdr;
    35.8 +static unsigned int sover;
    35.9 +
   35.10 +void set_shader(unsigned int sdr)
   35.11 +{
   35.12 +	cur_sdr = sdr;
   35.13 +	if(!sover) {
   35.14 +		bind_program(sdr);
   35.15 +	}
   35.16 +}
   35.17 +
   35.18 +unsigned int current_shader()
   35.19 +{
   35.20 +	return sover ? sover : cur_sdr;
   35.21 +}
   35.22 +
   35.23 +void override_shader(unsigned int sdr)
   35.24 +{
   35.25 +	sover = sdr;
   35.26 +	if(sover) {
   35.27 +		bind_program(sdr);
   35.28 +	} else {
   35.29 +		bind_program(cur_sdr);
   35.30 +	}
   35.31 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/src/shader.h	Mon Aug 31 07:38:37 2015 +0300
    36.3 @@ -0,0 +1,8 @@
    36.4 +#ifndef SHADER_H_
    36.5 +#define SHADER_H_
    36.6 +
    36.7 +void set_shader(unsigned int sdr);
    36.8 +unsigned int current_shader();
    36.9 +void override_shader(unsigned int sdr);
   36.10 +
   36.11 +#endif	/* SHADER_H_ */
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/src/shadow.cc	Mon Aug 31 07:38:37 2015 +0300
    37.3 @@ -0,0 +1,141 @@
    37.4 +#include <assert.h>
    37.5 +#include "opengl.h"
    37.6 +#include "shadow.h"
    37.7 +#include "vmath/vmath.h"
    37.8 +
    37.9 +bool shadow_pass;
   37.10 +
   37.11 +static int tex_sz, prev_vp[4];
   37.12 +static unsigned int fbo, depth_tex, rb_color;
   37.13 +static Matrix4x4 shadow_mat;
   37.14 +
   37.15 +bool init_shadow(int sz)
   37.16 +{
   37.17 +	if(!glcaps.fbo || !glcaps.shadow) {
   37.18 +		return false;
   37.19 +	}
   37.20 +
   37.21 +	tex_sz = sz;
   37.22 +	printf("initializing shadow buffer (%dx%d)\n", tex_sz, tex_sz);
   37.23 +
   37.24 +	glGenFramebuffers(1, &fbo);
   37.25 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   37.26 +
   37.27 +	glGenTextures(1, &depth_tex);
   37.28 +	glBindTexture(GL_TEXTURE_2D, depth_tex);
   37.29 +	float border[] = {1, 1, 1, 1};
   37.30 +	glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
   37.31 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
   37.32 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
   37.33 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   37.34 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   37.35 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
   37.36 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex_sz, tex_sz, 0,
   37.37 +			GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
   37.38 +	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0);
   37.39 +
   37.40 +	assert(glGetError() == GL_NO_ERROR);
   37.41 +
   37.42 +	glDrawBuffer(GL_FALSE);
   37.43 +	glReadBuffer(GL_FALSE);
   37.44 +
   37.45 +	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
   37.46 +		fprintf(stderr, "incomplete framebuffer\n");
   37.47 +		return false;
   37.48 +	}
   37.49 +
   37.50 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
   37.51 +	glDrawBuffer(GL_BACK);
   37.52 +	glReadBuffer(GL_BACK);
   37.53 +	assert(glGetError() == GL_NO_ERROR);
   37.54 +
   37.55 +	return true;
   37.56 +}
   37.57 +
   37.58 +void destroy_shadow()
   37.59 +{
   37.60 +	glDeleteTextures(1, &depth_tex);
   37.61 +	glDeleteRenderbuffers(1, &rb_color);
   37.62 +	glDeleteFramebuffers(1, &fbo);
   37.63 +}
   37.64 +
   37.65 +void begin_shadow_pass(const Vector3 &lpos, const Vector3 &ltarg, float lfov)
   37.66 +{
   37.67 +	shadow_pass = true;
   37.68 +
   37.69 +	glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
   37.70 +	glDisable(GL_LIGHTING);
   37.71 +	glColorMask(0, 0, 0, 0);
   37.72 +	glDepthMask(1);
   37.73 +
   37.74 +	Matrix4x4 viewmat;
   37.75 +	glGetFloatv(GL_MODELVIEW_MATRIX, viewmat[0]);
   37.76 +	viewmat.transpose();
   37.77 +
   37.78 +	Matrix4x4 lt_viewmat, lt_projmat;
   37.79 +	lt_projmat.set_perspective(DEG_TO_RAD(lfov) * 2.0, 1.0, 8.0, 50.0);
   37.80 +	lt_viewmat.set_lookat(lpos, ltarg, Vector3(0, 1, 0));
   37.81 +	shadow_mat = lt_projmat * lt_viewmat * viewmat.inverse();
   37.82 +
   37.83 +	glMatrixMode(GL_PROJECTION);
   37.84 +	glPushMatrix();
   37.85 +	glLoadTransposeMatrixf(lt_projmat[0]);
   37.86 +
   37.87 +	glMatrixMode(GL_MODELVIEW);
   37.88 +	glPushMatrix();
   37.89 +	glLoadTransposeMatrixf(lt_viewmat[0]);
   37.90 +
   37.91 +	glGetIntegerv(GL_VIEWPORT, prev_vp);
   37.92 +	glViewport(0, 0, tex_sz, tex_sz);
   37.93 +
   37.94 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   37.95 +
   37.96 +	glPolygonOffset(2.0, 4.0);
   37.97 +	glEnable(GL_POLYGON_OFFSET_FILL);
   37.98 +
   37.99 +	glClear(GL_DEPTH_BUFFER_BIT);
  37.100 +	glUseProgram(0);
  37.101 +}
  37.102 +
  37.103 +
  37.104 +void end_shadow_pass()
  37.105 +{
  37.106 +	shadow_pass = false;
  37.107 +
  37.108 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
  37.109 +
  37.110 +	glViewport(prev_vp[0], prev_vp[1], prev_vp[2], prev_vp[3]);
  37.111 +
  37.112 +	glMatrixMode(GL_PROJECTION);
  37.113 +	glPopMatrix();
  37.114 +	glMatrixMode(GL_MODELVIEW);
  37.115 +	glPopMatrix();
  37.116 +
  37.117 +	glPopAttrib();
  37.118 +}
  37.119 +
  37.120 +Matrix4x4 get_shadow_matrix()
  37.121 +{
  37.122 +	return shadow_mat;
  37.123 +
  37.124 +	/*
  37.125 +	glMatrixMode(GL_MODELVIEW);
  37.126 +	glPushMatrix();
  37.127 +	glLoadIdentity();
  37.128 +	gluPerspective(lfov * 2.0, 1.0, 0.5, 50.0);
  37.129 +	gluLookAt(lpos.x, lpos.y, lpos.z, ltarg.x, ltarg.y, ltarg.z, 0, 1, 0);
  37.130 +
  37.131 +	float mat[16];
  37.132 +	glGetFloatv(GL_MODELVIEW_MATRIX, mat);
  37.133 +
  37.134 +	Matrix4x4 res;
  37.135 +	memcpy(res[0], mat, sizeof mat);
  37.136 +	res.transpose();
  37.137 +	return res;
  37.138 +	*/
  37.139 +}
  37.140 +
  37.141 +unsigned int get_shadow_tex()
  37.142 +{
  37.143 +	return depth_tex;
  37.144 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/src/shadow.h	Mon Aug 31 07:38:37 2015 +0300
    38.3 @@ -0,0 +1,17 @@
    38.4 +#ifndef SHADOW_H_
    38.5 +#define SHADOW_H_
    38.6 +
    38.7 +#include "vmath/vmath.h"
    38.8 +
    38.9 +extern bool shadow_pass;
   38.10 +
   38.11 +bool init_shadow(int sz);
   38.12 +void destroy_shadow();
   38.13 +
   38.14 +void begin_shadow_pass(const Vector3 &lpos, const Vector3 &ltarg, float lfov);
   38.15 +void end_shadow_pass();
   38.16 +
   38.17 +Matrix4x4 get_shadow_matrix();
   38.18 +unsigned int get_shadow_tex();
   38.19 +
   38.20 +#endif	// SHADOW_H_
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/src/snode.cc	Mon Aug 31 07:38:37 2015 +0300
    39.3 @@ -0,0 +1,188 @@
    39.4 +#include <float.h>
    39.5 +#include <assert.h>
    39.6 +#include <algorithm>
    39.7 +#include "snode.h"
    39.8 +
    39.9 +SceneNode::SceneNode()
   39.10 +	: scale(1, 1, 1)
   39.11 +{
   39.12 +	parent = 0;
   39.13 +}
   39.14 +
   39.15 +SceneNode::SceneNode(Object *obj)
   39.16 +	: scale(1, 1, 1)
   39.17 +{
   39.18 +	parent = 0;
   39.19 +	add_object(obj);
   39.20 +}
   39.21 +
   39.22 +void SceneNode::add_child(SceneNode *node)
   39.23 +{
   39.24 +	if(node->parent) {
   39.25 +		if(node->parent == this) {
   39.26 +			return;
   39.27 +		}
   39.28 +		node->parent->remove_child(node);
   39.29 +	}
   39.30 +
   39.31 +	children.push_back(node);
   39.32 +	node->parent = this;
   39.33 +}
   39.34 +
   39.35 +bool SceneNode::remove_child(SceneNode *node)
   39.36 +{
   39.37 +	for(size_t i=0; i<children.size(); i++) {
   39.38 +		if(children[i] == node) {
   39.39 +			assert(node->parent == this);
   39.40 +			node->parent = 0;
   39.41 +			return true;
   39.42 +		}
   39.43 +	}
   39.44 +	return false;
   39.45 +}
   39.46 +
   39.47 +int SceneNode::get_num_children() const
   39.48 +{
   39.49 +	return (int)children.size();
   39.50 +}
   39.51 +
   39.52 +SceneNode *SceneNode::get_child(int idx) const
   39.53 +{
   39.54 +	return children[idx];
   39.55 +}
   39.56 +
   39.57 +SceneNode *SceneNode::get_parent() const
   39.58 +{
   39.59 +	return parent;
   39.60 +}
   39.61 +
   39.62 +void SceneNode::add_object(Object *obj)
   39.63 +{
   39.64 +	if(std::find(this->obj.begin(), this->obj.end(), obj) == this->obj.end()) {
   39.65 +		this->obj.push_back(obj);
   39.66 +	}
   39.67 +}
   39.68 +
   39.69 +int SceneNode::get_num_objects() const
   39.70 +{
   39.71 +	return (int)obj.size();
   39.72 +}
   39.73 +
   39.74 +Object *SceneNode::get_object(int idx) const
   39.75 +{
   39.76 +	return obj[idx];
   39.77 +}
   39.78 +
   39.79 +void SceneNode::set_position(const Vector3 &pos)
   39.80 +{
   39.81 +	this->pos = pos;
   39.82 +}
   39.83 +
   39.84 +void SceneNode::set_rotation(const Quaternion &rot)
   39.85 +{
   39.86 +	this->rot = rot;
   39.87 +}
   39.88 +
   39.89 +void SceneNode::set_scaling(const Vector3 &scale)
   39.90 +{
   39.91 +	this->scale = scale;
   39.92 +}
   39.93 +
   39.94 +
   39.95 +const Vector3 &SceneNode::get_node_position() const
   39.96 +{
   39.97 +	return pos;
   39.98 +}
   39.99 +
  39.100 +const Quaternion &SceneNode::get_node_rotation() const
  39.101 +{
  39.102 +	return rot;
  39.103 +}
  39.104 +
  39.105 +const Vector3 &SceneNode::get_node_scaling() const
  39.106 +{
  39.107 +	return scale;
  39.108 +}
  39.109 +
  39.110 +
  39.111 +Vector3 SceneNode::get_position() const
  39.112 +{
  39.113 +	return Vector3(0, 0, 0).transformed(xform);
  39.114 +}
  39.115 +
  39.116 +Quaternion SceneNode::get_rotation() const
  39.117 +{
  39.118 +	return rot;	// TODO
  39.119 +}
  39.120 +
  39.121 +Vector3 SceneNode::get_scaling() const
  39.122 +{
  39.123 +	return scale;	// TODO
  39.124 +}
  39.125 +
  39.126 +const Matrix4x4 &SceneNode::get_matrix() const
  39.127 +{
  39.128 +	return xform;
  39.129 +}
  39.130 +
  39.131 +const Matrix4x4 &SceneNode::get_inv_matrix() const
  39.132 +{
  39.133 +	return inv_xform;
  39.134 +}
  39.135 +
  39.136 +
  39.137 +void SceneNode::update_node(long msec)
  39.138 +{
  39.139 +	xform.reset_identity();
  39.140 +	xform.translate(pos);
  39.141 +	xform.rotate(rot);
  39.142 +	xform.scale(scale);
  39.143 +
  39.144 +	if(parent) {
  39.145 +		xform = parent->xform * xform;
  39.146 +	}
  39.147 +	inv_xform = xform.inverse();
  39.148 +}
  39.149 +
  39.150 +void SceneNode::update(long msec)
  39.151 +{
  39.152 +	update_node(msec);
  39.153 +
  39.154 +	for(size_t i=0; i<children.size(); i++) {
  39.155 +		children[i]->update(msec);
  39.156 +	}
  39.157 +}
  39.158 +
  39.159 +
  39.160 +bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
  39.161 +{
  39.162 +	Ray local_ray = ray.transformed(inv_xform);
  39.163 +
  39.164 +	HitPoint nearest;
  39.165 +	nearest.dist = FLT_MAX;
  39.166 +	for(size_t i=0; i<obj.size(); i++) {
  39.167 +		if(obj[i]->intersect(local_ray, hit)) {
  39.168 +			if(!hit) return true;
  39.169 +			if(hit->dist < nearest.dist) {
  39.170 +				nearest = *hit;
  39.171 +				nearest.node = this;
  39.172 +			}
  39.173 +		}
  39.174 +	}
  39.175 +
  39.176 +	for(size_t i=0; i<children.size(); i++) {
  39.177 +		if(children[i]->intersect(ray, hit)) {
  39.178 +			if(!hit) return true;
  39.179 +			if(hit->dist < nearest.dist) {
  39.180 +				nearest = *hit;
  39.181 +			}
  39.182 +		}
  39.183 +	}
  39.184 +
  39.185 +	if(nearest.dist < FLT_MAX) {
  39.186 +		*hit = nearest;
  39.187 +		hit->ray = ray;
  39.188 +		return true;
  39.189 +	}
  39.190 +	return false;
  39.191 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/src/snode.h	Mon Aug 31 07:38:37 2015 +0300
    40.3 @@ -0,0 +1,60 @@
    40.4 +#ifndef SNODE_H_
    40.5 +#define SNODE_H_
    40.6 +
    40.7 +#include <vector>
    40.8 +#include "object.h"
    40.9 +#include "vmath/vmath.h"
   40.10 +#include "geom.h"
   40.11 +
   40.12 +class SceneNode {
   40.13 +private:
   40.14 +	Vector3 pos;
   40.15 +	Quaternion rot;
   40.16 +	Vector3 scale;
   40.17 +
   40.18 +	std::vector<Object*> obj;
   40.19 +
   40.20 +	SceneNode *parent;
   40.21 +	std::vector<SceneNode*> children;
   40.22 +
   40.23 +	Matrix4x4 xform;
   40.24 +	Matrix4x4 inv_xform;
   40.25 +
   40.26 +public:
   40.27 +	SceneNode();
   40.28 +	explicit SceneNode(Object *obj);
   40.29 +
   40.30 +	void add_child(SceneNode *node);
   40.31 +	bool remove_child(SceneNode *node);
   40.32 +
   40.33 +	int get_num_children() const;
   40.34 +	SceneNode *get_child(int idx) const;
   40.35 +
   40.36 +	SceneNode *get_parent() const;
   40.37 +
   40.38 +	void add_object(Object *obj);
   40.39 +	int get_num_objects() const;
   40.40 +	Object *get_object(int idx) const;
   40.41 +
   40.42 +	void set_position(const Vector3 &pos);
   40.43 +	void set_rotation(const Quaternion &rot);
   40.44 +	void set_scaling(const Vector3 &scale);
   40.45 +
   40.46 +	const Vector3 &get_node_position() const;
   40.47 +	const Quaternion &get_node_rotation() const;
   40.48 +	const Vector3 &get_node_scaling() const;
   40.49 +
   40.50 +	Vector3 get_position() const;
   40.51 +	Quaternion get_rotation() const;
   40.52 +	Vector3 get_scaling() const;
   40.53 +
   40.54 +	const Matrix4x4 &get_matrix() const;
   40.55 +	const Matrix4x4 &get_inv_matrix() const;
   40.56 +
   40.57 +	void update_node(long msec = 0);
   40.58 +	void update(long msec = 0);
   40.59 +
   40.60 +	bool intersect(const Ray &ray, HitPoint *hit) const;
   40.61 +};
   40.62 +
   40.63 +#endif	// SNODE_H_