3dphotoshoot

changeset 25:ac80210d5fbe

preparing a pc version for easier development of non-android-specifics
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 18 Jun 2015 03:12:30 +0300
parents 2712c5da2e00
children a460b1e5af4a
files Makefile sdr/color.p.glsl sdr/normvis.p.glsl sdr/vertex.glsl src/android/amain.c src/android/camera.c src/camera.h src/game.cc src/geom.cc src/geom.h src/mesh.cc src/mesh.h src/meshgen.cc src/meshgen.h src/pc/camera.c
diffstat 15 files changed, 2392 insertions(+), 48 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Thu Jun 18 03:12:30 2015 +0300
     1.3 @@ -0,0 +1,22 @@
     1.4 +root = .
     1.5 +include $(root)/proj.mk
     1.6 +
     1.7 +src += $(wildcard $(root)/src/glut/*.c)
     1.8 +obj = $(src:.c=.o) $(ccsrc:.cc=.o)
     1.9 +
    1.10 +ifeq ($(shell uname -s), Darwin)
    1.11 +	libgl = -framework OpenGL -framework GLUT
    1.12 +else
    1.13 +	libgl = -lGL -lGLU -lglut
    1.14 +endif
    1.15 +
    1.16 +CXXFLAGS = -pedantic -Wall -g $(defs) -I$(root)/src/glut $(incpaths)
    1.17 +CFLAGS = $(CXXFLAGS)
    1.18 +LDFLAGS = $(libpaths) $(libs) $(libgl)
    1.19 +
    1.20 +$(bin): $(obj)
    1.21 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    1.22 +
    1.23 +.PHONY: clean
    1.24 +clean:
    1.25 +	rm -f $(obj) $(bin)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/sdr/color.p.glsl	Thu Jun 18 03:12:30 2015 +0300
     2.3 @@ -0,0 +1,8 @@
     2.4 +precision mediump float;
     2.5 +
     2.6 +uniform vec4 color;
     2.7 +
     2.8 +void main()
     2.9 +{
    2.10 +	gl_FragColor = color;
    2.11 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/sdr/normvis.p.glsl	Thu Jun 18 03:12:30 2015 +0300
     3.3 @@ -0,0 +1,10 @@
     3.4 +precision mediump float;
     3.5 +
     3.6 +varying vec3 normal;
     3.7 +
     3.8 +void main()
     3.9 +{
    3.10 +	vec3 ncol = normal * 0.5 + 0.5;
    3.11 +	gl_FragColor.rgb = ncol;
    3.12 +	gl_FragColor.a = 1.0;
    3.13 +}
     4.1 --- a/sdr/vertex.glsl	Tue Jun 16 06:17:59 2015 +0300
     4.2 +++ b/sdr/vertex.glsl	Thu Jun 18 03:12:30 2015 +0300
     4.3 @@ -1,7 +1,9 @@
     4.4 -attribute vec4 attr_vertex, attr_texcoord, attr_color;
     4.5 +attribute vec4 attr_vertex, attr_normal, attr_texcoord, attr_color;
     4.6  
     4.7  uniform mat4 matrix_modelview, matrix_projection, matrix_texture;
     4.8 +uniform mat3 matrix_normal;
     4.9  
    4.10 +varying vec3 normal;
    4.11  varying vec4 tex_coords, color;
    4.12  
    4.13  void main()
    4.14 @@ -10,4 +12,5 @@
    4.15  	gl_Position = mvp * attr_vertex;
    4.16  	tex_coords = matrix_texture * attr_texcoord;
    4.17  	color = attr_color;
    4.18 +	normal = matrix_normal * attr_normal.xyz;
    4.19  }
     5.1 --- a/src/android/amain.c	Tue Jun 16 06:17:59 2015 +0300
     5.2 +++ b/src/android/amain.c	Thu Jun 18 03:12:30 2015 +0300
     5.3 @@ -117,15 +117,26 @@
     5.4  			switch(evid) {
     5.5  			case EVID_SENS_ACCEL:
     5.6  				if(sens_accel) {
     5.7 -					float accel[3];
     5.8 +					static double prev_sec = -1.0;
     5.9 +					double sec, dt;
    5.10 +					double accel[3] = {0, 0, 0};
    5.11 +					static double velocity[3];
    5.12 +
    5.13  					while(ASensorEventQueue_getEvents(sens_evq_accel, &sens_ev, 1) > 0) {
    5.14 -						accel[0] = sens_ev.acceleration.x;
    5.15 -						accel[1] = sens_ev.acceleration.y;
    5.16 -						accel[2] = sens_ev.acceleration.z;
    5.17 +						accel[0] += sens_ev.acceleration.x;
    5.18 +						accel[1] += sens_ev.acceleration.y;
    5.19 +						accel[2] += sens_ev.acceleration.z;
    5.20  					}
    5.21  
    5.22 -					// TODO: integrate over time
    5.23 -					game_6dof_translation(accel[0], accel[1], accel[2]);
    5.24 +					sec = get_time_sec();
    5.25 +					dt = prev_sec >= 0.0 ? sec - prev_sec : 0.0;
    5.26 +					prev_sec = sec;
    5.27 +
    5.28 +					velocity[0] += accel[0] * dt;
    5.29 +					velocity[1] += accel[1] * dt;
    5.30 +					velocity[2] += accel[2] * dt;
    5.31 +
    5.32 +					game_6dof_translation(velocity[0] * dt, velocity[1] * dt, velocity[2] * dt);
    5.33  				}
    5.34  				break;
    5.35  
     6.1 --- a/src/android/camera.c	Tue Jun 16 06:17:59 2015 +0300
     6.2 +++ b/src/android/camera.c	Thu Jun 18 03:12:30 2015 +0300
     6.3 @@ -4,6 +4,8 @@
     6.4  #include <jni.h>
     6.5  #include "opengl.h"
     6.6  #include "camera.h"
     6.7 +#include "sdr.h"
     6.8 +#include "sanegl.h"
     6.9  
    6.10  
    6.11  static JavaVM *jvm;
    6.12 @@ -15,6 +17,10 @@
    6.13  static jfloatArray jtex_matrix;
    6.14  static int capturing;
    6.15  
    6.16 +static unsigned int sdr_cam;
    6.17 +static int aloc_vertex, aloc_texcoord;
    6.18 +
    6.19 +
    6.20  int cam_init(void *platform_data)
    6.21  {
    6.22  	int glerr;
    6.23 @@ -26,6 +32,13 @@
    6.24  
    6.25  	jtex_matrix = (*jni)->NewFloatArray(jni, 16);
    6.26  
    6.27 +	// load preview shader
    6.28 +	if(!(sdr_cam = create_program_load("sdr/vertex.glsl", "sdr/android_cam_preview.p.glsl"))) {
    6.29 +		return -1;
    6.30 +	}
    6.31 +	aloc_vertex = glGetAttribLocation(sdr_cam, "attr_vertex");
    6.32 +	aloc_texcoord = glGetAttribLocation(sdr_cam, "attr_texcoord");
    6.33 +
    6.34  	// create the camera texture
    6.35  	assert(glGetError() == GL_NO_ERROR);
    6.36  	glGenTextures(1, &tex);
    6.37 @@ -44,6 +57,8 @@
    6.38  	glDeleteTextures(1, &tex);
    6.39  	tex = 0;
    6.40  
    6.41 +	free_program(sdr_cam);
    6.42 +
    6.43  	if(jni) {
    6.44  		(*jni)->DeleteGlobalRef(jni, jtex_matrix);
    6.45  	}
    6.46 @@ -171,3 +186,28 @@
    6.47  {
    6.48  	return -1;	// TODO
    6.49  }
    6.50 +
    6.51 +void cam_draw_preview(void)
    6.52 +{
    6.53 +	const float *tex_matrix = cam_texture_matrix();
    6.54 +
    6.55 +	gl_matrix_mode(GL_TEXTURE);
    6.56 +	gl_load_matrixf(tex_matrix);
    6.57 +
    6.58 +	glUseProgram(sdr_cam);
    6.59 +	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
    6.60 +
    6.61 +	gl_begin(GL_QUADS);
    6.62 +	gl_texcoord2f(0, 0);
    6.63 +	gl_vertex2f(-1, -1);
    6.64 +	gl_texcoord2f(1, 0);
    6.65 +	gl_vertex2f(1, -1);
    6.66 +	gl_texcoord2f(1, 1);
    6.67 +	gl_vertex2f(1, 1);
    6.68 +	gl_texcoord2f(0, 1);
    6.69 +	gl_vertex2f(-1, 1);
    6.70 +	gl_end();
    6.71 +
    6.72 +	gl_matrix_mode(GL_TEXTURE);
    6.73 +	gl_load_identity();
    6.74 +}
     7.1 --- a/src/camera.h	Tue Jun 16 06:17:59 2015 +0300
     7.2 +++ b/src/camera.h	Thu Jun 18 03:12:30 2015 +0300
     7.3 @@ -30,6 +30,8 @@
     7.4  
     7.5  int cam_take_picture(void);
     7.6  
     7.7 +void cam_draw_preview(void);
     7.8 +
     7.9  #ifdef __cplusplus
    7.10  }
    7.11  #endif
     8.1 --- a/src/game.cc	Tue Jun 16 06:17:59 2015 +0300
     8.2 +++ b/src/game.cc	Thu Jun 18 03:12:30 2015 +0300
     8.3 @@ -2,6 +2,7 @@
     8.4  #include <stdlib.h>
     8.5  #include <math.h>
     8.6  #include <assert.h>
     8.7 +#include <algorithm>
     8.8  #include "opengl.h"
     8.9  #include "game.h"
    8.10  #include "camera.h"
    8.11 @@ -10,8 +11,12 @@
    8.12  #include "shader.h"
    8.13  #include "text.h"
    8.14  #include "vmath/vmath.h"
    8.15 +#include "mesh.h"
    8.16 +#include "meshgen.h"
    8.17  
    8.18  static void draw_quad(float hsz, float vsz);
    8.19 +static void draw_rotation_gizmo();
    8.20 +static void draw_disc_wedge(float start, float end, int subdiv);
    8.21  
    8.22  int win_width, win_height;
    8.23  
    8.24 @@ -20,10 +25,15 @@
    8.25  static float video_aspect;
    8.26  static struct texture *test_tex;
    8.27  
    8.28 -static SdrProg *sdr_cam, *sdr_tex;
    8.29 +static SdrProg *sdr_tex, *sdr_color, *sdr_debug;
    8.30  
    8.31 -static Quaternion qrot;
    8.32 -static Vector3 trans;
    8.33 +static Quaternion last_rot;
    8.34 +static Vector3 last_trans;
    8.35 +
    8.36 +static Quaternion rot;
    8.37 +static Vector3 rot_euler;
    8.38 +
    8.39 +static Mesh *mesh;
    8.40  
    8.41  extern "C" int game_init(void)
    8.42  {
    8.43 @@ -32,10 +42,13 @@
    8.44  
    8.45  	glClearColor(0.4, 0.4, 0.4, 1);
    8.46  
    8.47 -	if(!(sdr_cam = get_sdrprog("sdr/vertex.glsl", "sdr/android_cam_preview.p.glsl"))) {
    8.48 +	if(!(sdr_tex = get_sdrprog("sdr/vertex.glsl", "sdr/tex.p.glsl"))) {
    8.49  		return -1;
    8.50  	}
    8.51 -	if(!(sdr_tex = get_sdrprog("sdr/vertex.glsl", "sdr/tex.p.glsl"))) {
    8.52 +	if(!(sdr_color = get_sdrprog("sdr/vertex.glsl", "sdr/color.p.glsl"))) {
    8.53 +		return -1;
    8.54 +	}
    8.55 +	if(!(sdr_debug = get_sdrprog("sdr/vertex.glsl", "sdr/normvis.p.glsl"))) {
    8.56  		return -1;
    8.57  	}
    8.58  
    8.59 @@ -43,6 +56,9 @@
    8.60  		return -1;
    8.61  	}
    8.62  
    8.63 +	mesh = new Mesh;
    8.64 +	gen_cylinder(mesh, 0.2, 1.0, 16, 1);
    8.65 +
    8.66  	cam_start_video();
    8.67  	cam_video_size(&video_width, &video_height);
    8.68  	if(video_height) {
    8.69 @@ -58,31 +74,28 @@
    8.70  extern "C" void game_shutdown(void)
    8.71  {
    8.72  	cam_shutdown();
    8.73 -	delete sdr_cam;
    8.74  	delete sdr_tex;
    8.75  }
    8.76  
    8.77  extern "C" void game_display(unsigned long msec)
    8.78  {
    8.79  	unsigned int tex;
    8.80 -	const float *tex_matrix;
    8.81  	float xscale, yscale;
    8.82  
    8.83  	cam_update();
    8.84  	tex = cam_texture();
    8.85 -	tex_matrix = cam_texture_matrix();
    8.86  
    8.87  	//float tsec = (float)msec / 1000.0f;
    8.88  
    8.89  	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    8.90  
    8.91 +	// draw video preview frame
    8.92 +	gl_matrix_mode(GL_PROJECTION);
    8.93 +	gl_push_matrix();
    8.94 +	gl_load_identity();
    8.95 +	gl_scalef((float)win_height / (float)win_width, 1, 1);
    8.96  	gl_matrix_mode(GL_MODELVIEW);
    8.97  	gl_load_identity();
    8.98 -	gl_matrix_mode(GL_TEXTURE);
    8.99 -	gl_load_matrixf(tex_matrix);
   8.100 -
   8.101 -	sdr_cam->bind();
   8.102 -	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
   8.103  
   8.104  	if(video_aspect > win_aspect) {
   8.105  		xscale = 1.0;
   8.106 @@ -91,34 +104,27 @@
   8.107  		xscale = video_aspect;
   8.108  		yscale = 1.0;
   8.109  	}
   8.110 -	draw_quad(xscale, yscale);
   8.111 +	gl_scalef(xscale, yscale, 1);
   8.112  
   8.113 -	gl_matrix_mode(GL_TEXTURE);
   8.114 -	gl_load_identity();
   8.115 -	gl_translatef(0, 1, 0);
   8.116 -	gl_scalef(1, -1, 1);
   8.117 +	cam_draw_preview();
   8.118 +
   8.119 +	gl_matrix_mode(GL_PROJECTION);
   8.120 +	gl_pop_matrix();
   8.121 +	// done drawing preview
   8.122 +
   8.123 +
   8.124  	gl_matrix_mode(GL_MODELVIEW);
   8.125  	gl_load_identity();
   8.126 -	gl_scalef((float)test_tex->width / (float)test_tex->height, 1, 1);
   8.127 +	gl_translatef(0, 0, -6);
   8.128  
   8.129 -	sdr_tex->bind();
   8.130 -	glBindTexture(GL_TEXTURE_2D, test_tex->texid);
   8.131 -
   8.132 -	glEnable(GL_BLEND);
   8.133 -	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   8.134 -	draw_quad(0.5, 0.5);
   8.135 -	glDisable(GL_BLEND);
   8.136 -
   8.137 -	gl_matrix_mode(GL_TEXTURE);
   8.138 -	gl_load_identity();
   8.139 -
   8.140 +	draw_rotation_gizmo();
   8.141  
   8.142  	// print the rotation quaternion
   8.143  	text_color(1, 1, 1, 1);
   8.144  	text_position(0, 0);
   8.145 -	text_printf("translation (% .3f, % .3f, % .3f)", trans.x, trans.y, trans.z);
   8.146 +	text_printf("translation (% .3f, % .3f, % .3f)", last_trans.x, last_trans.y, last_trans.z);
   8.147  	text_position(0, 1);
   8.148 -	text_printf("Rotation quat ([% 1.3f, % 1.3f, % 1.3f], % 1.3f)", qrot.v.x, qrot.v.y, qrot.v.z, qrot.s);
   8.149 +	text_printf("Rotation quat ([% 1.3f, % 1.3f, % 1.3f], % 1.3f)", last_rot.v.x, last_rot.v.y, last_rot.v.z, last_rot.s);
   8.150  }
   8.151  
   8.152  static void draw_quad(float hsz, float vsz)
   8.153 @@ -147,6 +153,65 @@
   8.154  	gl_pop_matrix();
   8.155  }
   8.156  
   8.157 +static void draw_rotation_gizmo()
   8.158 +{
   8.159 +	/*static const float axis[][3] = {
   8.160 +		{1, 0, 0}, {0, 1, 0}, {0, 0, 1}
   8.161 +	};*/
   8.162 +
   8.163 +	last_rot.normalize();
   8.164 +	Matrix4x4 rmat = last_rot.get_rotation_matrix().transposed();
   8.165 +	gl_matrix_mode(GL_MODELVIEW);
   8.166 +	gl_push_matrix();
   8.167 +	gl_mult_matrixf(rmat[0]);
   8.168 +	gl_apply_xform(sdr_debug->get_globj());
   8.169 +
   8.170 +	sdr_debug->bind();
   8.171 +
   8.172 +	mesh->draw();
   8.173 +
   8.174 +	gl_pop_matrix();
   8.175 +}
   8.176 +
   8.177 +static void draw_disc_wedge(float start, float end, int subdiv)
   8.178 +{
   8.179 +	if(start > end) {
   8.180 +		float tmp = start;
   8.181 +		start = end;
   8.182 +		end = tmp;
   8.183 +	}
   8.184 +
   8.185 +	float arc_size = end - start;
   8.186 +	subdiv = std::max<int>(subdiv * arc_size, 1);
   8.187 +	int nverts = subdiv + 2;
   8.188 +
   8.189 +	float *varr = (float*)alloca(nverts * 3 * sizeof *varr);
   8.190 +	float *vptr = varr;
   8.191 +
   8.192 +	// start with the center vertex
   8.193 +	vptr[0] = vptr[1] = vptr[2] = 0;
   8.194 +	vptr += 3;
   8.195 +
   8.196 +	// then add the arc vertices in sequence
   8.197 +	float u = start;
   8.198 +	float du = arc_size / (float)subdiv;
   8.199 +	for(int i=0; i<subdiv + 1; i++) {
   8.200 +		float angle = u * M_PI * 2.0;
   8.201 +		vptr[0] = sin(angle);
   8.202 +		vptr[1] = cos(angle);
   8.203 +		vptr[2] = 0.0;
   8.204 +		vptr += 3;
   8.205 +		u += du;
   8.206 +	}
   8.207 +
   8.208 +	glEnableVertexAttribArray(SDR_ATTR_VERTEX);
   8.209 +	glVertexAttribPointer(SDR_ATTR_VERTEX, 3, GL_FLOAT, 0, 0, varr);
   8.210 +
   8.211 +	glDrawArrays(GL_TRIANGLE_FAN, 0, nverts);
   8.212 +
   8.213 +	glDisableVertexAttribArray(SDR_ATTR_VERTEX);
   8.214 +}
   8.215 +
   8.216  extern "C" void game_reshape(int x, int y)
   8.217  {
   8.218  	win_width = x;
   8.219 @@ -155,8 +220,7 @@
   8.220  	glViewport(0, 0, x, y);
   8.221  
   8.222  	gl_matrix_mode(GL_PROJECTION);
   8.223 -	gl_load_identity();
   8.224 -	gl_scalef((float)win_height / (float)win_width, 1, 1);
   8.225 +	glu_perspective(50.0, win_aspect, 0.5, 500.0);
   8.226  }
   8.227  
   8.228  extern "C" void game_keyboard(int key, int pressed)
   8.229 @@ -223,15 +287,17 @@
   8.230  
   8.231  void game_6dof_translation(float dx, float dy, float dz)
   8.232  {
   8.233 -	trans.x = dx;
   8.234 -	trans.y = dy;
   8.235 -	trans.z = dz;
   8.236 +	last_trans.x = dx;
   8.237 +	last_trans.y = dy;
   8.238 +	last_trans.z = dz;
   8.239  }
   8.240  
   8.241  void game_6dof_rotation(float qx, float qy, float qz, float qw)
   8.242  {
   8.243 -	qrot.v.x = qx;
   8.244 -	qrot.v.y = qy;
   8.245 -	qrot.v.z = qz;
   8.246 -	qrot.s = qw;
   8.247 +	last_rot.v.x = qx;
   8.248 +	last_rot.v.y = qy;
   8.249 +	last_rot.v.z = qz;
   8.250 +	last_rot.s = qw;
   8.251 +
   8.252 +	rot.rotate(last_rot);
   8.253  }
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/geom.cc	Thu Jun 18 03:12:30 2015 +0300
     9.3 @@ -0,0 +1,251 @@
     9.4 +#include <algorithm>
     9.5 +#include <float.h>
     9.6 +#include "geom.h"
     9.7 +
     9.8 +GeomObject::~GeomObject()
     9.9 +{
    9.10 +}
    9.11 +
    9.12 +
    9.13 +Sphere::Sphere()
    9.14 +{
    9.15 +	radius = 1.0;
    9.16 +}
    9.17 +
    9.18 +Sphere::Sphere(const Vector3 &cent, float radius)
    9.19 +	: center(cent)
    9.20 +{
    9.21 +	this->radius = radius;
    9.22 +}
    9.23 +
    9.24 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
    9.25 +{
    9.26 +	const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
    9.27 +	const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
    9.28 +
    9.29 +	if(!sph1 || !sph2) {
    9.30 +		fprintf(stderr, "Sphere::set_union: arguments must be spheres");
    9.31 +		return;
    9.32 +	}
    9.33 +
    9.34 +	float dist = (sph1->center - sph2->center).length();
    9.35 +	float surf_dist = dist - (sph1->radius + sph2->radius);
    9.36 +	float d1 = sph1->radius + surf_dist / 2.0;
    9.37 +	float d2 = sph2->radius + surf_dist / 2.0;
    9.38 +	float t = d1 / (d1 + d2);
    9.39 +
    9.40 +	if(t < 0.0) t = 0.0;
    9.41 +	if(t > 1.0) t = 1.0;
    9.42 +
    9.43 +	center = sph1->center * t + sph2->center * (1.0 - t);
    9.44 +	radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
    9.45 +}
    9.46 +
    9.47 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
    9.48 +{
    9.49 +	fprintf(stderr, "Sphere::intersection undefined\n");
    9.50 +}
    9.51 +
    9.52 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
    9.53 +{
    9.54 +	float a = dot_product(ray.dir, ray.dir);
    9.55 +	float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
    9.56 +		2.0 * ray.dir.y * (ray.origin.y - center.y) +
    9.57 +		2.0 * ray.dir.z * (ray.origin.z - center.z);
    9.58 +	float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
    9.59 +		2.0 * dot_product(ray.origin, center) - radius * radius;
    9.60 +
    9.61 +	float discr = b * b - 4.0 * a * c;
    9.62 +	if(discr < 1e-4) {
    9.63 +		return false;
    9.64 +	}
    9.65 +
    9.66 +	float sqrt_discr = sqrt(discr);
    9.67 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
    9.68 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
    9.69 +
    9.70 +	if(t0 < 1e-4)
    9.71 +		t0 = t1;
    9.72 +	if(t1 < 1e-4)
    9.73 +		t1 = t0;
    9.74 +
    9.75 +	float t = t0 < t1 ? t0 : t1;
    9.76 +	if(t < 1e-4) {
    9.77 +		return false;
    9.78 +	}
    9.79 +
    9.80 +	// fill the HitPoint structure
    9.81 +	if(hit) {
    9.82 +		hit->obj = this;
    9.83 +		hit->dist = t;
    9.84 +		hit->pos = ray.origin + ray.dir * t;
    9.85 +		hit->normal = (hit->pos - center) / radius;
    9.86 +	}
    9.87 +	return true;
    9.88 +}
    9.89 +
    9.90 +
    9.91 +AABox::AABox()
    9.92 +{
    9.93 +}
    9.94 +
    9.95 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
    9.96 +	: min(vmin), max(vmax)
    9.97 +{
    9.98 +}
    9.99 +
   9.100 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
   9.101 +{
   9.102 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   9.103 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   9.104 +
   9.105 +	if(!box1 || !box2) {
   9.106 +		fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n");
   9.107 +		return;
   9.108 +	}
   9.109 +
   9.110 +	min.x = std::min(box1->min.x, box2->min.x);
   9.111 +	min.y = std::min(box1->min.y, box2->min.y);
   9.112 +	min.z = std::min(box1->min.z, box2->min.z);
   9.113 +
   9.114 +	max.x = std::max(box1->max.x, box2->max.x);
   9.115 +	max.y = std::max(box1->max.y, box2->max.y);
   9.116 +	max.z = std::max(box1->max.z, box2->max.z);
   9.117 +}
   9.118 +
   9.119 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   9.120 +{
   9.121 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   9.122 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   9.123 +
   9.124 +	if(!box1 || !box2) {
   9.125 +		fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n");
   9.126 +		return;
   9.127 +	}
   9.128 +
   9.129 +	for(int i=0; i<3; i++) {
   9.130 +		min[i] = std::max(box1->min[i], box2->min[i]);
   9.131 +		max[i] = std::min(box1->max[i], box2->max[i]);
   9.132 +
   9.133 +		if(max[i] < min[i]) {
   9.134 +			max[i] = min[i];
   9.135 +		}
   9.136 +	}
   9.137 +}
   9.138 +
   9.139 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const
   9.140 +{
   9.141 +	Vector3 param[2] = {min, max};
   9.142 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
   9.143 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
   9.144 +
   9.145 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
   9.146 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
   9.147 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
   9.148 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
   9.149 +
   9.150 +	if(tmin > tymax || tymin > tmax) {
   9.151 +		return false;
   9.152 +	}
   9.153 +	if(tymin > tmin) {
   9.154 +		tmin = tymin;
   9.155 +	}
   9.156 +	if(tymax < tmax) {
   9.157 +		tmax = tymax;
   9.158 +	}
   9.159 +
   9.160 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
   9.161 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
   9.162 +
   9.163 +	if(tmin > tzmax || tzmin > tmax) {
   9.164 +		return false;
   9.165 +	}
   9.166 +	if(tzmin > tmin) {
   9.167 +		tmin = tzmin;
   9.168 +	}
   9.169 +	if(tzmax < tmax) {
   9.170 +		tmax = tzmax;
   9.171 +	}
   9.172 +
   9.173 +	float t = tmin < 1e-4 ? tmax : tmin;
   9.174 +	if(t >= 1e-4) {
   9.175 +
   9.176 +		if(hit) {
   9.177 +			hit->obj = this;
   9.178 +			hit->dist = t;
   9.179 +			hit->pos = ray.origin + ray.dir * t;
   9.180 +
   9.181 +			float min_dist = FLT_MAX;
   9.182 +			Vector3 offs = min + (max - min) / 2.0;
   9.183 +			Vector3 local_hit = hit->pos - offs;
   9.184 +
   9.185 +			static const Vector3 axis[] = {
   9.186 +				Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
   9.187 +			};
   9.188 +			//int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
   9.189 +
   9.190 +			for(int i=0; i<3; i++) {
   9.191 +				float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
   9.192 +				if(dist < min_dist) {
   9.193 +					min_dist = dist;
   9.194 +					hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
   9.195 +					//hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
   9.196 +				}
   9.197 +			}
   9.198 +		}
   9.199 +		return true;
   9.200 +	}
   9.201 +	return false;
   9.202 +
   9.203 +}
   9.204 +
   9.205 +Plane::Plane()
   9.206 +	: normal(0.0, 1.0, 0.0)
   9.207 +{
   9.208 +}
   9.209 +
   9.210 +Plane::Plane(const Vector3 &p, const Vector3 &norm)
   9.211 +	: pt(p)
   9.212 +{
   9.213 +	normal = norm.normalized();
   9.214 +}
   9.215 +
   9.216 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
   9.217 +	: pt(p1)
   9.218 +{
   9.219 +	normal = cross_product(p2 - p1, p3 - p1).normalized();
   9.220 +}
   9.221 +
   9.222 +Plane::Plane(const Vector3 &normal, float dist)
   9.223 +{
   9.224 +	this->normal = normal.normalized();
   9.225 +	pt = this->normal * dist;
   9.226 +}
   9.227 +
   9.228 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
   9.229 +{
   9.230 +	fprintf(stderr, "Plane::set_union undefined\n");
   9.231 +}
   9.232 +
   9.233 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   9.234 +{
   9.235 +	fprintf(stderr, "Plane::set_intersection undefined\n");
   9.236 +}
   9.237 +
   9.238 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const
   9.239 +{
   9.240 +	float ndotdir = dot_product(normal, ray.dir);
   9.241 +	if(fabs(ndotdir) < 1e-4) {
   9.242 +		return false;
   9.243 +	}
   9.244 +
   9.245 +	if(hit) {
   9.246 +		Vector3 ptdir = pt - ray.origin;
   9.247 +		float t = dot_product(normal, ptdir) / ndotdir;
   9.248 +
   9.249 +		hit->pos = ray.origin + ray.dir * t;
   9.250 +		hit->normal = normal;
   9.251 +		hit->obj = this;
   9.252 +	}
   9.253 +	return true;
   9.254 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/geom.h	Thu Jun 18 03:12:30 2015 +0300
    10.3 @@ -0,0 +1,67 @@
    10.4 +#ifndef GEOMOBJ_H_
    10.5 +#define GEOMOBJ_H_
    10.6 +
    10.7 +#include "vmath/vmath.h"
    10.8 +
    10.9 +class GeomObject;
   10.10 +
   10.11 +struct HitPoint {
   10.12 +	float dist;				//< parametric distance along the ray
   10.13 +	Vector3 pos;			//< position of intersection (orig + dir * dist)
   10.14 +	Vector3 normal;			//< normal at the point of intersection
   10.15 +	const void *obj;		//< pointer to the intersected object
   10.16 +};
   10.17 +
   10.18 +class GeomObject {
   10.19 +public:
   10.20 +	virtual ~GeomObject();
   10.21 +
   10.22 +	virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0;
   10.23 +	virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0;
   10.24 +
   10.25 +	virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0;
   10.26 +};
   10.27 +
   10.28 +class Sphere : public GeomObject {
   10.29 +public:
   10.30 +	Vector3 center;
   10.31 +	float radius;
   10.32 +
   10.33 +	Sphere();
   10.34 +	Sphere(const Vector3 &center, float radius);
   10.35 +
   10.36 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   10.37 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   10.38 +
   10.39 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   10.40 +};
   10.41 +
   10.42 +class AABox : public GeomObject {
   10.43 +public:
   10.44 +	Vector3 min, max;
   10.45 +
   10.46 +	AABox();
   10.47 +	AABox(const Vector3 &min, const Vector3 &max);
   10.48 +
   10.49 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   10.50 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   10.51 +
   10.52 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   10.53 +};
   10.54 +
   10.55 +class Plane : public GeomObject {
   10.56 +public:
   10.57 +	Vector3 pt, normal;
   10.58 +
   10.59 +	Plane();
   10.60 +	Plane(const Vector3 &pt, const Vector3 &normal);
   10.61 +	Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3);
   10.62 +	Plane(const Vector3 &normal, float dist);
   10.63 +
   10.64 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
   10.65 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
   10.66 +
   10.67 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   10.68 +};
   10.69 +
   10.70 +#endif	// GEOMOBJ_H_
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/mesh.cc	Thu Jun 18 03:12:30 2015 +0300
    11.3 @@ -0,0 +1,1190 @@
    11.4 +#include <stdio.h>
    11.5 +#include <stdlib.h>
    11.6 +#include <float.h>
    11.7 +#include <assert.h>
    11.8 +#include "opengl.h"
    11.9 +#include "mesh.h"
   11.10 +//#include "xform_node.h"
   11.11 +#include "shader.h"
   11.12 +
   11.13 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = {
   11.14 +	(int)SDR_ATTR_VERTEX,
   11.15 +	(int)SDR_ATTR_NORMAL,
   11.16 +	(int)SDR_ATTR_TANGENT,
   11.17 +	(int)SDR_ATTR_TEXCOORD,
   11.18 +	(int)SDR_ATTR_COLOR,
   11.19 +	-1, -1};
   11.20 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
   11.21 +float Mesh::vertex_sel_dist = 0.01;
   11.22 +float Mesh::vis_vecsize = 1.0;
   11.23 +
   11.24 +Mesh::Mesh()
   11.25 +{
   11.26 +	clear();
   11.27 +
   11.28 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   11.29 +
   11.30 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   11.31 +		vattr[i].vbo = buffer_objects[i];
   11.32 +	}
   11.33 +	ibo = buffer_objects[NUM_MESH_ATTR];
   11.34 +	wire_ibo = 0;
   11.35 +}
   11.36 +
   11.37 +Mesh::~Mesh()
   11.38 +{
   11.39 +	glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   11.40 +
   11.41 +	if(wire_ibo) {
   11.42 +		glDeleteBuffers(1, &wire_ibo);
   11.43 +	}
   11.44 +}
   11.45 +
   11.46 +Mesh::Mesh(const Mesh &rhs)
   11.47 +{
   11.48 +	clear();
   11.49 +
   11.50 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   11.51 +
   11.52 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   11.53 +		vattr[i].vbo = buffer_objects[i];
   11.54 +	}
   11.55 +	ibo = buffer_objects[NUM_MESH_ATTR];
   11.56 +	wire_ibo = 0;
   11.57 +
   11.58 +	clone(rhs);
   11.59 +}
   11.60 +
   11.61 +Mesh &Mesh::operator =(const Mesh &rhs)
   11.62 +{
   11.63 +	if(&rhs != this) {
   11.64 +		clone(rhs);
   11.65 +	}
   11.66 +	return *this;
   11.67 +}
   11.68 +
   11.69 +bool Mesh::clone(const Mesh &m)
   11.70 +{
   11.71 +	clear();
   11.72 +
   11.73 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   11.74 +		if(m.has_attrib(i)) {
   11.75 +			m.get_attrib_data(i);	// force validation of the actual data on the source mesh
   11.76 +
   11.77 +			vattr[i].nelem = m.vattr[i].nelem;
   11.78 +			vattr[i].data = m.vattr[i].data;	// copy the actual data
   11.79 +			vattr[i].data_valid = true;
   11.80 +		}
   11.81 +	}
   11.82 +
   11.83 +	if(m.is_indexed()) {
   11.84 +		m.get_index_data();		// again, force validation
   11.85 +
   11.86 +		// copy the index data
   11.87 +		idata = m.idata;
   11.88 +		idata_valid = true;
   11.89 +	}
   11.90 +
   11.91 +	name = m.name;
   11.92 +	nverts = m.nverts;
   11.93 +	nfaces = m.nfaces;
   11.94 +
   11.95 +	//bones = m.bones;
   11.96 +
   11.97 +	memcpy(cur_val, m.cur_val, sizeof cur_val);
   11.98 +
   11.99 +	aabb = m.aabb;
  11.100 +	aabb_valid = m.aabb_valid;
  11.101 +	bsph = m.bsph;
  11.102 +	bsph_valid = m.bsph_valid;
  11.103 +
  11.104 +	hitface = m.hitface;
  11.105 +	hitvert = m.hitvert;
  11.106 +
  11.107 +	intersect_mode = m.intersect_mode;
  11.108 +	vertex_sel_dist = m.vertex_sel_dist;
  11.109 +	vis_vecsize = m.vis_vecsize;
  11.110 +
  11.111 +	return true;
  11.112 +}
  11.113 +
  11.114 +void Mesh::set_name(const char *name)
  11.115 +{
  11.116 +	this->name = name;
  11.117 +}
  11.118 +
  11.119 +const char *Mesh::get_name() const
  11.120 +{
  11.121 +	return name.c_str();
  11.122 +}
  11.123 +
  11.124 +bool Mesh::has_attrib(int attr) const
  11.125 +{
  11.126 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  11.127 +		return false;
  11.128 +	}
  11.129 +
  11.130 +	// if neither of these is valid, then nobody has set this attribute
  11.131 +	return vattr[attr].vbo_valid || vattr[attr].data_valid;
  11.132 +}
  11.133 +
  11.134 +bool Mesh::is_indexed() const
  11.135 +{
  11.136 +	return ibo_valid || idata_valid;
  11.137 +}
  11.138 +
  11.139 +void Mesh::clear()
  11.140 +{
  11.141 +	//bones.clear();
  11.142 +
  11.143 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.144 +		vattr[i].nelem = 0;
  11.145 +		vattr[i].vbo_valid = false;
  11.146 +		vattr[i].data_valid = false;
  11.147 +		//vattr[i].sdr_loc = -1;
  11.148 +		vattr[i].data.clear();
  11.149 +	}
  11.150 +	ibo_valid = idata_valid = false;
  11.151 +	idata.clear();
  11.152 +
  11.153 +	wire_ibo_valid = false;
  11.154 +
  11.155 +	nverts = nfaces = 0;
  11.156 +
  11.157 +	bsph_valid = false;
  11.158 +	aabb_valid = false;
  11.159 +}
  11.160 +
  11.161 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
  11.162 +{
  11.163 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  11.164 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  11.165 +		return 0;
  11.166 +	}
  11.167 +
  11.168 +	if(nverts && num != nverts) {
  11.169 +		fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
  11.170 +		return 0;
  11.171 +	}
  11.172 +	nverts = num;
  11.173 +
  11.174 +	vattr[attrib].data.clear();
  11.175 +	vattr[attrib].nelem = nelem;
  11.176 +	vattr[attrib].data.resize(num * nelem);
  11.177 +
  11.178 +	if(data) {
  11.179 +		memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
  11.180 +	}
  11.181 +
  11.182 +	vattr[attrib].data_valid = true;
  11.183 +	vattr[attrib].vbo_valid = false;
  11.184 +	return &vattr[attrib].data[0];
  11.185 +}
  11.186 +
  11.187 +float *Mesh::get_attrib_data(int attrib)
  11.188 +{
  11.189 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  11.190 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  11.191 +		return 0;
  11.192 +	}
  11.193 +
  11.194 +	vattr[attrib].vbo_valid = false;
  11.195 +	return (float*)((const Mesh*)this)->get_attrib_data(attrib);
  11.196 +}
  11.197 +
  11.198 +const float *Mesh::get_attrib_data(int attrib) const
  11.199 +{
  11.200 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  11.201 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  11.202 +		return 0;
  11.203 +	}
  11.204 +
  11.205 +	if(!vattr[attrib].data_valid) {
  11.206 +#if GL_ES_VERSION_2_0
  11.207 +		fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
  11.208 +		return 0;
  11.209 +#else
  11.210 +		if(!vattr[attrib].vbo_valid) {
  11.211 +			fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
  11.212 +			return 0;
  11.213 +		}
  11.214 +
  11.215 +		// local data copy is unavailable, grab the data from the vbo
  11.216 +		Mesh *m = (Mesh*)this;
  11.217 +		m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
  11.218 +
  11.219 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
  11.220 +		void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
  11.221 +		memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
  11.222 +		glUnmapBuffer(GL_ARRAY_BUFFER);
  11.223 +
  11.224 +		vattr[attrib].data_valid = true;
  11.225 +#endif
  11.226 +	}
  11.227 +
  11.228 +	return &vattr[attrib].data[0];
  11.229 +}
  11.230 +
  11.231 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
  11.232 +{
  11.233 +	float *data = get_attrib_data(attrib);
  11.234 +	if(data) {
  11.235 +		data += idx * vattr[attrib].nelem;
  11.236 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  11.237 +			data[i] = v[i];
  11.238 +		}
  11.239 +	}
  11.240 +}
  11.241 +
  11.242 +Vector4 Mesh::get_attrib(int attrib, int idx) const
  11.243 +{
  11.244 +	Vector4 v(0.0, 0.0, 0.0, 1.0);
  11.245 +	const float *data = get_attrib_data(attrib);
  11.246 +	if(data) {
  11.247 +		data += idx * vattr[attrib].nelem;
  11.248 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  11.249 +			v[i] = data[i];
  11.250 +		}
  11.251 +	}
  11.252 +	return v;
  11.253 +}
  11.254 +
  11.255 +int Mesh::get_attrib_count(int attrib) const
  11.256 +{
  11.257 +	return has_attrib(attrib) ? nverts : 0;
  11.258 +}
  11.259 +
  11.260 +
  11.261 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
  11.262 +{
  11.263 +	int nidx = nfaces * 3;
  11.264 +	if(nidx && num != nidx) {
  11.265 +		fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
  11.266 +		return 0;
  11.267 +	}
  11.268 +	nfaces = num / 3;
  11.269 +
  11.270 +	idata.clear();
  11.271 +	idata.resize(num);
  11.272 +
  11.273 +	if(indices) {
  11.274 +		memcpy(&idata[0], indices, num * sizeof *indices);
  11.275 +	}
  11.276 +
  11.277 +	idata_valid = true;
  11.278 +	ibo_valid = false;
  11.279 +
  11.280 +	return &idata[0];
  11.281 +}
  11.282 +
  11.283 +unsigned int *Mesh::get_index_data()
  11.284 +{
  11.285 +	ibo_valid = false;
  11.286 +	return (unsigned int*)((const Mesh*)this)->get_index_data();
  11.287 +}
  11.288 +
  11.289 +const unsigned int *Mesh::get_index_data() const
  11.290 +{
  11.291 +	if(!idata_valid) {
  11.292 +#if GL_ES_VERSION_2_0
  11.293 +		fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
  11.294 +		return 0;
  11.295 +#else
  11.296 +		if(!ibo_valid) {
  11.297 +			fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
  11.298 +			return 0;
  11.299 +		}
  11.300 +
  11.301 +		// local data copy is unavailable, gram the data from the ibo
  11.302 +		Mesh *m = (Mesh*)this;
  11.303 +		int nidx = nfaces * 3;
  11.304 +		m->idata.resize(nidx);
  11.305 +
  11.306 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  11.307 +		void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
  11.308 +		memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
  11.309 +		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
  11.310 +
  11.311 +		idata_valid = true;
  11.312 +#endif
  11.313 +	}
  11.314 +
  11.315 +	return &idata[0];
  11.316 +}
  11.317 +
  11.318 +int Mesh::get_index_count() const
  11.319 +{
  11.320 +	return nfaces * 3;
  11.321 +}
  11.322 +
  11.323 +void Mesh::append(const Mesh &mesh)
  11.324 +{
  11.325 +	unsigned int idxoffs = nverts;
  11.326 +
  11.327 +	nverts += mesh.nverts;
  11.328 +	nfaces += mesh.nfaces;
  11.329 +
  11.330 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.331 +		if(has_attrib(i) && mesh.has_attrib(i)) {
  11.332 +			// force validating the data arrays
  11.333 +			get_attrib_data(i);
  11.334 +			mesh.get_attrib_data(i);
  11.335 +
  11.336 +			// append the mesh data
  11.337 +			vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
  11.338 +		}
  11.339 +	}
  11.340 +
  11.341 +	if(ibo_valid || idata_valid) {
  11.342 +		// make index arrays valid
  11.343 +		get_index_data();
  11.344 +		mesh.get_index_data();
  11.345 +
  11.346 +		size_t orig_sz = idata.size();
  11.347 +
  11.348 +		idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
  11.349 +
  11.350 +		// fixup all the new indices
  11.351 +		for(size_t i=orig_sz; i<idata.size(); i++) {
  11.352 +			idata[i] += idxoffs;
  11.353 +		}
  11.354 +	}
  11.355 +
  11.356 +	// fuck everything
  11.357 +	wire_ibo_valid = false;
  11.358 +	aabb_valid = false;
  11.359 +	bsph_valid = false;
  11.360 +}
  11.361 +
  11.362 +// assemble a complete vertex by adding all the useful attributes
  11.363 +void Mesh::vertex(float x, float y, float z)
  11.364 +{
  11.365 +	cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
  11.366 +	vattr[MESH_ATTR_VERTEX].data_valid = true;
  11.367 +	vattr[MESH_ATTR_VERTEX].nelem = 3;
  11.368 +
  11.369 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.370 +		if(vattr[i].data_valid) {
  11.371 +			for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
  11.372 +				vattr[i].data.push_back(cur_val[i][j]);
  11.373 +			}
  11.374 +		}
  11.375 +		vattr[i].vbo_valid = false;
  11.376 +	}
  11.377 +
  11.378 +	if(idata_valid) {
  11.379 +		idata.clear();
  11.380 +	}
  11.381 +	ibo_valid = idata_valid = false;
  11.382 +}
  11.383 +
  11.384 +void Mesh::normal(float nx, float ny, float nz)
  11.385 +{
  11.386 +	cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
  11.387 +	vattr[MESH_ATTR_NORMAL].data_valid = true;
  11.388 +	vattr[MESH_ATTR_NORMAL].nelem = 3;
  11.389 +}
  11.390 +
  11.391 +void Mesh::tangent(float tx, float ty, float tz)
  11.392 +{
  11.393 +	cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
  11.394 +	vattr[MESH_ATTR_TANGENT].data_valid = true;
  11.395 +	vattr[MESH_ATTR_TANGENT].nelem = 3;
  11.396 +}
  11.397 +
  11.398 +void Mesh::texcoord(float u, float v, float w)
  11.399 +{
  11.400 +	cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
  11.401 +	vattr[MESH_ATTR_TEXCOORD].data_valid = true;
  11.402 +	vattr[MESH_ATTR_TEXCOORD].nelem = 3;
  11.403 +}
  11.404 +
  11.405 +void Mesh::boneweights(float w1, float w2, float w3, float w4)
  11.406 +{
  11.407 +	cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
  11.408 +	vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
  11.409 +	vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
  11.410 +}
  11.411 +
  11.412 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
  11.413 +{
  11.414 +	cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
  11.415 +	vattr[MESH_ATTR_BONEIDX].data_valid = true;
  11.416 +	vattr[MESH_ATTR_BONEIDX].nelem = 4;
  11.417 +}
  11.418 +
  11.419 +int Mesh::get_poly_count() const
  11.420 +{
  11.421 +	if(nfaces) {
  11.422 +		return nfaces;
  11.423 +	}
  11.424 +	if(nverts) {
  11.425 +		return nverts / 3;
  11.426 +	}
  11.427 +	return 0;
  11.428 +}
  11.429 +
  11.430 +/// static function
  11.431 +void Mesh::set_attrib_location(int attr, int loc)
  11.432 +{
  11.433 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  11.434 +		return;
  11.435 +	}
  11.436 +	Mesh::global_sdr_loc[attr] = loc;
  11.437 +}
  11.438 +
  11.439 +/// static function
  11.440 +int Mesh::get_attrib_location(int attr)
  11.441 +{
  11.442 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  11.443 +		return -1;
  11.444 +	}
  11.445 +	return Mesh::global_sdr_loc[attr];
  11.446 +}
  11.447 +
  11.448 +/// static function
  11.449 +void Mesh::clear_attrib_locations()
  11.450 +{
  11.451 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.452 +		Mesh::global_sdr_loc[i] = -1;
  11.453 +	}
  11.454 +}
  11.455 +
  11.456 +/// static function
  11.457 +void Mesh::set_vis_vecsize(float sz)
  11.458 +{
  11.459 +	Mesh::vis_vecsize = sz;
  11.460 +}
  11.461 +
  11.462 +float Mesh::get_vis_vecsize()
  11.463 +{
  11.464 +	return Mesh::vis_vecsize;
  11.465 +}
  11.466 +
  11.467 +void Mesh::apply_xform(const Matrix4x4 &xform)
  11.468 +{
  11.469 +	Matrix4x4 dir_xform = xform;
  11.470 +	dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
  11.471 +	dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
  11.472 +	dir_xform[3][3] = 1.0f;
  11.473 +
  11.474 +	apply_xform(xform, dir_xform);
  11.475 +}
  11.476 +
  11.477 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
  11.478 +{
  11.479 +	for(unsigned int i=0; i<nverts; i++) {
  11.480 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  11.481 +		set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
  11.482 +
  11.483 +		if(has_attrib(MESH_ATTR_NORMAL)) {
  11.484 +			Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
  11.485 +			set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
  11.486 +		}
  11.487 +		if(has_attrib(MESH_ATTR_TANGENT)) {
  11.488 +			Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
  11.489 +			set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
  11.490 +		}
  11.491 +	}
  11.492 +}
  11.493 +
  11.494 +void Mesh::flip()
  11.495 +{
  11.496 +	flip_faces();
  11.497 +	flip_normals();
  11.498 +}
  11.499 +
  11.500 +void Mesh::flip_faces()
  11.501 +{
  11.502 +	if(is_indexed()) {
  11.503 +		unsigned int *indices = get_index_data();
  11.504 +		if(!indices) return;
  11.505 +
  11.506 +		int idxnum = get_index_count();
  11.507 +		for(int i=0; i<idxnum; i+=3) {
  11.508 +			unsigned int tmp = indices[i + 2];
  11.509 +			indices[i + 2] = indices[i + 1];
  11.510 +			indices[i + 1] = tmp;
  11.511 +		}
  11.512 +
  11.513 +	} else {
  11.514 +		Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  11.515 +		if(!verts) return;
  11.516 +
  11.517 +		int vnum = get_attrib_count(MESH_ATTR_VERTEX);
  11.518 +		for(int i=0; i<vnum; i+=3) {
  11.519 +			Vector3 tmp = verts[i + 2];
  11.520 +			verts[i + 2] = verts[i + 1];
  11.521 +			verts[i + 1] = tmp;
  11.522 +		}
  11.523 +	}
  11.524 +}
  11.525 +
  11.526 +void Mesh::flip_normals()
  11.527 +{
  11.528 +	Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  11.529 +	if(!normals) return;
  11.530 +
  11.531 +	int num = get_attrib_count(MESH_ATTR_NORMAL);
  11.532 +	for(int i=0; i<num; i++) {
  11.533 +		normals[i] = -normals[i];
  11.534 +	}
  11.535 +}
  11.536 +
  11.537 +/*
  11.538 +int Mesh::add_bone(XFormNode *bone)
  11.539 +{
  11.540 +	int idx = bones.size();
  11.541 +	bones.push_back(bone);
  11.542 +	return idx;
  11.543 +}
  11.544 +
  11.545 +const XFormNode *Mesh::get_bone(int idx) const
  11.546 +{
  11.547 +	if(idx < 0 || idx >= (int)bones.size()) {
  11.548 +		return 0;
  11.549 +	}
  11.550 +	return bones[idx];
  11.551 +}
  11.552 +
  11.553 +int Mesh::get_bones_count() const
  11.554 +{
  11.555 +	return (int)bones.size();
  11.556 +}
  11.557 +*/
  11.558 +
  11.559 +void Mesh::draw() const
  11.560 +{
  11.561 +#ifdef GL_ES_VERSION_2_0
  11.562 +	if(!SdrProg::active) {
  11.563 +		fprintf(stderr, "%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
  11.564 +		return;
  11.565 +	}
  11.566 +#endif
  11.567 +
  11.568 +	((Mesh*)this)->update_buffers();
  11.569 +
  11.570 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  11.571 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  11.572 +		return;
  11.573 +	}
  11.574 +
  11.575 +	if(SdrProg::active) {
  11.576 +		// rendering with shaders
  11.577 +		if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  11.578 +			fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  11.579 +			return;
  11.580 +		}
  11.581 +
  11.582 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.583 +			int loc = global_sdr_loc[i];
  11.584 +			if(loc >= 0 && vattr[i].vbo_valid) {
  11.585 +				glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  11.586 +				glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  11.587 +				glEnableVertexAttribArray(loc);
  11.588 +			}
  11.589 +		}
  11.590 +	} else {
  11.591 +#ifndef GL_ES_VERSION_2_0
  11.592 +		// rendering with fixed-function (not available in GLES2)
  11.593 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
  11.594 +		glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
  11.595 +		glEnableClientState(GL_VERTEX_ARRAY);
  11.596 +
  11.597 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  11.598 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
  11.599 +			glNormalPointer(GL_FLOAT, 0, 0);
  11.600 +			glEnableClientState(GL_NORMAL_ARRAY);
  11.601 +		}
  11.602 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  11.603 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
  11.604 +			glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
  11.605 +			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  11.606 +		}
  11.607 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  11.608 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
  11.609 +			glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
  11.610 +			glEnableClientState(GL_COLOR_ARRAY);
  11.611 +		}
  11.612 +#endif
  11.613 +	}
  11.614 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  11.615 +
  11.616 +	if(ibo_valid) {
  11.617 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  11.618 +		glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
  11.619 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  11.620 +	} else {
  11.621 +		glDrawArrays(GL_TRIANGLES, 0, nverts);
  11.622 +	}
  11.623 +
  11.624 +	if(SdrProg::active) {
  11.625 +		// rendered with shaders
  11.626 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.627 +			int loc = global_sdr_loc[i];
  11.628 +			if(loc >= 0 && vattr[i].vbo_valid) {
  11.629 +				glDisableVertexAttribArray(loc);
  11.630 +			}
  11.631 +		}
  11.632 +	} else {
  11.633 +#ifndef GL_ES_VERSION_2_0
  11.634 +		// rendered with fixed-function
  11.635 +		glDisableClientState(GL_VERTEX_ARRAY);
  11.636 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  11.637 +			glDisableClientState(GL_NORMAL_ARRAY);
  11.638 +		}
  11.639 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  11.640 +			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  11.641 +		}
  11.642 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  11.643 +			glDisableClientState(GL_COLOR_ARRAY);
  11.644 +		}
  11.645 +#endif
  11.646 +	}
  11.647 +}
  11.648 +
  11.649 +void Mesh::draw_wire() const
  11.650 +{
  11.651 +	((Mesh*)this)->update_wire_ibo();
  11.652 +
  11.653 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
  11.654 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  11.655 +		return;
  11.656 +	}
  11.657 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  11.658 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  11.659 +		return;
  11.660 +	}
  11.661 +
  11.662 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.663 +		int loc = global_sdr_loc[i];
  11.664 +		if(loc >= 0 && vattr[i].vbo_valid) {
  11.665 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  11.666 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  11.667 +			glEnableVertexAttribArray(loc);
  11.668 +		}
  11.669 +	}
  11.670 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  11.671 +
  11.672 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  11.673 +	glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
  11.674 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  11.675 +
  11.676 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.677 +		int loc = global_sdr_loc[i];
  11.678 +		if(loc >= 0 && vattr[i].vbo_valid) {
  11.679 +			glDisableVertexAttribArray(loc);
  11.680 +		}
  11.681 +	}
  11.682 +}
  11.683 +
  11.684 +void Mesh::draw_vertices() const
  11.685 +{
  11.686 +	((Mesh*)this)->update_buffers();
  11.687 +
  11.688 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  11.689 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  11.690 +		return;
  11.691 +	}
  11.692 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  11.693 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  11.694 +		return;
  11.695 +	}
  11.696 +
  11.697 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.698 +		int loc = global_sdr_loc[i];
  11.699 +		if(loc >= 0 && vattr[i].vbo_valid) {
  11.700 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  11.701 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  11.702 +			glEnableVertexAttribArray(loc);
  11.703 +		}
  11.704 +	}
  11.705 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  11.706 +
  11.707 +	glDrawArrays(GL_POINTS, 0, nverts);
  11.708 +
  11.709 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.710 +		int loc = global_sdr_loc[i];
  11.711 +		if(loc >= 0 && vattr[i].vbo_valid) {
  11.712 +			glDisableVertexAttribArray(loc);
  11.713 +		}
  11.714 +	}
  11.715 +}
  11.716 +
  11.717 +void Mesh::draw_normals() const
  11.718 +{
  11.719 +#ifdef USE_OLDGL
  11.720 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  11.721 +	Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  11.722 +	if(!varr || !norm) {
  11.723 +		return;
  11.724 +	}
  11.725 +
  11.726 +	glBegin(GL_LINES);
  11.727 +	if(get_current_shader()) {
  11.728 +		int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  11.729 +		if(vert_loc < 0) {
  11.730 +			glEnd();
  11.731 +			return;
  11.732 +		}
  11.733 +
  11.734 +		for(size_t i=0; i<nverts; i++) {
  11.735 +			glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  11.736 +			Vector3 end = varr[i] + norm[i] * vis_vecsize;
  11.737 +			glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  11.738 +		}
  11.739 +	} else {
  11.740 +		for(size_t i=0; i<nverts; i++) {
  11.741 +			glVertex3f(varr[i].x, varr[i].y, varr[i].z);
  11.742 +			Vector3 end = varr[i] + norm[i] * vis_vecsize;
  11.743 +			glVertex3f(end.x, end.y, end.z);
  11.744 +		}
  11.745 +	}
  11.746 +	glEnd();
  11.747 +#endif	// USE_OLDGL
  11.748 +}
  11.749 +
  11.750 +void Mesh::draw_tangents() const
  11.751 +{
  11.752 +#ifdef USE_OLDGL
  11.753 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  11.754 +	Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
  11.755 +	if(!varr || !tang) {
  11.756 +		return;
  11.757 +	}
  11.758 +
  11.759 +	glBegin(GL_LINES);
  11.760 +	if(get_current_shader()) {
  11.761 +		int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  11.762 +		if(vert_loc < 0) {
  11.763 +			glEnd();
  11.764 +			return;
  11.765 +		}
  11.766 +
  11.767 +		for(size_t i=0; i<nverts; i++) {
  11.768 +			glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  11.769 +			Vector3 end = varr[i] + tang[i] * vis_vecsize;
  11.770 +			glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  11.771 +		}
  11.772 +	} else {
  11.773 +		for(size_t i=0; i<nverts; i++) {
  11.774 +			glVertex3f(varr[i].x, varr[i].y, varr[i].z);
  11.775 +			Vector3 end = varr[i] + tang[i] * vis_vecsize;
  11.776 +			glVertex3f(end.x, end.y, end.z);
  11.777 +		}
  11.778 +	}
  11.779 +	glEnd();
  11.780 +#endif	// USE_OLDGL
  11.781 +}
  11.782 +
  11.783 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
  11.784 +{
  11.785 +	if(!aabb_valid) {
  11.786 +		((Mesh*)this)->calc_aabb();
  11.787 +	}
  11.788 +	*vmin = aabb.min;
  11.789 +	*vmax = aabb.max;
  11.790 +}
  11.791 +
  11.792 +const AABox &Mesh::get_aabbox() const
  11.793 +{
  11.794 +	if(!aabb_valid) {
  11.795 +		((Mesh*)this)->calc_aabb();
  11.796 +	}
  11.797 +	return aabb;
  11.798 +}
  11.799 +
  11.800 +float Mesh::get_bsphere(Vector3 *center, float *rad) const
  11.801 +{
  11.802 +	if(!bsph_valid) {
  11.803 +		((Mesh*)this)->calc_bsph();
  11.804 +	}
  11.805 +	*center = bsph.center;
  11.806 +	*rad = bsph.radius;
  11.807 +	return bsph.radius;
  11.808 +}
  11.809 +
  11.810 +const Sphere &Mesh::get_bsphere() const
  11.811 +{
  11.812 +	if(!bsph_valid) {
  11.813 +		((Mesh*)this)->calc_bsph();
  11.814 +	}
  11.815 +	return bsph;
  11.816 +}
  11.817 +
  11.818 +/// static function
  11.819 +void Mesh::set_intersect_mode(unsigned int mode)
  11.820 +{
  11.821 +	Mesh::intersect_mode = mode;
  11.822 +}
  11.823 +
  11.824 +/// static function
  11.825 +unsigned int Mesh::get_intersect_mode()
  11.826 +{
  11.827 +	return Mesh::intersect_mode;
  11.828 +}
  11.829 +
  11.830 +/// static function
  11.831 +void Mesh::set_vertex_select_distance(float dist)
  11.832 +{
  11.833 +	Mesh::vertex_sel_dist = dist;
  11.834 +}
  11.835 +
  11.836 +/// static function
  11.837 +float Mesh::get_vertex_select_distance()
  11.838 +{
  11.839 +	return Mesh::vertex_sel_dist;
  11.840 +}
  11.841 +
  11.842 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
  11.843 +{
  11.844 +	assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
  11.845 +
  11.846 +	const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  11.847 +	const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  11.848 +	if(!varr) {
  11.849 +		return false;
  11.850 +	}
  11.851 +	const unsigned int *idxarr = get_index_data();
  11.852 +
  11.853 +	// first test with the bounding box
  11.854 +	AABox box;
  11.855 +	get_aabbox(&box.min, &box.max);
  11.856 +	if(!box.intersect(ray)) {
  11.857 +		return false;
  11.858 +	}
  11.859 +
  11.860 +	HitPoint nearest_hit;
  11.861 +	nearest_hit.dist = FLT_MAX;
  11.862 +	nearest_hit.obj = 0;
  11.863 +
  11.864 +	if(Mesh::intersect_mode & ISECT_VERTICES) {
  11.865 +		// we asked for "intersections" with the vertices of the mesh
  11.866 +		long nearest_vidx = -1;
  11.867 +		float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
  11.868 +
  11.869 +		for(unsigned int i=0; i<nverts; i++) {
  11.870 +
  11.871 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
  11.872 +				continue;
  11.873 +			}
  11.874 +
  11.875 +			// project the vertex onto the ray line
  11.876 +			float t = dot_product(varr[i] - ray.origin, ray.dir);
  11.877 +			Vector3 vproj = ray.origin + ray.dir * t;
  11.878 +
  11.879 +			float dist_sq = (vproj - varr[i]).length_sq();
  11.880 +			if(dist_sq < thres_sq) {
  11.881 +				if(!hit) {
  11.882 +					return true;
  11.883 +				}
  11.884 +				if(t < nearest_hit.dist) {
  11.885 +					nearest_hit.dist = t;
  11.886 +					nearest_vidx = i;
  11.887 +				}
  11.888 +			}
  11.889 +		}
  11.890 +
  11.891 +		if(nearest_vidx != -1) {
  11.892 +			hitvert = varr[nearest_vidx];
  11.893 +			nearest_hit.obj = &hitvert;
  11.894 +		}
  11.895 +
  11.896 +	} else {
  11.897 +		// regular intersection test with polygons
  11.898 +
  11.899 +		for(unsigned int i=0; i<nfaces; i++) {
  11.900 +			Triangle face(i, varr, idxarr);
  11.901 +
  11.902 +			// ignore back-facing polygons if the mode flags include ISECT_FRONT
  11.903 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
  11.904 +				continue;
  11.905 +			}
  11.906 +
  11.907 +			HitPoint fhit;
  11.908 +			if(face.intersect(ray, hit ? &fhit : 0)) {
  11.909 +				if(!hit) {
  11.910 +					return true;
  11.911 +				}
  11.912 +				if(fhit.dist < nearest_hit.dist) {
  11.913 +					nearest_hit = fhit;
  11.914 +					hitface = face;
  11.915 +				}
  11.916 +			}
  11.917 +		}
  11.918 +	}
  11.919 +
  11.920 +	if(nearest_hit.obj) {
  11.921 +		if(hit) {
  11.922 +			*hit = nearest_hit;
  11.923 +
  11.924 +			// if we are interested in the mesh and not the faces set obj to this
  11.925 +			if(Mesh::intersect_mode & ISECT_FACE) {
  11.926 +				hit->obj = &hitface;
  11.927 +			} else if(Mesh::intersect_mode & ISECT_VERTICES) {
  11.928 +				hit->obj = &hitvert;
  11.929 +			} else {
  11.930 +				hit->obj = this;
  11.931 +			}
  11.932 +		}
  11.933 +		return true;
  11.934 +	}
  11.935 +	return false;
  11.936 +}
  11.937 +
  11.938 +
  11.939 +// ------ private member functions ------
  11.940 +
  11.941 +void Mesh::calc_aabb()
  11.942 +{
  11.943 +	// the cast is to force calling the const version which doesn't invalidate
  11.944 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  11.945 +		return;
  11.946 +	}
  11.947 +
  11.948 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  11.949 +	aabb.max = -aabb.min;
  11.950 +
  11.951 +	for(unsigned int i=0; i<nverts; i++) {
  11.952 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  11.953 +		for(int j=0; j<3; j++) {
  11.954 +			if(v[j] < aabb.min[j]) {
  11.955 +				aabb.min[j] = v[j];
  11.956 +			}
  11.957 +			if(v[j] > aabb.max[j]) {
  11.958 +				aabb.max[j] = v[j];
  11.959 +			}
  11.960 +		}
  11.961 +	}
  11.962 +	aabb_valid = true;
  11.963 +}
  11.964 +
  11.965 +void Mesh::calc_bsph()
  11.966 +{
  11.967 +	// the cast is to force calling the const version which doesn't invalidate
  11.968 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  11.969 +		return;
  11.970 +	}
  11.971 +
  11.972 +	Vector3 v;
  11.973 +	bsph.center = Vector3(0, 0, 0);
  11.974 +
  11.975 +	// first find the center
  11.976 +	for(unsigned int i=0; i<nverts; i++) {
  11.977 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  11.978 +		bsph.center += v;
  11.979 +	}
  11.980 +	bsph.center /= (float)nverts;
  11.981 +
  11.982 +	bsph.radius = 0.0f;
  11.983 +	for(unsigned int i=0; i<nverts; i++) {
  11.984 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  11.985 +		float dist_sq = (v - bsph.center).length_sq();
  11.986 +		if(dist_sq > bsph.radius) {
  11.987 +			bsph.radius = dist_sq;
  11.988 +		}
  11.989 +	}
  11.990 +	bsph.radius = sqrt(bsph.radius);
  11.991 +
  11.992 +	bsph_valid = true;
  11.993 +}
  11.994 +
  11.995 +void Mesh::update_buffers()
  11.996 +{
  11.997 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  11.998 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
  11.999 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
 11.1000 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
 11.1001 +			vattr[i].vbo_valid = true;
 11.1002 +		}
 11.1003 +	}
 11.1004 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
 11.1005 +
 11.1006 +	if(idata_valid && !ibo_valid) {
 11.1007 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
 11.1008 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
 11.1009 +		ibo_valid = true;
 11.1010 +	}
 11.1011 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 11.1012 +}
 11.1013 +
 11.1014 +void Mesh::update_wire_ibo()
 11.1015 +{
 11.1016 +	update_buffers();
 11.1017 +
 11.1018 +	if(wire_ibo_valid) {
 11.1019 +		return;
 11.1020 +	}
 11.1021 +
 11.1022 +	if(!wire_ibo) {
 11.1023 +		glGenBuffers(1, &wire_ibo);
 11.1024 +	}
 11.1025 +
 11.1026 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
 11.1027 +	unsigned int *dest = wire_idxarr;
 11.1028 +
 11.1029 +	if(ibo_valid) {
 11.1030 +		// we're dealing with an indexed mesh
 11.1031 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
 11.1032 +
 11.1033 +		for(unsigned int i=0; i<nfaces; i++) {
 11.1034 +			*dest++ = idxarr[0];
 11.1035 +			*dest++ = idxarr[1];
 11.1036 +			*dest++ = idxarr[1];
 11.1037 +			*dest++ = idxarr[2];
 11.1038 +			*dest++ = idxarr[2];
 11.1039 +			*dest++ = idxarr[0];
 11.1040 +			idxarr += 3;
 11.1041 +		}
 11.1042 +	} else {
 11.1043 +		// not an indexed mesh ...
 11.1044 +		for(unsigned int i=0; i<nfaces; i++) {
 11.1045 +			int vidx = i * 3;
 11.1046 +			*dest++ = vidx;
 11.1047 +			*dest++ = vidx + 1;
 11.1048 +			*dest++ = vidx + 1;
 11.1049 +			*dest++ = vidx + 2;
 11.1050 +			*dest++ = vidx + 2;
 11.1051 +			*dest++ = vidx;
 11.1052 +		}
 11.1053 +	}
 11.1054 +
 11.1055 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
 11.1056 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
 11.1057 +	delete [] wire_idxarr;
 11.1058 +	wire_ibo_valid = true;
 11.1059 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 11.1060 +}
 11.1061 +
 11.1062 +
 11.1063 +// ------ class Triangle ------
 11.1064 +Triangle::Triangle()
 11.1065 +{
 11.1066 +	normal_valid = false;
 11.1067 +	id = -1;
 11.1068 +}
 11.1069 +
 11.1070 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
 11.1071 +{
 11.1072 +	v[0] = v0;
 11.1073 +	v[1] = v1;
 11.1074 +	v[2] = v2;
 11.1075 +	normal_valid = false;
 11.1076 +	id = -1;
 11.1077 +}
 11.1078 +
 11.1079 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
 11.1080 +{
 11.1081 +	if(idxarr) {
 11.1082 +		v[0] = varr[idxarr[n * 3]];
 11.1083 +		v[1] = varr[idxarr[n * 3 + 1]];
 11.1084 +		v[2] = varr[idxarr[n * 3 + 2]];
 11.1085 +	} else {
 11.1086 +		v[0] = varr[n * 3];
 11.1087 +		v[1] = varr[n * 3 + 1];
 11.1088 +		v[2] = varr[n * 3 + 2];
 11.1089 +	}
 11.1090 +	normal_valid = false;
 11.1091 +	id = n;
 11.1092 +}
 11.1093 +
 11.1094 +void Triangle::calc_normal()
 11.1095 +{
 11.1096 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
 11.1097 +	normal_valid = true;
 11.1098 +}
 11.1099 +
 11.1100 +const Vector3 &Triangle::get_normal() const
 11.1101 +{
 11.1102 +	if(!normal_valid) {
 11.1103 +		((Triangle*)this)->calc_normal();
 11.1104 +	}
 11.1105 +	return normal;
 11.1106 +}
 11.1107 +
 11.1108 +void Triangle::transform(const Matrix4x4 &xform)
 11.1109 +{
 11.1110 +	v[0].transform(xform);
 11.1111 +	v[1].transform(xform);
 11.1112 +	v[2].transform(xform);
 11.1113 +	normal_valid = false;
 11.1114 +}
 11.1115 +
 11.1116 +void Triangle::draw() const
 11.1117 +{
 11.1118 +	Vector3 n[3];
 11.1119 +	n[0] = get_normal();
 11.1120 +	n[1] = get_normal();
 11.1121 +	n[2] = get_normal();
 11.1122 +
 11.1123 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 11.1124 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
 11.1125 +
 11.1126 +	glEnableVertexAttribArray(vloc);
 11.1127 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 11.1128 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
 11.1129 +
 11.1130 +	glDrawArrays(GL_TRIANGLES, 0, 3);
 11.1131 +
 11.1132 +	glDisableVertexAttribArray(vloc);
 11.1133 +	glDisableVertexAttribArray(nloc);
 11.1134 +	CHECK_GLERROR;
 11.1135 +}
 11.1136 +
 11.1137 +void Triangle::draw_wire() const
 11.1138 +{
 11.1139 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
 11.1140 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 11.1141 +
 11.1142 +	glEnableVertexAttribArray(vloc);
 11.1143 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 11.1144 +
 11.1145 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
 11.1146 +
 11.1147 +	glDisableVertexAttribArray(vloc);
 11.1148 +	CHECK_GLERROR;
 11.1149 +}
 11.1150 +
 11.1151 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
 11.1152 +{
 11.1153 +	Vector3 norm = get_normal();
 11.1154 +
 11.1155 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
 11.1156 +	if(area_sq < 1e-5) {
 11.1157 +		return Vector3(0, 0, 0);
 11.1158 +	}
 11.1159 +
 11.1160 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
 11.1161 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
 11.1162 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
 11.1163 +
 11.1164 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
 11.1165 +}
 11.1166 +
 11.1167 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
 11.1168 +{
 11.1169 +	Vector3 normal = get_normal();
 11.1170 +
 11.1171 +	float ndotdir = dot_product(ray.dir, normal);
 11.1172 +	if(fabs(ndotdir) < 1e-4) {
 11.1173 +		return false;
 11.1174 +	}
 11.1175 +
 11.1176 +	Vector3 vertdir = v[0] - ray.origin;
 11.1177 +	float t = dot_product(normal, vertdir) / ndotdir;
 11.1178 +
 11.1179 +	Vector3 pos = ray.origin + ray.dir * t;
 11.1180 +	Vector3 bary = calc_barycentric(pos);
 11.1181 +
 11.1182 +	if(bary.x + bary.y + bary.z > 1.00001) {
 11.1183 +		return false;
 11.1184 +	}
 11.1185 +
 11.1186 +	if(hit) {
 11.1187 +		hit->dist = t;
 11.1188 +		hit->pos = ray.origin + ray.dir * t;
 11.1189 +		hit->normal = normal;
 11.1190 +		hit->obj = this;
 11.1191 +	}
 11.1192 +	return true;
 11.1193 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/mesh.h	Thu Jun 18 03:12:30 2015 +0300
    12.3 @@ -0,0 +1,225 @@
    12.4 +#ifndef MESH_H_
    12.5 +#define MESH_H_
    12.6 +
    12.7 +#include <string>
    12.8 +#include <vector>
    12.9 +#include "vmath/vmath.h"
   12.10 +#include "geom.h"
   12.11 +
   12.12 +enum {
   12.13 +	MESH_ATTR_VERTEX,
   12.14 +	MESH_ATTR_NORMAL,
   12.15 +	MESH_ATTR_TANGENT,
   12.16 +	MESH_ATTR_TEXCOORD,
   12.17 +	MESH_ATTR_COLOR,
   12.18 +	MESH_ATTR_BONEWEIGHTS,
   12.19 +	MESH_ATTR_BONEIDX,
   12.20 +
   12.21 +	NUM_MESH_ATTR
   12.22 +};
   12.23 +
   12.24 +// intersection mode flags
   12.25 +enum {
   12.26 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
   12.27 +	ISECT_FRONT		= 1,	// front-faces only
   12.28 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
   12.29 +	ISECT_VERTICES	= 4		// return (?) TODO
   12.30 +};
   12.31 +
   12.32 +//class XFormNode;
   12.33 +
   12.34 +
   12.35 +class Triangle {
   12.36 +public:
   12.37 +	Vector3 v[3];
   12.38 +	Vector3 normal;
   12.39 +	bool normal_valid;
   12.40 +	int id;
   12.41 +
   12.42 +	Triangle();
   12.43 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
   12.44 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
   12.45 +
   12.46 +	/// calculate normal (quite expensive)
   12.47 +	void calc_normal();
   12.48 +	const Vector3 &get_normal() const;
   12.49 +
   12.50 +	void transform(const Matrix4x4 &xform);
   12.51 +
   12.52 +	void draw() const;
   12.53 +	void draw_wire() const;
   12.54 +
   12.55 +	/// calculate barycentric coordinates of a point
   12.56 +	Vector3 calc_barycentric(const Vector3 &pos) const;
   12.57 +
   12.58 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   12.59 +};
   12.60 +
   12.61 +
   12.62 +class Mesh {
   12.63 +private:
   12.64 +	std::string name;
   12.65 +	unsigned int nverts, nfaces;
   12.66 +
   12.67 +	// current value for each attribute for the immedate mode
   12.68 +	// interface.
   12.69 +	Vector4 cur_val[NUM_MESH_ATTR];
   12.70 +
   12.71 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
   12.72 +
   12.73 +	// vertex attribute data and buffer objects
   12.74 +	struct {
   12.75 +		int nelem;					// number of elements per attribute range: [1, 4]
   12.76 +		std::vector<float> data;
   12.77 +		unsigned int vbo;
   12.78 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
   12.79 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
   12.80 +		//int sdr_loc;
   12.81 +	} vattr[NUM_MESH_ATTR];
   12.82 +
   12.83 +	static int global_sdr_loc[NUM_MESH_ATTR];
   12.84 +
   12.85 +	//std::vector<XFormNode*> bones;	// bones affecting this mesh
   12.86 +
   12.87 +	// index data and buffer object
   12.88 +	std::vector<unsigned int> idata;
   12.89 +	unsigned int ibo;
   12.90 +	mutable bool ibo_valid;
   12.91 +	mutable bool idata_valid;
   12.92 +
   12.93 +	// index buffer object for wireframe rendering (constructed on demand)
   12.94 +	unsigned int wire_ibo;
   12.95 +	mutable bool wire_ibo_valid;
   12.96 +
   12.97 +	// axis-aligned bounding box
   12.98 +	mutable AABox aabb;
   12.99 +	mutable bool aabb_valid;
  12.100 +
  12.101 +	// bounding sphere
  12.102 +	mutable Sphere bsph;
  12.103 +	mutable bool bsph_valid;
  12.104 +
  12.105 +	// keeps the last intersected face
  12.106 +	mutable Triangle hitface;
  12.107 +	// keeps the last intersected vertex position
  12.108 +	mutable Vector3 hitvert;
  12.109 +
  12.110 +	void calc_aabb();
  12.111 +	void calc_bsph();
  12.112 +
  12.113 +	static unsigned int intersect_mode;
  12.114 +	static float vertex_sel_dist;
  12.115 +
  12.116 +	static float vis_vecsize;
  12.117 +
  12.118 +	/// update the VBOs after data has changed (invalid vbo/ibo)
  12.119 +	void update_buffers();
  12.120 +	/// construct/update the wireframe index buffer (called from draw_wire).
  12.121 +	void update_wire_ibo();
  12.122 +
  12.123 +
  12.124 +public:
  12.125 +	Mesh();
  12.126 +	~Mesh();
  12.127 +
  12.128 +	Mesh(const Mesh &rhs);
  12.129 +	Mesh &operator =(const Mesh &rhs);
  12.130 +	bool clone(const Mesh &m);
  12.131 +
  12.132 +	void set_name(const char *name);
  12.133 +	const char *get_name() const;
  12.134 +
  12.135 +	bool has_attrib(int attr) const;
  12.136 +	bool is_indexed() const;
  12.137 +
  12.138 +	// clears everything about this mesh, and returns to the newly constructed state
  12.139 +	void clear();
  12.140 +
  12.141 +	// access the vertex attribute data
  12.142 +	// if vdata == 0, space is just allocated
  12.143 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
  12.144 +	float *get_attrib_data(int attrib);	// invalidates vbo
  12.145 +	const float *get_attrib_data(int attrib) const;
  12.146 +
  12.147 +	// simple access to any particular attribute
  12.148 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
  12.149 +	Vector4 get_attrib(int attrib, int idx) const;
  12.150 +
  12.151 +	int get_attrib_count(int attrib) const;
  12.152 +
  12.153 +	// ... same for index data
  12.154 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
  12.155 +	unsigned int *get_index_data();	// invalidates ibo
  12.156 +	const unsigned int *get_index_data() const;
  12.157 +
  12.158 +	int get_index_count() const;
  12.159 +
  12.160 +	void append(const Mesh &mesh);
  12.161 +
  12.162 +	// immediate-mode style mesh construction interface
  12.163 +	void vertex(float x, float y, float z);
  12.164 +	void normal(float nx, float ny, float nz);
  12.165 +	void tangent(float tx, float ty, float tz);
  12.166 +	void texcoord(float u, float v, float w);
  12.167 +	void boneweights(float w1, float w2, float w3, float w4);
  12.168 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
  12.169 +
  12.170 +	int get_poly_count() const;
  12.171 +
  12.172 +	/* apply a transformation to the vertices and its inverse-transpose
  12.173 +	 * to the normals and tangents.
  12.174 +	 */
  12.175 +	void apply_xform(const Matrix4x4 &xform);
  12.176 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
  12.177 +
  12.178 +	void flip();	// both faces and normals
  12.179 +	void flip_faces();
  12.180 +	void flip_normals();
  12.181 +
  12.182 +	// adds a bone and returns its index
  12.183 +	/*int add_bone(XFormNode *bone);
  12.184 +	const XFormNode *get_bone(int idx) const;
  12.185 +	int get_bones_count() const;*/
  12.186 +
  12.187 +	// access the shader attribute locations
  12.188 +	static void set_attrib_location(int attr, int loc);
  12.189 +	static int get_attrib_location(int attr);
  12.190 +	static void clear_attrib_locations();
  12.191 +
  12.192 +	static void set_vis_vecsize(float sz);
  12.193 +	static float get_vis_vecsize();
  12.194 +
  12.195 +	void draw() const;
  12.196 +	void draw_wire() const;
  12.197 +	void draw_vertices() const;
  12.198 +	void draw_normals() const;
  12.199 +	void draw_tangents() const;
  12.200 +
  12.201 +	/** get the bounding box in local space. The result will be cached, and subsequent
  12.202 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  12.203 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  12.204 +	 * @{ */
  12.205 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
  12.206 +	const AABox &get_aabbox() const;
  12.207 +	/// @}
  12.208 +
  12.209 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
  12.210 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  12.211 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  12.212 +	 * @{ */
  12.213 +	float get_bsphere(Vector3 *center, float *rad) const;
  12.214 +	const Sphere &get_bsphere() const;
  12.215 +
  12.216 +	static void set_intersect_mode(unsigned int mode);
  12.217 +	static unsigned int get_intersect_mode();
  12.218 +	static void set_vertex_select_distance(float dist);
  12.219 +	static float get_vertex_select_distance();
  12.220 +
  12.221 +	/** Find the intersection between the mesh and a ray.
  12.222 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
  12.223 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
  12.224 +	 */
  12.225 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
  12.226 +};
  12.227 +
  12.228 +#endif	// MESH_H_
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/meshgen.cc	Thu Jun 18 03:12:30 2015 +0300
    13.3 @@ -0,0 +1,395 @@
    13.4 +#include <stdio.h>
    13.5 +#include "meshgen.h"
    13.6 +#include "mesh.h"
    13.7 +
    13.8 +// -------- sphere --------
    13.9 +
   13.10 +#define SURAD(u)	((u) * 2.0 * M_PI)
   13.11 +#define SVRAD(v)	((v) * M_PI)
   13.12 +
   13.13 +static Vector3 sphvec(float theta, float phi)
   13.14 +{
   13.15 +	return Vector3(sin(theta) * sin(phi),
   13.16 +			cos(phi),
   13.17 +			cos(theta) * sin(phi));
   13.18 +}
   13.19 +
   13.20 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
   13.21 +{
   13.22 +	if(usub < 4) usub = 4;
   13.23 +	if(vsub < 2) vsub = 2;
   13.24 +
   13.25 +	int uverts = usub + 1;
   13.26 +	int vverts = vsub + 1;
   13.27 +
   13.28 +	int num_verts = uverts * vverts;
   13.29 +	int num_quads = usub * vsub;
   13.30 +	int num_tri = num_quads * 2;
   13.31 +
   13.32 +	mesh->clear();
   13.33 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
   13.34 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
   13.35 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
   13.36 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
   13.37 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
   13.38 +
   13.39 +	float du = urange / (float)(uverts - 1);
   13.40 +	float dv = vrange / (float)(vverts - 1);
   13.41 +
   13.42 +	float u = 0.0;
   13.43 +	for(int i=0; i<uverts; i++) {
   13.44 +		float theta = SURAD(u * urange);
   13.45 +
   13.46 +		float v = 0.0;
   13.47 +		for(int j=0; j<vverts; j++) {
   13.48 +			float phi = SVRAD(v * vrange);
   13.49 +
   13.50 +			Vector3 pos = sphvec(theta, phi);
   13.51 +
   13.52 +			*varr++ = pos * rad;
   13.53 +			*narr++ = pos;
   13.54 +			*tarr++ = (sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f)).normalized();
   13.55 +			*uvarr++ = Vector2(u * urange, v * vrange);
   13.56 +
   13.57 +			if(i < usub && j < vsub) {
   13.58 +				int idx = i * vverts + j;
   13.59 +				*idxarr++ = idx;
   13.60 +				*idxarr++ = idx + 1;
   13.61 +				*idxarr++ = idx + vverts + 1;
   13.62 +
   13.63 +				*idxarr++ = idx;
   13.64 +				*idxarr++ = idx + vverts + 1;
   13.65 +				*idxarr++ = idx + vverts;
   13.66 +			}
   13.67 +
   13.68 +			v += dv;
   13.69 +		}
   13.70 +		u += du;
   13.71 +	}
   13.72 +}
   13.73 +
   13.74 +
   13.75 +// -------- cylinder --------
   13.76 +
   13.77 +static Vector3 cylvec(float theta, float height)
   13.78 +{
   13.79 +	return Vector3(sin(theta), height, cos(theta));
   13.80 +}
   13.81 +
   13.82 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
   13.83 +{
   13.84 +	if(usub < 4) usub = 4;
   13.85 +	if(vsub < 1) vsub = 1;
   13.86 +
   13.87 +	int uverts = usub + 1;
   13.88 +	int vverts = vsub + 1;
   13.89 +
   13.90 +	int num_body_verts = uverts * vverts;
   13.91 +	int num_body_quads = usub * vsub;
   13.92 +	int num_body_tri = num_body_quads * 2;
   13.93 +
   13.94 +	int capvverts = capsub ? capsub + 1 : 0;
   13.95 +	int num_cap_verts = uverts * capvverts;
   13.96 +	int num_cap_quads = usub * capsub;
   13.97 +	int num_cap_tri = num_cap_quads * 2;
   13.98 +
   13.99 +	int num_verts = num_body_verts + num_cap_verts * 2;
  13.100 +	int num_tri = num_body_tri + num_cap_tri * 2;
  13.101 +
  13.102 +	mesh->clear();
  13.103 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  13.104 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  13.105 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  13.106 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  13.107 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  13.108 +
  13.109 +	float du = urange / (float)(uverts - 1);
  13.110 +	float dv = vrange / (float)(vverts - 1);
  13.111 +
  13.112 +	float u = 0.0;
  13.113 +	for(int i=0; i<uverts; i++) {
  13.114 +		float theta = SURAD(u);
  13.115 +
  13.116 +		float v = 0.0;
  13.117 +		for(int j=0; j<vverts; j++) {
  13.118 +			float y = (v - 0.5) * height;
  13.119 +			Vector3 pos = cylvec(theta, y);
  13.120 +
  13.121 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  13.122 +			*narr++ = Vector3(pos.x, 0.0, pos.z);
  13.123 +			*tarr++ = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  13.124 +			*uvarr++ = Vector2(u * urange, v * vrange);
  13.125 +
  13.126 +			if(i < usub && j < vsub) {
  13.127 +				int idx = i * vverts + j;
  13.128 +
  13.129 +				*idxarr++ = idx;
  13.130 +				*idxarr++ = idx + vverts + 1;
  13.131 +				*idxarr++ = idx + 1;
  13.132 +
  13.133 +				*idxarr++ = idx;
  13.134 +				*idxarr++ = idx + vverts;
  13.135 +				*idxarr++ = idx + vverts + 1;
  13.136 +			}
  13.137 +
  13.138 +			v += dv;
  13.139 +		}
  13.140 +		u += du;
  13.141 +	}
  13.142 +
  13.143 +
  13.144 +	// now the cap!
  13.145 +	if(!capsub) {
  13.146 +		return;
  13.147 +	}
  13.148 +
  13.149 +	dv = 1.0 / (float)(capvverts - 1);
  13.150 +
  13.151 +	u = 0.0;
  13.152 +	for(int i=0; i<uverts; i++) {
  13.153 +		float theta = SURAD(u);
  13.154 +
  13.155 +		float v = 0.0;
  13.156 +		for(int j=0; j<capvverts; j++) {
  13.157 +			float r = v * rad;
  13.158 +
  13.159 +			Vector3 pos = cylvec(theta, height / 2.0) * r;
  13.160 +			pos.y = height / 2.0;
  13.161 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  13.162 +
  13.163 +			*varr++ = pos;
  13.164 +			*narr++ = Vector3(0, 1, 0);
  13.165 +			*tarr++ = tang;
  13.166 +			*uvarr++ = Vector2(u * urange, v);
  13.167 +
  13.168 +			pos.y = -height / 2.0;
  13.169 +			*varr++ = pos;
  13.170 +			*narr++ = Vector3(0, -1, 0);
  13.171 +			*tarr++ = -tang;
  13.172 +			*uvarr++ = Vector2(u * urange, v);
  13.173 +
  13.174 +			if(i < usub && j < capsub) {
  13.175 +				unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
  13.176 +
  13.177 +				unsigned int vidx[4] = {
  13.178 +					idx,
  13.179 +					idx + capvverts * 2,
  13.180 +					idx + (capvverts + 1) * 2,
  13.181 +					idx + 2
  13.182 +				};
  13.183 +
  13.184 +				*idxarr++ = vidx[0];
  13.185 +				*idxarr++ = vidx[2];
  13.186 +				*idxarr++ = vidx[1];
  13.187 +				*idxarr++ = vidx[0];
  13.188 +				*idxarr++ = vidx[3];
  13.189 +				*idxarr++ = vidx[2];
  13.190 +
  13.191 +				*idxarr++ = vidx[0] + 1;
  13.192 +				*idxarr++ = vidx[1] + 1;
  13.193 +				*idxarr++ = vidx[2] + 1;
  13.194 +				*idxarr++ = vidx[0] + 1;
  13.195 +				*idxarr++ = vidx[2] + 1;
  13.196 +				*idxarr++ = vidx[3] + 1;
  13.197 +			}
  13.198 +
  13.199 +			v += dv;
  13.200 +		}
  13.201 +		u += du;
  13.202 +	}
  13.203 +}
  13.204 +
  13.205 +// -------- cone --------
  13.206 +
  13.207 +static Vector3 conevec(float theta, float y, float height)
  13.208 +{
  13.209 +	float scale = 1.0 - y / height;
  13.210 +	return Vector3(sin(theta) * scale, y, cos(theta) * scale);
  13.211 +}
  13.212 +
  13.213 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
  13.214 +{
  13.215 +	if(usub < 4) usub = 4;
  13.216 +	if(vsub < 1) vsub = 1;
  13.217 +
  13.218 +	int uverts = usub + 1;
  13.219 +	int vverts = vsub + 1;
  13.220 +
  13.221 +	int num_body_verts = uverts * vverts;
  13.222 +	int num_body_quads = usub * vsub;
  13.223 +	int num_body_tri = num_body_quads * 2;
  13.224 +
  13.225 +	int capvverts = capsub ? capsub + 1 : 0;
  13.226 +	int num_cap_verts = uverts * capvverts;
  13.227 +	int num_cap_quads = usub * capsub;
  13.228 +	int num_cap_tri = num_cap_quads * 2;
  13.229 +
  13.230 +	int num_verts = num_body_verts + num_cap_verts;
  13.231 +	int num_tri = num_body_tri + num_cap_tri;
  13.232 +
  13.233 +	mesh->clear();
  13.234 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  13.235 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  13.236 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  13.237 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  13.238 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  13.239 +
  13.240 +	float du = urange / (float)(uverts - 1);
  13.241 +	float dv = vrange / (float)(vverts - 1);
  13.242 +
  13.243 +	float u = 0.0;
  13.244 +	for(int i=0; i<uverts; i++) {
  13.245 +		float theta = SURAD(u);
  13.246 +
  13.247 +		float v = 0.0;
  13.248 +		for(int j=0; j<vverts; j++) {
  13.249 +			float y = v * height;
  13.250 +			Vector3 pos = conevec(theta, y, height);
  13.251 +
  13.252 +			Vector3 tang = (conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height)).normalized();
  13.253 +			Vector3 bitang = (conevec(theta, y + 0.1, height) - pos).normalized();
  13.254 +
  13.255 +			*varr++ = Vector3(pos.x * rad, pos.y, pos.z * rad);
  13.256 +			*narr++ = cross_product(tang, bitang);
  13.257 +			*tarr++ = tang;
  13.258 +			*uvarr++ = Vector2(u * urange, v * vrange);
  13.259 +
  13.260 +			if(i < usub && j < vsub) {
  13.261 +				int idx = i * vverts + j;
  13.262 +
  13.263 +				*idxarr++ = idx;
  13.264 +				*idxarr++ = idx + vverts + 1;
  13.265 +				*idxarr++ = idx + 1;
  13.266 +
  13.267 +				*idxarr++ = idx;
  13.268 +				*idxarr++ = idx + vverts;
  13.269 +				*idxarr++ = idx + vverts + 1;
  13.270 +			}
  13.271 +
  13.272 +			v += dv;
  13.273 +		}
  13.274 +		u += du;
  13.275 +	}
  13.276 +
  13.277 +
  13.278 +	// now the bottom cap!
  13.279 +	if(!capsub) {
  13.280 +		return;
  13.281 +	}
  13.282 +
  13.283 +	dv = 1.0 / (float)(capvverts - 1);
  13.284 +
  13.285 +	u = 0.0;
  13.286 +	for(int i=0; i<uverts; i++) {
  13.287 +		float theta = SURAD(u);
  13.288 +
  13.289 +		float v = 0.0;
  13.290 +		for(int j=0; j<capvverts; j++) {
  13.291 +			float r = v * rad;
  13.292 +
  13.293 +			Vector3 pos = conevec(theta, 0.0, height) * r;
  13.294 +			Vector3 tang = (cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)).normalized();
  13.295 +
  13.296 +			*varr++ = pos;
  13.297 +			*narr++ = Vector3(0, -1, 0);
  13.298 +			*tarr++ = tang;
  13.299 +			*uvarr++ = Vector2(u * urange, v);
  13.300 +
  13.301 +			if(i < usub && j < capsub) {
  13.302 +				unsigned int idx = num_body_verts + i * capvverts + j;
  13.303 +
  13.304 +				unsigned int vidx[4] = {
  13.305 +					idx,
  13.306 +					idx + capvverts,
  13.307 +					idx + (capvverts + 1),
  13.308 +					idx + 1
  13.309 +				};
  13.310 +
  13.311 +				*idxarr++ = vidx[0];
  13.312 +				*idxarr++ = vidx[1];
  13.313 +				*idxarr++ = vidx[2];
  13.314 +				*idxarr++ = vidx[0];
  13.315 +				*idxarr++ = vidx[2];
  13.316 +				*idxarr++ = vidx[3];
  13.317 +			}
  13.318 +
  13.319 +			v += dv;
  13.320 +		}
  13.321 +		u += du;
  13.322 +	}
  13.323 +}
  13.324 +
  13.325 +
  13.326 +// -------- plane --------
  13.327 +
  13.328 +void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
  13.329 +{
  13.330 +	gen_heightmap(mesh, width, height, usub, vsub, 0);
  13.331 +}
  13.332 +
  13.333 +
  13.334 +// ----- heightmap ------
  13.335 +
  13.336 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
  13.337 +{
  13.338 +	if(usub < 1) usub = 1;
  13.339 +	if(vsub < 1) vsub = 1;
  13.340 +
  13.341 +	mesh->clear();
  13.342 +
  13.343 +	int uverts = usub + 1;
  13.344 +	int vverts = vsub + 1;
  13.345 +	int num_verts = uverts * vverts;
  13.346 +
  13.347 +	int num_quads = usub * vsub;
  13.348 +	int num_tri = num_quads * 2;
  13.349 +
  13.350 +	Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
  13.351 +	Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
  13.352 +	Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
  13.353 +	Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
  13.354 +	unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
  13.355 +
  13.356 +	float du = 1.0 / (float)usub;
  13.357 +	float dv = 1.0 / (float)vsub;
  13.358 +
  13.359 +	float u = 0.0;
  13.360 +	for(int i=0; i<uverts; i++) {
  13.361 +		float v = 0.0;
  13.362 +		for(int j=0; j<vverts; j++) {
  13.363 +			float x = (u - 0.5) * width;
  13.364 +			float y = (v - 0.5) * height;
  13.365 +			float z = hf ? hf(u, v, hfdata) : 0.0;
  13.366 +
  13.367 +			Vector3 normal = Vector3(0, 0, 1);
  13.368 +			if(hf) {
  13.369 +				float u1z = hf(u + du, v, hfdata);
  13.370 +				float v1z = hf(u, v + dv, hfdata);
  13.371 +
  13.372 +				Vector3 tang = Vector3(du * width, 0, u1z - z);
  13.373 +				Vector3 bitan = Vector3(0, dv * height, v1z - z);
  13.374 +				normal = cross_product(tang, bitan).normalized();
  13.375 +			}
  13.376 +
  13.377 +			*varr++ = Vector3(x, y, z);
  13.378 +			*narr++ = normal;
  13.379 +			*tarr++ = Vector3(1, 0, 0);
  13.380 +			*uvarr++ = Vector2(u, v);
  13.381 +
  13.382 +			if(i < usub && j < vsub) {
  13.383 +				int idx = i * vverts + j;
  13.384 +
  13.385 +				*idxarr++ = idx;
  13.386 +				*idxarr++ = idx + vverts + 1;
  13.387 +				*idxarr++ = idx + 1;
  13.388 +
  13.389 +				*idxarr++ = idx;
  13.390 +				*idxarr++ = idx + vverts;
  13.391 +				*idxarr++ = idx + vverts + 1;
  13.392 +			}
  13.393 +
  13.394 +			v += dv;
  13.395 +		}
  13.396 +		u += du;
  13.397 +	}
  13.398 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/meshgen.h	Thu Jun 18 03:12:30 2015 +0300
    14.3 @@ -0,0 +1,12 @@
    14.4 +#ifndef MESHGEN_H_
    14.5 +#define MESHGEN_H_
    14.6 +
    14.7 +class Mesh;
    14.8 +
    14.9 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange = 1.0, float vrange = 1.0);
   14.10 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   14.11 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0);
   14.12 +void gen_plane(Mesh *mesh, float width, float height, int usub = 1, int vsub = 1);
   14.13 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata = 0);
   14.14 +
   14.15 +#endif	// MESHGEN_H_
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/pc/camera.c	Thu Jun 18 03:12:30 2015 +0300
    15.3 @@ -0,0 +1,42 @@
    15.4 +#include "camera.h"
    15.5 +
    15.6 +int cam_init(void *platform_data)
    15.7 +{
    15.8 +	return -1;
    15.9 +}
   15.10 +
   15.11 +void cam_shutdown(void)
   15.12 +{
   15.13 +}
   15.14 +
   15.15 +unsigned int cam_texture(void)
   15.16 +{
   15.17 +}
   15.18 +
   15.19 +const float *cam_texture_matrix(void)
   15.20 +{
   15.21 +}
   15.22 +
   15.23 +int cam_start_video(void)
   15.24 +{
   15.25 +}
   15.26 +
   15.27 +int cam_stop_video(void)
   15.28 +{
   15.29 +}
   15.30 +
   15.31 +int cam_update(void)
   15.32 +{
   15.33 +}
   15.34 +
   15.35 +int cam_is_capturing(void)
   15.36 +{
   15.37 +}
   15.38 +
   15.39 +int cam_video_size(int *xsz, int *ysz)
   15.40 +{
   15.41 +}
   15.42 +
   15.43 +int cam_take_picture(void)
   15.44 +{
   15.45 +}