ld33_umonster

changeset 0:4a6683050e29

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 22 Aug 2015 07:15:00 +0300
parents
children bed0e207acb6
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/scene.cc src/scene.h 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 34 files changed, 4450 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sat Aug 22 07:15:00 2015 +0300
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +^umonster$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Sat Aug 22 07:15:00 2015 +0300
     2.3 @@ -0,0 +1,35 @@
     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 = umonster
    2.10 +
    2.11 +sys = $(shell uname -s)
    2.12 +
    2.13 +CFLAGS = -pedantic -Wall -g
    2.14 +CXXFLAGS = $(CFLAGS)
    2.15 +LDFLAGS = $(libgl_$(sys)) -lvmath -limago -lpsys -lanim -lm
    2.16 +
    2.17 +libgl_Linux = -lGL -lGLU -lglut -lGLEW
    2.18 +libgl_Darwin = -framework OpenGL -framework GLUT -lGLEW
    2.19 +
    2.20 +
    2.21 +$(bin): $(obj)
    2.22 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    2.23 +
    2.24 +-include $(dep)
    2.25 +
    2.26 +%.d: %.c
    2.27 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.28 +
    2.29 +%.d: %.cc
    2.30 +	@$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.31 +
    2.32 +.PHONY: clean
    2.33 +clean:
    2.34 +	rm -f $(obj) $(bin)
    2.35 +
    2.36 +.PHONY: cleandep
    2.37 +cleandep:
    2.38 +	rm -f $(dep)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/sdr/shadow-notex.p.glsl	Sat Aug 22 07:15:00 2015 +0300
     3.3 @@ -0,0 +1,29 @@
     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 +
    3.18 +	vec3 n = normalize(normal);
    3.19 +	vec3 v = normalize(vdir);
    3.20 +	vec3 l = normalize(ldir);
    3.21 +	vec3 h = normalize(l + v);
    3.22 +
    3.23 +	float ndotl = max(dot(n, l), 0.0);
    3.24 +	float ndoth = max(dot(n, h), 0.0);
    3.25 +
    3.26 +	vec3 diffuse = KD * gl_LightSource[0].diffuse.rgb * ndotl;
    3.27 +	vec3 specular = KS * gl_LightSource[0].specular.rgb * pow(ndoth, SPOW);
    3.28 +
    3.29 +	vec3 ambient = gl_LightModel.ambient.rgb * KD;
    3.30 +	gl_FragColor.rgb = ambient + (diffuse + specular) * shadow;
    3.31 +	gl_FragColor.a = gl_FrontMaterial.diffuse.a;
    3.32 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/sdr/shadow.p.glsl	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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 = 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	Sat Aug 22 07:15:00 2015 +0300
     6.3 @@ -0,0 +1,219 @@
     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 +
    6.13 +static void draw_scene();
    6.14 +
    6.15 +int win_width, win_height;
    6.16 +unsigned long cur_time;
    6.17 +bool dbg_wireframe;
    6.18 +int dbg_int;
    6.19 +
    6.20 +unsigned int sdr_shadow, sdr_shadow_notex;
    6.21 +
    6.22 +static float cam_theta, cam_phi = 25, cam_dist = 8;
    6.23 +static bool bnstate[8];
    6.24 +static int prev_x, prev_y;
    6.25 +
    6.26 +static unsigned int modkeys;
    6.27 +
    6.28 +
    6.29 +bool game_init()
    6.30 +{
    6.31 +	if(init_opengl() == -1) {
    6.32 +		return false;
    6.33 +	}
    6.34 +
    6.35 +	glEnable(GL_DEPTH_TEST);
    6.36 +	glEnable(GL_CULL_FACE);
    6.37 +	glEnable(GL_NORMALIZE);
    6.38 +	glEnable(GL_LIGHTING);
    6.39 +	glEnable(GL_LIGHT0);
    6.40 +
    6.41 +	float amb[] = {0.3, 0.3, 0.3, 1.0};
    6.42 +	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
    6.43 +
    6.44 +	if(glcaps.sep_spec) {
    6.45 +		glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
    6.46 +	}
    6.47 +	glEnable(GL_MULTISAMPLE);
    6.48 +
    6.49 +	if(!init_shadow(4096)) {
    6.50 +		fprintf(stderr, "failed to initialize shadowmaps\n");
    6.51 +		return false;
    6.52 +	}
    6.53 +	if(!(sdr_shadow = create_program_load("sdr/shadow.v.glsl", "sdr/shadow.p.glsl"))) {
    6.54 +		return false;
    6.55 +	}
    6.56 +	set_uniform_int(sdr_shadow, "tex", 0);
    6.57 +	set_uniform_int(sdr_shadow, "shadowmap", 1);
    6.58 +
    6.59 +	if(!(sdr_shadow_notex = create_program_load("sdr/shadow.v.glsl", "sdr/shadow-notex.p.glsl"))) {
    6.60 +		return false;
    6.61 +	}
    6.62 +	set_uniform_int(sdr_shadow_notex, "shadowmap", 1);
    6.63 +
    6.64 +
    6.65 +	assert(glGetError() == GL_NO_ERROR);
    6.66 +	return true;
    6.67 +}
    6.68 +
    6.69 +void game_cleanup()
    6.70 +{
    6.71 +}
    6.72 +
    6.73 +void game_update(unsigned long time_msec)
    6.74 +{
    6.75 +	cur_time = time_msec;
    6.76 +}
    6.77 +
    6.78 +void game_display()
    6.79 +{
    6.80 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    6.81 +
    6.82 +	glMatrixMode(GL_MODELVIEW);
    6.83 +	glLoadIdentity();
    6.84 +	glTranslatef(0, 0.1, -cam_dist);
    6.85 +	glRotatef(cam_phi, 1, 0, 0);
    6.86 +	glRotatef(cam_theta, 0, 1, 0);
    6.87 +
    6.88 +	float lpos[] = {-10, 20, 10, 1};
    6.89 +	glLightfv(GL_LIGHT0, GL_POSITION, lpos);
    6.90 +
    6.91 +	if(opt.shadows && sdr_shadow) {
    6.92 +		begin_shadow_pass(Vector3(lpos[0], lpos[1], lpos[2]), Vector3(0, 0, 0), 5);
    6.93 +		draw_scene();
    6.94 +		end_shadow_pass();
    6.95 +
    6.96 +		glActiveTexture(GL_TEXTURE1);
    6.97 +		glBindTexture(GL_TEXTURE_2D, get_shadow_tex());
    6.98 +
    6.99 +		glMatrixMode(GL_TEXTURE);
   6.100 +		Matrix4x4 shadow_matrix = get_shadow_matrix();
   6.101 +		glLoadTransposeMatrixf(shadow_matrix[0]);
   6.102 +
   6.103 +		glActiveTexture(GL_TEXTURE0);
   6.104 +		glMatrixMode(GL_MODELVIEW);
   6.105 +
   6.106 +		set_shader(sdr_shadow_notex);
   6.107 +
   6.108 +		draw_scene();
   6.109 +
   6.110 +		glActiveTexture(GL_TEXTURE1);
   6.111 +		glBindTexture(GL_TEXTURE_2D, 0);
   6.112 +		glActiveTexture(GL_TEXTURE0);
   6.113 +		glBindTexture(GL_TEXTURE_2D, 0);
   6.114 +	} else {
   6.115 +		draw_scene();
   6.116 +	}
   6.117 +}
   6.118 +
   6.119 +static void glmaterial(float r, float g, float b, float spec, float shin)
   6.120 +{
   6.121 +	float color[] = {r, g, b, 1};
   6.122 +	float scolor[] = {spec, spec, spec, 1};
   6.123 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
   6.124 +	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scolor);
   6.125 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shin);
   6.126 +}
   6.127 +
   6.128 +static void draw_scene()
   6.129 +{
   6.130 +	glPushMatrix();
   6.131 +	glTranslatef(0, -1, 0);
   6.132 +
   6.133 +	glmaterial(0.5, 0.5, 0.5, 0.8, 40.0);
   6.134 +
   6.135 +	glBegin(GL_QUADS);
   6.136 +	glNormal3f(0, 1, 0);
   6.137 +	glVertex3f(-10, 0, 10);
   6.138 +	glVertex3f(10, 0, 10);
   6.139 +	glVertex3f(10, 0, -10);
   6.140 +	glVertex3f(-10, 0, -10);
   6.141 +	glEnd();
   6.142 +
   6.143 +	glPopMatrix();
   6.144 +
   6.145 +	glmaterial(0.2, 0.3, 1.0, 0.8, 60.0);
   6.146 +	draw_teapot();
   6.147 +}
   6.148 +
   6.149 +
   6.150 +void game_reshape(int x, int y)
   6.151 +{
   6.152 +	glMatrixMode(GL_PROJECTION);
   6.153 +	glLoadIdentity();
   6.154 +	gluPerspective(45, (float)x / (float)y, 0.2, 200.0);
   6.155 +
   6.156 +	glViewport(0, 0, x, y);
   6.157 +}
   6.158 +
   6.159 +void game_keyboard(int bn, bool press)
   6.160 +{
   6.161 +	if(press) {
   6.162 +		switch(bn) {
   6.163 +		case 27:
   6.164 +			quit();
   6.165 +
   6.166 +		case 'w':
   6.167 +			dbg_wireframe = !dbg_wireframe;
   6.168 +			redisplay();
   6.169 +			break;
   6.170 +
   6.171 +		case 's':
   6.172 +			opt.shadows = !opt.shadows;
   6.173 +			redisplay();
   6.174 +			break;
   6.175 +		}
   6.176 +	}
   6.177 +}
   6.178 +
   6.179 +void game_modifier_key(int key, bool press)
   6.180 +{
   6.181 +	if(press) {
   6.182 +		modkeys |= (1 << key);
   6.183 +	} else {
   6.184 +		modkeys &= ~(1 << key);
   6.185 +	}
   6.186 +}
   6.187 +
   6.188 +void game_mbutton(int bn, bool press, int x, int y)
   6.189 +{
   6.190 +	bnstate[bn] = press;
   6.191 +	prev_x = x;
   6.192 +	prev_y = y;
   6.193 +
   6.194 +	if(modkeys) {
   6.195 +		return;
   6.196 +	}
   6.197 +
   6.198 +	if(bn == 0) {
   6.199 +	}
   6.200 +}
   6.201 +
   6.202 +void game_mmotion(int x, int y)
   6.203 +{
   6.204 +	int dx = x - prev_x;
   6.205 +	int dy = y - prev_y;
   6.206 +	prev_x = x;
   6.207 +	prev_y = y;
   6.208 +
   6.209 +	if(modkeys) {
   6.210 +		if(bnstate[0]) {
   6.211 +			cam_theta += dx * 0.5;
   6.212 +			cam_phi += dy * 0.5;
   6.213 +
   6.214 +			if(cam_phi < -90) cam_phi = -90;
   6.215 +			if(cam_phi > 90) cam_phi = 90;
   6.216 +		}
   6.217 +		if(bnstate[2]) {
   6.218 +			cam_dist += dy * 0.1;
   6.219 +			if(cam_dist < 0.0) cam_dist = 0.0;
   6.220 +		}
   6.221 +	}
   6.222 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/game.h	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 2015 +0300
     8.3 @@ -0,0 +1,251 @@
     8.4 +#include <algorithm>
     8.5 +#include <float.h>
     8.6 +#include "geom.h"
     8.7 +
     8.8 +GeomObject::~GeomObject()
     8.9 +{
    8.10 +}
    8.11 +
    8.12 +
    8.13 +Sphere::Sphere()
    8.14 +{
    8.15 +	radius = 1.0;
    8.16 +}
    8.17 +
    8.18 +Sphere::Sphere(const Vector3 &cent, float radius)
    8.19 +	: center(cent)
    8.20 +{
    8.21 +	this->radius = radius;
    8.22 +}
    8.23 +
    8.24 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
    8.25 +{
    8.26 +	const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
    8.27 +	const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
    8.28 +
    8.29 +	if(!sph1 || !sph2) {
    8.30 +		fprintf(stderr, "Sphere::set_union: arguments must be spheres");
    8.31 +		return;
    8.32 +	}
    8.33 +
    8.34 +	float dist = (sph1->center - sph2->center).length();
    8.35 +	float surf_dist = dist - (sph1->radius + sph2->radius);
    8.36 +	float d1 = sph1->radius + surf_dist / 2.0;
    8.37 +	float d2 = sph2->radius + surf_dist / 2.0;
    8.38 +	float t = d1 / (d1 + d2);
    8.39 +
    8.40 +	if(t < 0.0) t = 0.0;
    8.41 +	if(t > 1.0) t = 1.0;
    8.42 +
    8.43 +	center = sph1->center * t + sph2->center * (1.0 - t);
    8.44 +	radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
    8.45 +}
    8.46 +
    8.47 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
    8.48 +{
    8.49 +	fprintf(stderr, "Sphere::intersection undefined\n");
    8.50 +}
    8.51 +
    8.52 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
    8.53 +{
    8.54 +	float a = dot_product(ray.dir, ray.dir);
    8.55 +	float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
    8.56 +		2.0 * ray.dir.y * (ray.origin.y - center.y) +
    8.57 +		2.0 * ray.dir.z * (ray.origin.z - center.z);
    8.58 +	float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
    8.59 +		2.0 * dot_product(ray.origin, center) - radius * radius;
    8.60 +
    8.61 +	float discr = b * b - 4.0 * a * c;
    8.62 +	if(discr < 1e-4) {
    8.63 +		return false;
    8.64 +	}
    8.65 +
    8.66 +	float sqrt_discr = sqrt(discr);
    8.67 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
    8.68 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
    8.69 +
    8.70 +	if(t0 < 1e-4)
    8.71 +		t0 = t1;
    8.72 +	if(t1 < 1e-4)
    8.73 +		t1 = t0;
    8.74 +
    8.75 +	float t = t0 < t1 ? t0 : t1;
    8.76 +	if(t < 1e-4) {
    8.77 +		return false;
    8.78 +	}
    8.79 +
    8.80 +	// fill the HitPoint structure
    8.81 +	if(hit) {
    8.82 +		hit->obj = this;
    8.83 +		hit->dist = t;
    8.84 +		hit->pos = ray.origin + ray.dir * t;
    8.85 +		hit->normal = (hit->pos - center) / radius;
    8.86 +	}
    8.87 +	return true;
    8.88 +}
    8.89 +
    8.90 +
    8.91 +AABox::AABox()
    8.92 +{
    8.93 +}
    8.94 +
    8.95 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
    8.96 +	: min(vmin), max(vmax)
    8.97 +{
    8.98 +}
    8.99 +
   8.100 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
   8.101 +{
   8.102 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   8.103 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   8.104 +
   8.105 +	if(!box1 || !box2) {
   8.106 +		fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n");
   8.107 +		return;
   8.108 +	}
   8.109 +
   8.110 +	min.x = std::min(box1->min.x, box2->min.x);
   8.111 +	min.y = std::min(box1->min.y, box2->min.y);
   8.112 +	min.z = std::min(box1->min.z, box2->min.z);
   8.113 +
   8.114 +	max.x = std::max(box1->max.x, box2->max.x);
   8.115 +	max.y = std::max(box1->max.y, box2->max.y);
   8.116 +	max.z = std::max(box1->max.z, box2->max.z);
   8.117 +}
   8.118 +
   8.119 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   8.120 +{
   8.121 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   8.122 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   8.123 +
   8.124 +	if(!box1 || !box2) {
   8.125 +		fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n");
   8.126 +		return;
   8.127 +	}
   8.128 +
   8.129 +	for(int i=0; i<3; i++) {
   8.130 +		min[i] = std::max(box1->min[i], box2->min[i]);
   8.131 +		max[i] = std::min(box1->max[i], box2->max[i]);
   8.132 +
   8.133 +		if(max[i] < min[i]) {
   8.134 +			max[i] = min[i];
   8.135 +		}
   8.136 +	}
   8.137 +}
   8.138 +
   8.139 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const
   8.140 +{
   8.141 +	Vector3 param[2] = {min, max};
   8.142 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
   8.143 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
   8.144 +
   8.145 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
   8.146 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
   8.147 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
   8.148 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
   8.149 +
   8.150 +	if(tmin > tymax || tymin > tmax) {
   8.151 +		return false;
   8.152 +	}
   8.153 +	if(tymin > tmin) {
   8.154 +		tmin = tymin;
   8.155 +	}
   8.156 +	if(tymax < tmax) {
   8.157 +		tmax = tymax;
   8.158 +	}
   8.159 +
   8.160 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
   8.161 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
   8.162 +
   8.163 +	if(tmin > tzmax || tzmin > tmax) {
   8.164 +		return false;
   8.165 +	}
   8.166 +	if(tzmin > tmin) {
   8.167 +		tmin = tzmin;
   8.168 +	}
   8.169 +	if(tzmax < tmax) {
   8.170 +		tmax = tzmax;
   8.171 +	}
   8.172 +
   8.173 +	float t = tmin < 1e-4 ? tmax : tmin;
   8.174 +	if(t >= 1e-4) {
   8.175 +
   8.176 +		if(hit) {
   8.177 +			hit->obj = this;
   8.178 +			hit->dist = t;
   8.179 +			hit->pos = ray.origin + ray.dir * t;
   8.180 +
   8.181 +			float min_dist = FLT_MAX;
   8.182 +			Vector3 offs = min + (max - min) / 2.0;
   8.183 +			Vector3 local_hit = hit->pos - offs;
   8.184 +
   8.185 +			static const Vector3 axis[] = {
   8.186 +				Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
   8.187 +			};
   8.188 +			//int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
   8.189 +
   8.190 +			for(int i=0; i<3; i++) {
   8.191 +				float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
   8.192 +				if(dist < min_dist) {
   8.193 +					min_dist = dist;
   8.194 +					hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
   8.195 +					//hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
   8.196 +				}
   8.197 +			}
   8.198 +		}
   8.199 +		return true;
   8.200 +	}
   8.201 +	return false;
   8.202 +
   8.203 +}
   8.204 +
   8.205 +Plane::Plane()
   8.206 +	: normal(0.0, 1.0, 0.0)
   8.207 +{
   8.208 +}
   8.209 +
   8.210 +Plane::Plane(const Vector3 &p, const Vector3 &norm)
   8.211 +	: pt(p)
   8.212 +{
   8.213 +	normal = norm.normalized();
   8.214 +}
   8.215 +
   8.216 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
   8.217 +	: pt(p1)
   8.218 +{
   8.219 +	normal = cross_product(p2 - p1, p3 - p1).normalized();
   8.220 +}
   8.221 +
   8.222 +Plane::Plane(const Vector3 &normal, float dist)
   8.223 +{
   8.224 +	this->normal = normal.normalized();
   8.225 +	pt = this->normal * dist;
   8.226 +}
   8.227 +
   8.228 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
   8.229 +{
   8.230 +	fprintf(stderr, "Plane::set_union undefined\n");
   8.231 +}
   8.232 +
   8.233 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   8.234 +{
   8.235 +	fprintf(stderr, "Plane::set_intersection undefined\n");
   8.236 +}
   8.237 +
   8.238 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const
   8.239 +{
   8.240 +	float ndotdir = dot_product(normal, ray.dir);
   8.241 +	if(fabs(ndotdir) < 1e-4) {
   8.242 +		return false;
   8.243 +	}
   8.244 +
   8.245 +	if(hit) {
   8.246 +		Vector3 ptdir = pt - ray.origin;
   8.247 +		float t = dot_product(normal, ptdir) / ndotdir;
   8.248 +
   8.249 +		hit->pos = ray.origin + ray.dir * t;
   8.250 +		hit->normal = normal;
   8.251 +		hit->obj = this;
   8.252 +	}
   8.253 +	return true;
   8.254 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/geom.h	Sat Aug 22 07:15:00 2015 +0300
     9.3 @@ -0,0 +1,70 @@
     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 +#endif	// GEOMOBJ_H_
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/light.cc	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 2015 +0300
    13.3 @@ -0,0 +1,1237 @@
    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;
  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 +// ------ private member functions ------
  13.989 +
  13.990 +void Mesh::calc_aabb()
  13.991 +{
  13.992 +	// the cast is to force calling the const version which doesn't invalidate
  13.993 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  13.994 +		return;
  13.995 +	}
  13.996 +
  13.997 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  13.998 +	aabb.max = -aabb.min;
  13.999 +
 13.1000 +	for(unsigned int i=0; i<nverts; i++) {
 13.1001 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
 13.1002 +		for(int j=0; j<3; j++) {
 13.1003 +			if(v[j] < aabb.min[j]) {
 13.1004 +				aabb.min[j] = v[j];
 13.1005 +			}
 13.1006 +			if(v[j] > aabb.max[j]) {
 13.1007 +				aabb.max[j] = v[j];
 13.1008 +			}
 13.1009 +		}
 13.1010 +	}
 13.1011 +	aabb_valid = true;
 13.1012 +}
 13.1013 +
 13.1014 +void Mesh::calc_bsph()
 13.1015 +{
 13.1016 +	// the cast is to force calling the const version which doesn't invalidate
 13.1017 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
 13.1018 +		return;
 13.1019 +	}
 13.1020 +
 13.1021 +	Vector3 v;
 13.1022 +	bsph.center = Vector3(0, 0, 0);
 13.1023 +
 13.1024 +	// first find the center
 13.1025 +	for(unsigned int i=0; i<nverts; i++) {
 13.1026 +		v = get_attrib(MESH_ATTR_VERTEX, i);
 13.1027 +		bsph.center += v;
 13.1028 +	}
 13.1029 +	bsph.center /= (float)nverts;
 13.1030 +
 13.1031 +	bsph.radius = 0.0f;
 13.1032 +	for(unsigned int i=0; i<nverts; i++) {
 13.1033 +		v = get_attrib(MESH_ATTR_VERTEX, i);
 13.1034 +		float dist_sq = (v - bsph.center).length_sq();
 13.1035 +		if(dist_sq > bsph.radius) {
 13.1036 +			bsph.radius = dist_sq;
 13.1037 +		}
 13.1038 +	}
 13.1039 +	bsph.radius = sqrt(bsph.radius);
 13.1040 +
 13.1041 +	bsph_valid = true;
 13.1042 +}
 13.1043 +
 13.1044 +void Mesh::update_buffers()
 13.1045 +{
 13.1046 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
 13.1047 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
 13.1048 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
 13.1049 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
 13.1050 +			vattr[i].vbo_valid = true;
 13.1051 +		}
 13.1052 +	}
 13.1053 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
 13.1054 +
 13.1055 +	if(idata_valid && !ibo_valid) {
 13.1056 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
 13.1057 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
 13.1058 +		ibo_valid = true;
 13.1059 +	}
 13.1060 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 13.1061 +}
 13.1062 +
 13.1063 +void Mesh::update_wire_ibo()
 13.1064 +{
 13.1065 +	update_buffers();
 13.1066 +
 13.1067 +	if(wire_ibo_valid) {
 13.1068 +		return;
 13.1069 +	}
 13.1070 +
 13.1071 +	if(!wire_ibo) {
 13.1072 +		glGenBuffers(1, &wire_ibo);
 13.1073 +	}
 13.1074 +
 13.1075 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
 13.1076 +	unsigned int *dest = wire_idxarr;
 13.1077 +
 13.1078 +	if(ibo_valid) {
 13.1079 +		// we're dealing with an indexed mesh
 13.1080 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
 13.1081 +
 13.1082 +		for(unsigned int i=0; i<nfaces; i++) {
 13.1083 +			*dest++ = idxarr[0];
 13.1084 +			*dest++ = idxarr[1];
 13.1085 +			*dest++ = idxarr[1];
 13.1086 +			*dest++ = idxarr[2];
 13.1087 +			*dest++ = idxarr[2];
 13.1088 +			*dest++ = idxarr[0];
 13.1089 +			idxarr += 3;
 13.1090 +		}
 13.1091 +	} else {
 13.1092 +		// not an indexed mesh ...
 13.1093 +		for(unsigned int i=0; i<nfaces; i++) {
 13.1094 +			int vidx = i * 3;
 13.1095 +			*dest++ = vidx;
 13.1096 +			*dest++ = vidx + 1;
 13.1097 +			*dest++ = vidx + 1;
 13.1098 +			*dest++ = vidx + 2;
 13.1099 +			*dest++ = vidx + 2;
 13.1100 +			*dest++ = vidx;
 13.1101 +		}
 13.1102 +	}
 13.1103 +
 13.1104 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
 13.1105 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
 13.1106 +	delete [] wire_idxarr;
 13.1107 +	wire_ibo_valid = true;
 13.1108 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 13.1109 +}
 13.1110 +
 13.1111 +
 13.1112 +// ------ class Triangle ------
 13.1113 +Triangle::Triangle()
 13.1114 +{
 13.1115 +	normal_valid = false;
 13.1116 +	id = -1;
 13.1117 +}
 13.1118 +
 13.1119 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
 13.1120 +{
 13.1121 +	v[0] = v0;
 13.1122 +	v[1] = v1;
 13.1123 +	v[2] = v2;
 13.1124 +	normal_valid = false;
 13.1125 +	id = -1;
 13.1126 +}
 13.1127 +
 13.1128 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
 13.1129 +{
 13.1130 +	if(idxarr) {
 13.1131 +		v[0] = varr[idxarr[n * 3]];
 13.1132 +		v[1] = varr[idxarr[n * 3 + 1]];
 13.1133 +		v[2] = varr[idxarr[n * 3 + 2]];
 13.1134 +	} else {
 13.1135 +		v[0] = varr[n * 3];
 13.1136 +		v[1] = varr[n * 3 + 1];
 13.1137 +		v[2] = varr[n * 3 + 2];
 13.1138 +	}
 13.1139 +	normal_valid = false;
 13.1140 +	id = n;
 13.1141 +}
 13.1142 +
 13.1143 +void Triangle::calc_normal()
 13.1144 +{
 13.1145 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
 13.1146 +	normal_valid = true;
 13.1147 +}
 13.1148 +
 13.1149 +const Vector3 &Triangle::get_normal() const
 13.1150 +{
 13.1151 +	if(!normal_valid) {
 13.1152 +		((Triangle*)this)->calc_normal();
 13.1153 +	}
 13.1154 +	return normal;
 13.1155 +}
 13.1156 +
 13.1157 +void Triangle::transform(const Matrix4x4 &xform)
 13.1158 +{
 13.1159 +	v[0].transform(xform);
 13.1160 +	v[1].transform(xform);
 13.1161 +	v[2].transform(xform);
 13.1162 +	normal_valid = false;
 13.1163 +}
 13.1164 +
 13.1165 +void Triangle::draw() const
 13.1166 +{
 13.1167 +	Vector3 n[3];
 13.1168 +	n[0] = get_normal();
 13.1169 +	n[1] = get_normal();
 13.1170 +	n[2] = get_normal();
 13.1171 +
 13.1172 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 13.1173 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
 13.1174 +
 13.1175 +	glEnableVertexAttribArray(vloc);
 13.1176 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 13.1177 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
 13.1178 +
 13.1179 +	glDrawArrays(GL_TRIANGLES, 0, 3);
 13.1180 +
 13.1181 +	glDisableVertexAttribArray(vloc);
 13.1182 +	glDisableVertexAttribArray(nloc);
 13.1183 +}
 13.1184 +
 13.1185 +void Triangle::draw_wire() const
 13.1186 +{
 13.1187 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
 13.1188 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 13.1189 +
 13.1190 +	glEnableVertexAttribArray(vloc);
 13.1191 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 13.1192 +
 13.1193 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
 13.1194 +
 13.1195 +	glDisableVertexAttribArray(vloc);
 13.1196 +}
 13.1197 +
 13.1198 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
 13.1199 +{
 13.1200 +	Vector3 norm = get_normal();
 13.1201 +
 13.1202 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
 13.1203 +	if(area_sq < 1e-5) {
 13.1204 +		return Vector3(0, 0, 0);
 13.1205 +	}
 13.1206 +
 13.1207 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
 13.1208 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
 13.1209 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
 13.1210 +
 13.1211 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
 13.1212 +}
 13.1213 +
 13.1214 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
 13.1215 +{
 13.1216 +	Vector3 normal = get_normal();
 13.1217 +
 13.1218 +	float ndotdir = dot_product(ray.dir, normal);
 13.1219 +	if(fabs(ndotdir) < 1e-4) {
 13.1220 +		return false;
 13.1221 +	}
 13.1222 +
 13.1223 +	Vector3 vertdir = v[0] - ray.origin;
 13.1224 +	float t = dot_product(normal, vertdir) / ndotdir;
 13.1225 +
 13.1226 +	Vector3 pos = ray.origin + ray.dir * t;
 13.1227 +	Vector3 bary = calc_barycentric(pos);
 13.1228 +
 13.1229 +	if(bary.x + bary.y + bary.z > 1.00001) {
 13.1230 +		return false;
 13.1231 +	}
 13.1232 +
 13.1233 +	if(hit) {
 13.1234 +		hit->dist = t;
 13.1235 +		hit->pos = ray.origin + ray.dir * t;
 13.1236 +		hit->normal = normal;
 13.1237 +		hit->obj = this;
 13.1238 +	}
 13.1239 +	return true;
 13.1240 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/mesh.h	Sat Aug 22 07:15:00 2015 +0300
    14.3 @@ -0,0 +1,236 @@
    14.4 +#ifndef MESH_H_
    14.5 +#define MESH_H_
    14.6 +
    14.7 +#include <string>
    14.8 +#include <vector>
    14.9 +#include "vmath/vmath.h"
   14.10 +#include "geom.h"
   14.11 +
   14.12 +enum {
   14.13 +	MESH_ATTR_VERTEX,
   14.14 +	MESH_ATTR_NORMAL,
   14.15 +	MESH_ATTR_TANGENT,
   14.16 +	MESH_ATTR_TEXCOORD,
   14.17 +	MESH_ATTR_COLOR,
   14.18 +	MESH_ATTR_BONEWEIGHTS,
   14.19 +	MESH_ATTR_BONEIDX,
   14.20 +
   14.21 +	NUM_MESH_ATTR
   14.22 +};
   14.23 +
   14.24 +// intersection mode flags
   14.25 +enum {
   14.26 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
   14.27 +	ISECT_FRONT		= 1,	// front-faces only
   14.28 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
   14.29 +	ISECT_VERTICES	= 4		// return (?) TODO
   14.30 +};
   14.31 +
   14.32 +//class XFormNode;
   14.33 +
   14.34 +
   14.35 +class Triangle {
   14.36 +public:
   14.37 +	Vector3 v[3];
   14.38 +	Vector3 normal;
   14.39 +	bool normal_valid;
   14.40 +	int id;
   14.41 +
   14.42 +	Triangle();
   14.43 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
   14.44 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
   14.45 +
   14.46 +	/// calculate normal (quite expensive)
   14.47 +	void calc_normal();
   14.48 +	const Vector3 &get_normal() const;
   14.49 +
   14.50 +	void transform(const Matrix4x4 &xform);
   14.51 +
   14.52 +	void draw() const;
   14.53 +	void draw_wire() const;
   14.54 +
   14.55 +	/// calculate barycentric coordinates of a point
   14.56 +	Vector3 calc_barycentric(const Vector3 &pos) const;
   14.57 +
   14.58 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   14.59 +};
   14.60 +
   14.61 +
   14.62 +class Mesh {
   14.63 +private:
   14.64 +	std::string name;
   14.65 +	unsigned int nverts, nfaces;
   14.66 +
   14.67 +	// current value for each attribute for the immedate mode
   14.68 +	// interface.
   14.69 +	Vector4 cur_val[NUM_MESH_ATTR];
   14.70 +
   14.71 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
   14.72 +
   14.73 +	// vertex attribute data and buffer objects
   14.74 +	struct {
   14.75 +		int nelem;					// number of elements per attribute range: [1, 4]
   14.76 +		std::vector<float> data;
   14.77 +		unsigned int vbo;
   14.78 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
   14.79 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
   14.80 +		//int sdr_loc;
   14.81 +	} vattr[NUM_MESH_ATTR];
   14.82 +
   14.83 +	static int global_sdr_loc[NUM_MESH_ATTR];
   14.84 +
   14.85 +	//std::vector<XFormNode*> bones;	// bones affecting this mesh
   14.86 +
   14.87 +	// index data and buffer object
   14.88 +	std::vector<unsigned int> idata;
   14.89 +	unsigned int ibo;
   14.90 +	mutable bool ibo_valid;
   14.91 +	mutable bool idata_valid;
   14.92 +
   14.93 +	// index buffer object for wireframe rendering (constructed on demand)
   14.94 +	unsigned int wire_ibo;
   14.95 +	mutable bool wire_ibo_valid;
   14.96 +
   14.97 +	// axis-aligned bounding box
   14.98 +	mutable AABox aabb;
   14.99 +	mutable bool aabb_valid;
  14.100 +
  14.101 +	// bounding sphere
  14.102 +	mutable Sphere bsph;
  14.103 +	mutable bool bsph_valid;
  14.104 +
  14.105 +	// keeps the last intersected face
  14.106 +	mutable Triangle hitface;
  14.107 +	// keeps the last intersected vertex position
  14.108 +	mutable Vector3 hitvert;
  14.109 +
  14.110 +	void calc_aabb();
  14.111 +	void calc_bsph();
  14.112 +
  14.113 +	static unsigned int intersect_mode;
  14.114 +	static float vertex_sel_dist;
  14.115 +
  14.116 +	static float vis_vecsize;
  14.117 +
  14.118 +	/// update the VBOs after data has changed (invalid vbo/ibo)
  14.119 +	void update_buffers();
  14.120 +	/// construct/update the wireframe index buffer (called from draw_wire).
  14.121 +	void update_wire_ibo();
  14.122 +
  14.123 +	mutable int cur_sdr;
  14.124 +	bool pre_draw() const;
  14.125 +	void post_draw() const;
  14.126 +
  14.127 +
  14.128 +public:
  14.129 +	static bool use_custom_sdr_attr;
  14.130 +
  14.131 +	Mesh();
  14.132 +	~Mesh();
  14.133 +
  14.134 +	Mesh(const Mesh &rhs);
  14.135 +	Mesh &operator =(const Mesh &rhs);
  14.136 +	bool clone(const Mesh &m);
  14.137 +
  14.138 +	void set_name(const char *name);
  14.139 +	const char *get_name() const;
  14.140 +
  14.141 +	bool has_attrib(int attr) const;
  14.142 +	bool is_indexed() const;
  14.143 +
  14.144 +	// clears everything about this mesh, and returns to the newly constructed state
  14.145 +	void clear();
  14.146 +
  14.147 +	// access the vertex attribute data
  14.148 +	// if vdata == 0, space is just allocated
  14.149 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
  14.150 +	float *get_attrib_data(int attrib);	// invalidates vbo
  14.151 +	const float *get_attrib_data(int attrib) const;
  14.152 +
  14.153 +	// simple access to any particular attribute
  14.154 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
  14.155 +	Vector4 get_attrib(int attrib, int idx) const;
  14.156 +
  14.157 +	int get_attrib_count(int attrib) const;
  14.158 +
  14.159 +	// ... same for index data
  14.160 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
  14.161 +	unsigned int *get_index_data();	// invalidates ibo
  14.162 +	const unsigned int *get_index_data() const;
  14.163 +
  14.164 +	int get_index_count() const;
  14.165 +
  14.166 +	void append(const Mesh &mesh);
  14.167 +
  14.168 +	// immediate-mode style mesh construction interface
  14.169 +	void vertex(float x, float y, float z);
  14.170 +	void normal(float nx, float ny, float nz);
  14.171 +	void tangent(float tx, float ty, float tz);
  14.172 +	void texcoord(float u, float v, float w);
  14.173 +	void boneweights(float w1, float w2, float w3, float w4);
  14.174 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
  14.175 +
  14.176 +	int get_poly_count() const;
  14.177 +
  14.178 +	/* apply a transformation to the vertices and its inverse-transpose
  14.179 +	 * to the normals and tangents.
  14.180 +	 */
  14.181 +	void apply_xform(const Matrix4x4 &xform);
  14.182 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
  14.183 +
  14.184 +	void flip();	// both faces and normals
  14.185 +	void flip_faces();
  14.186 +	void flip_normals();
  14.187 +
  14.188 +	// adds a bone and returns its index
  14.189 +	/*int add_bone(XFormNode *bone);
  14.190 +	const XFormNode *get_bone(int idx) const;
  14.191 +	int get_bones_count() const;*/
  14.192 +
  14.193 +	// access the shader attribute locations
  14.194 +	static void set_attrib_location(int attr, int loc);
  14.195 +	static int get_attrib_location(int attr);
  14.196 +	static void clear_attrib_locations();
  14.197 +
  14.198 +	static void set_vis_vecsize(float sz);
  14.199 +	static float get_vis_vecsize();
  14.200 +
  14.201 +	void draw() const;
  14.202 +	void draw_wire() const;
  14.203 +	void draw_vertices() const;
  14.204 +	void draw_normals() const;
  14.205 +	void draw_tangents() const;
  14.206 +
  14.207 +	/** get the bounding box in local space. The result will be cached, and subsequent
  14.208 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  14.209 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  14.210 +	 * @{ */
  14.211 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
  14.212 +	const AABox &get_aabbox() const;
  14.213 +	/// @}
  14.214 +
  14.215 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
  14.216 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  14.217 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  14.218 +	 * @{ */
  14.219 +	float get_bsphere(Vector3 *center, float *rad) const;
  14.220 +	const Sphere &get_bsphere() const;
  14.221 +
  14.222 +	static void set_intersect_mode(unsigned int mode);
  14.223 +	static unsigned int get_intersect_mode();
  14.224 +	static void set_vertex_select_distance(float dist);
  14.225 +	static float get_vertex_select_distance();
  14.226 +
  14.227 +	/** Find the intersection between the mesh and a ray.
  14.228 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
  14.229 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
  14.230 +	 */
  14.231 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
  14.232 +
  14.233 +	// texture coordinate manipulation
  14.234 +	void texcoord_apply_xform(const Matrix4x4 &xform);
  14.235 +	void texcoord_gen_plane(const Vector3 &norm, const Vector3 &tang);
  14.236 +	void texcoord_gen_box();
  14.237 +};
  14.238 +
  14.239 +#endif	// MESH_H_
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/meshgen.cc	Sat Aug 22 07:15:00 2015 +0300
    15.3 @@ -0,0 +1,581 @@
    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 = SURAD(u * urange);
   15.45 +
   15.46 +		float v = 0.0;
   15.47 +		for(int j=0; j<vverts; j++) {
   15.48 +			float phi = SVRAD(v * vrange);
   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 +
   15.75 +// -------- cylinder --------
   15.76 +
   15.77 +static Vector3 cylvec(float theta, float height)
   15.78 +{
   15.79 +	return Vector3(sin(theta), height, cos(theta));
   15.80 +}
   15.81 +
   15.82 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
   15.83 +{
   15.84 +	if(usub < 4) usub = 4;
   15.85 +	if(vsub < 1) vsub = 1;
   15.86 +
   15.87 +	int uverts = usub + 1;
   15.88 +	int vverts = vsub + 1;
   15.89 +
   15.90 +	int num_body_verts = uverts * vverts;
   15.91 +	int num_body_quads = usub * vsub;
   15.92 +	int num_body_tri = num_body_quads * 2;
   15.93 +
   15.94 +	int capvverts = capsub ? capsub + 1 : 0;
   15.95 +	int num_cap_verts = uverts * capvverts;
   15.96 +	int num_cap_quads = usub * capsub;
   15.97 +	int num_cap_tri = num_cap_quads * 2;
   15.98 +
   15.99 +	int num_verts = num_body_verts + num_cap_verts * 2;
  15.100 +	int num_tri = num_body_tri + num_cap_tri * 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 = SURAD(u);
  15.115 +
  15.116 +		float v = 0.0;
  15.117 +		for(int j=0; j<vverts; j++) {
  15.118 +			float y = (v - 0.5) * height;
  15.119 +			Vector3 pos = cylvec(theta, y);
  15.120 +
  15.121 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  15.122 +			*narr++ = Vector3(pos.x, 0.0, pos.z);
  15.123 +			*tarr++ = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  15.124 +			*uvarr++ = Vector2(u * urange, v * vrange);
  15.125 +
  15.126 +			if(i < usub && j < vsub) {
  15.127 +				int idx = i * vverts + j;
  15.128 +
  15.129 +				*idxarr++ = idx;
  15.130 +				*idxarr++ = idx + vverts + 1;
  15.131 +				*idxarr++ = idx + 1;
  15.132 +
  15.133 +				*idxarr++ = idx;
  15.134 +				*idxarr++ = idx + vverts;
  15.135 +				*idxarr++ = idx + vverts + 1;
  15.136 +			}
  15.137 +
  15.138 +			v += dv;
  15.139 +		}
  15.140 +		u += du;
  15.141 +	}
  15.142 +
  15.143 +
  15.144 +	// now the cap!
  15.145 +	if(!capsub) {
  15.146 +		return;
  15.147 +	}
  15.148 +
  15.149 +	dv = 1.0 / (float)(capvverts - 1);
  15.150 +
  15.151 +	u = 0.0;
  15.152 +	for(int i=0; i<uverts; i++) {
  15.153 +		float theta = SURAD(u);
  15.154 +
  15.155 +		float v = 0.0;
  15.156 +		for(int j=0; j<capvverts; j++) {
  15.157 +			float r = v * rad;
  15.158 +
  15.159 +			Vector3 pos = cylvec(theta, height / 2.0) * r;
  15.160 +			pos.y = height / 2.0;
  15.161 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  15.162 +
  15.163 +			*varr++ = pos;
  15.164 +			*narr++ = Vector3(0, 1, 0);
  15.165 +			*tarr++ = tang;
  15.166 +			*uvarr++ = Vector2(u * urange, v);
  15.167 +
  15.168 +			pos.y = -height / 2.0;
  15.169 +			*varr++ = pos;
  15.170 +			*narr++ = Vector3(0, -1, 0);
  15.171 +			*tarr++ = -tang;
  15.172 +			*uvarr++ = Vector2(u * urange, v);
  15.173 +
  15.174 +			if(i < usub && j < capsub) {
  15.175 +				unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
  15.176 +
  15.177 +				unsigned int vidx[4] = {
  15.178 +					idx,
  15.179 +					idx + capvverts * 2,
  15.180 +					idx + (capvverts + 1) * 2,
  15.181 +					idx + 2
  15.182 +				};
  15.183 +
  15.184 +				*idxarr++ = vidx[0];
  15.185 +				*idxarr++ = vidx[2];
  15.186 +				*idxarr++ = vidx[1];
  15.187 +				*idxarr++ = vidx[0];
  15.188 +				*idxarr++ = vidx[3];
  15.189 +				*idxarr++ = vidx[2];
  15.190 +
  15.191 +				*idxarr++ = vidx[0] + 1;
  15.192 +				*idxarr++ = vidx[1] + 1;
  15.193 +				*idxarr++ = vidx[2] + 1;
  15.194 +				*idxarr++ = vidx[0] + 1;
  15.195 +				*idxarr++ = vidx[2] + 1;
  15.196 +				*idxarr++ = vidx[3] + 1;
  15.197 +			}
  15.198 +
  15.199 +			v += dv;
  15.200 +		}
  15.201 +		u += du;
  15.202 +	}
  15.203 +}
  15.204 +
  15.205 +// -------- cone --------
  15.206 +
  15.207 +static Vector3 conevec(float theta, float y, float height)
  15.208 +{
  15.209 +	float scale = 1.0 - y / height;
  15.210 +	return Vector3(sin(theta) * scale, y, cos(theta) * scale);
  15.211 +}
  15.212 +
  15.213 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
  15.214 +{
  15.215 +	if(usub < 4) usub = 4;
  15.216 +	if(vsub < 1) vsub = 1;
  15.217 +
  15.218 +	int uverts = usub + 1;
  15.219 +	int vverts = vsub + 1;
  15.220 +
  15.221 +	int num_body_verts = uverts * vverts;
  15.222 +	int num_body_quads = usub * vsub;
  15.223 +	int num_body_tri = num_body_quads * 2;
  15.224 +
  15.225 +	int capvverts = capsub ? capsub + 1 : 0;
  15.226 +	int num_cap_verts = uverts * capvverts;
  15.227 +	int num_cap_quads = usub * capsub;
  15.228 +	int num_cap_tri = num_cap_quads * 2;
  15.229 +
  15.230 +	int num_verts = num_body_verts + num_cap_verts;
  15.231 +	int num_tri = num_body_tri + num_cap_tri;
  15.232 +
  15.233 +	mesh->clear();
  15.234 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.235 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.236 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.237 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.238 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.239 +
  15.240 +	float du = urange / (float)(uverts - 1);
  15.241 +	float dv = vrange / (float)(vverts - 1);
  15.242 +
  15.243 +	float u = 0.0;
  15.244 +	for(int i=0; i<uverts; i++) {
  15.245 +		float theta = SURAD(u);
  15.246 +
  15.247 +		float v = 0.0;
  15.248 +		for(int j=0; j<vverts; j++) {
  15.249 +			float y = v * height;
  15.250 +			Vector3 pos = conevec(theta, y, height);
  15.251 +
  15.252 +			Vector3 tang = (conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height)).normalized();
  15.253 +			Vector3 bitang = (conevec(theta, y + 0.1, height) - pos).normalized();
  15.254 +
  15.255 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  15.256 +			*narr++ = cross_product(tang, bitang);
  15.257 +			*tarr++ = tang;
  15.258 +			*uvarr++ = Vector2(u * urange, v * vrange);
  15.259 +
  15.260 +			if(i < usub && j < vsub) {
  15.261 +				int idx = i * vverts + j;
  15.262 +
  15.263 +				*idxarr++ = idx;
  15.264 +				*idxarr++ = idx + vverts + 1;
  15.265 +				*idxarr++ = idx + 1;
  15.266 +
  15.267 +				*idxarr++ = idx;
  15.268 +				*idxarr++ = idx + vverts;
  15.269 +				*idxarr++ = idx + vverts + 1;
  15.270 +			}
  15.271 +
  15.272 +			v += dv;
  15.273 +		}
  15.274 +		u += du;
  15.275 +	}
  15.276 +
  15.277 +
  15.278 +	// now the bottom cap!
  15.279 +	if(!capsub) {
  15.280 +		return;
  15.281 +	}
  15.282 +
  15.283 +	dv = 1.0 / (float)(capvverts - 1);
  15.284 +
  15.285 +	u = 0.0;
  15.286 +	for(int i=0; i<uverts; i++) {
  15.287 +		float theta = SURAD(u);
  15.288 +
  15.289 +		float v = 0.0;
  15.290 +		for(int j=0; j<capvverts; j++) {
  15.291 +			float r = v * rad;
  15.292 +
  15.293 +			Vector3 pos = conevec(theta, 0.0, height) * r;
  15.294 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  15.295 +
  15.296 +			*varr++ = pos;
  15.297 +			*narr++ = Vector3(0, -1, 0);
  15.298 +			*tarr++ = tang;
  15.299 +			*uvarr++ = Vector2(u * urange, v);
  15.300 +
  15.301 +			if(i < usub && j < capsub) {
  15.302 +				unsigned int idx = num_body_verts + i * capvverts + j;
  15.303 +
  15.304 +				unsigned int vidx[4] = {
  15.305 +					idx,
  15.306 +					idx + capvverts,
  15.307 +					idx + (capvverts + 1),
  15.308 +					idx + 1
  15.309 +				};
  15.310 +
  15.311 +				*idxarr++ = vidx[0];
  15.312 +				*idxarr++ = vidx[1];
  15.313 +				*idxarr++ = vidx[2];
  15.314 +				*idxarr++ = vidx[0];
  15.315 +				*idxarr++ = vidx[2];
  15.316 +				*idxarr++ = vidx[3];
  15.317 +			}
  15.318 +
  15.319 +			v += dv;
  15.320 +		}
  15.321 +		u += du;
  15.322 +	}
  15.323 +}
  15.324 +
  15.325 +
  15.326 +// -------- plane --------
  15.327 +
  15.328 +void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
  15.329 +{
  15.330 +	gen_heightmap(mesh, width, height, usub, vsub, 0);
  15.331 +}
  15.332 +
  15.333 +
  15.334 +// ----- heightmap ------
  15.335 +
  15.336 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
  15.337 +{
  15.338 +	if(usub < 1) usub = 1;
  15.339 +	if(vsub < 1) vsub = 1;
  15.340 +
  15.341 +	mesh->clear();
  15.342 +
  15.343 +	int uverts = usub + 1;
  15.344 +	int vverts = vsub + 1;
  15.345 +	int num_verts = uverts * vverts;
  15.346 +
  15.347 +	int num_quads = usub * vsub;
  15.348 +	int num_tri = num_quads * 2;
  15.349 +
  15.350 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.351 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.352 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.353 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.354 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.355 +
  15.356 +	float du = 1.0 / (float)usub;
  15.357 +	float dv = 1.0 / (float)vsub;
  15.358 +
  15.359 +	float u = 0.0;
  15.360 +	for(int i=0; i<uverts; i++) {
  15.361 +		float v = 0.0;
  15.362 +		for(int j=0; j<vverts; j++) {
  15.363 +			float x = (u - 0.5) * width;
  15.364 +			float y = (v - 0.5) * height;
  15.365 +			float z = hf ? hf(u, v, hfdata) : 0.0;
  15.366 +
  15.367 +			Vector3 normal = Vector3(0, 0, 1);
  15.368 +			if(hf) {
  15.369 +				float u1z = hf(u + du, v, hfdata);
  15.370 +				float v1z = hf(u, v + dv, hfdata);
  15.371 +
  15.372 +				Vector3 tang = Vector3(du * width, 0, u1z - z);
  15.373 +				Vector3 bitan = Vector3(0, dv * height, v1z - z);
  15.374 +				normal = cross_product(tang, bitan).normalized();
  15.375 +			}
  15.376 +
  15.377 +			*varr++ = Vector3(x, y, z);
  15.378 +			*narr++ = normal;
  15.379 +			*tarr++ = Vector3(1, 0, 0);
  15.380 +			*uvarr++ = Vector2(u, v);
  15.381 +
  15.382 +			if(i < usub && j < vsub) {
  15.383 +				int idx = i * vverts + j;
  15.384 +
  15.385 +				*idxarr++ = idx;
  15.386 +				*idxarr++ = idx + vverts + 1;
  15.387 +				*idxarr++ = idx + 1;
  15.388 +
  15.389 +				*idxarr++ = idx;
  15.390 +				*idxarr++ = idx + vverts;
  15.391 +				*idxarr++ = idx + vverts + 1;
  15.392 +			}
  15.393 +
  15.394 +			v += dv;
  15.395 +		}
  15.396 +		u += du;
  15.397 +	}
  15.398 +}
  15.399 +
  15.400 +// ----- heightmap ------
  15.401 +
  15.402 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz)
  15.403 +{
  15.404 +	mesh->clear();
  15.405 +
  15.406 +	const int num_faces = 6;
  15.407 +	int num_verts = num_faces * 4;
  15.408 +	int num_tri = num_faces * 2;
  15.409 +
  15.410 +	float x = xsz / 2.0;
  15.411 +	float y = ysz / 2.0;
  15.412 +	float z = zsz / 2.0;
  15.413 +
  15.414 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.415 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.416 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.417 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.418 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.419 +
  15.420 +	static const Vector2 uv[] = { Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(0, 1) };
  15.421 +
  15.422 +	// front
  15.423 +	for(int i=0; i<4; i++) {
  15.424 +		*narr++ = Vector3(0, 0, 1);
  15.425 +		*tarr++ = Vector3(1, 0, 0);
  15.426 +		*uvarr++ = uv[i];
  15.427 +	}
  15.428 +	*varr++ = Vector3(-x, -y, z);
  15.429 +	*varr++ = Vector3(x, -y, z);
  15.430 +	*varr++ = Vector3(x, y, z);
  15.431 +	*varr++ = Vector3(-x, y, z);
  15.432 +	// right
  15.433 +	for(int i=0; i<4; i++) {
  15.434 +		*narr++ = Vector3(1, 0, 0);
  15.435 +		*tarr++ = Vector3(0, 0, -1);
  15.436 +		*uvarr++ = uv[i];
  15.437 +	}
  15.438 +	*varr++ = Vector3(x, -y, z);
  15.439 +	*varr++ = Vector3(x, -y, -z);
  15.440 +	*varr++ = Vector3(x, y, -z);
  15.441 +	*varr++ = Vector3(x, y, z);
  15.442 +	// back
  15.443 +	for(int i=0; i<4; i++) {
  15.444 +		*narr++ = Vector3(0, 0, -1);
  15.445 +		*tarr++ = Vector3(-1, 0, 0);
  15.446 +		*uvarr++ = uv[i];
  15.447 +	}
  15.448 +	*varr++ = Vector3(x, -y, -z);
  15.449 +	*varr++ = Vector3(-x, -y, -z);
  15.450 +	*varr++ = Vector3(-x, y, -z);
  15.451 +	*varr++ = Vector3(x, y, -z);
  15.452 +	// left
  15.453 +	for(int i=0; i<4; i++) {
  15.454 +		*narr++ = Vector3(-1, 0, 0);
  15.455 +		*tarr++ = Vector3(0, 0, 1);
  15.456 +		*uvarr++ = uv[i];
  15.457 +	}
  15.458 +	*varr++ = Vector3(-x, -y, -z);
  15.459 +	*varr++ = Vector3(-x, -y, z);
  15.460 +	*varr++ = Vector3(-x, y, z);
  15.461 +	*varr++ = Vector3(-x, y, -z);
  15.462 +	// top
  15.463 +	for(int i=0; i<4; i++) {
  15.464 +		*narr++ = Vector3(0, 1, 0);
  15.465 +		*tarr++ = Vector3(1, 0, 0);
  15.466 +		*uvarr++ = uv[i];
  15.467 +	}
  15.468 +	*varr++ = Vector3(-x, y, z);
  15.469 +	*varr++ = Vector3(x, y, z);
  15.470 +	*varr++ = Vector3(x, y, -z);
  15.471 +	*varr++ = Vector3(-x, y, -z);
  15.472 +	// bottom
  15.473 +	for(int i=0; i<4; i++) {
  15.474 +		*narr++ = Vector3(0, -1, 0);
  15.475 +		*tarr++ = Vector3(1, 0, 0);
  15.476 +		*uvarr++ = uv[i];
  15.477 +	}
  15.478 +	*varr++ = Vector3(-x, -y, -z);
  15.479 +	*varr++ = Vector3(x, -y, -z);
  15.480 +	*varr++ = Vector3(x, -y, z);
  15.481 +	*varr++ = Vector3(-x, -y, z);
  15.482 +
  15.483 +	// index array
  15.484 +	static const int faceidx[] = {0, 1, 2, 0, 2, 3};
  15.485 +	for(int i=0; i<num_faces; i++) {
  15.486 +		for(int j=0; j<6; j++) {
  15.487 +			*idxarr++ = faceidx[j] + i * 4;
  15.488 +		}
  15.489 +	}
  15.490 +}
  15.491 +
  15.492 +static inline Vector3 rev_vert(float u, float v, Vector2 (*rf)(float, float, void*), void *cls)
  15.493 +{
  15.494 +	Vector2 pos = rf(u, v, cls);
  15.495 +
  15.496 +	float angle = u * 2.0 * M_PI;
  15.497 +	float x = pos.x * cos(angle);
  15.498 +	float y = pos.y;
  15.499 +	float z = pos.x * sin(angle);
  15.500 +
  15.501 +	return Vector3(x, y, z);
  15.502 +}
  15.503 +
  15.504 +// ------ surface of revolution -------
  15.505 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), void *cls)
  15.506 +{
  15.507 +	gen_revol(mesh, usub, vsub, rfunc, 0, cls);
  15.508 +}
  15.509 +
  15.510 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*),
  15.511 +		Vector2 (*nfunc)(float, float, void*), void *cls)
  15.512 +{
  15.513 +	if(!rfunc) return;
  15.514 +	if(usub < 3) usub = 3;
  15.515 +	if(vsub < 1) vsub = 1;
  15.516 +
  15.517 +	mesh->clear();
  15.518 +
  15.519 +	int uverts = usub + 1;
  15.520 +	int vverts = vsub + 1;
  15.521 +	int num_verts = uverts * vverts;
  15.522 +
  15.523 +	int num_quads = usub * vsub;
  15.524 +	int num_tri = num_quads * 2;
  15.525 +
  15.526 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  15.527 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  15.528 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  15.529 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  15.530 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  15.531 +
  15.532 +	float du = 1.0 / (float)(uverts - 1);
  15.533 +	float dv = 1.0 / (float)(vverts - 1);
  15.534 +
  15.535 +	float u = 0.0;
  15.536 +	for(int i=0; i<uverts; i++) {
  15.537 +		float v = 0.0;
  15.538 +		for(int j=0; j<vverts; j++) {
  15.539 +			Vector3 pos = rev_vert(u, v, rfunc, cls);
  15.540 +
  15.541 +			Vector3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls);
  15.542 +			Vector3 tang = nextu - pos;
  15.543 +			if(tang.length_sq() < 1e-6) {
  15.544 +				float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
  15.545 +				nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls);
  15.546 +				tang = nextu - pos;
  15.547 +			}
  15.548 +
  15.549 +			Vector3 normal;
  15.550 +			if(nfunc) {
  15.551 +				normal = rev_vert(u, v, nfunc, cls);
  15.552 +			} else {
  15.553 +				Vector3 nextv = rev_vert(u, v + dv, rfunc, cls);
  15.554 +				Vector3 bitan = nextv - pos;
  15.555 +				if(bitan.length_sq() < 1e-6) {
  15.556 +					nextv = rev_vert(u, v - dv, rfunc, cls);
  15.557 +					bitan = pos - nextv;
  15.558 +				}
  15.559 +
  15.560 +				normal = cross_product(tang, bitan);
  15.561 +			}
  15.562 +
  15.563 +			*varr++ = pos;
  15.564 +			*narr++ = normal.normalized();
  15.565 +			*tarr++ = tang.normalized();
  15.566 +			*uvarr++ = Vector2(u, v);
  15.567 +
  15.568 +			if(i < usub && j < vsub) {
  15.569 +				int idx = i * vverts + j;
  15.570 +
  15.571 +				*idxarr++ = idx;
  15.572 +				*idxarr++ = idx + vverts + 1;
  15.573 +				*idxarr++ = idx + 1;
  15.574 +
  15.575 +				*idxarr++ = idx;
  15.576 +				*idxarr++ = idx + vverts;
  15.577 +				*idxarr++ = idx + vverts + 1;
  15.578 +			}
  15.579 +
  15.580 +			v += dv;
  15.581 +		}
  15.582 +		u += du;
  15.583 +	}
  15.584 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/meshgen.h	Sat Aug 22 07:15:00 2015 +0300
    16.3 @@ -0,0 +1,18 @@
    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_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   16.13 +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.14 +void gen_plane(Mesh *mesh, float width, float height, int usub = 1, int vsub = 1);
   16.15 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata = 0);
   16.16 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz);
   16.17 +
   16.18 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), void *cls = 0);
   16.19 +void gen_revol(Mesh *mesh, int usub, int vsub, Vector2 (*rfunc)(float, float, void*), Vector2 (*nfunc)(float, float, void*), void *cls);
   16.20 +
   16.21 +#endif	// MESHGEN_H_
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/object.cc	Sat Aug 22 07:15:00 2015 +0300
    17.3 @@ -0,0 +1,225 @@
    17.4 +#include "object.h"
    17.5 +#include "opengl.h"
    17.6 +#include "shadow.h"
    17.7 +
    17.8 +Material::Material()
    17.9 +	: diffuse(1, 1, 1), specular(0, 0, 0)
   17.10 +{
   17.11 +	shininess = 60.0;
   17.12 +	alpha = 1.0;
   17.13 +}
   17.14 +
   17.15 +RenderOps::RenderOps()
   17.16 +{
   17.17 +	zwrite = true;
   17.18 +	cast_shadows = true;
   17.19 +	transparent = false;
   17.20 +}
   17.21 +
   17.22 +void RenderOps::setup() const
   17.23 +{
   17.24 +	if(!zwrite) {
   17.25 +		glDepthMask(0);
   17.26 +	}
   17.27 +	if(transparent) {
   17.28 +		glEnable(GL_BLEND);
   17.29 +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   17.30 +	} else {
   17.31 +		glDisable(GL_BLEND);
   17.32 +	}
   17.33 +}
   17.34 +
   17.35 +Object::Object()
   17.36 +{
   17.37 +	mesh = 0;
   17.38 +	tex = 0;
   17.39 +	sdr = 0;
   17.40 +}
   17.41 +
   17.42 +Object::~Object()
   17.43 +{
   17.44 +	delete mesh;
   17.45 +}
   17.46 +
   17.47 +Matrix4x4 &Object::xform()
   17.48 +{
   17.49 +	return matrix;
   17.50 +}
   17.51 +
   17.52 +const Matrix4x4 &Object::xform() const
   17.53 +{
   17.54 +	return matrix;
   17.55 +}
   17.56 +
   17.57 +Matrix4x4 &Object::tex_xform()
   17.58 +{
   17.59 +	return tex_matrix;
   17.60 +}
   17.61 +
   17.62 +const Matrix4x4 &Object::tex_xform() const
   17.63 +{
   17.64 +	return tex_matrix;
   17.65 +}
   17.66 +
   17.67 +void Object::set_mesh(Mesh *m)
   17.68 +{
   17.69 +	this->mesh = m;
   17.70 +}
   17.71 +
   17.72 +Mesh *Object::get_mesh() const
   17.73 +{
   17.74 +	return mesh;
   17.75 +}
   17.76 +
   17.77 +void Object::set_texture(unsigned int tex)
   17.78 +{
   17.79 +	this->tex = tex;
   17.80 +}
   17.81 +
   17.82 +void Object::set_shader(unsigned int sdr)
   17.83 +{
   17.84 +	if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader) {
   17.85 +		this->sdr = sdr;
   17.86 +	}
   17.87 +}
   17.88 +
   17.89 +unsigned int Object::get_shader() const
   17.90 +{
   17.91 +	return sdr;
   17.92 +}
   17.93 +
   17.94 +void Object::draw() const
   17.95 +{
   17.96 +	if(!mesh) return;
   17.97 +
   17.98 +	if(shadow_pass && !rop.cast_shadows) {
   17.99 +		return;
  17.100 +	}
  17.101 +
  17.102 +	glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
  17.103 +	rop.setup();
  17.104 +
  17.105 +	if(glcaps.shaders) {
  17.106 +		if(sdr) {
  17.107 +			if(!shadow_pass) {
  17.108 +				glUseProgram(sdr);
  17.109 +			}
  17.110 +		} else {
  17.111 +			glUseProgram(0);
  17.112 +		}
  17.113 +	}
  17.114 +
  17.115 +	if(tex) {
  17.116 +		glBindTexture(GL_TEXTURE_2D, tex);
  17.117 +		glEnable(GL_TEXTURE_2D);
  17.118 +
  17.119 +		glMatrixMode(GL_TEXTURE);
  17.120 +		glPushMatrix();
  17.121 +		glLoadTransposeMatrixf(tex_matrix[0]);
  17.122 +	} else {
  17.123 +		glDisable(GL_TEXTURE_2D);
  17.124 +	}
  17.125 +
  17.126 +	glMatrixMode(GL_MODELVIEW);
  17.127 +	glPushMatrix();
  17.128 +	glMultTransposeMatrixf(matrix[0]);
  17.129 +
  17.130 +	float dcol[] = {mtl.diffuse.x, mtl.diffuse.y, mtl.diffuse.z, mtl.alpha};
  17.131 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dcol);
  17.132 +	float scol[] = {mtl.specular.x, mtl.specular.y, mtl.specular.z, 1.0f};
  17.133 +	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol);
  17.134 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mtl.shininess);
  17.135 +
  17.136 +	mesh->draw();
  17.137 +
  17.138 +	if(tex) {
  17.139 +		glDisable(GL_TEXTURE_2D);
  17.140 +
  17.141 +		glMatrixMode(GL_TEXTURE);
  17.142 +		glPopMatrix();
  17.143 +	}
  17.144 +
  17.145 +	if(sdr) {
  17.146 +		glUseProgram(0);
  17.147 +	}
  17.148 +
  17.149 +	glMatrixMode(GL_MODELVIEW);
  17.150 +	glPopMatrix();
  17.151 +
  17.152 +	glPopAttrib();
  17.153 +}
  17.154 +
  17.155 +void Object::draw_wire(const Vector4 &col) const
  17.156 +{
  17.157 +	if(shadow_pass) return;
  17.158 +
  17.159 +	glPushAttrib(GL_ENABLE_BIT);
  17.160 +	glDisable(GL_LIGHTING);
  17.161 +	glUseProgram(0);
  17.162 +
  17.163 +	glMatrixMode(GL_MODELVIEW);
  17.164 +	glPushMatrix();
  17.165 +	glMultTransposeMatrixf(matrix[0]);
  17.166 +
  17.167 +	glColor4f(col.x, col.y, col.z, col.w);
  17.168 +	mesh->draw_wire();
  17.169 +
  17.170 +	glPopMatrix();
  17.171 +	glPopAttrib();
  17.172 +}
  17.173 +
  17.174 +void Object::draw_vertices(const Vector4 &col) const
  17.175 +{
  17.176 +	glPushAttrib(GL_ENABLE_BIT);
  17.177 +	glDisable(GL_LIGHTING);
  17.178 +	glUseProgram(0);
  17.179 +
  17.180 +	glMatrixMode(GL_MODELVIEW);
  17.181 +	glPushMatrix();
  17.182 +	glMultTransposeMatrixf(matrix[0]);
  17.183 +
  17.184 +	glColor4f(col.x, col.y, col.z, col.w);
  17.185 +	mesh->draw_vertices();
  17.186 +
  17.187 +	glPopMatrix();
  17.188 +	glPopAttrib();
  17.189 +}
  17.190 +
  17.191 +void Object::draw_normals(float len, const Vector4 &col) const
  17.192 +{
  17.193 +	glPushAttrib(GL_ENABLE_BIT);
  17.194 +	glDisable(GL_LIGHTING);
  17.195 +
  17.196 +	glMatrixMode(GL_MODELVIEW);
  17.197 +	glPushMatrix();
  17.198 +	glMultTransposeMatrixf(matrix[0]);
  17.199 +
  17.200 +	glColor4f(col.x, col.y, col.z, col.w);
  17.201 +	mesh->set_vis_vecsize(len);
  17.202 +	mesh->draw_normals();
  17.203 +
  17.204 +	glPopMatrix();
  17.205 +	glPopAttrib();
  17.206 +}
  17.207 +
  17.208 +void Object::draw_tangents(float len, const Vector4 &col) const
  17.209 +{
  17.210 +	glPushAttrib(GL_ENABLE_BIT);
  17.211 +	glDisable(GL_LIGHTING);
  17.212 +
  17.213 +	glMatrixMode(GL_MODELVIEW);
  17.214 +	glPushMatrix();
  17.215 +	glMultTransposeMatrixf(matrix[0]);
  17.216 +
  17.217 +	glColor4f(col.x, col.y, col.z, col.w);
  17.218 +	mesh->set_vis_vecsize(len);
  17.219 +	mesh->draw_tangents();
  17.220 +
  17.221 +	glPopMatrix();
  17.222 +	glPopAttrib();
  17.223 +}
  17.224 +
  17.225 +bool Object::intersect(const Ray &ray, HitPoint *hit) const
  17.226 +{
  17.227 +	return false;	// TODO
  17.228 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/object.h	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 2015 +0300
    21.3 @@ -0,0 +1,17 @@
    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 +	// TODO read config files, parse args, etc...
   21.12 +
   21.13 +	opt.xres = 1280;
   21.14 +	opt.yres = 800;
   21.15 +	opt.fullscreen = false;
   21.16 +	opt.shadows = true;
   21.17 +	opt.reflections = true;
   21.18 +
   21.19 +	return true;
   21.20 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/opt.h	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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	Sat Aug 22 07:15:00 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/scene.cc	Sat Aug 22 07:15:00 2015 +0300
    25.3 @@ -0,0 +1,57 @@
    25.4 +#include "scene.h"
    25.5 +#include "opengl.h"
    25.6 +#include "opt.h"
    25.7 +#include "game.h"
    25.8 +
    25.9 +static int max_lights = -1;
   25.10 +
   25.11 +Scene::~Scene()
   25.12 +{
   25.13 +	clear();
   25.14 +}
   25.15 +
   25.16 +void Scene::clear()
   25.17 +{
   25.18 +	for(size_t i=0; i<objects.size(); i++) {
   25.19 +		delete objects[i];
   25.20 +	}
   25.21 +	objects.clear();
   25.22 +
   25.23 +	for(size_t i=0; i<lights.size(); i++) {
   25.24 +		delete lights[i];
   25.25 +	}
   25.26 +	lights.clear();
   25.27 +}
   25.28 +
   25.29 +void Scene::add_object(Object *obj)
   25.30 +{
   25.31 +	objects.push_back(obj);
   25.32 +}
   25.33 +
   25.34 +void Scene::add_lights(Light *lt)
   25.35 +{
   25.36 +	lights.push_back(lt);
   25.37 +}
   25.38 +
   25.39 +void Scene::draw(unsigned int flags) const
   25.40 +{
   25.41 +	if(max_lights == -1) {
   25.42 +		glGetIntegerv(GL_MAX_LIGHTS, &max_lights);
   25.43 +		printf("max lights: %d\n", max_lights);
   25.44 +	}
   25.45 +
   25.46 +	for(size_t i=0; i<lights.size(); i++) {
   25.47 +		lights[i]->setup(i);
   25.48 +	}
   25.49 +
   25.50 +	for(size_t i=0; i<objects.size(); i++) {
   25.51 +		unsigned int mask = objects[i]->rop.transparent ? DRAW_TRANSPARENT : DRAW_SOLID;
   25.52 +		if(mask & flags) {
   25.53 +			if(dbg_wireframe) {
   25.54 +				objects[i]->draw_wire();
   25.55 +			} else {
   25.56 +				objects[i]->draw();
   25.57 +			}
   25.58 +		}
   25.59 +	}
   25.60 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/scene.h	Sat Aug 22 07:15:00 2015 +0300
    26.3 @@ -0,0 +1,29 @@
    26.4 +#ifndef SCENE_H_
    26.5 +#define SCENE_H_
    26.6 +
    26.7 +#include <vector>
    26.8 +#include "object.h"
    26.9 +#include "light.h"
   26.10 +
   26.11 +enum {
   26.12 +	DRAW_SOLID = 1,
   26.13 +	DRAW_TRANSPARENT = 2,
   26.14 +	DRAW_ALL = 0x7fffffff
   26.15 +};
   26.16 +
   26.17 +class Scene {
   26.18 +public:
   26.19 +	std::vector<Object*> objects;
   26.20 +	std::vector<Light*> lights;
   26.21 +
   26.22 +	~Scene();
   26.23 +
   26.24 +	void clear();
   26.25 +
   26.26 +	void add_object(Object *obj);
   26.27 +	void add_lights(Light *lt);
   26.28 +
   26.29 +	void draw(unsigned int flags = DRAW_ALL) const;
   26.30 +};
   26.31 +
   26.32 +#endif	// SCENE_H_
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/sdr.c	Sat Aug 22 07:15:00 2015 +0300
    27.3 @@ -0,0 +1,407 @@
    27.4 +#include <stdio.h>
    27.5 +#include <stdlib.h>
    27.6 +#include <string.h>
    27.7 +#include <errno.h>
    27.8 +#include <stdarg.h>
    27.9 +#include <assert.h>
   27.10 +#include "opengl.h"
   27.11 +
   27.12 +#if defined(unix) || defined(__unix__)
   27.13 +#include <unistd.h>
   27.14 +#include <sys/stat.h>
   27.15 +#endif	/* unix */
   27.16 +
   27.17 +#include "sdr.h"
   27.18 +
   27.19 +static const char *sdrtypestr(unsigned int sdrtype);
   27.20 +
   27.21 +unsigned int create_vertex_shader(const char *src)
   27.22 +{
   27.23 +	return create_shader(src, GL_VERTEX_SHADER);
   27.24 +}
   27.25 +
   27.26 +unsigned int create_pixel_shader(const char *src)
   27.27 +{
   27.28 +	return create_shader(src, GL_FRAGMENT_SHADER);
   27.29 +}
   27.30 +
   27.31 +unsigned int create_tessctl_shader(const char *src)
   27.32 +{
   27.33 +#ifdef GL_TESS_CONTROL_SHADER
   27.34 +	return create_shader(src, GL_TESS_CONTROL_SHADER);
   27.35 +#else
   27.36 +	return 0;
   27.37 +#endif
   27.38 +}
   27.39 +
   27.40 +unsigned int create_tesseval_shader(const char *src)
   27.41 +{
   27.42 +#ifdef GL_TESS_EVALUATION_SHADER
   27.43 +	return create_shader(src, GL_TESS_EVALUATION_SHADER);
   27.44 +#else
   27.45 +	return 0;
   27.46 +#endif
   27.47 +}
   27.48 +
   27.49 +unsigned int create_geometry_shader(const char *src)
   27.50 +{
   27.51 +#ifdef GL_GEOMETRY_SHADER
   27.52 +	return create_shader(src, GL_GEOMETRY_SHADER);
   27.53 +#else
   27.54 +	return 0;
   27.55 +#endif
   27.56 +}
   27.57 +
   27.58 +unsigned int create_shader(const char *src, unsigned int sdr_type)
   27.59 +{
   27.60 +	unsigned int sdr;
   27.61 +	int success, info_len;
   27.62 +	char *info_str = 0;
   27.63 +	GLenum err;
   27.64 +
   27.65 +	sdr = glCreateShader(sdr_type);
   27.66 +	assert(glGetError() == GL_NO_ERROR);
   27.67 +	glShaderSource(sdr, 1, &src, 0);
   27.68 +	err = glGetError();
   27.69 +	assert(err == GL_NO_ERROR);
   27.70 +	glCompileShader(sdr);
   27.71 +	assert(glGetError() == GL_NO_ERROR);
   27.72 +
   27.73 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
   27.74 +	assert(glGetError() == GL_NO_ERROR);
   27.75 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
   27.76 +	assert(glGetError() == GL_NO_ERROR);
   27.77 +
   27.78 +	if(info_len) {
   27.79 +		if((info_str = malloc(info_len + 1))) {
   27.80 +			glGetShaderInfoLog(sdr, info_len, 0, info_str);
   27.81 +			assert(glGetError() == GL_NO_ERROR);
   27.82 +			info_str[info_len] = 0;
   27.83 +		}
   27.84 +	}
   27.85 +
   27.86 +	if(success) {
   27.87 +		fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
   27.88 +	} else {
   27.89 +		fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
   27.90 +		glDeleteShader(sdr);
   27.91 +		sdr = 0;
   27.92 +	}
   27.93 +
   27.94 +	free(info_str);
   27.95 +	return sdr;
   27.96 +}
   27.97 +
   27.98 +void free_shader(unsigned int sdr)
   27.99 +{
  27.100 +	glDeleteShader(sdr);
  27.101 +}
  27.102 +
  27.103 +unsigned int load_vertex_shader(const char *fname)
  27.104 +{
  27.105 +	return load_shader(fname, GL_VERTEX_SHADER);
  27.106 +}
  27.107 +
  27.108 +unsigned int load_pixel_shader(const char *fname)
  27.109 +{
  27.110 +	return load_shader(fname, GL_FRAGMENT_SHADER);
  27.111 +}
  27.112 +
  27.113 +unsigned int load_tessctl_shader(const char *fname)
  27.114 +{
  27.115 +#ifdef GL_TESS_CONTROL_SHADER
  27.116 +	return load_shader(fname, GL_TESS_CONTROL_SHADER);
  27.117 +#else
  27.118 +	return 0;
  27.119 +#endif
  27.120 +}
  27.121 +
  27.122 +unsigned int load_tesseval_shader(const char *fname)
  27.123 +{
  27.124 +#ifdef GL_TESS_EVALUATION_SHADER
  27.125 +	return load_shader(fname, GL_TESS_EVALUATION_SHADER);
  27.126 +#else
  27.127 +	return 0;
  27.128 +#endif
  27.129 +}
  27.130 +
  27.131 +unsigned int load_geometry_shader(const char *fname)
  27.132 +{
  27.133 +#ifdef GL_GEOMETRY_SHADER
  27.134 +	return load_shader(fname, GL_GEOMETRY_SHADER);
  27.135 +#else
  27.136 +	return 0;
  27.137 +#endif
  27.138 +}
  27.139 +
  27.140 +unsigned int load_shader(const char *fname, unsigned int sdr_type)
  27.141 +{
  27.142 +	unsigned int sdr;
  27.143 +	size_t filesize;
  27.144 +	FILE *fp;
  27.145 +	char *src;
  27.146 +
  27.147 +	if(!(fp = fopen(fname, "rb"))) {
  27.148 +		fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
  27.149 +		return 0;
  27.150 +	}
  27.151 +
  27.152 +	fseek(fp, 0, SEEK_END);
  27.153 +	filesize = ftell(fp);
  27.154 +	fseek(fp, 0, SEEK_SET);
  27.155 +
  27.156 +	if(!(src = malloc(filesize + 1))) {
  27.157 +		fclose(fp);
  27.158 +		return 0;
  27.159 +	}
  27.160 +	fread(src, 1, filesize, fp);
  27.161 +	src[filesize] = 0;
  27.162 +	fclose(fp);
  27.163 +
  27.164 +	fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
  27.165 +	sdr = create_shader(src, sdr_type);
  27.166 +
  27.167 +	free(src);
  27.168 +	return sdr;
  27.169 +}
  27.170 +
  27.171 +
  27.172 +/* ---- gpu programs ---- */
  27.173 +
  27.174 +unsigned int create_program(void)
  27.175 +{
  27.176 +	unsigned int prog = glCreateProgram();
  27.177 +	assert(glGetError() == GL_NO_ERROR);
  27.178 +	return prog;
  27.179 +}
  27.180 +
  27.181 +unsigned int create_program_link(unsigned int sdr0, ...)
  27.182 +{
  27.183 +	unsigned int prog, sdr;
  27.184 +	va_list ap;
  27.185 +
  27.186 +	if(!(prog = create_program())) {
  27.187 +		return 0;
  27.188 +	}
  27.189 +
  27.190 +	attach_shader(prog, sdr0);
  27.191 +	if(glGetError()) {
  27.192 +		return 0;
  27.193 +	}
  27.194 +
  27.195 +	va_start(ap, sdr0);
  27.196 +	while((sdr = va_arg(ap, unsigned int))) {
  27.197 +		attach_shader(prog, sdr);
  27.198 +		if(glGetError()) {
  27.199 +			return 0;
  27.200 +		}
  27.201 +	}
  27.202 +	va_end(ap);
  27.203 +
  27.204 +	if(link_program(prog) == -1) {
  27.205 +		free_program(prog);
  27.206 +		return 0;
  27.207 +	}
  27.208 +	return prog;
  27.209 +}
  27.210 +
  27.211 +unsigned int create_program_load(const char *vfile, const char *pfile)
  27.212 +{
  27.213 +	unsigned int vs = 0, ps = 0;
  27.214 +
  27.215 +	if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
  27.216 +		return 0;
  27.217 +	}
  27.218 +	if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
  27.219 +		return 0;
  27.220 +	}
  27.221 +	return create_program_link(vs, ps, 0);
  27.222 +}
  27.223 +
  27.224 +void free_program(unsigned int sdr)
  27.225 +{
  27.226 +	glDeleteProgram(sdr);
  27.227 +}
  27.228 +
  27.229 +void attach_shader(unsigned int prog, unsigned int sdr)
  27.230 +{
  27.231 +	int err;
  27.232 +
  27.233 +	if(prog && sdr) {
  27.234 +		assert(glGetError() == GL_NO_ERROR);
  27.235 +		glAttachShader(prog, sdr);
  27.236 +		if((err = glGetError()) != GL_NO_ERROR) {
  27.237 +			fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
  27.238 +			abort();
  27.239 +		}
  27.240 +	}
  27.241 +}
  27.242 +
  27.243 +int link_program(unsigned int prog)
  27.244 +{
  27.245 +	int linked, info_len, retval = 0;
  27.246 +	char *info_str = 0;
  27.247 +
  27.248 +	glLinkProgram(prog);
  27.249 +	assert(glGetError() == GL_NO_ERROR);
  27.250 +	glGetProgramiv(prog, GL_LINK_STATUS, &linked);
  27.251 +	assert(glGetError() == GL_NO_ERROR);
  27.252 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
  27.253 +	assert(glGetError() == GL_NO_ERROR);
  27.254 +
  27.255 +	if(info_len) {
  27.256 +		if((info_str = malloc(info_len + 1))) {
  27.257 +			glGetProgramInfoLog(prog, info_len, 0, info_str);
  27.258 +			assert(glGetError() == GL_NO_ERROR);
  27.259 +			info_str[info_len] = 0;
  27.260 +		}
  27.261 +	}
  27.262 +
  27.263 +	if(linked) {
  27.264 +		fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
  27.265 +	} else {
  27.266 +		fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
  27.267 +		retval = -1;
  27.268 +	}
  27.269 +
  27.270 +	free(info_str);
  27.271 +	return retval;
  27.272 +}
  27.273 +
  27.274 +int bind_program(unsigned int prog)
  27.275 +{
  27.276 +	GLenum err;
  27.277 +
  27.278 +	glUseProgram(prog);
  27.279 +	if(prog && (err = glGetError()) != GL_NO_ERROR) {
  27.280 +		/* maybe the program is not linked, try linking first */
  27.281 +		if(err == GL_INVALID_OPERATION) {
  27.282 +			if(link_program(prog) == -1) {
  27.283 +				return -1;
  27.284 +			}
  27.285 +			glUseProgram(prog);
  27.286 +			return glGetError() == GL_NO_ERROR ? 0 : -1;
  27.287 +		}
  27.288 +		return -1;
  27.289 +	}
  27.290 +	return 0;
  27.291 +}
  27.292 +
  27.293 +/* ugly but I'm not going to write the same bloody code over and over */
  27.294 +#define BEGIN_UNIFORM_CODE \
  27.295 +	int loc, curr_prog; \
  27.296 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
  27.297 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
  27.298 +		return -1; \
  27.299 +	} \
  27.300 +	if((loc = glGetUniformLocation(prog, name)) != -1)
  27.301 +
  27.302 +#define END_UNIFORM_CODE \
  27.303 +	if((unsigned int)curr_prog != prog) { \
  27.304 +		bind_program(curr_prog); \
  27.305 +	} \
  27.306 +	return loc == -1 ? -1 : 0
  27.307 +
  27.308 +int set_uniform_int(unsigned int prog, const char *name, int val)
  27.309 +{
  27.310 +	BEGIN_UNIFORM_CODE {
  27.311 +		glUniform1i(loc, val);
  27.312 +	}
  27.313 +	END_UNIFORM_CODE;
  27.314 +}
  27.315 +
  27.316 +int set_uniform_float(unsigned int prog, const char *name, float val)
  27.317 +{
  27.318 +	BEGIN_UNIFORM_CODE {
  27.319 +		glUniform1f(loc, val);
  27.320 +	}
  27.321 +	END_UNIFORM_CODE;
  27.322 +}
  27.323 +
  27.324 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
  27.325 +{
  27.326 +	BEGIN_UNIFORM_CODE {
  27.327 +		glUniform2f(loc, x, y);
  27.328 +	}
  27.329 +	END_UNIFORM_CODE;
  27.330 +}
  27.331 +
  27.332 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
  27.333 +{
  27.334 +	BEGIN_UNIFORM_CODE {
  27.335 +		glUniform3f(loc, x, y, z);
  27.336 +	}
  27.337 +	END_UNIFORM_CODE;
  27.338 +}
  27.339 +
  27.340 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
  27.341 +{
  27.342 +	BEGIN_UNIFORM_CODE {
  27.343 +		glUniform4f(loc, x, y, z, w);
  27.344 +	}
  27.345 +	END_UNIFORM_CODE;
  27.346 +}
  27.347 +
  27.348 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat)
  27.349 +{
  27.350 +	BEGIN_UNIFORM_CODE {
  27.351 +		glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
  27.352 +	}
  27.353 +	END_UNIFORM_CODE;
  27.354 +}
  27.355 +
  27.356 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat)
  27.357 +{
  27.358 +	BEGIN_UNIFORM_CODE {
  27.359 +		glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
  27.360 +	}
  27.361 +	END_UNIFORM_CODE;
  27.362 +}
  27.363 +
  27.364 +int get_attrib_loc(unsigned int prog, const char *name)
  27.365 +{
  27.366 +	int loc, curr_prog;
  27.367 +
  27.368 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
  27.369 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
  27.370 +		return -1;
  27.371 +	}
  27.372 +
  27.373 +	loc = glGetAttribLocation(prog, (char*)name);
  27.374 +
  27.375 +	if((unsigned int)curr_prog != prog) {
  27.376 +		bind_program(curr_prog);
  27.377 +	}
  27.378 +	return loc;
  27.379 +}
  27.380 +
  27.381 +void set_attrib_float3(int attr_loc, float x, float y, float z)
  27.382 +{
  27.383 +	glVertexAttrib3f(attr_loc, x, y, z);
  27.384 +}
  27.385 +
  27.386 +static const char *sdrtypestr(unsigned int sdrtype)
  27.387 +{
  27.388 +	switch(sdrtype) {
  27.389 +	case GL_VERTEX_SHADER:
  27.390 +		return "vertex";
  27.391 +	case GL_FRAGMENT_SHADER:
  27.392 +		return "pixel";
  27.393 +#ifdef GL_TESS_CONTROL_SHADER
  27.394 +	case GL_TESS_CONTROL_SHADER:
  27.395 +		return "tessellation control";
  27.396 +#endif
  27.397 +#ifdef GL_TESS_EVALUATION_SHADER
  27.398 +	case GL_TESS_EVALUATION_SHADER:
  27.399 +		return "tessellation evaluation";
  27.400 +#endif
  27.401 +#ifdef GL_GEOMETRY_SHADER
  27.402 +	case GL_GEOMETRY_SHADER:
  27.403 +		return "geometry";
  27.404 +#endif
  27.405 +
  27.406 +	default:
  27.407 +		break;
  27.408 +	}
  27.409 +	return "<unknown>";
  27.410 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/sdr.h	Sat Aug 22 07:15:00 2015 +0300
    28.3 @@ -0,0 +1,52 @@
    28.4 +#ifndef SDR_H_
    28.5 +#define SDR_H_
    28.6 +
    28.7 +#ifdef __cplusplus
    28.8 +extern "C" {
    28.9 +#endif	/* __cplusplus */
   28.10 +
   28.11 +/* ---- shaders ---- */
   28.12 +unsigned int create_vertex_shader(const char *src);
   28.13 +unsigned int create_pixel_shader(const char *src);
   28.14 +unsigned int create_tessctl_shader(const char *src);
   28.15 +unsigned int create_tesseval_shader(const char *src);
   28.16 +unsigned int create_geometry_shader(const char *src);
   28.17 +unsigned int create_shader(const char *src, unsigned int sdr_type);
   28.18 +void free_shader(unsigned int sdr);
   28.19 +
   28.20 +unsigned int load_vertex_shader(const char *fname);
   28.21 +unsigned int load_pixel_shader(const char *fname);
   28.22 +unsigned int load_tessctl_shader(const char *fname);
   28.23 +unsigned int load_tesseval_shader(const char *fname);
   28.24 +unsigned int load_geometry_shader(const char *fname);
   28.25 +unsigned int load_shader(const char *src, unsigned int sdr_type);
   28.26 +
   28.27 +int add_shader(const char *fname, unsigned int sdr);
   28.28 +int remove_shader(const char *fname);
   28.29 +
   28.30 +/* ---- gpu programs ---- */
   28.31 +unsigned int create_program(void);
   28.32 +unsigned int create_program_link(unsigned int sdr0, ...);
   28.33 +unsigned int create_program_load(const char *vfile, const char *pfile);
   28.34 +void free_program(unsigned int sdr);
   28.35 +
   28.36 +void attach_shader(unsigned int prog, unsigned int sdr);
   28.37 +int link_program(unsigned int prog);
   28.38 +int bind_program(unsigned int prog);
   28.39 +
   28.40 +int set_uniform_int(unsigned int prog, const char *name, int val);
   28.41 +int set_uniform_float(unsigned int prog, const char *name, float val);
   28.42 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y);
   28.43 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z);
   28.44 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w);
   28.45 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat);
   28.46 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat);
   28.47 +
   28.48 +int get_attrib_loc(unsigned int prog, const char *name);
   28.49 +void set_attrib_float3(int attr_loc, float x, float y, float z);
   28.50 +
   28.51 +#ifdef __cplusplus
   28.52 +}
   28.53 +#endif	/* __cplusplus */
   28.54 +
   28.55 +#endif	/* SDR_H_ */
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/src/shader.cc	Sat Aug 22 07:15:00 2015 +0300
    29.3 @@ -0,0 +1,28 @@
    29.4 +#include "shader.h"
    29.5 +#include "sdr.h"
    29.6 +
    29.7 +static unsigned int cur_sdr;
    29.8 +static unsigned int sover;
    29.9 +
   29.10 +void set_shader(unsigned int sdr)
   29.11 +{
   29.12 +	cur_sdr = sdr;
   29.13 +	if(!sover) {
   29.14 +		bind_program(sdr);
   29.15 +	}
   29.16 +}
   29.17 +
   29.18 +unsigned int current_shader()
   29.19 +{
   29.20 +	return sover ? sover : cur_sdr;
   29.21 +}
   29.22 +
   29.23 +void override_shader(unsigned int sdr)
   29.24 +{
   29.25 +	sover = sdr;
   29.26 +	if(sover) {
   29.27 +		bind_program(sdr);
   29.28 +	} else {
   29.29 +		bind_program(cur_sdr);
   29.30 +	}
   29.31 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/shader.h	Sat Aug 22 07:15:00 2015 +0300
    30.3 @@ -0,0 +1,8 @@
    30.4 +#ifndef SHADER_H_
    30.5 +#define SHADER_H_
    30.6 +
    30.7 +void set_shader(unsigned int sdr);
    30.8 +unsigned int current_shader();
    30.9 +void override_shader(unsigned int sdr);
   30.10 +
   30.11 +#endif	/* SHADER_H_ */
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/src/shadow.cc	Sat Aug 22 07:15:00 2015 +0300
    31.3 @@ -0,0 +1,141 @@
    31.4 +#include <assert.h>
    31.5 +#include "opengl.h"
    31.6 +#include "shadow.h"
    31.7 +#include "vmath/vmath.h"
    31.8 +
    31.9 +bool shadow_pass;
   31.10 +
   31.11 +static int tex_sz, prev_vp[4];
   31.12 +static unsigned int fbo, depth_tex, rb_color;
   31.13 +static Matrix4x4 shadow_mat;
   31.14 +
   31.15 +bool init_shadow(int sz)
   31.16 +{
   31.17 +	if(!glcaps.fbo || !glcaps.shadow) {
   31.18 +		return false;
   31.19 +	}
   31.20 +
   31.21 +	tex_sz = sz;
   31.22 +	printf("initializing shadow buffer (%dx%d)\n", tex_sz, tex_sz);
   31.23 +
   31.24 +	glGenFramebuffers(1, &fbo);
   31.25 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   31.26 +
   31.27 +	glGenTextures(1, &depth_tex);
   31.28 +	glBindTexture(GL_TEXTURE_2D, depth_tex);
   31.29 +	float border[] = {1, 1, 1, 1};
   31.30 +	glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
   31.31 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
   31.32 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
   31.33 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   31.34 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   31.35 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
   31.36 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex_sz, tex_sz, 0,
   31.37 +			GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
   31.38 +	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0);
   31.39 +
   31.40 +	assert(glGetError() == GL_NO_ERROR);
   31.41 +
   31.42 +	glDrawBuffer(GL_FALSE);
   31.43 +	glReadBuffer(GL_FALSE);
   31.44 +
   31.45 +	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
   31.46 +		fprintf(stderr, "incomplete framebuffer\n");
   31.47 +		return false;
   31.48 +	}
   31.49 +
   31.50 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
   31.51 +	glDrawBuffer(GL_BACK);
   31.52 +	glReadBuffer(GL_BACK);
   31.53 +	assert(glGetError() == GL_NO_ERROR);
   31.54 +
   31.55 +	return true;
   31.56 +}
   31.57 +
   31.58 +void destroy_shadow()
   31.59 +{
   31.60 +	glDeleteTextures(1, &depth_tex);
   31.61 +	glDeleteRenderbuffers(1, &rb_color);
   31.62 +	glDeleteFramebuffers(1, &fbo);
   31.63 +}
   31.64 +
   31.65 +void begin_shadow_pass(const Vector3 &lpos, const Vector3 &ltarg, float lfov)
   31.66 +{
   31.67 +	shadow_pass = true;
   31.68 +
   31.69 +	glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
   31.70 +	glDisable(GL_LIGHTING);
   31.71 +	glColorMask(0, 0, 0, 0);
   31.72 +	glDepthMask(1);
   31.73 +
   31.74 +	Matrix4x4 viewmat;
   31.75 +	glGetFloatv(GL_MODELVIEW_MATRIX, viewmat[0]);
   31.76 +	viewmat.transpose();
   31.77 +
   31.78 +	Matrix4x4 lt_viewmat, lt_projmat;
   31.79 +	lt_projmat.set_perspective(DEG_TO_RAD(lfov) * 2.0, 1.0, 8.0, 50.0);
   31.80 +	lt_viewmat.set_lookat(lpos, ltarg, Vector3(0, 1, 0));
   31.81 +	shadow_mat = lt_projmat * lt_viewmat * viewmat.inverse();
   31.82 +
   31.83 +	glMatrixMode(GL_PROJECTION);
   31.84 +	glPushMatrix();
   31.85 +	glLoadTransposeMatrixf(lt_projmat[0]);
   31.86 +
   31.87 +	glMatrixMode(GL_MODELVIEW);
   31.88 +	glPushMatrix();
   31.89 +	glLoadTransposeMatrixf(lt_viewmat[0]);
   31.90 +
   31.91 +	glGetIntegerv(GL_VIEWPORT, prev_vp);
   31.92 +	glViewport(0, 0, tex_sz, tex_sz);
   31.93 +
   31.94 +	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
   31.95 +
   31.96 +	glPolygonOffset(2, 1);
   31.97 +	glEnable(GL_POLYGON_OFFSET_FILL);
   31.98 +
   31.99 +	glClear(GL_DEPTH_BUFFER_BIT);
  31.100 +	glUseProgram(0);
  31.101 +}
  31.102 +
  31.103 +
  31.104 +void end_shadow_pass()
  31.105 +{
  31.106 +	shadow_pass = false;
  31.107 +
  31.108 +	glBindFramebuffer(GL_FRAMEBUFFER, 0);
  31.109 +
  31.110 +	glViewport(prev_vp[0], prev_vp[1], prev_vp[2], prev_vp[3]);
  31.111 +
  31.112 +	glMatrixMode(GL_PROJECTION);
  31.113 +	glPopMatrix();
  31.114 +	glMatrixMode(GL_MODELVIEW);
  31.115 +	glPopMatrix();
  31.116 +
  31.117 +	glPopAttrib();
  31.118 +}
  31.119 +
  31.120 +Matrix4x4 get_shadow_matrix()
  31.121 +{
  31.122 +	return shadow_mat;
  31.123 +
  31.124 +	/*
  31.125 +	glMatrixMode(GL_MODELVIEW);
  31.126 +	glPushMatrix();
  31.127 +	glLoadIdentity();
  31.128 +	gluPerspective(lfov * 2.0, 1.0, 0.5, 50.0);
  31.129 +	gluLookAt(lpos.x, lpos.y, lpos.z, ltarg.x, ltarg.y, ltarg.z, 0, 1, 0);
  31.130 +
  31.131 +	float mat[16];
  31.132 +	glGetFloatv(GL_MODELVIEW_MATRIX, mat);
  31.133 +
  31.134 +	Matrix4x4 res;
  31.135 +	memcpy(res[0], mat, sizeof mat);
  31.136 +	res.transpose();
  31.137 +	return res;
  31.138 +	*/
  31.139 +}
  31.140 +
  31.141 +unsigned int get_shadow_tex()
  31.142 +{
  31.143 +	return depth_tex;
  31.144 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/src/shadow.h	Sat Aug 22 07:15:00 2015 +0300
    32.3 @@ -0,0 +1,17 @@
    32.4 +#ifndef SHADOW_H_
    32.5 +#define SHADOW_H_
    32.6 +
    32.7 +#include "vmath/vmath.h"
    32.8 +
    32.9 +extern bool shadow_pass;
   32.10 +
   32.11 +bool init_shadow(int sz);
   32.12 +void destroy_shadow();
   32.13 +
   32.14 +void begin_shadow_pass(const Vector3 &lpos, const Vector3 &ltarg, float lfov);
   32.15 +void end_shadow_pass();
   32.16 +
   32.17 +Matrix4x4 get_shadow_matrix();
   32.18 +unsigned int get_shadow_tex();
   32.19 +
   32.20 +#endif	// SHADOW_H_
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/src/snode.cc	Sat Aug 22 07:15:00 2015 +0300
    33.3 @@ -0,0 +1,188 @@
    33.4 +#include <float.h>
    33.5 +#include <assert.h>
    33.6 +#include <algorithm>
    33.7 +#include "snode.h"
    33.8 +
    33.9 +SceneNode::SceneNode()
   33.10 +	: scale(1, 1, 1)
   33.11 +{
   33.12 +	parent = 0;
   33.13 +}
   33.14 +
   33.15 +SceneNode::SceneNode(Object *obj)
   33.16 +	: scale(1, 1, 1)
   33.17 +{
   33.18 +	parent = 0;
   33.19 +	add_object(obj);
   33.20 +}
   33.21 +
   33.22 +void SceneNode::add_child(SceneNode *node)
   33.23 +{
   33.24 +	if(node->parent) {
   33.25 +		if(node->parent == this) {
   33.26 +			return;
   33.27 +		}
   33.28 +		node->parent->remove_child(node);
   33.29 +	}
   33.30 +
   33.31 +	children.push_back(node);
   33.32 +	node->parent = this;
   33.33 +}
   33.34 +
   33.35 +bool SceneNode::remove_child(SceneNode *node)
   33.36 +{
   33.37 +	for(size_t i=0; i<children.size(); i++) {
   33.38 +		if(children[i] == node) {
   33.39 +			assert(node->parent == this);
   33.40 +			node->parent = 0;
   33.41 +			return true;
   33.42 +		}
   33.43 +	}
   33.44 +	return false;
   33.45 +}
   33.46 +
   33.47 +int SceneNode::get_num_children() const
   33.48 +{
   33.49 +	return (int)children.size();
   33.50 +}
   33.51 +
   33.52 +SceneNode *SceneNode::get_child(int idx) const
   33.53 +{
   33.54 +	return children[idx];
   33.55 +}
   33.56 +
   33.57 +SceneNode *SceneNode::get_parent() const
   33.58 +{
   33.59 +	return parent;
   33.60 +}
   33.61 +
   33.62 +void SceneNode::add_object(Object *obj)
   33.63 +{
   33.64 +	if(std::find(this->obj.begin(), this->obj.end(), obj) == this->obj.end()) {
   33.65 +		this->obj.push_back(obj);
   33.66 +	}
   33.67 +}
   33.68 +
   33.69 +int SceneNode::get_num_objects() const
   33.70 +{
   33.71 +	return (int)obj.size();
   33.72 +}
   33.73 +
   33.74 +Object *SceneNode::get_object(int idx) const
   33.75 +{
   33.76 +	return obj[idx];
   33.77 +}
   33.78 +
   33.79 +void SceneNode::set_position(const Vector3 &pos)
   33.80 +{
   33.81 +	this->pos = pos;
   33.82 +}
   33.83 +
   33.84 +void SceneNode::set_rotation(const Quaternion &rot)
   33.85 +{
   33.86 +	this->rot = rot;
   33.87 +}
   33.88 +
   33.89 +void SceneNode::set_scaling(const Vector3 &scale)
   33.90 +{
   33.91 +	this->scale = scale;
   33.92 +}
   33.93 +
   33.94 +
   33.95 +const Vector3 &SceneNode::get_node_position() const
   33.96 +{
   33.97 +	return pos;
   33.98 +}
   33.99 +
  33.100 +const Quaternion &SceneNode::get_node_rotation() const
  33.101 +{
  33.102 +	return rot;
  33.103 +}
  33.104 +
  33.105 +const Vector3 &SceneNode::get_node_scaling() const
  33.106 +{
  33.107 +	return scale;
  33.108 +}
  33.109 +
  33.110 +
  33.111 +Vector3 SceneNode::get_position() const
  33.112 +{
  33.113 +	return Vector3(0, 0, 0).transformed(xform);
  33.114 +}
  33.115 +
  33.116 +Quaternion SceneNode::get_rotation() const
  33.117 +{
  33.118 +	return rot;	// TODO
  33.119 +}
  33.120 +
  33.121 +Vector3 SceneNode::get_scaling() const
  33.122 +{
  33.123 +	return scale;	// TODO
  33.124 +}
  33.125 +
  33.126 +const Matrix4x4 &SceneNode::get_matrix() const
  33.127 +{
  33.128 +	return xform;
  33.129 +}
  33.130 +
  33.131 +const Matrix4x4 &SceneNode::get_inv_matrix() const
  33.132 +{
  33.133 +	return inv_xform;
  33.134 +}
  33.135 +
  33.136 +
  33.137 +void SceneNode::update_node(long msec)
  33.138 +{
  33.139 +	xform.reset_identity();
  33.140 +	xform.translate(pos);
  33.141 +	xform.rotate(rot);
  33.142 +	xform.scale(scale);
  33.143 +
  33.144 +	if(parent) {
  33.145 +		xform = parent->xform * xform;
  33.146 +	}
  33.147 +	inv_xform = xform.inverse();
  33.148 +}
  33.149 +
  33.150 +void SceneNode::update(long msec)
  33.151 +{
  33.152 +	update_node(msec);
  33.153 +
  33.154 +	for(size_t i=0; i<children.size(); i++) {
  33.155 +		children[i]->update(msec);
  33.156 +	}
  33.157 +}
  33.158 +
  33.159 +
  33.160 +bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
  33.161 +{
  33.162 +	Ray local_ray = ray.transformed(inv_xform);
  33.163 +
  33.164 +	HitPoint nearest;
  33.165 +	nearest.dist = FLT_MAX;
  33.166 +	for(size_t i=0; i<obj.size(); i++) {
  33.167 +		if(obj[i]->intersect(local_ray, hit)) {
  33.168 +			if(!hit) return true;
  33.169 +			if(hit->dist < nearest.dist) {
  33.170 +				nearest = *hit;
  33.171 +				nearest.node = this;
  33.172 +			}
  33.173 +		}
  33.174 +	}
  33.175 +
  33.176 +	for(size_t i=0; i<children.size(); i++) {
  33.177 +		if(children[i]->intersect(ray, hit)) {
  33.178 +			if(!hit) return true;
  33.179 +			if(hit->dist < nearest.dist) {
  33.180 +				nearest = *hit;
  33.181 +			}
  33.182 +		}
  33.183 +	}
  33.184 +
  33.185 +	if(nearest.dist < FLT_MAX) {
  33.186 +		*hit = nearest;
  33.187 +		hit->ray = ray;
  33.188 +		return true;
  33.189 +	}
  33.190 +	return false;
  33.191 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/src/snode.h	Sat Aug 22 07:15:00 2015 +0300
    34.3 @@ -0,0 +1,60 @@
    34.4 +#ifndef SNODE_H_
    34.5 +#define SNODE_H_
    34.6 +
    34.7 +#include <vector>
    34.8 +#include "object.h"
    34.9 +#include "vmath/vmath.h"
   34.10 +#include "geom.h"
   34.11 +
   34.12 +class SceneNode {
   34.13 +private:
   34.14 +	Vector3 pos;
   34.15 +	Quaternion rot;
   34.16 +	Vector3 scale;
   34.17 +
   34.18 +	std::vector<Object*> obj;
   34.19 +
   34.20 +	SceneNode *parent;
   34.21 +	std::vector<SceneNode*> children;
   34.22 +
   34.23 +	Matrix4x4 xform;
   34.24 +	Matrix4x4 inv_xform;
   34.25 +
   34.26 +public:
   34.27 +	SceneNode();
   34.28 +	explicit SceneNode(Object *obj);
   34.29 +
   34.30 +	void add_child(SceneNode *node);
   34.31 +	bool remove_child(SceneNode *node);
   34.32 +
   34.33 +	int get_num_children() const;
   34.34 +	SceneNode *get_child(int idx) const;
   34.35 +
   34.36 +	SceneNode *get_parent() const;
   34.37 +
   34.38 +	void add_object(Object *obj);
   34.39 +	int get_num_objects() const;
   34.40 +	Object *get_object(int idx) const;
   34.41 +
   34.42 +	void set_position(const Vector3 &pos);
   34.43 +	void set_rotation(const Quaternion &rot);
   34.44 +	void set_scaling(const Vector3 &scale);
   34.45 +
   34.46 +	const Vector3 &get_node_position() const;
   34.47 +	const Quaternion &get_node_rotation() const;
   34.48 +	const Vector3 &get_node_scaling() const;
   34.49 +
   34.50 +	Vector3 get_position() const;
   34.51 +	Quaternion get_rotation() const;
   34.52 +	Vector3 get_scaling() const;
   34.53 +
   34.54 +	const Matrix4x4 &get_matrix() const;
   34.55 +	const Matrix4x4 &get_inv_matrix() const;
   34.56 +
   34.57 +	void update_node(long msec = 0);
   34.58 +	void update(long msec = 0);
   34.59 +
   34.60 +	bool intersect(const Ray &ray, HitPoint *hit) const;
   34.61 +};
   34.62 +
   34.63 +#endif	// SNODE_H_