tavli

changeset 0:52e0dd47753b

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 21 Jun 2015 06:30:39 +0300
parents
children 3fcd7b4d631f
files .hgignore Makefile src/board.cc src/board.h src/game.cc src/game.h src/geom.cc src/geom.h src/main.cc src/mesh.cc src/mesh.h src/opengl.h
diffstat 12 files changed, 2097 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sun Jun 21 06:30:39 2015 +0300
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.swp$
     1.6 +\.d$
     1.7 +^tavli$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Sun Jun 21 06:30:39 2015 +0300
     2.3 @@ -0,0 +1,31 @@
     2.4 +PREFIX ?= /usr/local
     2.5 +
     2.6 +src = $(wildcard src/*.cc)
     2.7 +obj = $(src:.cc=.o)
     2.8 +
     2.9 +bin = tavli
    2.10 +
    2.11 +CXXFLAGS = -pedantic -Wall -g
    2.12 +LDFLAGS = $(libgl)
    2.13 +
    2.14 +ifeq ($(shell uname -s), Darwin)
    2.15 +	libgl = -framework OpenGL -framework GLUT -lGLEW
    2.16 +else
    2.17 +	libgl = -lGL -lGLU -lglut -lGLEW
    2.18 +endif
    2.19 +
    2.20 +$(bin): $(obj)
    2.21 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    2.22 +
    2.23 +.PHONY: clean
    2.24 +clean:
    2.25 +	rm -f $(obj) $(bin)
    2.26 +
    2.27 +.PHONY: install
    2.28 +install: $(bin)
    2.29 +	mkdir -p $(PREFIX)/bin
    2.30 +	cp $(bin) $(PREFIX)/bin/$(bin)
    2.31 +
    2.32 +.PHONY: uninstall
    2.33 +uninstall:
    2.34 +	rm -f $(PREFIX)/bin/$(bin)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/board.cc	Sun Jun 21 06:30:39 2015 +0300
     3.3 @@ -0,0 +1,54 @@
     3.4 +#include "opengl.h"
     3.5 +#include "board.h"
     3.6 +
     3.7 +static Mesh *gen_board_mesh();
     3.8 +static Mesh *gen_puck_mesh();
     3.9 +
    3.10 +Board::Board()
    3.11 +{
    3.12 +	clear();
    3.13 +}
    3.14 +
    3.15 +Board::~Board()
    3.16 +{
    3.17 +	destroy();
    3.18 +}
    3.19 +
    3.20 +bool Board::init()
    3.21 +{
    3.22 +	if(!(board_mesh = gen_board_mesh())) {
    3.23 +		return false;
    3.24 +	}
    3.25 +	if(!(puck_mesh = gen_puck_mesh())) {
    3.26 +		return false;
    3.27 +	}
    3.28 +	return true;
    3.29 +}
    3.30 +
    3.31 +void Board::destroy()
    3.32 +{
    3.33 +	delete board_mesh;
    3.34 +	delete puck_mesh;
    3.35 +	board_mesh = puck_mesh = 0;
    3.36 +}
    3.37 +
    3.38 +void Board::clear()
    3.39 +{
    3.40 +	memset(slots, 0, sizeof slots);
    3.41 +}
    3.42 +
    3.43 +void Board::draw() const
    3.44 +{
    3.45 +	if(board_mesh)
    3.46 +		board_mesh->draw();
    3.47 +}
    3.48 +
    3.49 +static Mesh *gen_board_mesh()
    3.50 +{
    3.51 +	return 0;
    3.52 +}
    3.53 +
    3.54 +static Mesh *gen_puck_mesh()
    3.55 +{
    3.56 +	return 0;
    3.57 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/board.h	Sun Jun 21 06:30:39 2015 +0300
     4.3 @@ -0,0 +1,28 @@
     4.4 +#ifndef BOARD_H_
     4.5 +#define BOARD_H_
     4.6 +
     4.7 +#include "mesh.h"
     4.8 +
     4.9 +#define NUM_SLOTS	24
    4.10 +#define MAX_PUCKS	30
    4.11 +
    4.12 +enum { EMPTY = 0, MINE, OTHER };
    4.13 +
    4.14 +class Board {
    4.15 +private:
    4.16 +	int slots[NUM_SLOTS][MAX_PUCKS];
    4.17 +	Mesh *board_mesh, *puck_mesh;
    4.18 +
    4.19 +public:
    4.20 +	Board();
    4.21 +	~Board();
    4.22 +
    4.23 +	bool init();
    4.24 +	void destroy();
    4.25 +
    4.26 +	void clear();
    4.27 +
    4.28 +	void draw() const;
    4.29 +};
    4.30 +
    4.31 +#endif	// BOARD_H_
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/game.cc	Sun Jun 21 06:30:39 2015 +0300
     5.3 @@ -0,0 +1,132 @@
     5.4 +#include <stdio.h>
     5.5 +#include <GL/glew.h>
     5.6 +#include "game.h"
     5.7 +
     5.8 +static void draw_backdrop();
     5.9 +
    5.10 +int win_width, win_height;
    5.11 +
    5.12 +static float cam_theta, cam_phi = 25, cam_dist = 6;
    5.13 +static bool bnstate[8];
    5.14 +static int prev_x, prev_y;
    5.15 +
    5.16 +
    5.17 +bool game_init()
    5.18 +{
    5.19 +	glEnable(GL_DEPTH_TEST);
    5.20 +	glEnable(GL_CULL_FACE);
    5.21 +
    5.22 +	glEnable(GL_LIGHTING);
    5.23 +	glEnable(GL_LIGHT0);
    5.24 +
    5.25 +	return true;
    5.26 +}
    5.27 +
    5.28 +void game_cleanup()
    5.29 +{
    5.30 +}
    5.31 +
    5.32 +void game_update(unsigned long time_msec)
    5.33 +{
    5.34 +}
    5.35 +
    5.36 +void game_display()
    5.37 +{
    5.38 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    5.39 +
    5.40 +	glMatrixMode(GL_MODELVIEW);
    5.41 +	glLoadIdentity();
    5.42 +	glTranslatef(0, 0, -cam_dist);
    5.43 +	glRotatef(cam_phi, 1, 0, 0);
    5.44 +	glRotatef(cam_theta, 0, 1, 0);
    5.45 +
    5.46 +	draw_backdrop();
    5.47 +
    5.48 +	glBegin(GL_QUADS);
    5.49 +	glNormal3f(0, 1, 0);
    5.50 +	glVertex3f(-1, 0, 1);
    5.51 +	glVertex3f(1, 0, 1);
    5.52 +	glVertex3f(1, 0, -1);
    5.53 +	glVertex3f(-1, 0, -1);
    5.54 +	glEnd();
    5.55 +}
    5.56 +
    5.57 +static void draw_backdrop()
    5.58 +{
    5.59 +	glPushAttrib(GL_ENABLE_BIT);
    5.60 +	glDisable(GL_LIGHTING);
    5.61 +	glDisable(GL_DEPTH_TEST);
    5.62 +
    5.63 +	glMatrixMode(GL_PROJECTION);
    5.64 +	glPushMatrix();
    5.65 +	glLoadIdentity();
    5.66 +	glMatrixMode(GL_MODELVIEW);
    5.67 +	glPushMatrix();
    5.68 +	glLoadIdentity();
    5.69 +
    5.70 +	glBegin(GL_QUADS);
    5.71 +	glColor3f(0.9, 0.8, 0.6);
    5.72 +	glVertex2f(-1, -1);
    5.73 +	glVertex2f(1, -1);
    5.74 +	glColor3f(0.4, 0.5, 0.8);
    5.75 +	glVertex2f(1, 1);
    5.76 +	glVertex2f(-1, 1);
    5.77 +	glEnd();
    5.78 +
    5.79 +	glMatrixMode(GL_PROJECTION);
    5.80 +	glPopMatrix();
    5.81 +	glMatrixMode(GL_MODELVIEW);
    5.82 +	glPopMatrix();
    5.83 +
    5.84 +	glPopAttrib();
    5.85 +}
    5.86 +
    5.87 +void game_reshape(int x, int y)
    5.88 +{
    5.89 +	glMatrixMode(GL_PROJECTION);
    5.90 +	glLoadIdentity();
    5.91 +	gluPerspective(50, (float)x / (float)y, 0.5, 500.0);
    5.92 +
    5.93 +	glViewport(0, 0, x, y);
    5.94 +}
    5.95 +
    5.96 +void game_keyboard(int bn, bool press)
    5.97 +{
    5.98 +	if(press) {
    5.99 +		switch(bn) {
   5.100 +		case 27:
   5.101 +			quit();
   5.102 +		}
   5.103 +	}
   5.104 +}
   5.105 +
   5.106 +void game_mbutton(int bn, bool press, int x, int y)
   5.107 +{
   5.108 +	bnstate[bn] = press;
   5.109 +	prev_x = x;
   5.110 +	prev_y = y;
   5.111 +}
   5.112 +
   5.113 +void game_mmotion(int x, int y)
   5.114 +{
   5.115 +	int dx = x - prev_x;
   5.116 +	int dy = y - prev_y;
   5.117 +	prev_x = x;
   5.118 +	prev_y = y;
   5.119 +
   5.120 +	if(bnstate[0]) {
   5.121 +		cam_theta += dx * 0.5;
   5.122 +		cam_phi += dy * 0.5;
   5.123 +
   5.124 +		if(cam_phi < -90) cam_phi = -90;
   5.125 +		if(cam_phi > 90) cam_phi = 90;
   5.126 +
   5.127 +		redisplay();
   5.128 +	}
   5.129 +	if(bnstate[2]) {
   5.130 +		cam_dist += dy * 0.1;
   5.131 +		if(cam_dist < 0.0) cam_dist = 0.0;
   5.132 +
   5.133 +		redisplay();
   5.134 +	}
   5.135 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/game.h	Sun Jun 21 06:30:39 2015 +0300
     6.3 @@ -0,0 +1,18 @@
     6.4 +#ifndef GAME_H_
     6.5 +#define GAME_H_
     6.6 +
     6.7 +extern int win_width, win_height;
     6.8 +
     6.9 +bool game_init();
    6.10 +void game_cleanup();
    6.11 +void game_update(unsigned long time_msec);
    6.12 +void game_display();
    6.13 +void game_reshape(int x, int y);
    6.14 +void game_keyboard(int bn, bool press);
    6.15 +void game_mbutton(int bn, bool press, int x, int y);
    6.16 +void game_mmotion(int x, int y);
    6.17 +
    6.18 +void redisplay();
    6.19 +void quit();
    6.20 +
    6.21 +#endif	/* GAME_H_ */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/geom.cc	Sun Jun 21 06:30:39 2015 +0300
     7.3 @@ -0,0 +1,251 @@
     7.4 +#include <algorithm>
     7.5 +#include <float.h>
     7.6 +#include "geom.h"
     7.7 +
     7.8 +GeomObject::~GeomObject()
     7.9 +{
    7.10 +}
    7.11 +
    7.12 +
    7.13 +Sphere::Sphere()
    7.14 +{
    7.15 +	radius = 1.0;
    7.16 +}
    7.17 +
    7.18 +Sphere::Sphere(const Vector3 &cent, float radius)
    7.19 +	: center(cent)
    7.20 +{
    7.21 +	this->radius = radius;
    7.22 +}
    7.23 +
    7.24 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
    7.25 +{
    7.26 +	const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
    7.27 +	const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
    7.28 +
    7.29 +	if(!sph1 || !sph2) {
    7.30 +		fprintf(stderr, "Sphere::set_union: arguments must be spheres");
    7.31 +		return;
    7.32 +	}
    7.33 +
    7.34 +	float dist = (sph1->center - sph2->center).length();
    7.35 +	float surf_dist = dist - (sph1->radius + sph2->radius);
    7.36 +	float d1 = sph1->radius + surf_dist / 2.0;
    7.37 +	float d2 = sph2->radius + surf_dist / 2.0;
    7.38 +	float t = d1 / (d1 + d2);
    7.39 +
    7.40 +	if(t < 0.0) t = 0.0;
    7.41 +	if(t > 1.0) t = 1.0;
    7.42 +
    7.43 +	center = sph1->center * t + sph2->center * (1.0 - t);
    7.44 +	radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
    7.45 +}
    7.46 +
    7.47 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
    7.48 +{
    7.49 +	fprintf(stderr, "Sphere::intersection undefined\n");
    7.50 +}
    7.51 +
    7.52 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
    7.53 +{
    7.54 +	float a = dot_product(ray.dir, ray.dir);
    7.55 +	float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
    7.56 +		2.0 * ray.dir.y * (ray.origin.y - center.y) +
    7.57 +		2.0 * ray.dir.z * (ray.origin.z - center.z);
    7.58 +	float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
    7.59 +		2.0 * dot_product(ray.origin, center) - radius * radius;
    7.60 +
    7.61 +	float discr = b * b - 4.0 * a * c;
    7.62 +	if(discr < 1e-4) {
    7.63 +		return false;
    7.64 +	}
    7.65 +
    7.66 +	float sqrt_discr = sqrt(discr);
    7.67 +	float t0 = (-b + sqrt_discr) / (2.0 * a);
    7.68 +	float t1 = (-b - sqrt_discr) / (2.0 * a);
    7.69 +
    7.70 +	if(t0 < 1e-4)
    7.71 +		t0 = t1;
    7.72 +	if(t1 < 1e-4)
    7.73 +		t1 = t0;
    7.74 +
    7.75 +	float t = t0 < t1 ? t0 : t1;
    7.76 +	if(t < 1e-4) {
    7.77 +		return false;
    7.78 +	}
    7.79 +
    7.80 +	// fill the HitPoint structure
    7.81 +	if(hit) {
    7.82 +		hit->obj = this;
    7.83 +		hit->dist = t;
    7.84 +		hit->pos = ray.origin + ray.dir * t;
    7.85 +		hit->normal = (hit->pos - center) / radius;
    7.86 +	}
    7.87 +	return true;
    7.88 +}
    7.89 +
    7.90 +
    7.91 +AABox::AABox()
    7.92 +{
    7.93 +}
    7.94 +
    7.95 +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
    7.96 +	: min(vmin), max(vmax)
    7.97 +{
    7.98 +}
    7.99 +
   7.100 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
   7.101 +{
   7.102 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   7.103 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   7.104 +
   7.105 +	if(!box1 || !box2) {
   7.106 +		fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n");
   7.107 +		return;
   7.108 +	}
   7.109 +
   7.110 +	min.x = std::min(box1->min.x, box2->min.x);
   7.111 +	min.y = std::min(box1->min.y, box2->min.y);
   7.112 +	min.z = std::min(box1->min.z, box2->min.z);
   7.113 +
   7.114 +	max.x = std::max(box1->max.x, box2->max.x);
   7.115 +	max.y = std::max(box1->max.y, box2->max.y);
   7.116 +	max.z = std::max(box1->max.z, box2->max.z);
   7.117 +}
   7.118 +
   7.119 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   7.120 +{
   7.121 +	const AABox *box1 = dynamic_cast<const AABox*>(obj1);
   7.122 +	const AABox *box2 = dynamic_cast<const AABox*>(obj2);
   7.123 +
   7.124 +	if(!box1 || !box2) {
   7.125 +		fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n");
   7.126 +		return;
   7.127 +	}
   7.128 +
   7.129 +	for(int i=0; i<3; i++) {
   7.130 +		min[i] = std::max(box1->min[i], box2->min[i]);
   7.131 +		max[i] = std::min(box1->max[i], box2->max[i]);
   7.132 +
   7.133 +		if(max[i] < min[i]) {
   7.134 +			max[i] = min[i];
   7.135 +		}
   7.136 +	}
   7.137 +}
   7.138 +
   7.139 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const
   7.140 +{
   7.141 +	Vector3 param[2] = {min, max};
   7.142 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
   7.143 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
   7.144 +
   7.145 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
   7.146 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
   7.147 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
   7.148 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
   7.149 +
   7.150 +	if(tmin > tymax || tymin > tmax) {
   7.151 +		return false;
   7.152 +	}
   7.153 +	if(tymin > tmin) {
   7.154 +		tmin = tymin;
   7.155 +	}
   7.156 +	if(tymax < tmax) {
   7.157 +		tmax = tymax;
   7.158 +	}
   7.159 +
   7.160 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
   7.161 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
   7.162 +
   7.163 +	if(tmin > tzmax || tzmin > tmax) {
   7.164 +		return false;
   7.165 +	}
   7.166 +	if(tzmin > tmin) {
   7.167 +		tmin = tzmin;
   7.168 +	}
   7.169 +	if(tzmax < tmax) {
   7.170 +		tmax = tzmax;
   7.171 +	}
   7.172 +
   7.173 +	float t = tmin < 1e-4 ? tmax : tmin;
   7.174 +	if(t >= 1e-4) {
   7.175 +
   7.176 +		if(hit) {
   7.177 +			hit->obj = this;
   7.178 +			hit->dist = t;
   7.179 +			hit->pos = ray.origin + ray.dir * t;
   7.180 +
   7.181 +			float min_dist = FLT_MAX;
   7.182 +			Vector3 offs = min + (max - min) / 2.0;
   7.183 +			Vector3 local_hit = hit->pos - offs;
   7.184 +
   7.185 +			static const Vector3 axis[] = {
   7.186 +				Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
   7.187 +			};
   7.188 +			//int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
   7.189 +
   7.190 +			for(int i=0; i<3; i++) {
   7.191 +				float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
   7.192 +				if(dist < min_dist) {
   7.193 +					min_dist = dist;
   7.194 +					hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
   7.195 +					//hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
   7.196 +				}
   7.197 +			}
   7.198 +		}
   7.199 +		return true;
   7.200 +	}
   7.201 +	return false;
   7.202 +
   7.203 +}
   7.204 +
   7.205 +Plane::Plane()
   7.206 +	: normal(0.0, 1.0, 0.0)
   7.207 +{
   7.208 +}
   7.209 +
   7.210 +Plane::Plane(const Vector3 &p, const Vector3 &norm)
   7.211 +	: pt(p)
   7.212 +{
   7.213 +	normal = norm.normalized();
   7.214 +}
   7.215 +
   7.216 +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
   7.217 +	: pt(p1)
   7.218 +{
   7.219 +	normal = cross_product(p2 - p1, p3 - p1).normalized();
   7.220 +}
   7.221 +
   7.222 +Plane::Plane(const Vector3 &normal, float dist)
   7.223 +{
   7.224 +	this->normal = normal.normalized();
   7.225 +	pt = this->normal * dist;
   7.226 +}
   7.227 +
   7.228 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
   7.229 +{
   7.230 +	fprintf(stderr, "Plane::set_union undefined\n");
   7.231 +}
   7.232 +
   7.233 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
   7.234 +{
   7.235 +	fprintf(stderr, "Plane::set_intersection undefined\n");
   7.236 +}
   7.237 +
   7.238 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const
   7.239 +{
   7.240 +	float ndotdir = dot_product(normal, ray.dir);
   7.241 +	if(fabs(ndotdir) < 1e-4) {
   7.242 +		return false;
   7.243 +	}
   7.244 +
   7.245 +	if(hit) {
   7.246 +		Vector3 ptdir = pt - ray.origin;
   7.247 +		float t = dot_product(normal, ptdir) / ndotdir;
   7.248 +
   7.249 +		hit->pos = ray.origin + ray.dir * t;
   7.250 +		hit->normal = normal;
   7.251 +		hit->obj = this;
   7.252 +	}
   7.253 +	return true;
   7.254 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/geom.h	Sun Jun 21 06:30:39 2015 +0300
     8.3 @@ -0,0 +1,67 @@
     8.4 +#ifndef GEOMOBJ_H_
     8.5 +#define GEOMOBJ_H_
     8.6 +
     8.7 +#include "vmath/vmath.h"
     8.8 +
     8.9 +class GeomObject;
    8.10 +
    8.11 +struct HitPoint {
    8.12 +	float dist;				//< parametric distance along the ray
    8.13 +	Vector3 pos;			//< position of intersection (orig + dir * dist)
    8.14 +	Vector3 normal;			//< normal at the point of intersection
    8.15 +	const void *obj;		//< pointer to the intersected object
    8.16 +};
    8.17 +
    8.18 +class GeomObject {
    8.19 +public:
    8.20 +	virtual ~GeomObject();
    8.21 +
    8.22 +	virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0;
    8.23 +	virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0;
    8.24 +
    8.25 +	virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0;
    8.26 +};
    8.27 +
    8.28 +class Sphere : public GeomObject {
    8.29 +public:
    8.30 +	Vector3 center;
    8.31 +	float radius;
    8.32 +
    8.33 +	Sphere();
    8.34 +	Sphere(const Vector3 &center, float radius);
    8.35 +
    8.36 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
    8.37 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
    8.38 +
    8.39 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    8.40 +};
    8.41 +
    8.42 +class AABox : public GeomObject {
    8.43 +public:
    8.44 +	Vector3 min, max;
    8.45 +
    8.46 +	AABox();
    8.47 +	AABox(const Vector3 &min, const Vector3 &max);
    8.48 +
    8.49 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
    8.50 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
    8.51 +
    8.52 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    8.53 +};
    8.54 +
    8.55 +class Plane : public GeomObject {
    8.56 +public:
    8.57 +	Vector3 pt, normal;
    8.58 +
    8.59 +	Plane();
    8.60 +	Plane(const Vector3 &pt, const Vector3 &normal);
    8.61 +	Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3);
    8.62 +	Plane(const Vector3 &normal, float dist);
    8.63 +
    8.64 +	void set_union(const GeomObject *obj1, const GeomObject *obj2);
    8.65 +	void set_intersection(const GeomObject *obj1, const GeomObject *obj2);
    8.66 +
    8.67 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
    8.68 +};
    8.69 +
    8.70 +#endif	// GEOMOBJ_H_
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/main.cc	Sun Jun 21 06:30:39 2015 +0300
     9.3 @@ -0,0 +1,91 @@
     9.4 +#include <stdio.h>
     9.5 +#include <stdlib.h>
     9.6 +#include <assert.h>
     9.7 +#include <GL/glew.h>
     9.8 +#ifdef __APPLE__
     9.9 +#include <GLUT/glut.h>
    9.10 +#else
    9.11 +#include <GL/glut.h>
    9.12 +#endif
    9.13 +#include "game.h"
    9.14 +
    9.15 +static void display();
    9.16 +static void reshape(int x, int y);
    9.17 +static void keypress(unsigned char key, int x, int y);
    9.18 +static void keyrelease(unsigned char key, int x, int y);
    9.19 +static void mouse(int bn, int st, int x, int y);
    9.20 +static void motion(int x, int y);
    9.21 +
    9.22 +int main(int argc, char **argv)
    9.23 +{
    9.24 +	glutInit(&argc, argv);
    9.25 +	glutInitWindowSize(1280, 800);
    9.26 +	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    9.27 +	glutCreateWindow("Tavli");
    9.28 +
    9.29 +	glutDisplayFunc(display);
    9.30 +	glutReshapeFunc(reshape);
    9.31 +	glutKeyboardFunc(keypress);
    9.32 +	glutKeyboardUpFunc(keyrelease);
    9.33 +	glutMouseFunc(mouse);
    9.34 +	glutMotionFunc(motion);
    9.35 +	glutPassiveMotionFunc(motion);
    9.36 +
    9.37 +	glewInit();
    9.38 +
    9.39 +	if(!game_init()) {
    9.40 +		return 1;
    9.41 +	}
    9.42 +	atexit(game_cleanup);
    9.43 +
    9.44 +	glutMainLoop();
    9.45 +	return 0;
    9.46 +}
    9.47 +
    9.48 +void redisplay()
    9.49 +{
    9.50 +	glutPostRedisplay();
    9.51 +}
    9.52 +
    9.53 +void quit()
    9.54 +{
    9.55 +	exit(0);
    9.56 +}
    9.57 +
    9.58 +static void display()
    9.59 +{
    9.60 +	unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
    9.61 +	game_update(msec);
    9.62 +	game_display();
    9.63 +
    9.64 +	assert(glGetError() == GL_NO_ERROR);
    9.65 +	glutSwapBuffers();
    9.66 +}
    9.67 +
    9.68 +static void reshape(int x, int y)
    9.69 +{
    9.70 +	win_width = x;
    9.71 +	win_height = y;
    9.72 +
    9.73 +	game_reshape(x, y);
    9.74 +}
    9.75 +
    9.76 +static void keypress(unsigned char key, int x, int y)
    9.77 +{
    9.78 +	game_keyboard(key, true);
    9.79 +}
    9.80 +
    9.81 +static void keyrelease(unsigned char key, int x, int y)
    9.82 +{
    9.83 +	game_keyboard(key, false);
    9.84 +}
    9.85 +
    9.86 +static void mouse(int bn, int st, int x, int y)
    9.87 +{
    9.88 +	game_mbutton(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y);
    9.89 +}
    9.90 +
    9.91 +static void motion(int x, int y)
    9.92 +{
    9.93 +	game_mmotion(x, y);
    9.94 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/mesh.cc	Sun Jun 21 06:30:39 2015 +0300
    10.3 @@ -0,0 +1,1190 @@
    10.4 +#include <stdio.h>
    10.5 +#include <stdlib.h>
    10.6 +#include <float.h>
    10.7 +#include <assert.h>
    10.8 +#include "opengl.h"
    10.9 +#include "mesh.h"
   10.10 +//#include "xform_node.h"
   10.11 +#include "shader.h"
   10.12 +
   10.13 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = {
   10.14 +	(int)SDR_ATTR_VERTEX,
   10.15 +	(int)SDR_ATTR_NORMAL,
   10.16 +	(int)SDR_ATTR_TANGENT,
   10.17 +	(int)SDR_ATTR_TEXCOORD,
   10.18 +	(int)SDR_ATTR_COLOR,
   10.19 +	-1, -1};
   10.20 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
   10.21 +float Mesh::vertex_sel_dist = 0.01;
   10.22 +float Mesh::vis_vecsize = 1.0;
   10.23 +
   10.24 +Mesh::Mesh()
   10.25 +{
   10.26 +	clear();
   10.27 +
   10.28 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   10.29 +
   10.30 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   10.31 +		vattr[i].vbo = buffer_objects[i];
   10.32 +	}
   10.33 +	ibo = buffer_objects[NUM_MESH_ATTR];
   10.34 +	wire_ibo = 0;
   10.35 +}
   10.36 +
   10.37 +Mesh::~Mesh()
   10.38 +{
   10.39 +	glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   10.40 +
   10.41 +	if(wire_ibo) {
   10.42 +		glDeleteBuffers(1, &wire_ibo);
   10.43 +	}
   10.44 +}
   10.45 +
   10.46 +Mesh::Mesh(const Mesh &rhs)
   10.47 +{
   10.48 +	clear();
   10.49 +
   10.50 +	glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
   10.51 +
   10.52 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   10.53 +		vattr[i].vbo = buffer_objects[i];
   10.54 +	}
   10.55 +	ibo = buffer_objects[NUM_MESH_ATTR];
   10.56 +	wire_ibo = 0;
   10.57 +
   10.58 +	clone(rhs);
   10.59 +}
   10.60 +
   10.61 +Mesh &Mesh::operator =(const Mesh &rhs)
   10.62 +{
   10.63 +	if(&rhs != this) {
   10.64 +		clone(rhs);
   10.65 +	}
   10.66 +	return *this;
   10.67 +}
   10.68 +
   10.69 +bool Mesh::clone(const Mesh &m)
   10.70 +{
   10.71 +	clear();
   10.72 +
   10.73 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
   10.74 +		if(m.has_attrib(i)) {
   10.75 +			m.get_attrib_data(i);	// force validation of the actual data on the source mesh
   10.76 +
   10.77 +			vattr[i].nelem = m.vattr[i].nelem;
   10.78 +			vattr[i].data = m.vattr[i].data;	// copy the actual data
   10.79 +			vattr[i].data_valid = true;
   10.80 +		}
   10.81 +	}
   10.82 +
   10.83 +	if(m.is_indexed()) {
   10.84 +		m.get_index_data();		// again, force validation
   10.85 +
   10.86 +		// copy the index data
   10.87 +		idata = m.idata;
   10.88 +		idata_valid = true;
   10.89 +	}
   10.90 +
   10.91 +	name = m.name;
   10.92 +	nverts = m.nverts;
   10.93 +	nfaces = m.nfaces;
   10.94 +
   10.95 +	//bones = m.bones;
   10.96 +
   10.97 +	memcpy(cur_val, m.cur_val, sizeof cur_val);
   10.98 +
   10.99 +	aabb = m.aabb;
  10.100 +	aabb_valid = m.aabb_valid;
  10.101 +	bsph = m.bsph;
  10.102 +	bsph_valid = m.bsph_valid;
  10.103 +
  10.104 +	hitface = m.hitface;
  10.105 +	hitvert = m.hitvert;
  10.106 +
  10.107 +	intersect_mode = m.intersect_mode;
  10.108 +	vertex_sel_dist = m.vertex_sel_dist;
  10.109 +	vis_vecsize = m.vis_vecsize;
  10.110 +
  10.111 +	return true;
  10.112 +}
  10.113 +
  10.114 +void Mesh::set_name(const char *name)
  10.115 +{
  10.116 +	this->name = name;
  10.117 +}
  10.118 +
  10.119 +const char *Mesh::get_name() const
  10.120 +{
  10.121 +	return name.c_str();
  10.122 +}
  10.123 +
  10.124 +bool Mesh::has_attrib(int attr) const
  10.125 +{
  10.126 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  10.127 +		return false;
  10.128 +	}
  10.129 +
  10.130 +	// if neither of these is valid, then nobody has set this attribute
  10.131 +	return vattr[attr].vbo_valid || vattr[attr].data_valid;
  10.132 +}
  10.133 +
  10.134 +bool Mesh::is_indexed() const
  10.135 +{
  10.136 +	return ibo_valid || idata_valid;
  10.137 +}
  10.138 +
  10.139 +void Mesh::clear()
  10.140 +{
  10.141 +	//bones.clear();
  10.142 +
  10.143 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.144 +		vattr[i].nelem = 0;
  10.145 +		vattr[i].vbo_valid = false;
  10.146 +		vattr[i].data_valid = false;
  10.147 +		//vattr[i].sdr_loc = -1;
  10.148 +		vattr[i].data.clear();
  10.149 +	}
  10.150 +	ibo_valid = idata_valid = false;
  10.151 +	idata.clear();
  10.152 +
  10.153 +	wire_ibo_valid = false;
  10.154 +
  10.155 +	nverts = nfaces = 0;
  10.156 +
  10.157 +	bsph_valid = false;
  10.158 +	aabb_valid = false;
  10.159 +}
  10.160 +
  10.161 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
  10.162 +{
  10.163 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  10.164 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  10.165 +		return 0;
  10.166 +	}
  10.167 +
  10.168 +	if(nverts && num != nverts) {
  10.169 +		fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
  10.170 +		return 0;
  10.171 +	}
  10.172 +	nverts = num;
  10.173 +
  10.174 +	vattr[attrib].data.clear();
  10.175 +	vattr[attrib].nelem = nelem;
  10.176 +	vattr[attrib].data.resize(num * nelem);
  10.177 +
  10.178 +	if(data) {
  10.179 +		memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
  10.180 +	}
  10.181 +
  10.182 +	vattr[attrib].data_valid = true;
  10.183 +	vattr[attrib].vbo_valid = false;
  10.184 +	return &vattr[attrib].data[0];
  10.185 +}
  10.186 +
  10.187 +float *Mesh::get_attrib_data(int attrib)
  10.188 +{
  10.189 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  10.190 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  10.191 +		return 0;
  10.192 +	}
  10.193 +
  10.194 +	vattr[attrib].vbo_valid = false;
  10.195 +	return (float*)((const Mesh*)this)->get_attrib_data(attrib);
  10.196 +}
  10.197 +
  10.198 +const float *Mesh::get_attrib_data(int attrib) const
  10.199 +{
  10.200 +	if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
  10.201 +		fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
  10.202 +		return 0;
  10.203 +	}
  10.204 +
  10.205 +	if(!vattr[attrib].data_valid) {
  10.206 +#if GL_ES_VERSION_2_0
  10.207 +		fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
  10.208 +		return 0;
  10.209 +#else
  10.210 +		if(!vattr[attrib].vbo_valid) {
  10.211 +			fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
  10.212 +			return 0;
  10.213 +		}
  10.214 +
  10.215 +		// local data copy is unavailable, grab the data from the vbo
  10.216 +		Mesh *m = (Mesh*)this;
  10.217 +		m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
  10.218 +
  10.219 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
  10.220 +		void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
  10.221 +		memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
  10.222 +		glUnmapBuffer(GL_ARRAY_BUFFER);
  10.223 +
  10.224 +		vattr[attrib].data_valid = true;
  10.225 +#endif
  10.226 +	}
  10.227 +
  10.228 +	return &vattr[attrib].data[0];
  10.229 +}
  10.230 +
  10.231 +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v)
  10.232 +{
  10.233 +	float *data = get_attrib_data(attrib);
  10.234 +	if(data) {
  10.235 +		data += idx * vattr[attrib].nelem;
  10.236 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  10.237 +			data[i] = v[i];
  10.238 +		}
  10.239 +	}
  10.240 +}
  10.241 +
  10.242 +Vector4 Mesh::get_attrib(int attrib, int idx) const
  10.243 +{
  10.244 +	Vector4 v(0.0, 0.0, 0.0, 1.0);
  10.245 +	const float *data = get_attrib_data(attrib);
  10.246 +	if(data) {
  10.247 +		data += idx * vattr[attrib].nelem;
  10.248 +		for(int i=0; i<vattr[attrib].nelem; i++) {
  10.249 +			v[i] = data[i];
  10.250 +		}
  10.251 +	}
  10.252 +	return v;
  10.253 +}
  10.254 +
  10.255 +int Mesh::get_attrib_count(int attrib) const
  10.256 +{
  10.257 +	return has_attrib(attrib) ? nverts : 0;
  10.258 +}
  10.259 +
  10.260 +
  10.261 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
  10.262 +{
  10.263 +	int nidx = nfaces * 3;
  10.264 +	if(nidx && num != nidx) {
  10.265 +		fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
  10.266 +		return 0;
  10.267 +	}
  10.268 +	nfaces = num / 3;
  10.269 +
  10.270 +	idata.clear();
  10.271 +	idata.resize(num);
  10.272 +
  10.273 +	if(indices) {
  10.274 +		memcpy(&idata[0], indices, num * sizeof *indices);
  10.275 +	}
  10.276 +
  10.277 +	idata_valid = true;
  10.278 +	ibo_valid = false;
  10.279 +
  10.280 +	return &idata[0];
  10.281 +}
  10.282 +
  10.283 +unsigned int *Mesh::get_index_data()
  10.284 +{
  10.285 +	ibo_valid = false;
  10.286 +	return (unsigned int*)((const Mesh*)this)->get_index_data();
  10.287 +}
  10.288 +
  10.289 +const unsigned int *Mesh::get_index_data() const
  10.290 +{
  10.291 +	if(!idata_valid) {
  10.292 +#if GL_ES_VERSION_2_0
  10.293 +		fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
  10.294 +		return 0;
  10.295 +#else
  10.296 +		if(!ibo_valid) {
  10.297 +			fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
  10.298 +			return 0;
  10.299 +		}
  10.300 +
  10.301 +		// local data copy is unavailable, gram the data from the ibo
  10.302 +		Mesh *m = (Mesh*)this;
  10.303 +		int nidx = nfaces * 3;
  10.304 +		m->idata.resize(nidx);
  10.305 +
  10.306 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  10.307 +		void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
  10.308 +		memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
  10.309 +		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
  10.310 +
  10.311 +		idata_valid = true;
  10.312 +#endif
  10.313 +	}
  10.314 +
  10.315 +	return &idata[0];
  10.316 +}
  10.317 +
  10.318 +int Mesh::get_index_count() const
  10.319 +{
  10.320 +	return nfaces * 3;
  10.321 +}
  10.322 +
  10.323 +void Mesh::append(const Mesh &mesh)
  10.324 +{
  10.325 +	unsigned int idxoffs = nverts;
  10.326 +
  10.327 +	nverts += mesh.nverts;
  10.328 +	nfaces += mesh.nfaces;
  10.329 +
  10.330 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.331 +		if(has_attrib(i) && mesh.has_attrib(i)) {
  10.332 +			// force validating the data arrays
  10.333 +			get_attrib_data(i);
  10.334 +			mesh.get_attrib_data(i);
  10.335 +
  10.336 +			// append the mesh data
  10.337 +			vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
  10.338 +		}
  10.339 +	}
  10.340 +
  10.341 +	if(ibo_valid || idata_valid) {
  10.342 +		// make index arrays valid
  10.343 +		get_index_data();
  10.344 +		mesh.get_index_data();
  10.345 +
  10.346 +		size_t orig_sz = idata.size();
  10.347 +
  10.348 +		idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
  10.349 +
  10.350 +		// fixup all the new indices
  10.351 +		for(size_t i=orig_sz; i<idata.size(); i++) {
  10.352 +			idata[i] += idxoffs;
  10.353 +		}
  10.354 +	}
  10.355 +
  10.356 +	// fuck everything
  10.357 +	wire_ibo_valid = false;
  10.358 +	aabb_valid = false;
  10.359 +	bsph_valid = false;
  10.360 +}
  10.361 +
  10.362 +// assemble a complete vertex by adding all the useful attributes
  10.363 +void Mesh::vertex(float x, float y, float z)
  10.364 +{
  10.365 +	cur_val[MESH_ATTR_VERTEX] = Vector4(x, y, z, 1.0f);
  10.366 +	vattr[MESH_ATTR_VERTEX].data_valid = true;
  10.367 +	vattr[MESH_ATTR_VERTEX].nelem = 3;
  10.368 +
  10.369 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.370 +		if(vattr[i].data_valid) {
  10.371 +			for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
  10.372 +				vattr[i].data.push_back(cur_val[i][j]);
  10.373 +			}
  10.374 +		}
  10.375 +		vattr[i].vbo_valid = false;
  10.376 +	}
  10.377 +
  10.378 +	if(idata_valid) {
  10.379 +		idata.clear();
  10.380 +	}
  10.381 +	ibo_valid = idata_valid = false;
  10.382 +}
  10.383 +
  10.384 +void Mesh::normal(float nx, float ny, float nz)
  10.385 +{
  10.386 +	cur_val[MESH_ATTR_NORMAL] = Vector4(nx, ny, nz, 1.0f);
  10.387 +	vattr[MESH_ATTR_NORMAL].data_valid = true;
  10.388 +	vattr[MESH_ATTR_NORMAL].nelem = 3;
  10.389 +}
  10.390 +
  10.391 +void Mesh::tangent(float tx, float ty, float tz)
  10.392 +{
  10.393 +	cur_val[MESH_ATTR_TANGENT] = Vector4(tx, ty, tz, 1.0f);
  10.394 +	vattr[MESH_ATTR_TANGENT].data_valid = true;
  10.395 +	vattr[MESH_ATTR_TANGENT].nelem = 3;
  10.396 +}
  10.397 +
  10.398 +void Mesh::texcoord(float u, float v, float w)
  10.399 +{
  10.400 +	cur_val[MESH_ATTR_TEXCOORD] = Vector4(u, v, w, 1.0f);
  10.401 +	vattr[MESH_ATTR_TEXCOORD].data_valid = true;
  10.402 +	vattr[MESH_ATTR_TEXCOORD].nelem = 3;
  10.403 +}
  10.404 +
  10.405 +void Mesh::boneweights(float w1, float w2, float w3, float w4)
  10.406 +{
  10.407 +	cur_val[MESH_ATTR_BONEWEIGHTS] = Vector4(w1, w2, w3, w4);
  10.408 +	vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
  10.409 +	vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
  10.410 +}
  10.411 +
  10.412 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
  10.413 +{
  10.414 +	cur_val[MESH_ATTR_BONEIDX] = Vector4(idx1, idx2, idx3, idx4);
  10.415 +	vattr[MESH_ATTR_BONEIDX].data_valid = true;
  10.416 +	vattr[MESH_ATTR_BONEIDX].nelem = 4;
  10.417 +}
  10.418 +
  10.419 +int Mesh::get_poly_count() const
  10.420 +{
  10.421 +	if(nfaces) {
  10.422 +		return nfaces;
  10.423 +	}
  10.424 +	if(nverts) {
  10.425 +		return nverts / 3;
  10.426 +	}
  10.427 +	return 0;
  10.428 +}
  10.429 +
  10.430 +/// static function
  10.431 +void Mesh::set_attrib_location(int attr, int loc)
  10.432 +{
  10.433 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  10.434 +		return;
  10.435 +	}
  10.436 +	Mesh::global_sdr_loc[attr] = loc;
  10.437 +}
  10.438 +
  10.439 +/// static function
  10.440 +int Mesh::get_attrib_location(int attr)
  10.441 +{
  10.442 +	if(attr < 0 || attr >= NUM_MESH_ATTR) {
  10.443 +		return -1;
  10.444 +	}
  10.445 +	return Mesh::global_sdr_loc[attr];
  10.446 +}
  10.447 +
  10.448 +/// static function
  10.449 +void Mesh::clear_attrib_locations()
  10.450 +{
  10.451 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.452 +		Mesh::global_sdr_loc[i] = -1;
  10.453 +	}
  10.454 +}
  10.455 +
  10.456 +/// static function
  10.457 +void Mesh::set_vis_vecsize(float sz)
  10.458 +{
  10.459 +	Mesh::vis_vecsize = sz;
  10.460 +}
  10.461 +
  10.462 +float Mesh::get_vis_vecsize()
  10.463 +{
  10.464 +	return Mesh::vis_vecsize;
  10.465 +}
  10.466 +
  10.467 +void Mesh::apply_xform(const Matrix4x4 &xform)
  10.468 +{
  10.469 +	Matrix4x4 dir_xform = xform;
  10.470 +	dir_xform[0][3] = dir_xform[1][3] = dir_xform[2][3] = 0.0f;
  10.471 +	dir_xform[3][0] = dir_xform[3][1] = dir_xform[3][2] = 0.0f;
  10.472 +	dir_xform[3][3] = 1.0f;
  10.473 +
  10.474 +	apply_xform(xform, dir_xform);
  10.475 +}
  10.476 +
  10.477 +void Mesh::apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform)
  10.478 +{
  10.479 +	for(unsigned int i=0; i<nverts; i++) {
  10.480 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  10.481 +		set_attrib(MESH_ATTR_VERTEX, i, v.transformed(xform));
  10.482 +
  10.483 +		if(has_attrib(MESH_ATTR_NORMAL)) {
  10.484 +			Vector3 n = get_attrib(MESH_ATTR_NORMAL, i);
  10.485 +			set_attrib(MESH_ATTR_NORMAL, i, n.transformed(dir_xform));
  10.486 +		}
  10.487 +		if(has_attrib(MESH_ATTR_TANGENT)) {
  10.488 +			Vector3 t = get_attrib(MESH_ATTR_TANGENT, i);
  10.489 +			set_attrib(MESH_ATTR_TANGENT, i, t.transformed(dir_xform));
  10.490 +		}
  10.491 +	}
  10.492 +}
  10.493 +
  10.494 +void Mesh::flip()
  10.495 +{
  10.496 +	flip_faces();
  10.497 +	flip_normals();
  10.498 +}
  10.499 +
  10.500 +void Mesh::flip_faces()
  10.501 +{
  10.502 +	if(is_indexed()) {
  10.503 +		unsigned int *indices = get_index_data();
  10.504 +		if(!indices) return;
  10.505 +
  10.506 +		int idxnum = get_index_count();
  10.507 +		for(int i=0; i<idxnum; i+=3) {
  10.508 +			unsigned int tmp = indices[i + 2];
  10.509 +			indices[i + 2] = indices[i + 1];
  10.510 +			indices[i + 1] = tmp;
  10.511 +		}
  10.512 +
  10.513 +	} else {
  10.514 +		Vector3 *verts = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  10.515 +		if(!verts) return;
  10.516 +
  10.517 +		int vnum = get_attrib_count(MESH_ATTR_VERTEX);
  10.518 +		for(int i=0; i<vnum; i+=3) {
  10.519 +			Vector3 tmp = verts[i + 2];
  10.520 +			verts[i + 2] = verts[i + 1];
  10.521 +			verts[i + 1] = tmp;
  10.522 +		}
  10.523 +	}
  10.524 +}
  10.525 +
  10.526 +void Mesh::flip_normals()
  10.527 +{
  10.528 +	Vector3 *normals = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  10.529 +	if(!normals) return;
  10.530 +
  10.531 +	int num = get_attrib_count(MESH_ATTR_NORMAL);
  10.532 +	for(int i=0; i<num; i++) {
  10.533 +		normals[i] = -normals[i];
  10.534 +	}
  10.535 +}
  10.536 +
  10.537 +/*
  10.538 +int Mesh::add_bone(XFormNode *bone)
  10.539 +{
  10.540 +	int idx = bones.size();
  10.541 +	bones.push_back(bone);
  10.542 +	return idx;
  10.543 +}
  10.544 +
  10.545 +const XFormNode *Mesh::get_bone(int idx) const
  10.546 +{
  10.547 +	if(idx < 0 || idx >= (int)bones.size()) {
  10.548 +		return 0;
  10.549 +	}
  10.550 +	return bones[idx];
  10.551 +}
  10.552 +
  10.553 +int Mesh::get_bones_count() const
  10.554 +{
  10.555 +	return (int)bones.size();
  10.556 +}
  10.557 +*/
  10.558 +
  10.559 +void Mesh::draw() const
  10.560 +{
  10.561 +#ifdef GL_ES_VERSION_2_0
  10.562 +	if(!SdrProg::active) {
  10.563 +		fprintf(stderr, "%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__);
  10.564 +		return;
  10.565 +	}
  10.566 +#endif
  10.567 +
  10.568 +	((Mesh*)this)->update_buffers();
  10.569 +
  10.570 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  10.571 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  10.572 +		return;
  10.573 +	}
  10.574 +
  10.575 +	if(SdrProg::active) {
  10.576 +		// rendering with shaders
  10.577 +		if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  10.578 +			fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  10.579 +			return;
  10.580 +		}
  10.581 +
  10.582 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.583 +			int loc = global_sdr_loc[i];
  10.584 +			if(loc >= 0 && vattr[i].vbo_valid) {
  10.585 +				glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  10.586 +				glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  10.587 +				glEnableVertexAttribArray(loc);
  10.588 +			}
  10.589 +		}
  10.590 +	} else {
  10.591 +#ifndef GL_ES_VERSION_2_0
  10.592 +		// rendering with fixed-function (not available in GLES2)
  10.593 +		glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
  10.594 +		glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
  10.595 +		glEnableClientState(GL_VERTEX_ARRAY);
  10.596 +
  10.597 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  10.598 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
  10.599 +			glNormalPointer(GL_FLOAT, 0, 0);
  10.600 +			glEnableClientState(GL_NORMAL_ARRAY);
  10.601 +		}
  10.602 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  10.603 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
  10.604 +			glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
  10.605 +			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  10.606 +		}
  10.607 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  10.608 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
  10.609 +			glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
  10.610 +			glEnableClientState(GL_COLOR_ARRAY);
  10.611 +		}
  10.612 +#endif
  10.613 +	}
  10.614 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  10.615 +
  10.616 +	if(ibo_valid) {
  10.617 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  10.618 +		glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
  10.619 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  10.620 +	} else {
  10.621 +		glDrawArrays(GL_TRIANGLES, 0, nverts);
  10.622 +	}
  10.623 +
  10.624 +	if(SdrProg::active) {
  10.625 +		// rendered with shaders
  10.626 +		for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.627 +			int loc = global_sdr_loc[i];
  10.628 +			if(loc >= 0 && vattr[i].vbo_valid) {
  10.629 +				glDisableVertexAttribArray(loc);
  10.630 +			}
  10.631 +		}
  10.632 +	} else {
  10.633 +#ifndef GL_ES_VERSION_2_0
  10.634 +		// rendered with fixed-function
  10.635 +		glDisableClientState(GL_VERTEX_ARRAY);
  10.636 +		if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
  10.637 +			glDisableClientState(GL_NORMAL_ARRAY);
  10.638 +		}
  10.639 +		if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
  10.640 +			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  10.641 +		}
  10.642 +		if(vattr[MESH_ATTR_COLOR].vbo_valid) {
  10.643 +			glDisableClientState(GL_COLOR_ARRAY);
  10.644 +		}
  10.645 +#endif
  10.646 +	}
  10.647 +}
  10.648 +
  10.649 +void Mesh::draw_wire() const
  10.650 +{
  10.651 +	((Mesh*)this)->update_wire_ibo();
  10.652 +
  10.653 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) {
  10.654 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  10.655 +		return;
  10.656 +	}
  10.657 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  10.658 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  10.659 +		return;
  10.660 +	}
  10.661 +
  10.662 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.663 +		int loc = global_sdr_loc[i];
  10.664 +		if(loc >= 0 && vattr[i].vbo_valid) {
  10.665 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  10.666 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  10.667 +			glEnableVertexAttribArray(loc);
  10.668 +		}
  10.669 +	}
  10.670 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  10.671 +
  10.672 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
  10.673 +	glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
  10.674 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  10.675 +
  10.676 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.677 +		int loc = global_sdr_loc[i];
  10.678 +		if(loc >= 0 && vattr[i].vbo_valid) {
  10.679 +			glDisableVertexAttribArray(loc);
  10.680 +		}
  10.681 +	}
  10.682 +}
  10.683 +
  10.684 +void Mesh::draw_vertices() const
  10.685 +{
  10.686 +	((Mesh*)this)->update_buffers();
  10.687 +
  10.688 +	if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
  10.689 +		fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
  10.690 +		return;
  10.691 +	}
  10.692 +	if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
  10.693 +		fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
  10.694 +		return;
  10.695 +	}
  10.696 +
  10.697 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.698 +		int loc = global_sdr_loc[i];
  10.699 +		if(loc >= 0 && vattr[i].vbo_valid) {
  10.700 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
  10.701 +			glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
  10.702 +			glEnableVertexAttribArray(loc);
  10.703 +		}
  10.704 +	}
  10.705 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
  10.706 +
  10.707 +	glDrawArrays(GL_POINTS, 0, nverts);
  10.708 +
  10.709 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.710 +		int loc = global_sdr_loc[i];
  10.711 +		if(loc >= 0 && vattr[i].vbo_valid) {
  10.712 +			glDisableVertexAttribArray(loc);
  10.713 +		}
  10.714 +	}
  10.715 +}
  10.716 +
  10.717 +void Mesh::draw_normals() const
  10.718 +{
  10.719 +#ifdef USE_OLDGL
  10.720 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  10.721 +	Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  10.722 +	if(!varr || !norm) {
  10.723 +		return;
  10.724 +	}
  10.725 +
  10.726 +	glBegin(GL_LINES);
  10.727 +	if(get_current_shader()) {
  10.728 +		int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  10.729 +		if(vert_loc < 0) {
  10.730 +			glEnd();
  10.731 +			return;
  10.732 +		}
  10.733 +
  10.734 +		for(size_t i=0; i<nverts; i++) {
  10.735 +			glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  10.736 +			Vector3 end = varr[i] + norm[i] * vis_vecsize;
  10.737 +			glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  10.738 +		}
  10.739 +	} else {
  10.740 +		for(size_t i=0; i<nverts; i++) {
  10.741 +			glVertex3f(varr[i].x, varr[i].y, varr[i].z);
  10.742 +			Vector3 end = varr[i] + norm[i] * vis_vecsize;
  10.743 +			glVertex3f(end.x, end.y, end.z);
  10.744 +		}
  10.745 +	}
  10.746 +	glEnd();
  10.747 +#endif	// USE_OLDGL
  10.748 +}
  10.749 +
  10.750 +void Mesh::draw_tangents() const
  10.751 +{
  10.752 +#ifdef USE_OLDGL
  10.753 +	Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  10.754 +	Vector3 *tang = (Vector3*)get_attrib_data(MESH_ATTR_TANGENT);
  10.755 +	if(!varr || !tang) {
  10.756 +		return;
  10.757 +	}
  10.758 +
  10.759 +	glBegin(GL_LINES);
  10.760 +	if(get_current_shader()) {
  10.761 +		int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
  10.762 +		if(vert_loc < 0) {
  10.763 +			glEnd();
  10.764 +			return;
  10.765 +		}
  10.766 +
  10.767 +		for(size_t i=0; i<nverts; i++) {
  10.768 +			glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
  10.769 +			Vector3 end = varr[i] + tang[i] * vis_vecsize;
  10.770 +			glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
  10.771 +		}
  10.772 +	} else {
  10.773 +		for(size_t i=0; i<nverts; i++) {
  10.774 +			glVertex3f(varr[i].x, varr[i].y, varr[i].z);
  10.775 +			Vector3 end = varr[i] + tang[i] * vis_vecsize;
  10.776 +			glVertex3f(end.x, end.y, end.z);
  10.777 +		}
  10.778 +	}
  10.779 +	glEnd();
  10.780 +#endif	// USE_OLDGL
  10.781 +}
  10.782 +
  10.783 +void Mesh::get_aabbox(Vector3 *vmin, Vector3 *vmax) const
  10.784 +{
  10.785 +	if(!aabb_valid) {
  10.786 +		((Mesh*)this)->calc_aabb();
  10.787 +	}
  10.788 +	*vmin = aabb.min;
  10.789 +	*vmax = aabb.max;
  10.790 +}
  10.791 +
  10.792 +const AABox &Mesh::get_aabbox() const
  10.793 +{
  10.794 +	if(!aabb_valid) {
  10.795 +		((Mesh*)this)->calc_aabb();
  10.796 +	}
  10.797 +	return aabb;
  10.798 +}
  10.799 +
  10.800 +float Mesh::get_bsphere(Vector3 *center, float *rad) const
  10.801 +{
  10.802 +	if(!bsph_valid) {
  10.803 +		((Mesh*)this)->calc_bsph();
  10.804 +	}
  10.805 +	*center = bsph.center;
  10.806 +	*rad = bsph.radius;
  10.807 +	return bsph.radius;
  10.808 +}
  10.809 +
  10.810 +const Sphere &Mesh::get_bsphere() const
  10.811 +{
  10.812 +	if(!bsph_valid) {
  10.813 +		((Mesh*)this)->calc_bsph();
  10.814 +	}
  10.815 +	return bsph;
  10.816 +}
  10.817 +
  10.818 +/// static function
  10.819 +void Mesh::set_intersect_mode(unsigned int mode)
  10.820 +{
  10.821 +	Mesh::intersect_mode = mode;
  10.822 +}
  10.823 +
  10.824 +/// static function
  10.825 +unsigned int Mesh::get_intersect_mode()
  10.826 +{
  10.827 +	return Mesh::intersect_mode;
  10.828 +}
  10.829 +
  10.830 +/// static function
  10.831 +void Mesh::set_vertex_select_distance(float dist)
  10.832 +{
  10.833 +	Mesh::vertex_sel_dist = dist;
  10.834 +}
  10.835 +
  10.836 +/// static function
  10.837 +float Mesh::get_vertex_select_distance()
  10.838 +{
  10.839 +	return Mesh::vertex_sel_dist;
  10.840 +}
  10.841 +
  10.842 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
  10.843 +{
  10.844 +	assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
  10.845 +
  10.846 +	const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX);
  10.847 +	const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL);
  10.848 +	if(!varr) {
  10.849 +		return false;
  10.850 +	}
  10.851 +	const unsigned int *idxarr = get_index_data();
  10.852 +
  10.853 +	// first test with the bounding box
  10.854 +	AABox box;
  10.855 +	get_aabbox(&box.min, &box.max);
  10.856 +	if(!box.intersect(ray)) {
  10.857 +		return false;
  10.858 +	}
  10.859 +
  10.860 +	HitPoint nearest_hit;
  10.861 +	nearest_hit.dist = FLT_MAX;
  10.862 +	nearest_hit.obj = 0;
  10.863 +
  10.864 +	if(Mesh::intersect_mode & ISECT_VERTICES) {
  10.865 +		// we asked for "intersections" with the vertices of the mesh
  10.866 +		long nearest_vidx = -1;
  10.867 +		float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
  10.868 +
  10.869 +		for(unsigned int i=0; i<nverts; i++) {
  10.870 +
  10.871 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(narr[i], ray.dir) > 0) {
  10.872 +				continue;
  10.873 +			}
  10.874 +
  10.875 +			// project the vertex onto the ray line
  10.876 +			float t = dot_product(varr[i] - ray.origin, ray.dir);
  10.877 +			Vector3 vproj = ray.origin + ray.dir * t;
  10.878 +
  10.879 +			float dist_sq = (vproj - varr[i]).length_sq();
  10.880 +			if(dist_sq < thres_sq) {
  10.881 +				if(!hit) {
  10.882 +					return true;
  10.883 +				}
  10.884 +				if(t < nearest_hit.dist) {
  10.885 +					nearest_hit.dist = t;
  10.886 +					nearest_vidx = i;
  10.887 +				}
  10.888 +			}
  10.889 +		}
  10.890 +
  10.891 +		if(nearest_vidx != -1) {
  10.892 +			hitvert = varr[nearest_vidx];
  10.893 +			nearest_hit.obj = &hitvert;
  10.894 +		}
  10.895 +
  10.896 +	} else {
  10.897 +		// regular intersection test with polygons
  10.898 +
  10.899 +		for(unsigned int i=0; i<nfaces; i++) {
  10.900 +			Triangle face(i, varr, idxarr);
  10.901 +
  10.902 +			// ignore back-facing polygons if the mode flags include ISECT_FRONT
  10.903 +			if((Mesh::intersect_mode & ISECT_FRONT) && dot_product(face.get_normal(), ray.dir) > 0) {
  10.904 +				continue;
  10.905 +			}
  10.906 +
  10.907 +			HitPoint fhit;
  10.908 +			if(face.intersect(ray, hit ? &fhit : 0)) {
  10.909 +				if(!hit) {
  10.910 +					return true;
  10.911 +				}
  10.912 +				if(fhit.dist < nearest_hit.dist) {
  10.913 +					nearest_hit = fhit;
  10.914 +					hitface = face;
  10.915 +				}
  10.916 +			}
  10.917 +		}
  10.918 +	}
  10.919 +
  10.920 +	if(nearest_hit.obj) {
  10.921 +		if(hit) {
  10.922 +			*hit = nearest_hit;
  10.923 +
  10.924 +			// if we are interested in the mesh and not the faces set obj to this
  10.925 +			if(Mesh::intersect_mode & ISECT_FACE) {
  10.926 +				hit->obj = &hitface;
  10.927 +			} else if(Mesh::intersect_mode & ISECT_VERTICES) {
  10.928 +				hit->obj = &hitvert;
  10.929 +			} else {
  10.930 +				hit->obj = this;
  10.931 +			}
  10.932 +		}
  10.933 +		return true;
  10.934 +	}
  10.935 +	return false;
  10.936 +}
  10.937 +
  10.938 +
  10.939 +// ------ private member functions ------
  10.940 +
  10.941 +void Mesh::calc_aabb()
  10.942 +{
  10.943 +	// the cast is to force calling the const version which doesn't invalidate
  10.944 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  10.945 +		return;
  10.946 +	}
  10.947 +
  10.948 +	aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  10.949 +	aabb.max = -aabb.min;
  10.950 +
  10.951 +	for(unsigned int i=0; i<nverts; i++) {
  10.952 +		Vector4 v = get_attrib(MESH_ATTR_VERTEX, i);
  10.953 +		for(int j=0; j<3; j++) {
  10.954 +			if(v[j] < aabb.min[j]) {
  10.955 +				aabb.min[j] = v[j];
  10.956 +			}
  10.957 +			if(v[j] > aabb.max[j]) {
  10.958 +				aabb.max[j] = v[j];
  10.959 +			}
  10.960 +		}
  10.961 +	}
  10.962 +	aabb_valid = true;
  10.963 +}
  10.964 +
  10.965 +void Mesh::calc_bsph()
  10.966 +{
  10.967 +	// the cast is to force calling the const version which doesn't invalidate
  10.968 +	if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
  10.969 +		return;
  10.970 +	}
  10.971 +
  10.972 +	Vector3 v;
  10.973 +	bsph.center = Vector3(0, 0, 0);
  10.974 +
  10.975 +	// first find the center
  10.976 +	for(unsigned int i=0; i<nverts; i++) {
  10.977 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  10.978 +		bsph.center += v;
  10.979 +	}
  10.980 +	bsph.center /= (float)nverts;
  10.981 +
  10.982 +	bsph.radius = 0.0f;
  10.983 +	for(unsigned int i=0; i<nverts; i++) {
  10.984 +		v = get_attrib(MESH_ATTR_VERTEX, i);
  10.985 +		float dist_sq = (v - bsph.center).length_sq();
  10.986 +		if(dist_sq > bsph.radius) {
  10.987 +			bsph.radius = dist_sq;
  10.988 +		}
  10.989 +	}
  10.990 +	bsph.radius = sqrt(bsph.radius);
  10.991 +
  10.992 +	bsph_valid = true;
  10.993 +}
  10.994 +
  10.995 +void Mesh::update_buffers()
  10.996 +{
  10.997 +	for(int i=0; i<NUM_MESH_ATTR; i++) {
  10.998 +		if(has_attrib(i) && !vattr[i].vbo_valid) {
  10.999 +			glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
 10.1000 +			glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
 10.1001 +			vattr[i].vbo_valid = true;
 10.1002 +		}
 10.1003 +	}
 10.1004 +	glBindBuffer(GL_ARRAY_BUFFER, 0);
 10.1005 +
 10.1006 +	if(idata_valid && !ibo_valid) {
 10.1007 +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
 10.1008 +		glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
 10.1009 +		ibo_valid = true;
 10.1010 +	}
 10.1011 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 10.1012 +}
 10.1013 +
 10.1014 +void Mesh::update_wire_ibo()
 10.1015 +{
 10.1016 +	update_buffers();
 10.1017 +
 10.1018 +	if(wire_ibo_valid) {
 10.1019 +		return;
 10.1020 +	}
 10.1021 +
 10.1022 +	if(!wire_ibo) {
 10.1023 +		glGenBuffers(1, &wire_ibo);
 10.1024 +	}
 10.1025 +
 10.1026 +	unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
 10.1027 +	unsigned int *dest = wire_idxarr;
 10.1028 +
 10.1029 +	if(ibo_valid) {
 10.1030 +		// we're dealing with an indexed mesh
 10.1031 +		const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
 10.1032 +
 10.1033 +		for(unsigned int i=0; i<nfaces; i++) {
 10.1034 +			*dest++ = idxarr[0];
 10.1035 +			*dest++ = idxarr[1];
 10.1036 +			*dest++ = idxarr[1];
 10.1037 +			*dest++ = idxarr[2];
 10.1038 +			*dest++ = idxarr[2];
 10.1039 +			*dest++ = idxarr[0];
 10.1040 +			idxarr += 3;
 10.1041 +		}
 10.1042 +	} else {
 10.1043 +		// not an indexed mesh ...
 10.1044 +		for(unsigned int i=0; i<nfaces; i++) {
 10.1045 +			int vidx = i * 3;
 10.1046 +			*dest++ = vidx;
 10.1047 +			*dest++ = vidx + 1;
 10.1048 +			*dest++ = vidx + 1;
 10.1049 +			*dest++ = vidx + 2;
 10.1050 +			*dest++ = vidx + 2;
 10.1051 +			*dest++ = vidx;
 10.1052 +		}
 10.1053 +	}
 10.1054 +
 10.1055 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
 10.1056 +	glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
 10.1057 +	delete [] wire_idxarr;
 10.1058 +	wire_ibo_valid = true;
 10.1059 +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 10.1060 +}
 10.1061 +
 10.1062 +
 10.1063 +// ------ class Triangle ------
 10.1064 +Triangle::Triangle()
 10.1065 +{
 10.1066 +	normal_valid = false;
 10.1067 +	id = -1;
 10.1068 +}
 10.1069 +
 10.1070 +Triangle::Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2)
 10.1071 +{
 10.1072 +	v[0] = v0;
 10.1073 +	v[1] = v1;
 10.1074 +	v[2] = v2;
 10.1075 +	normal_valid = false;
 10.1076 +	id = -1;
 10.1077 +}
 10.1078 +
 10.1079 +Triangle::Triangle(int n, const Vector3 *varr, const unsigned int *idxarr)
 10.1080 +{
 10.1081 +	if(idxarr) {
 10.1082 +		v[0] = varr[idxarr[n * 3]];
 10.1083 +		v[1] = varr[idxarr[n * 3 + 1]];
 10.1084 +		v[2] = varr[idxarr[n * 3 + 2]];
 10.1085 +	} else {
 10.1086 +		v[0] = varr[n * 3];
 10.1087 +		v[1] = varr[n * 3 + 1];
 10.1088 +		v[2] = varr[n * 3 + 2];
 10.1089 +	}
 10.1090 +	normal_valid = false;
 10.1091 +	id = n;
 10.1092 +}
 10.1093 +
 10.1094 +void Triangle::calc_normal()
 10.1095 +{
 10.1096 +	normal = cross_product(v[1] - v[0], v[2] - v[0]).normalized();
 10.1097 +	normal_valid = true;
 10.1098 +}
 10.1099 +
 10.1100 +const Vector3 &Triangle::get_normal() const
 10.1101 +{
 10.1102 +	if(!normal_valid) {
 10.1103 +		((Triangle*)this)->calc_normal();
 10.1104 +	}
 10.1105 +	return normal;
 10.1106 +}
 10.1107 +
 10.1108 +void Triangle::transform(const Matrix4x4 &xform)
 10.1109 +{
 10.1110 +	v[0].transform(xform);
 10.1111 +	v[1].transform(xform);
 10.1112 +	v[2].transform(xform);
 10.1113 +	normal_valid = false;
 10.1114 +}
 10.1115 +
 10.1116 +void Triangle::draw() const
 10.1117 +{
 10.1118 +	Vector3 n[3];
 10.1119 +	n[0] = get_normal();
 10.1120 +	n[1] = get_normal();
 10.1121 +	n[2] = get_normal();
 10.1122 +
 10.1123 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 10.1124 +	int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
 10.1125 +
 10.1126 +	glEnableVertexAttribArray(vloc);
 10.1127 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 10.1128 +	glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
 10.1129 +
 10.1130 +	glDrawArrays(GL_TRIANGLES, 0, 3);
 10.1131 +
 10.1132 +	glDisableVertexAttribArray(vloc);
 10.1133 +	glDisableVertexAttribArray(nloc);
 10.1134 +	CHECK_GLERROR;
 10.1135 +}
 10.1136 +
 10.1137 +void Triangle::draw_wire() const
 10.1138 +{
 10.1139 +	static const int idxarr[] = {0, 1, 1, 2, 2, 0};
 10.1140 +	int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
 10.1141 +
 10.1142 +	glEnableVertexAttribArray(vloc);
 10.1143 +	glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
 10.1144 +
 10.1145 +	glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
 10.1146 +
 10.1147 +	glDisableVertexAttribArray(vloc);
 10.1148 +	CHECK_GLERROR;
 10.1149 +}
 10.1150 +
 10.1151 +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const
 10.1152 +{
 10.1153 +	Vector3 norm = get_normal();
 10.1154 +
 10.1155 +	float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm));
 10.1156 +	if(area_sq < 1e-5) {
 10.1157 +		return Vector3(0, 0, 0);
 10.1158 +	}
 10.1159 +
 10.1160 +	float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm));
 10.1161 +	float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm));
 10.1162 +	float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm));
 10.1163 +
 10.1164 +	return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
 10.1165 +}
 10.1166 +
 10.1167 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
 10.1168 +{
 10.1169 +	Vector3 normal = get_normal();
 10.1170 +
 10.1171 +	float ndotdir = dot_product(ray.dir, normal);
 10.1172 +	if(fabs(ndotdir) < 1e-4) {
 10.1173 +		return false;
 10.1174 +	}
 10.1175 +
 10.1176 +	Vector3 vertdir = v[0] - ray.origin;
 10.1177 +	float t = dot_product(normal, vertdir) / ndotdir;
 10.1178 +
 10.1179 +	Vector3 pos = ray.origin + ray.dir * t;
 10.1180 +	Vector3 bary = calc_barycentric(pos);
 10.1181 +
 10.1182 +	if(bary.x + bary.y + bary.z > 1.00001) {
 10.1183 +		return false;
 10.1184 +	}
 10.1185 +
 10.1186 +	if(hit) {
 10.1187 +		hit->dist = t;
 10.1188 +		hit->pos = ray.origin + ray.dir * t;
 10.1189 +		hit->normal = normal;
 10.1190 +		hit->obj = this;
 10.1191 +	}
 10.1192 +	return true;
 10.1193 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/mesh.h	Sun Jun 21 06:30:39 2015 +0300
    11.3 @@ -0,0 +1,225 @@
    11.4 +#ifndef MESH_H_
    11.5 +#define MESH_H_
    11.6 +
    11.7 +#include <string>
    11.8 +#include <vector>
    11.9 +#include "vmath/vmath.h"
   11.10 +#include "geom.h"
   11.11 +
   11.12 +enum {
   11.13 +	MESH_ATTR_VERTEX,
   11.14 +	MESH_ATTR_NORMAL,
   11.15 +	MESH_ATTR_TANGENT,
   11.16 +	MESH_ATTR_TEXCOORD,
   11.17 +	MESH_ATTR_COLOR,
   11.18 +	MESH_ATTR_BONEWEIGHTS,
   11.19 +	MESH_ATTR_BONEIDX,
   11.20 +
   11.21 +	NUM_MESH_ATTR
   11.22 +};
   11.23 +
   11.24 +// intersection mode flags
   11.25 +enum {
   11.26 +	ISECT_DEFAULT	= 0,	// default (whole mesh, all intersections)
   11.27 +	ISECT_FRONT		= 1,	// front-faces only
   11.28 +	ISECT_FACE		= 2,	// return intersected face pointer instead of mesh
   11.29 +	ISECT_VERTICES	= 4		// return (?) TODO
   11.30 +};
   11.31 +
   11.32 +//class XFormNode;
   11.33 +
   11.34 +
   11.35 +class Triangle {
   11.36 +public:
   11.37 +	Vector3 v[3];
   11.38 +	Vector3 normal;
   11.39 +	bool normal_valid;
   11.40 +	int id;
   11.41 +
   11.42 +	Triangle();
   11.43 +	Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2);
   11.44 +	Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0);
   11.45 +
   11.46 +	/// calculate normal (quite expensive)
   11.47 +	void calc_normal();
   11.48 +	const Vector3 &get_normal() const;
   11.49 +
   11.50 +	void transform(const Matrix4x4 &xform);
   11.51 +
   11.52 +	void draw() const;
   11.53 +	void draw_wire() const;
   11.54 +
   11.55 +	/// calculate barycentric coordinates of a point
   11.56 +	Vector3 calc_barycentric(const Vector3 &pos) const;
   11.57 +
   11.58 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
   11.59 +};
   11.60 +
   11.61 +
   11.62 +class Mesh {
   11.63 +private:
   11.64 +	std::string name;
   11.65 +	unsigned int nverts, nfaces;
   11.66 +
   11.67 +	// current value for each attribute for the immedate mode
   11.68 +	// interface.
   11.69 +	Vector4 cur_val[NUM_MESH_ATTR];
   11.70 +
   11.71 +	unsigned int buffer_objects[NUM_MESH_ATTR + 1];
   11.72 +
   11.73 +	// vertex attribute data and buffer objects
   11.74 +	struct {
   11.75 +		int nelem;					// number of elements per attribute range: [1, 4]
   11.76 +		std::vector<float> data;
   11.77 +		unsigned int vbo;
   11.78 +		mutable bool vbo_valid;		// if this is false, the vbo needs updating from the data
   11.79 +		mutable bool data_valid;	// if this is false, the data needs to be pulled from the vbo
   11.80 +		//int sdr_loc;
   11.81 +	} vattr[NUM_MESH_ATTR];
   11.82 +
   11.83 +	static int global_sdr_loc[NUM_MESH_ATTR];
   11.84 +
   11.85 +	//std::vector<XFormNode*> bones;	// bones affecting this mesh
   11.86 +
   11.87 +	// index data and buffer object
   11.88 +	std::vector<unsigned int> idata;
   11.89 +	unsigned int ibo;
   11.90 +	mutable bool ibo_valid;
   11.91 +	mutable bool idata_valid;
   11.92 +
   11.93 +	// index buffer object for wireframe rendering (constructed on demand)
   11.94 +	unsigned int wire_ibo;
   11.95 +	mutable bool wire_ibo_valid;
   11.96 +
   11.97 +	// axis-aligned bounding box
   11.98 +	mutable AABox aabb;
   11.99 +	mutable bool aabb_valid;
  11.100 +
  11.101 +	// bounding sphere
  11.102 +	mutable Sphere bsph;
  11.103 +	mutable bool bsph_valid;
  11.104 +
  11.105 +	// keeps the last intersected face
  11.106 +	mutable Triangle hitface;
  11.107 +	// keeps the last intersected vertex position
  11.108 +	mutable Vector3 hitvert;
  11.109 +
  11.110 +	void calc_aabb();
  11.111 +	void calc_bsph();
  11.112 +
  11.113 +	static unsigned int intersect_mode;
  11.114 +	static float vertex_sel_dist;
  11.115 +
  11.116 +	static float vis_vecsize;
  11.117 +
  11.118 +	/// update the VBOs after data has changed (invalid vbo/ibo)
  11.119 +	void update_buffers();
  11.120 +	/// construct/update the wireframe index buffer (called from draw_wire).
  11.121 +	void update_wire_ibo();
  11.122 +
  11.123 +
  11.124 +public:
  11.125 +	Mesh();
  11.126 +	~Mesh();
  11.127 +
  11.128 +	Mesh(const Mesh &rhs);
  11.129 +	Mesh &operator =(const Mesh &rhs);
  11.130 +	bool clone(const Mesh &m);
  11.131 +
  11.132 +	void set_name(const char *name);
  11.133 +	const char *get_name() const;
  11.134 +
  11.135 +	bool has_attrib(int attr) const;
  11.136 +	bool is_indexed() const;
  11.137 +
  11.138 +	// clears everything about this mesh, and returns to the newly constructed state
  11.139 +	void clear();
  11.140 +
  11.141 +	// access the vertex attribute data
  11.142 +	// if vdata == 0, space is just allocated
  11.143 +	float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo
  11.144 +	float *get_attrib_data(int attrib);	// invalidates vbo
  11.145 +	const float *get_attrib_data(int attrib) const;
  11.146 +
  11.147 +	// simple access to any particular attribute
  11.148 +	void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo
  11.149 +	Vector4 get_attrib(int attrib, int idx) const;
  11.150 +
  11.151 +	int get_attrib_count(int attrib) const;
  11.152 +
  11.153 +	// ... same for index data
  11.154 +	unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo
  11.155 +	unsigned int *get_index_data();	// invalidates ibo
  11.156 +	const unsigned int *get_index_data() const;
  11.157 +
  11.158 +	int get_index_count() const;
  11.159 +
  11.160 +	void append(const Mesh &mesh);
  11.161 +
  11.162 +	// immediate-mode style mesh construction interface
  11.163 +	void vertex(float x, float y, float z);
  11.164 +	void normal(float nx, float ny, float nz);
  11.165 +	void tangent(float tx, float ty, float tz);
  11.166 +	void texcoord(float u, float v, float w);
  11.167 +	void boneweights(float w1, float w2, float w3, float w4);
  11.168 +	void boneidx(int idx1, int idx2, int idx3, int idx4);
  11.169 +
  11.170 +	int get_poly_count() const;
  11.171 +
  11.172 +	/* apply a transformation to the vertices and its inverse-transpose
  11.173 +	 * to the normals and tangents.
  11.174 +	 */
  11.175 +	void apply_xform(const Matrix4x4 &xform);
  11.176 +	void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform);
  11.177 +
  11.178 +	void flip();	// both faces and normals
  11.179 +	void flip_faces();
  11.180 +	void flip_normals();
  11.181 +
  11.182 +	// adds a bone and returns its index
  11.183 +	/*int add_bone(XFormNode *bone);
  11.184 +	const XFormNode *get_bone(int idx) const;
  11.185 +	int get_bones_count() const;*/
  11.186 +
  11.187 +	// access the shader attribute locations
  11.188 +	static void set_attrib_location(int attr, int loc);
  11.189 +	static int get_attrib_location(int attr);
  11.190 +	static void clear_attrib_locations();
  11.191 +
  11.192 +	static void set_vis_vecsize(float sz);
  11.193 +	static float get_vis_vecsize();
  11.194 +
  11.195 +	void draw() const;
  11.196 +	void draw_wire() const;
  11.197 +	void draw_vertices() const;
  11.198 +	void draw_normals() const;
  11.199 +	void draw_tangents() const;
  11.200 +
  11.201 +	/** get the bounding box in local space. The result will be cached, and subsequent
  11.202 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  11.203 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  11.204 +	 * @{ */
  11.205 +	void get_aabbox(Vector3 *vmin, Vector3 *vmax) const;
  11.206 +	const AABox &get_aabbox() const;
  11.207 +	/// @}
  11.208 +
  11.209 +	/** get the bounding sphere in local space. The result will be cached, and subsequent
  11.210 +	 * calls will return the same box. The cache gets invalidated by any functions that can affect
  11.211 +	 * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included).
  11.212 +	 * @{ */
  11.213 +	float get_bsphere(Vector3 *center, float *rad) const;
  11.214 +	const Sphere &get_bsphere() const;
  11.215 +
  11.216 +	static void set_intersect_mode(unsigned int mode);
  11.217 +	static unsigned int get_intersect_mode();
  11.218 +	static void set_vertex_select_distance(float dist);
  11.219 +	static float get_vertex_select_distance();
  11.220 +
  11.221 +	/** Find the intersection between the mesh and a ray.
  11.222 +	 * XXX Brute force at the moment, not intended to be used for anything other than picking in tools.
  11.223 +	 *     If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it!
  11.224 +	 */
  11.225 +	bool intersect(const Ray &ray, HitPoint *hit = 0) const;
  11.226 +};
  11.227 +
  11.228 +#endif	// MESH_H_
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/opengl.h	Sun Jun 21 06:30:39 2015 +0300
    12.3 @@ -0,0 +1,6 @@
    12.4 +#ifndef OPENGL_H_
    12.5 +#define OPENGL_H_
    12.6 +
    12.7 +#include <GL/glew.h>
    12.8 +
    12.9 +#endif	/* OPENGL_H_ */