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 ¢, 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 ¢er, 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_