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