cubemapper
changeset 0:8fc9e1d3aad2
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 27 Jul 2017 20:36:12 +0300 |
parents | |
children | d7a29cb7ac8d |
files | .hgignore Makefile src/app.cc src/app.h src/geom.cc src/geom.h src/main.cc src/mesh.cc src/mesh.h src/meshgen.cc src/meshgen.h src/opengl.cc src/opengl.h src/texture.cc src/texture.h |
diffstat | 15 files changed, 3457 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Thu Jul 27 20:36:12 2017 +0300 1.3 @@ -0,0 +1,12 @@ 1.4 +\.o$ 1.5 +\.d$ 1.6 +\.swp$ 1.7 +^data/ 1.8 +^Debug/ 1.9 +^Release/ 1.10 +\.sdf$ 1.11 +\.opensdf$ 1.12 +\.suo$ 1.13 +\.jpg$ 1.14 +\.png$ 1.15 +^cubemapper$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Thu Jul 27 20:36:12 2017 +0300 2.3 @@ -0,0 +1,38 @@ 2.4 +# -- options -- 2.5 +PREFIX = /usr/local 2.6 +opt = -O0 2.7 +dbg = -g 2.8 +# ------------- 2.9 + 2.10 +src = $(wildcard src/*.cc) 2.11 +obj = $(src:.cc=.o) 2.12 +dep = $(obj:.o=.d) 2.13 +bin = cubemapper 2.14 + 2.15 +CXXFLAGS = -pedantic -Wall $(opt) $(dbg) $(inc) 2.16 +LDFLAGS = $(libs) $(libgl_$(sys)) -lm 2.17 + 2.18 +sys = $(shell uname -s) 2.19 +libgl_Linux = -lGL -lGLU -lglut -lGLEW 2.20 +libgl_Darwin = -framework OpenGL -framework GLUT -lGLEW 2.21 + 2.22 +libs = -limago -lgmath 2.23 + 2.24 +$(bin): $(obj) 2.25 + $(CXX) -o $@ $(obj) $(LDFLAGS) 2.26 + 2.27 +-include $(dep) 2.28 + 2.29 +%.d: %.c 2.30 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 2.31 + 2.32 +%.d: %.cc 2.33 + @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ 2.34 + 2.35 +.PHONY: clean 2.36 +clean: 2.37 + rm -f $(obj) $(bin) 2.38 + 2.39 +.PHONY: cleandep 2.40 +cleandep: 2.41 + rm -f $(dep)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/app.cc Thu Jul 27 20:36:12 2017 +0300 3.3 @@ -0,0 +1,243 @@ 3.4 +#include <stdio.h> 3.5 +#include <stdlib.h> 3.6 +#include <string.h> 3.7 +#include <math.h> 3.8 +#include <assert.h> 3.9 +#include <imago2.h> 3.10 +#include "app.h" 3.11 +#include "opengl.h" 3.12 +#include "texture.h" 3.13 +#include "mesh.h" 3.14 +#include "meshgen.h" 3.15 + 3.16 +static void draw_scene(); // both near and infinite parts 3.17 +static void draw_scene_near(); // near scene: regular objects affected by parallax shift and translation 3.18 +// infinity scene: objects conceptually at infinity, not affected by parallax shift and translation 3.19 +static void draw_scene_inf(); 3.20 +static bool parse_args(int argc, char **argv); 3.21 + 3.22 +static const char *img_fname; 3.23 +static float cam_theta, cam_phi; 3.24 + 3.25 +static Texture *pano_tex; 3.26 +static Mesh *pano_mesh; 3.27 + 3.28 +static int win_width, win_height; 3.29 + 3.30 + 3.31 +bool app_init(int argc, char **argv) 3.32 +{ 3.33 + if(!parse_args(argc, argv)) { 3.34 + return false; 3.35 + } 3.36 + if(!img_fname) { 3.37 + fprintf(stderr, "please specify an equilateral panoramic image\n"); 3.38 + return false; 3.39 + } 3.40 + 3.41 + if(!init_opengl()) { 3.42 + return false; 3.43 + } 3.44 + 3.45 + glEnable(GL_CULL_FACE); 3.46 + 3.47 + if(GLEW_ARB_framebuffer_sRGB) { 3.48 + glGetError(); // discard previous errors 3.49 + glEnable(GL_FRAMEBUFFER_SRGB); 3.50 + if(glGetError() != GL_NO_ERROR) { 3.51 + fprintf(stderr, "failed to enable sRGB framebuffer\n"); 3.52 + } 3.53 + } 3.54 + 3.55 + Mesh::use_custom_sdr_attr = false; 3.56 + pano_mesh = new Mesh; 3.57 + gen_sphere(pano_mesh, 1.0, 80, 40); 3.58 + pano_mesh->flip(); 3.59 + Mat4 xform; 3.60 + xform.rotation_y(-M_PI / 2.0); // rotate the sphere to face the "front" part of the image 3.61 + pano_mesh->apply_xform(xform, xform); 3.62 + 3.63 + xform.scaling(-1, 1, 1); // flip horizontal texcoord since we're inside the sphere 3.64 + pano_mesh->texcoord_apply_xform(xform); 3.65 + 3.66 + pano_tex = new Texture; 3.67 + if(!pano_tex->load(img_fname)) { 3.68 + return false; 3.69 + } 3.70 + return true; 3.71 +} 3.72 + 3.73 +void app_cleanup() 3.74 +{ 3.75 + delete pano_mesh; 3.76 + delete pano_tex; 3.77 +} 3.78 + 3.79 +void app_draw() 3.80 +{ 3.81 + glClear(GL_COLOR_BUFFER_BIT); 3.82 + 3.83 + Mat4 view_matrix; 3.84 + view_matrix.pre_rotate_x(deg_to_rad(cam_phi)); 3.85 + view_matrix.pre_rotate_y(deg_to_rad(cam_theta)); 3.86 + 3.87 + glMatrixMode(GL_MODELVIEW); 3.88 + glLoadMatrixf(view_matrix[0]); 3.89 + 3.90 + draw_scene(); 3.91 + 3.92 + app_swap_buffers(); 3.93 + assert(glGetError() == GL_NO_ERROR); 3.94 +} 3.95 + 3.96 +void render_cubemap() 3.97 +{ 3.98 + int fbsize = win_width < win_height ? win_width : win_height; 3.99 + float *pixels = new float[fbsize * fbsize * 3]; 3.100 + 3.101 + glViewport(0, 0, fbsize, fbsize); 3.102 + 3.103 + Mat4 viewmat[6]; 3.104 + viewmat[0].rotation_y(deg_to_rad(90)); // +X 3.105 + viewmat[1].rotation_x(deg_to_rad(-90)); // +Y 3.106 + viewmat[2].rotation_y(deg_to_rad(180)); // +Z 3.107 + viewmat[3].rotation_y(deg_to_rad(-90)); // -X 3.108 + viewmat[4].rotation_x(deg_to_rad(90)); // -Y 3.109 + 3.110 + static const char *fname[] = { 3.111 + "cubemap_px.jpg", 3.112 + "cubemap_py.jpg", 3.113 + "cubemap_pz.jpg", 3.114 + "cubemap_nx.jpg", 3.115 + "cubemap_ny.jpg", 3.116 + "cubemap_nz.jpg" 3.117 + }; 3.118 + 3.119 + glMatrixMode(GL_PROJECTION); 3.120 + glLoadIdentity(); 3.121 + gluPerspective(45, 1.0, 0.5, 500.0); 3.122 + 3.123 + for(int i=0; i<6; i++) { 3.124 + glClear(GL_COLOR_BUFFER_BIT); 3.125 + 3.126 + glMatrixMode(GL_MODELVIEW); 3.127 + glLoadMatrixf(viewmat[i][0]); 3.128 + 3.129 + draw_scene(); 3.130 + 3.131 + glReadPixels(0, 0, fbsize, fbsize, GL_RGB, GL_FLOAT, pixels); 3.132 + if(img_save_pixels(fname[i], pixels, fbsize, fbsize, IMG_FMT_RGBF) == -1) { 3.133 + fprintf(stderr, "failed to save %dx%d image: %s\n", fbsize, fbsize, fname[i]); 3.134 + break; 3.135 + } 3.136 + } 3.137 + 3.138 + glViewport(0, 0, win_width, win_height); 3.139 + 3.140 + delete [] pixels; 3.141 +} 3.142 + 3.143 +// both near and infinite parts (see below) 3.144 +static void draw_scene() 3.145 +{ 3.146 + draw_scene_inf(); 3.147 + draw_scene_near(); 3.148 +} 3.149 + 3.150 +// infinity scene: objects conceptually at infinity, not affected by parallax shift and translation 3.151 +static void draw_scene_inf() 3.152 +{ 3.153 + pano_tex->bind(); 3.154 + glEnable(GL_TEXTURE_2D); 3.155 + pano_mesh->draw(); 3.156 + glDisable(GL_TEXTURE_2D); 3.157 +} 3.158 + 3.159 +// near scene: regular objects affected by parallax shift and translation 3.160 +static void draw_scene_near() 3.161 +{ 3.162 +} 3.163 + 3.164 +void app_reshape(int x, int y) 3.165 +{ 3.166 + glViewport(0, 0, x, y); 3.167 + 3.168 + glMatrixMode(GL_PROJECTION); 3.169 + glLoadIdentity(); 3.170 + gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); 3.171 + 3.172 + win_width = x; 3.173 + win_height = y; 3.174 +} 3.175 + 3.176 +void app_keyboard(int key, bool press) 3.177 +{ 3.178 + if(press) { 3.179 + switch(key) { 3.180 + case 27: 3.181 + app_quit(); 3.182 + break; 3.183 + 3.184 + case 's': 3.185 + printf("rendering cubemap\n"); 3.186 + render_cubemap(); 3.187 + break; 3.188 + } 3.189 + } 3.190 +} 3.191 + 3.192 +static float prev_x, prev_y; 3.193 +static bool bnstate[16]; 3.194 + 3.195 +void app_mouse_button(int bn, bool press, int x, int y) 3.196 +{ 3.197 + if(bn < (int)(sizeof bnstate / sizeof *bnstate)) { 3.198 + bnstate[bn] = press; 3.199 + } 3.200 + prev_x = x; 3.201 + prev_y = y; 3.202 +} 3.203 + 3.204 +void app_mouse_motion(int x, int y) 3.205 +{ 3.206 + float dx = x - prev_x; 3.207 + float dy = y - prev_y; 3.208 + prev_x = x; 3.209 + prev_y = y; 3.210 + 3.211 + if(!dx && !dy) return; 3.212 + 3.213 + if(bnstate[0]) { 3.214 + cam_theta += dx * 0.5; 3.215 + cam_phi += dy * 0.5; 3.216 + 3.217 + if(cam_phi < -90) cam_phi = -90; 3.218 + if(cam_phi > 90) cam_phi = 90; 3.219 + app_redisplay(); 3.220 + } 3.221 +} 3.222 + 3.223 +static bool parse_args(int argc, char **argv) 3.224 +{ 3.225 + for(int i=1; i<argc; i++) { 3.226 + if(argv[i][0] == '-') { 3.227 + /* 3.228 + } else if(strcmp(argv[i], "-help") == 0) { 3.229 + printf("usage: %s [options]\noptions:\n", argv[0]); 3.230 + printf(" -help: print usage information and exit\n"); 3.231 + exit(0); 3.232 + } else {*/ 3.233 + fprintf(stderr, "invalid option: %s\n", argv[i]); 3.234 + return false; 3.235 + //} 3.236 + } else { 3.237 + if(img_fname) { 3.238 + fprintf(stderr, "unexpected option: %s\n", argv[i]); 3.239 + return false; 3.240 + } 3.241 + img_fname = argv[i]; 3.242 + } 3.243 + } 3.244 + 3.245 + return true; 3.246 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/app.h Thu Jul 27 20:36:12 2017 +0300 4.3 @@ -0,0 +1,19 @@ 4.4 +#ifndef APP_H_ 4.5 +#define APP_H_ 4.6 + 4.7 +bool app_init(int argc, char **argv); 4.8 +void app_cleanup(); 4.9 + 4.10 +void app_draw(); 4.11 + 4.12 +void app_reshape(int x, int y); 4.13 +void app_keyboard(int key, bool press); 4.14 +void app_mouse_button(int bn, bool press, int x, int y); 4.15 +void app_mouse_motion(int x, int y); 4.16 + 4.17 +// functions implemented in main.cc 4.18 +void app_quit(); 4.19 +void app_redisplay(); 4.20 +void app_swap_buffers(); 4.21 + 4.22 +#endif // APP_H_
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/geom.cc Thu Jul 27 20:36:12 2017 +0300 5.3 @@ -0,0 +1,334 @@ 5.4 +#include <assert.h> 5.5 +#include <float.h> 5.6 +#include <algorithm> 5.7 +#include "geom.h" 5.8 + 5.9 +GeomObject::~GeomObject() 5.10 +{ 5.11 +} 5.12 + 5.13 + 5.14 +Sphere::Sphere() 5.15 +{ 5.16 + radius = 1.0; 5.17 +} 5.18 + 5.19 +Sphere::Sphere(const Vec3 ¢, float radius) 5.20 + : center(cent) 5.21 +{ 5.22 + this->radius = radius; 5.23 +} 5.24 + 5.25 +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2) 5.26 +{ 5.27 + const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1); 5.28 + const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2); 5.29 + 5.30 + if(!sph1 || !sph2) { 5.31 + fprintf(stderr, "Sphere::set_union: arguments must be spheres"); 5.32 + return; 5.33 + } 5.34 + 5.35 + float dist = length(sph1->center - sph2->center); 5.36 + float surf_dist = dist - (sph1->radius + sph2->radius); 5.37 + float d1 = sph1->radius + surf_dist / 2.0; 5.38 + float d2 = sph2->radius + surf_dist / 2.0; 5.39 + float t = d1 / (d1 + d2); 5.40 + 5.41 + if(t < 0.0) t = 0.0; 5.42 + if(t > 1.0) t = 1.0; 5.43 + 5.44 + center = sph1->center * t + sph2->center * (1.0 - t); 5.45 + radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius); 5.46 +} 5.47 + 5.48 +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2) 5.49 +{ 5.50 + fprintf(stderr, "Sphere::intersection undefined\n"); 5.51 +} 5.52 + 5.53 +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const 5.54 +{ 5.55 + float a = dot(ray.dir, ray.dir); 5.56 + float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) + 5.57 + 2.0 * ray.dir.y * (ray.origin.y - center.y) + 5.58 + 2.0 * ray.dir.z * (ray.origin.z - center.z); 5.59 + float c = dot(ray.origin, ray.origin) + dot(center, center) - 5.60 + 2.0 * dot(ray.origin, center) - radius * radius; 5.61 + 5.62 + float discr = b * b - 4.0 * a * c; 5.63 + if(discr < 1e-4) { 5.64 + return false; 5.65 + } 5.66 + 5.67 + float sqrt_discr = sqrt(discr); 5.68 + float t0 = (-b + sqrt_discr) / (2.0 * a); 5.69 + float t1 = (-b - sqrt_discr) / (2.0 * a); 5.70 + 5.71 + if(t0 < 1e-4) 5.72 + t0 = t1; 5.73 + if(t1 < 1e-4) 5.74 + t1 = t0; 5.75 + 5.76 + float t = t0 < t1 ? t0 : t1; 5.77 + if(t < 1e-4) { 5.78 + return false; 5.79 + } 5.80 + 5.81 + // fill the HitPoint structure 5.82 + if(hit) { 5.83 + hit->obj = this; 5.84 + hit->dist = t; 5.85 + hit->pos = ray.origin + ray.dir * t; 5.86 + hit->normal = (hit->pos - center) / radius; 5.87 + } 5.88 + return true; 5.89 +} 5.90 + 5.91 + 5.92 +AABox::AABox() 5.93 +{ 5.94 +} 5.95 + 5.96 +AABox::AABox(const Vec3 &vmin, const Vec3 &vmax) 5.97 + : min(vmin), max(vmax) 5.98 +{ 5.99 +} 5.100 + 5.101 +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) 5.102 +{ 5.103 + const AABox *box1 = dynamic_cast<const AABox*>(obj1); 5.104 + const AABox *box2 = dynamic_cast<const AABox*>(obj2); 5.105 + 5.106 + if(!box1 || !box2) { 5.107 + fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); 5.108 + return; 5.109 + } 5.110 + 5.111 + min.x = std::min(box1->min.x, box2->min.x); 5.112 + min.y = std::min(box1->min.y, box2->min.y); 5.113 + min.z = std::min(box1->min.z, box2->min.z); 5.114 + 5.115 + max.x = std::max(box1->max.x, box2->max.x); 5.116 + max.y = std::max(box1->max.y, box2->max.y); 5.117 + max.z = std::max(box1->max.z, box2->max.z); 5.118 +} 5.119 + 5.120 +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2) 5.121 +{ 5.122 + const AABox *box1 = dynamic_cast<const AABox*>(obj1); 5.123 + const AABox *box2 = dynamic_cast<const AABox*>(obj2); 5.124 + 5.125 + if(!box1 || !box2) { 5.126 + fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n"); 5.127 + return; 5.128 + } 5.129 + 5.130 + for(int i=0; i<3; i++) { 5.131 + min[i] = std::max(box1->min[i], box2->min[i]); 5.132 + max[i] = std::min(box1->max[i], box2->max[i]); 5.133 + 5.134 + if(max[i] < min[i]) { 5.135 + max[i] = min[i]; 5.136 + } 5.137 + } 5.138 +} 5.139 + 5.140 +bool AABox::intersect(const Ray &ray, HitPoint *hit) const 5.141 +{ 5.142 + Vec3 param[2] = {min, max}; 5.143 + Vec3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); 5.144 + int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; 5.145 + 5.146 + float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; 5.147 + float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; 5.148 + float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; 5.149 + float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; 5.150 + 5.151 + if(tmin > tymax || tymin > tmax) { 5.152 + return false; 5.153 + } 5.154 + if(tymin > tmin) { 5.155 + tmin = tymin; 5.156 + } 5.157 + if(tymax < tmax) { 5.158 + tmax = tymax; 5.159 + } 5.160 + 5.161 + float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; 5.162 + float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; 5.163 + 5.164 + if(tmin > tzmax || tzmin > tmax) { 5.165 + return false; 5.166 + } 5.167 + if(tzmin > tmin) { 5.168 + tmin = tzmin; 5.169 + } 5.170 + if(tzmax < tmax) { 5.171 + tmax = tzmax; 5.172 + } 5.173 + 5.174 + float t = tmin < 1e-4 ? tmax : tmin; 5.175 + if(t >= 1e-4) { 5.176 + 5.177 + if(hit) { 5.178 + hit->obj = this; 5.179 + hit->dist = t; 5.180 + hit->pos = ray.origin + ray.dir * t; 5.181 + 5.182 + float min_dist = FLT_MAX; 5.183 + Vec3 offs = min + (max - min) / 2.0; 5.184 + Vec3 local_hit = hit->pos - offs; 5.185 + 5.186 + static const Vec3 axis[] = { 5.187 + Vec3(1, 0, 0), Vec3(0, 1, 0), Vec3(0, 0, 1) 5.188 + }; 5.189 + //int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}}; 5.190 + 5.191 + for(int i=0; i<3; i++) { 5.192 + float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i])); 5.193 + if(dist < min_dist) { 5.194 + min_dist = dist; 5.195 + hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0); 5.196 + //hit->texcoord = Vec2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]); 5.197 + } 5.198 + } 5.199 + } 5.200 + return true; 5.201 + } 5.202 + return false; 5.203 + 5.204 +} 5.205 + 5.206 +Plane::Plane() 5.207 + : normal(0.0, 1.0, 0.0) 5.208 +{ 5.209 +} 5.210 + 5.211 +Plane::Plane(const Vec3 &p, const Vec3 &norm) 5.212 + : pt(p) 5.213 +{ 5.214 + normal = normalize(norm); 5.215 +} 5.216 + 5.217 +Plane::Plane(const Vec3 &p1, const Vec3 &p2, const Vec3 &p3) 5.218 + : pt(p1) 5.219 +{ 5.220 + normal = normalize(cross(p2 - p1, p3 - p1)); 5.221 +} 5.222 + 5.223 +Plane::Plane(const Vec3 &normal, float dist) 5.224 +{ 5.225 + this->normal = normalize(normal); 5.226 + pt = this->normal * dist; 5.227 +} 5.228 + 5.229 +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2) 5.230 +{ 5.231 + fprintf(stderr, "Plane::set_union undefined\n"); 5.232 +} 5.233 + 5.234 +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2) 5.235 +{ 5.236 + fprintf(stderr, "Plane::set_intersection undefined\n"); 5.237 +} 5.238 + 5.239 +bool Plane::intersect(const Ray &ray, HitPoint *hit) const 5.240 +{ 5.241 + float ndotdir = dot(normal, ray.dir); 5.242 + if(fabs(ndotdir) < 1e-4) { 5.243 + return false; 5.244 + } 5.245 + 5.246 + if(hit) { 5.247 + Vec3 ptdir = pt - ray.origin; 5.248 + float t = dot(normal, ptdir) / ndotdir; 5.249 + 5.250 + hit->pos = ray.origin + ray.dir * t; 5.251 + hit->normal = normal; 5.252 + hit->obj = this; 5.253 + } 5.254 + return true; 5.255 +} 5.256 + 5.257 +float sphere_distance(const Vec3 ¢, float rad, const Vec3 &pt) 5.258 +{ 5.259 + return length(pt - cent) - rad; 5.260 +} 5.261 + 5.262 +// TODO version which takes both radii into account 5.263 +float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt) 5.264 +{ 5.265 + Vec3 ab_dir = b - a; 5.266 + float ab_len_sq = length_sq(ab_dir); 5.267 + 5.268 + if(fabs(ab_len_sq) < 1e-5) { 5.269 + // if a == b, the capsule is a sphere with radius the maximum of the capsule radii 5.270 + return sphere_distance(a, std::max(ra, rb), pt); 5.271 + } 5.272 + float ab_len = sqrt(ab_len_sq); 5.273 + 5.274 + Vec3 ap_dir = pt - a; 5.275 + 5.276 + float t = dot(ap_dir, ab_dir / ab_len) / ab_len; 5.277 + if(t < 0.0) { 5.278 + return sphere_distance(a, ra, pt); 5.279 + } 5.280 + if(t >= 1.0) { 5.281 + return sphere_distance(b, rb, pt); 5.282 + } 5.283 + 5.284 + Vec3 pproj = a + ab_dir * t; 5.285 + return length(pproj - pt) - ra; 5.286 +} 5.287 + 5.288 +#if 0 5.289 +float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt) 5.290 +{ 5.291 + Vec3 ab_dir = b - a; 5.292 + 5.293 + if(fabs(length_sq(ab_dir)) < 1e-5) { 5.294 + // if a == b, the capsule is a sphere with radius the maximum of the capsule radii 5.295 + return sphere_distance(a, std::max(ra, rb), pt); 5.296 + } 5.297 + float ab_len = length(ab_dir); 5.298 + 5.299 + Vec3 ap_dir = pt - a; 5.300 + Vec3 rotaxis = normalize(cross(ab_dir, ap_dir)); 5.301 + 5.302 + Mat4 rmat; 5.303 + rmat.set_rotation(rotaxis, M_PI / 2.0); 5.304 + Vec3 right = rmat * ab_dir / ab_len; 5.305 + 5.306 + // XXX I think this check is redundant, always false, due to the cross product order 5.307 + //assert(dot(right, ab_dir) >= 0.0); 5.308 + if(dot(right, ab_dir) < 0.0) { 5.309 + right = -right; 5.310 + } 5.311 + Vec3 aa = a + right * ra; 5.312 + Vec3 bb = b + right * rb; 5.313 + 5.314 + // project pt to the line segment bb-aa, see if the projection lies within the interval [0, 1) 5.315 + Vec3 aabb_dir = bb - aa; 5.316 + float aabb_len = length(aabb_dir); 5.317 + Vec3 aap_dir = pt - aa; 5.318 + 5.319 + float t = dot(aap_dir, aabb_dir / aabb_len) / aabb_len; 5.320 + if(t < 0.0) { 5.321 + return sphere_distance(a, ra, pt); 5.322 + } 5.323 + if(t >= 1.0) { 5.324 + return sphere_distance(b, rb, pt); 5.325 + } 5.326 + 5.327 + Vec3 ppt = aa + aabb_dir * t; 5.328 + Vec3 norm = ppt - pt; 5.329 + float dist = length(norm); 5.330 + 5.331 + if(dot(norm, right) < 0.0) { 5.332 + // inside the cone 5.333 + dist = -dist; 5.334 + } 5.335 + return dist; 5.336 +} 5.337 +#endif
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/geom.h Thu Jul 27 20:36:12 2017 +0300 6.3 @@ -0,0 +1,73 @@ 6.4 +#ifndef GEOMOBJ_H_ 6.5 +#define GEOMOBJ_H_ 6.6 + 6.7 +#include <gmath/gmath.h> 6.8 + 6.9 +class GeomObject; 6.10 +class SceneNode; 6.11 + 6.12 +struct HitPoint { 6.13 + float dist; //< parametric distance along the ray 6.14 + Vec3 pos; //< position of intersection (orig + dir * dist) 6.15 + Vec3 normal; //< normal at the point of intersection 6.16 + const void *obj; //< pointer to the intersected object 6.17 + const SceneNode *node; 6.18 + Ray ray; 6.19 +}; 6.20 + 6.21 +class GeomObject { 6.22 +public: 6.23 + virtual ~GeomObject(); 6.24 + 6.25 + virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0; 6.26 + virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0; 6.27 + 6.28 + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0; 6.29 +}; 6.30 + 6.31 +class Sphere : public GeomObject { 6.32 +public: 6.33 + Vec3 center; 6.34 + float radius; 6.35 + 6.36 + Sphere(); 6.37 + Sphere(const Vec3 ¢er, float radius); 6.38 + 6.39 + void set_union(const GeomObject *obj1, const GeomObject *obj2); 6.40 + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); 6.41 + 6.42 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 6.43 +}; 6.44 + 6.45 +class AABox : public GeomObject { 6.46 +public: 6.47 + Vec3 min, max; 6.48 + 6.49 + AABox(); 6.50 + AABox(const Vec3 &min, const Vec3 &max); 6.51 + 6.52 + void set_union(const GeomObject *obj1, const GeomObject *obj2); 6.53 + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); 6.54 + 6.55 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 6.56 +}; 6.57 + 6.58 +class Plane : public GeomObject { 6.59 +public: 6.60 + Vec3 pt, normal; 6.61 + 6.62 + Plane(); 6.63 + Plane(const Vec3 &pt, const Vec3 &normal); 6.64 + Plane(const Vec3 &p1, const Vec3 &p2, const Vec3 &p3); 6.65 + Plane(const Vec3 &normal, float dist); 6.66 + 6.67 + void set_union(const GeomObject *obj1, const GeomObject *obj2); 6.68 + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); 6.69 + 6.70 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 6.71 +}; 6.72 + 6.73 +float sphere_distance(const Vec3 ¢, float rad, const Vec3 &pt); 6.74 +float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt); 6.75 + 6.76 +#endif // GEOMOBJ_H_
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/main.cc Thu Jul 27 20:36:12 2017 +0300 7.3 @@ -0,0 +1,75 @@ 7.4 +#include <stdlib.h> 7.5 +#ifdef __APPLE__ 7.6 +#include <GLUT/glut.h> 7.7 +#else 7.8 +#include <GL/glut.h> 7.9 +#endif 7.10 +#include "app.h" 7.11 + 7.12 +static void display(); 7.13 +static void reshape(int x, int y); 7.14 +static void keydown(unsigned char key, int x, int y); 7.15 +static void mouse(int bn, int st, int x, int y); 7.16 +static void motion(int x, int y); 7.17 + 7.18 +int main(int argc, char **argv) 7.19 +{ 7.20 + glutInit(&argc, argv); 7.21 + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 7.22 + glutInitWindowSize(1024, 768); 7.23 + glutCreateWindow("cubemapper"); 7.24 + 7.25 + glutDisplayFunc(display); 7.26 + glutReshapeFunc(reshape); 7.27 + glutKeyboardFunc(keydown); 7.28 + glutMouseFunc(mouse); 7.29 + glutMotionFunc(motion); 7.30 + 7.31 + if(!app_init(argc, argv)) { 7.32 + return 1; 7.33 + } 7.34 + 7.35 + glutMainLoop(); 7.36 + return 0; 7.37 +} 7.38 + 7.39 +void app_quit() 7.40 +{ 7.41 + app_cleanup(); 7.42 + exit(0); 7.43 +} 7.44 + 7.45 +void app_redisplay() 7.46 +{ 7.47 + glutPostRedisplay(); 7.48 +} 7.49 + 7.50 +void app_swap_buffers() 7.51 +{ 7.52 + glutSwapBuffers(); 7.53 +} 7.54 + 7.55 +static void display() 7.56 +{ 7.57 + app_draw(); 7.58 +} 7.59 + 7.60 +static void reshape(int x, int y) 7.61 +{ 7.62 + app_reshape(x, y); 7.63 +} 7.64 + 7.65 +static void keydown(unsigned char key, int x, int y) 7.66 +{ 7.67 + app_keyboard(key, true); 7.68 +} 7.69 + 7.70 +static void mouse(int bn, int st, int x, int y) 7.71 +{ 7.72 + app_mouse_button(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y); 7.73 +} 7.74 + 7.75 +static void motion(int x, int y) 7.76 +{ 7.77 + app_mouse_motion(x, y); 7.78 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/mesh.cc Thu Jul 27 20:36:12 2017 +0300 8.3 @@ -0,0 +1,1362 @@ 8.4 +#include <stdio.h> 8.5 +#include <stdlib.h> 8.6 +#include <float.h> 8.7 +#include <assert.h> 8.8 +#include "opengl.h" 8.9 +#include "mesh.h" 8.10 +//#include "xform_node.h" 8.11 + 8.12 +#define USE_OLDGL 8.13 + 8.14 +bool Mesh::use_custom_sdr_attr = true; 8.15 +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 }; 8.16 +/* 8.17 + (int)SDR_ATTR_VERTEX, 8.18 + (int)SDR_ATTR_NORMAL, 8.19 + (int)SDR_ATTR_TANGENT, 8.20 + (int)SDR_ATTR_TEXCOORD, 8.21 + (int)SDR_ATTR_COLOR, 8.22 + -1, -1}; 8.23 +*/ 8.24 +unsigned int Mesh::intersect_mode = ISECT_DEFAULT; 8.25 +float Mesh::vertex_sel_dist = 0.01; 8.26 +float Mesh::vis_vecsize = 1.0; 8.27 + 8.28 +Mesh::Mesh() 8.29 +{ 8.30 + clear(); 8.31 + 8.32 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 8.33 + 8.34 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.35 + vattr[i].vbo = buffer_objects[i]; 8.36 + } 8.37 + ibo = buffer_objects[NUM_MESH_ATTR]; 8.38 + wire_ibo = 0; 8.39 +} 8.40 + 8.41 +Mesh::~Mesh() 8.42 +{ 8.43 + glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects); 8.44 + 8.45 + if(wire_ibo) { 8.46 + glDeleteBuffers(1, &wire_ibo); 8.47 + } 8.48 +} 8.49 + 8.50 +Mesh::Mesh(const Mesh &rhs) 8.51 +{ 8.52 + clear(); 8.53 + 8.54 + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); 8.55 + 8.56 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.57 + vattr[i].vbo = buffer_objects[i]; 8.58 + } 8.59 + ibo = buffer_objects[NUM_MESH_ATTR]; 8.60 + wire_ibo = 0; 8.61 + 8.62 + clone(rhs); 8.63 +} 8.64 + 8.65 +Mesh &Mesh::operator =(const Mesh &rhs) 8.66 +{ 8.67 + if(&rhs != this) { 8.68 + clone(rhs); 8.69 + } 8.70 + return *this; 8.71 +} 8.72 + 8.73 +bool Mesh::clone(const Mesh &m) 8.74 +{ 8.75 + clear(); 8.76 + 8.77 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.78 + if(m.has_attrib(i)) { 8.79 + m.get_attrib_data(i); // force validation of the actual data on the source mesh 8.80 + 8.81 + vattr[i].nelem = m.vattr[i].nelem; 8.82 + vattr[i].data = m.vattr[i].data; // copy the actual data 8.83 + vattr[i].data_valid = true; 8.84 + } 8.85 + } 8.86 + 8.87 + if(m.is_indexed()) { 8.88 + m.get_index_data(); // again, force validation 8.89 + 8.90 + // copy the index data 8.91 + idata = m.idata; 8.92 + idata_valid = true; 8.93 + } 8.94 + 8.95 + name = m.name; 8.96 + nverts = m.nverts; 8.97 + nfaces = m.nfaces; 8.98 + 8.99 + //bones = m.bones; 8.100 + 8.101 + memcpy(cur_val, m.cur_val, sizeof cur_val); 8.102 + 8.103 + aabb = m.aabb; 8.104 + aabb_valid = m.aabb_valid; 8.105 + bsph = m.bsph; 8.106 + bsph_valid = m.bsph_valid; 8.107 + 8.108 + hitface = m.hitface; 8.109 + hitvert = m.hitvert; 8.110 + 8.111 + intersect_mode = m.intersect_mode; 8.112 + vertex_sel_dist = m.vertex_sel_dist; 8.113 + vis_vecsize = m.vis_vecsize; 8.114 + 8.115 + return true; 8.116 +} 8.117 + 8.118 +void Mesh::set_name(const char *name) 8.119 +{ 8.120 + this->name = name; 8.121 +} 8.122 + 8.123 +const char *Mesh::get_name() const 8.124 +{ 8.125 + return name.c_str(); 8.126 +} 8.127 + 8.128 +bool Mesh::has_attrib(int attr) const 8.129 +{ 8.130 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 8.131 + return false; 8.132 + } 8.133 + 8.134 + // if neither of these is valid, then nobody has set this attribute 8.135 + return vattr[attr].vbo_valid || vattr[attr].data_valid; 8.136 +} 8.137 + 8.138 +bool Mesh::is_indexed() const 8.139 +{ 8.140 + return ibo_valid || idata_valid; 8.141 +} 8.142 + 8.143 +void Mesh::clear() 8.144 +{ 8.145 + //bones.clear(); 8.146 + 8.147 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.148 + vattr[i].nelem = 0; 8.149 + vattr[i].vbo_valid = false; 8.150 + vattr[i].data_valid = false; 8.151 + //vattr[i].sdr_loc = -1; 8.152 + vattr[i].data.clear(); 8.153 + } 8.154 + ibo_valid = idata_valid = false; 8.155 + idata.clear(); 8.156 + 8.157 + wire_ibo_valid = false; 8.158 + 8.159 + nverts = nfaces = 0; 8.160 + 8.161 + bsph_valid = false; 8.162 + aabb_valid = false; 8.163 +} 8.164 + 8.165 +float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data) 8.166 +{ 8.167 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 8.168 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 8.169 + return 0; 8.170 + } 8.171 + 8.172 + if(nverts && num != nverts) { 8.173 + fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts); 8.174 + return 0; 8.175 + } 8.176 + nverts = num; 8.177 + 8.178 + vattr[attrib].data.clear(); 8.179 + vattr[attrib].nelem = nelem; 8.180 + vattr[attrib].data.resize(num * nelem); 8.181 + 8.182 + if(data) { 8.183 + memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data); 8.184 + } 8.185 + 8.186 + vattr[attrib].data_valid = true; 8.187 + vattr[attrib].vbo_valid = false; 8.188 + return &vattr[attrib].data[0]; 8.189 +} 8.190 + 8.191 +float *Mesh::get_attrib_data(int attrib) 8.192 +{ 8.193 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 8.194 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 8.195 + return 0; 8.196 + } 8.197 + 8.198 + vattr[attrib].vbo_valid = false; 8.199 + return (float*)((const Mesh*)this)->get_attrib_data(attrib); 8.200 +} 8.201 + 8.202 +const float *Mesh::get_attrib_data(int attrib) const 8.203 +{ 8.204 + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { 8.205 + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); 8.206 + return 0; 8.207 + } 8.208 + 8.209 + if(!vattr[attrib].data_valid) { 8.210 +#if GL_ES_VERSION_2_0 8.211 + fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__); 8.212 + return 0; 8.213 +#else 8.214 + if(!vattr[attrib].vbo_valid) { 8.215 + fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib); 8.216 + return 0; 8.217 + } 8.218 + 8.219 + // local data copy is unavailable, grab the data from the vbo 8.220 + Mesh *m = (Mesh*)this; 8.221 + m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem); 8.222 + 8.223 + glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo); 8.224 + void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 8.225 + memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float)); 8.226 + glUnmapBuffer(GL_ARRAY_BUFFER); 8.227 + 8.228 + vattr[attrib].data_valid = true; 8.229 +#endif 8.230 + } 8.231 + 8.232 + return &vattr[attrib].data[0]; 8.233 +} 8.234 + 8.235 +void Mesh::set_attrib(int attrib, int idx, const Vec4 &v) 8.236 +{ 8.237 + float *data = get_attrib_data(attrib); 8.238 + if(data) { 8.239 + data += idx * vattr[attrib].nelem; 8.240 + for(int i=0; i<vattr[attrib].nelem; i++) { 8.241 + data[i] = v[i]; 8.242 + } 8.243 + } 8.244 +} 8.245 + 8.246 +Vec4 Mesh::get_attrib(int attrib, int idx) const 8.247 +{ 8.248 + Vec4 v(0.0, 0.0, 0.0, 1.0); 8.249 + const float *data = get_attrib_data(attrib); 8.250 + if(data) { 8.251 + data += idx * vattr[attrib].nelem; 8.252 + for(int i=0; i<vattr[attrib].nelem; i++) { 8.253 + v[i] = data[i]; 8.254 + } 8.255 + } 8.256 + return v; 8.257 +} 8.258 + 8.259 +int Mesh::get_attrib_count(int attrib) const 8.260 +{ 8.261 + return has_attrib(attrib) ? nverts : 0; 8.262 +} 8.263 + 8.264 + 8.265 +unsigned int *Mesh::set_index_data(int num, const unsigned int *indices) 8.266 +{ 8.267 + int nidx = nfaces * 3; 8.268 + if(nidx && num != nidx) { 8.269 + fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx); 8.270 + return 0; 8.271 + } 8.272 + nfaces = num / 3; 8.273 + 8.274 + idata.clear(); 8.275 + idata.resize(num); 8.276 + 8.277 + if(indices) { 8.278 + memcpy(&idata[0], indices, num * sizeof *indices); 8.279 + } 8.280 + 8.281 + idata_valid = true; 8.282 + ibo_valid = false; 8.283 + 8.284 + return &idata[0]; 8.285 +} 8.286 + 8.287 +unsigned int *Mesh::get_index_data() 8.288 +{ 8.289 + ibo_valid = false; 8.290 + return (unsigned int*)((const Mesh*)this)->get_index_data(); 8.291 +} 8.292 + 8.293 +const unsigned int *Mesh::get_index_data() const 8.294 +{ 8.295 + if(!idata_valid) { 8.296 +#if GL_ES_VERSION_2_0 8.297 + fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__); 8.298 + return 0; 8.299 +#else 8.300 + if(!ibo_valid) { 8.301 + fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__); 8.302 + return 0; 8.303 + } 8.304 + 8.305 + // local data copy is unavailable, gram the data from the ibo 8.306 + Mesh *m = (Mesh*)this; 8.307 + int nidx = nfaces * 3; 8.308 + m->idata.resize(nidx); 8.309 + 8.310 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 8.311 + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); 8.312 + memcpy(&m->idata[0], data, nidx * sizeof(unsigned int)); 8.313 + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); 8.314 + 8.315 + idata_valid = true; 8.316 +#endif 8.317 + } 8.318 + 8.319 + return &idata[0]; 8.320 +} 8.321 + 8.322 +int Mesh::get_index_count() const 8.323 +{ 8.324 + return nfaces * 3; 8.325 +} 8.326 + 8.327 +void Mesh::append(const Mesh &mesh) 8.328 +{ 8.329 + unsigned int idxoffs = nverts; 8.330 + 8.331 + if(!nverts) { 8.332 + clone(mesh); 8.333 + return; 8.334 + } 8.335 + 8.336 + nverts += mesh.nverts; 8.337 + nfaces += mesh.nfaces; 8.338 + 8.339 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.340 + if(has_attrib(i) && mesh.has_attrib(i)) { 8.341 + // force validating the data arrays 8.342 + get_attrib_data(i); 8.343 + mesh.get_attrib_data(i); 8.344 + 8.345 + // append the mesh data 8.346 + vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end()); 8.347 + } 8.348 + } 8.349 + 8.350 + if(ibo_valid || idata_valid) { 8.351 + // make index arrays valid 8.352 + get_index_data(); 8.353 + mesh.get_index_data(); 8.354 + 8.355 + size_t orig_sz = idata.size(); 8.356 + 8.357 + idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end()); 8.358 + 8.359 + // fixup all the new indices 8.360 + for(size_t i=orig_sz; i<idata.size(); i++) { 8.361 + idata[i] += idxoffs; 8.362 + } 8.363 + } 8.364 + 8.365 + // fuck everything 8.366 + wire_ibo_valid = false; 8.367 + aabb_valid = false; 8.368 + bsph_valid = false; 8.369 +} 8.370 + 8.371 +// assemble a complete vertex by adding all the useful attributes 8.372 +void Mesh::vertex(float x, float y, float z) 8.373 +{ 8.374 + cur_val[MESH_ATTR_VERTEX] = Vec4(x, y, z, 1.0f); 8.375 + vattr[MESH_ATTR_VERTEX].data_valid = true; 8.376 + vattr[MESH_ATTR_VERTEX].nelem = 3; 8.377 + 8.378 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.379 + if(vattr[i].data_valid) { 8.380 + for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) { 8.381 + vattr[i].data.push_back(cur_val[i][j]); 8.382 + } 8.383 + } 8.384 + vattr[i].vbo_valid = false; 8.385 + } 8.386 + 8.387 + if(idata_valid) { 8.388 + idata.clear(); 8.389 + } 8.390 + ibo_valid = idata_valid = false; 8.391 +} 8.392 + 8.393 +void Mesh::normal(float nx, float ny, float nz) 8.394 +{ 8.395 + cur_val[MESH_ATTR_NORMAL] = Vec4(nx, ny, nz, 1.0f); 8.396 + vattr[MESH_ATTR_NORMAL].data_valid = true; 8.397 + vattr[MESH_ATTR_NORMAL].nelem = 3; 8.398 +} 8.399 + 8.400 +void Mesh::tangent(float tx, float ty, float tz) 8.401 +{ 8.402 + cur_val[MESH_ATTR_TANGENT] = Vec4(tx, ty, tz, 1.0f); 8.403 + vattr[MESH_ATTR_TANGENT].data_valid = true; 8.404 + vattr[MESH_ATTR_TANGENT].nelem = 3; 8.405 +} 8.406 + 8.407 +void Mesh::texcoord(float u, float v, float w) 8.408 +{ 8.409 + cur_val[MESH_ATTR_TEXCOORD] = Vec4(u, v, w, 1.0f); 8.410 + vattr[MESH_ATTR_TEXCOORD].data_valid = true; 8.411 + vattr[MESH_ATTR_TEXCOORD].nelem = 3; 8.412 +} 8.413 + 8.414 +void Mesh::boneweights(float w1, float w2, float w3, float w4) 8.415 +{ 8.416 + cur_val[MESH_ATTR_BONEWEIGHTS] = Vec4(w1, w2, w3, w4); 8.417 + vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true; 8.418 + vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4; 8.419 +} 8.420 + 8.421 +void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4) 8.422 +{ 8.423 + cur_val[MESH_ATTR_BONEIDX] = Vec4(idx1, idx2, idx3, idx4); 8.424 + vattr[MESH_ATTR_BONEIDX].data_valid = true; 8.425 + vattr[MESH_ATTR_BONEIDX].nelem = 4; 8.426 +} 8.427 + 8.428 +int Mesh::get_poly_count() const 8.429 +{ 8.430 + if(nfaces) { 8.431 + return nfaces; 8.432 + } 8.433 + if(nverts) { 8.434 + return nverts / 3; 8.435 + } 8.436 + return 0; 8.437 +} 8.438 + 8.439 +/// static function 8.440 +void Mesh::set_attrib_location(int attr, int loc) 8.441 +{ 8.442 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 8.443 + return; 8.444 + } 8.445 + Mesh::global_sdr_loc[attr] = loc; 8.446 +} 8.447 + 8.448 +/// static function 8.449 +int Mesh::get_attrib_location(int attr) 8.450 +{ 8.451 + if(attr < 0 || attr >= NUM_MESH_ATTR) { 8.452 + return -1; 8.453 + } 8.454 + return Mesh::global_sdr_loc[attr]; 8.455 +} 8.456 + 8.457 +/// static function 8.458 +void Mesh::clear_attrib_locations() 8.459 +{ 8.460 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.461 + Mesh::global_sdr_loc[i] = -1; 8.462 + } 8.463 +} 8.464 + 8.465 +/// static function 8.466 +void Mesh::set_vis_vecsize(float sz) 8.467 +{ 8.468 + Mesh::vis_vecsize = sz; 8.469 +} 8.470 + 8.471 +float Mesh::get_vis_vecsize() 8.472 +{ 8.473 + return Mesh::vis_vecsize; 8.474 +} 8.475 + 8.476 +void Mesh::apply_xform(const Mat4 &xform) 8.477 +{ 8.478 + Mat4 dir_xform = xform.upper3x3(); 8.479 + apply_xform(xform, dir_xform); 8.480 +} 8.481 + 8.482 +void Mesh::apply_xform(const Mat4 &xform, const Mat4 &dir_xform) 8.483 +{ 8.484 + for(unsigned int i=0; i<nverts; i++) { 8.485 + Vec4 v = get_attrib(MESH_ATTR_VERTEX, i); 8.486 + set_attrib(MESH_ATTR_VERTEX, i, xform * v); 8.487 + 8.488 + if(has_attrib(MESH_ATTR_NORMAL)) { 8.489 + Vec3 n = get_attrib(MESH_ATTR_NORMAL, i).xyz(); 8.490 + set_attrib(MESH_ATTR_NORMAL, i, Vec4(dir_xform * n)); 8.491 + } 8.492 + if(has_attrib(MESH_ATTR_TANGENT)) { 8.493 + Vec3 t = get_attrib(MESH_ATTR_TANGENT, i).xyz(); 8.494 + set_attrib(MESH_ATTR_TANGENT, i, Vec4(dir_xform * t)); 8.495 + } 8.496 + } 8.497 +} 8.498 + 8.499 +void Mesh::flip() 8.500 +{ 8.501 + flip_faces(); 8.502 + flip_normals(); 8.503 +} 8.504 + 8.505 +void Mesh::flip_faces() 8.506 +{ 8.507 + if(is_indexed()) { 8.508 + unsigned int *indices = get_index_data(); 8.509 + if(!indices) return; 8.510 + 8.511 + int idxnum = get_index_count(); 8.512 + for(int i=0; i<idxnum; i+=3) { 8.513 + unsigned int tmp = indices[i + 2]; 8.514 + indices[i + 2] = indices[i + 1]; 8.515 + indices[i + 1] = tmp; 8.516 + } 8.517 + 8.518 + } else { 8.519 + Vec3 *verts = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 8.520 + if(!verts) return; 8.521 + 8.522 + int vnum = get_attrib_count(MESH_ATTR_VERTEX); 8.523 + for(int i=0; i<vnum; i+=3) { 8.524 + Vec3 tmp = verts[i + 2]; 8.525 + verts[i + 2] = verts[i + 1]; 8.526 + verts[i + 1] = tmp; 8.527 + } 8.528 + } 8.529 +} 8.530 + 8.531 +void Mesh::flip_normals() 8.532 +{ 8.533 + Vec3 *normals = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL); 8.534 + if(!normals) return; 8.535 + 8.536 + int num = get_attrib_count(MESH_ATTR_NORMAL); 8.537 + for(int i=0; i<num; i++) { 8.538 + normals[i] = -normals[i]; 8.539 + } 8.540 +} 8.541 + 8.542 +/* 8.543 +int Mesh::add_bone(XFormNode *bone) 8.544 +{ 8.545 + int idx = bones.size(); 8.546 + bones.push_back(bone); 8.547 + return idx; 8.548 +} 8.549 + 8.550 +const XFormNode *Mesh::get_bone(int idx) const 8.551 +{ 8.552 + if(idx < 0 || idx >= (int)bones.size()) { 8.553 + return 0; 8.554 + } 8.555 + return bones[idx]; 8.556 +} 8.557 + 8.558 +int Mesh::get_bones_count() const 8.559 +{ 8.560 + return (int)bones.size(); 8.561 +} 8.562 +*/ 8.563 + 8.564 +bool Mesh::pre_draw() const 8.565 +{ 8.566 + cur_sdr = 0; 8.567 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 8.568 + 8.569 + ((Mesh*)this)->update_buffers(); 8.570 + 8.571 + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { 8.572 + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); 8.573 + return false; 8.574 + } 8.575 + 8.576 + if(cur_sdr && use_custom_sdr_attr) { 8.577 + // rendering with shaders 8.578 + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { 8.579 + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); 8.580 + return false; 8.581 + } 8.582 + 8.583 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.584 + int loc = global_sdr_loc[i]; 8.585 + if(loc >= 0 && vattr[i].vbo_valid) { 8.586 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 8.587 + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); 8.588 + glEnableVertexAttribArray(loc); 8.589 + } 8.590 + } 8.591 + } else { 8.592 +#ifndef GL_ES_VERSION_2_0 8.593 + // rendering with fixed-function (not available in GLES2) 8.594 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo); 8.595 + glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0); 8.596 + glEnableClientState(GL_VERTEX_ARRAY); 8.597 + 8.598 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 8.599 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo); 8.600 + glNormalPointer(GL_FLOAT, 0, 0); 8.601 + glEnableClientState(GL_NORMAL_ARRAY); 8.602 + } 8.603 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 8.604 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo); 8.605 + glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0); 8.606 + glEnableClientState(GL_TEXTURE_COORD_ARRAY); 8.607 + } 8.608 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 8.609 + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo); 8.610 + glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0); 8.611 + glEnableClientState(GL_COLOR_ARRAY); 8.612 + } 8.613 +#endif 8.614 + } 8.615 + glBindBuffer(GL_ARRAY_BUFFER, 0); 8.616 + 8.617 + return true; 8.618 +} 8.619 + 8.620 +void Mesh::draw() const 8.621 +{ 8.622 + if(!pre_draw()) return; 8.623 + 8.624 + if(ibo_valid) { 8.625 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 8.626 + glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0); 8.627 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 8.628 + } else { 8.629 + glDrawArrays(GL_TRIANGLES, 0, nverts); 8.630 + } 8.631 + 8.632 + post_draw(); 8.633 +} 8.634 + 8.635 +void Mesh::post_draw() const 8.636 +{ 8.637 + if(cur_sdr && use_custom_sdr_attr) { 8.638 + // rendered with shaders 8.639 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.640 + int loc = global_sdr_loc[i]; 8.641 + if(loc >= 0 && vattr[i].vbo_valid) { 8.642 + glDisableVertexAttribArray(loc); 8.643 + } 8.644 + } 8.645 + } else { 8.646 +#ifndef GL_ES_VERSION_2_0 8.647 + // rendered with fixed-function 8.648 + glDisableClientState(GL_VERTEX_ARRAY); 8.649 + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { 8.650 + glDisableClientState(GL_NORMAL_ARRAY); 8.651 + } 8.652 + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { 8.653 + glDisableClientState(GL_TEXTURE_COORD_ARRAY); 8.654 + } 8.655 + if(vattr[MESH_ATTR_COLOR].vbo_valid) { 8.656 + glDisableClientState(GL_COLOR_ARRAY); 8.657 + } 8.658 +#endif 8.659 + } 8.660 +} 8.661 + 8.662 +void Mesh::draw_wire() const 8.663 +{ 8.664 + if(!pre_draw()) return; 8.665 + 8.666 + ((Mesh*)this)->update_wire_ibo(); 8.667 + 8.668 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 8.669 + glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0); 8.670 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 8.671 + 8.672 + post_draw(); 8.673 +} 8.674 + 8.675 +void Mesh::draw_vertices() const 8.676 +{ 8.677 + if(!pre_draw()) return; 8.678 + 8.679 + glDrawArrays(GL_POINTS, 0, nverts); 8.680 + 8.681 + post_draw(); 8.682 +} 8.683 + 8.684 +void Mesh::draw_normals() const 8.685 +{ 8.686 +#ifdef USE_OLDGL 8.687 + int cur_sdr = 0; 8.688 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 8.689 + 8.690 + Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 8.691 + Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL); 8.692 + if(!varr || !norm) { 8.693 + return; 8.694 + } 8.695 + 8.696 + glBegin(GL_LINES); 8.697 + if(cur_sdr && use_custom_sdr_attr) { 8.698 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 8.699 + if(vert_loc < 0) { 8.700 + glEnd(); 8.701 + return; 8.702 + } 8.703 + 8.704 + for(size_t i=0; i<nverts; i++) { 8.705 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 8.706 + Vec3 end = varr[i] + norm[i] * vis_vecsize; 8.707 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 8.708 + } 8.709 + } else { 8.710 + for(size_t i=0; i<nverts; i++) { 8.711 + glVertex3f(varr[i].x, varr[i].y, varr[i].z); 8.712 + Vec3 end = varr[i] + norm[i] * vis_vecsize; 8.713 + glVertex3f(end.x, end.y, end.z); 8.714 + } 8.715 + } 8.716 + glEnd(); 8.717 +#endif // USE_OLDGL 8.718 +} 8.719 + 8.720 +void Mesh::draw_tangents() const 8.721 +{ 8.722 +#ifdef USE_OLDGL 8.723 + int cur_sdr = 0; 8.724 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 8.725 + 8.726 + Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 8.727 + Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT); 8.728 + if(!varr || !tang) { 8.729 + return; 8.730 + } 8.731 + 8.732 + glBegin(GL_LINES); 8.733 + if(cur_sdr && use_custom_sdr_attr) { 8.734 + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; 8.735 + if(vert_loc < 0) { 8.736 + glEnd(); 8.737 + return; 8.738 + } 8.739 + 8.740 + for(size_t i=0; i<nverts; i++) { 8.741 + glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z); 8.742 + Vec3 end = varr[i] + tang[i] * vis_vecsize; 8.743 + glVertexAttrib3f(vert_loc, end.x, end.y, end.z); 8.744 + } 8.745 + } else { 8.746 + for(size_t i=0; i<nverts; i++) { 8.747 + glVertex3f(varr[i].x, varr[i].y, varr[i].z); 8.748 + Vec3 end = varr[i] + tang[i] * vis_vecsize; 8.749 + glVertex3f(end.x, end.y, end.z); 8.750 + } 8.751 + } 8.752 + glEnd(); 8.753 +#endif // USE_OLDGL 8.754 +} 8.755 + 8.756 +void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const 8.757 +{ 8.758 + if(!aabb_valid) { 8.759 + ((Mesh*)this)->calc_aabb(); 8.760 + } 8.761 + *vmin = aabb.min; 8.762 + *vmax = aabb.max; 8.763 +} 8.764 + 8.765 +const AABox &Mesh::get_aabbox() const 8.766 +{ 8.767 + if(!aabb_valid) { 8.768 + ((Mesh*)this)->calc_aabb(); 8.769 + } 8.770 + return aabb; 8.771 +} 8.772 + 8.773 +float Mesh::get_bsphere(Vec3 *center, float *rad) const 8.774 +{ 8.775 + if(!bsph_valid) { 8.776 + ((Mesh*)this)->calc_bsph(); 8.777 + } 8.778 + *center = bsph.center; 8.779 + *rad = bsph.radius; 8.780 + return bsph.radius; 8.781 +} 8.782 + 8.783 +const Sphere &Mesh::get_bsphere() const 8.784 +{ 8.785 + if(!bsph_valid) { 8.786 + ((Mesh*)this)->calc_bsph(); 8.787 + } 8.788 + return bsph; 8.789 +} 8.790 + 8.791 +/// static function 8.792 +void Mesh::set_intersect_mode(unsigned int mode) 8.793 +{ 8.794 + Mesh::intersect_mode = mode; 8.795 +} 8.796 + 8.797 +/// static function 8.798 +unsigned int Mesh::get_intersect_mode() 8.799 +{ 8.800 + return Mesh::intersect_mode; 8.801 +} 8.802 + 8.803 +/// static function 8.804 +void Mesh::set_vertex_select_distance(float dist) 8.805 +{ 8.806 + Mesh::vertex_sel_dist = dist; 8.807 +} 8.808 + 8.809 +/// static function 8.810 +float Mesh::get_vertex_select_distance() 8.811 +{ 8.812 + return Mesh::vertex_sel_dist; 8.813 +} 8.814 + 8.815 +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const 8.816 +{ 8.817 + assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE)); 8.818 + 8.819 + const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX); 8.820 + const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL); 8.821 + if(!varr) { 8.822 + return false; 8.823 + } 8.824 + const unsigned int *idxarr = get_index_data(); 8.825 + 8.826 + // first test with the bounding box 8.827 + AABox box; 8.828 + get_aabbox(&box.min, &box.max); 8.829 + if(!box.intersect(ray)) { 8.830 + return false; 8.831 + } 8.832 + 8.833 + HitPoint nearest_hit; 8.834 + nearest_hit.dist = FLT_MAX; 8.835 + nearest_hit.obj = 0; 8.836 + 8.837 + if(Mesh::intersect_mode & ISECT_VERTICES) { 8.838 + // we asked for "intersections" with the vertices of the mesh 8.839 + long nearest_vidx = -1; 8.840 + float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist; 8.841 + 8.842 + for(unsigned int i=0; i<nverts; i++) { 8.843 + 8.844 + if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) { 8.845 + continue; 8.846 + } 8.847 + 8.848 + // project the vertex onto the ray line 8.849 + float t = dot(varr[i] - ray.origin, ray.dir); 8.850 + Vec3 vproj = ray.origin + ray.dir * t; 8.851 + 8.852 + float dist_sq = length_sq(vproj - varr[i]); 8.853 + if(dist_sq < thres_sq) { 8.854 + if(!hit) { 8.855 + return true; 8.856 + } 8.857 + if(t < nearest_hit.dist) { 8.858 + nearest_hit.dist = t; 8.859 + nearest_vidx = i; 8.860 + } 8.861 + } 8.862 + } 8.863 + 8.864 + if(nearest_vidx != -1) { 8.865 + hitvert = varr[nearest_vidx]; 8.866 + nearest_hit.obj = &hitvert; 8.867 + } 8.868 + 8.869 + } else { 8.870 + // regular intersection test with polygons 8.871 + 8.872 + for(unsigned int i=0; i<nfaces; i++) { 8.873 + Triangle face(i, varr, idxarr); 8.874 + 8.875 + // ignore back-facing polygons if the mode flags include ISECT_FRONT 8.876 + if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) { 8.877 + continue; 8.878 + } 8.879 + 8.880 + HitPoint fhit; 8.881 + if(face.intersect(ray, hit ? &fhit : 0)) { 8.882 + if(!hit) { 8.883 + return true; 8.884 + } 8.885 + if(fhit.dist < nearest_hit.dist) { 8.886 + nearest_hit = fhit; 8.887 + hitface = face; 8.888 + } 8.889 + } 8.890 + } 8.891 + } 8.892 + 8.893 + if(nearest_hit.obj) { 8.894 + if(hit) { 8.895 + *hit = nearest_hit; 8.896 + 8.897 + // if we are interested in the mesh and not the faces set obj to this 8.898 + if(Mesh::intersect_mode & ISECT_FACE) { 8.899 + hit->obj = &hitface; 8.900 + } else if(Mesh::intersect_mode & ISECT_VERTICES) { 8.901 + hit->obj = &hitvert; 8.902 + } else { 8.903 + hit->obj = this; 8.904 + } 8.905 + } 8.906 + return true; 8.907 + } 8.908 + return false; 8.909 +} 8.910 + 8.911 + 8.912 +// texture coordinate manipulation 8.913 +void Mesh::texcoord_apply_xform(const Mat4 &xform) 8.914 +{ 8.915 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 8.916 + return; 8.917 + } 8.918 + 8.919 + for(unsigned int i=0; i<nverts; i++) { 8.920 + Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i); 8.921 + set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc); 8.922 + } 8.923 +} 8.924 + 8.925 +void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang) 8.926 +{ 8.927 + if(!nverts) return; 8.928 + 8.929 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 8.930 + // allocate texture coordinate attribute array 8.931 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 8.932 + } 8.933 + 8.934 + Vec3 n = normalize(norm); 8.935 + Vec3 b = normalize(cross(n, tang)); 8.936 + Vec3 t = cross(b, n); 8.937 + 8.938 + for(unsigned int i=0; i<nverts; i++) { 8.939 + Vec3 pos = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 8.940 + 8.941 + // distance along the tangent direction 8.942 + float u = dot(pos, t); 8.943 + // distance along the bitangent direction 8.944 + float v = dot(pos, b); 8.945 + 8.946 + set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1)); 8.947 + } 8.948 +} 8.949 + 8.950 +void Mesh::texcoord_gen_box() 8.951 +{ 8.952 + if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return; 8.953 + 8.954 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 8.955 + // allocate texture coordinate attribute array 8.956 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 8.957 + } 8.958 + 8.959 + for(unsigned int i=0; i<nverts; i++) { 8.960 + Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5); 8.961 + Vec3 norm = get_attrib(MESH_ATTR_NORMAL, i).xyz(); 8.962 + 8.963 + float abs_nx = fabs(norm.x); 8.964 + float abs_ny = fabs(norm.y); 8.965 + float abs_nz = fabs(norm.z); 8.966 + int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2); 8.967 + 8.968 + float uv[2], *uvptr = uv; 8.969 + for(int j=0; j<3; j++) { 8.970 + if(j == dom) continue; // skip dominant axis 8.971 + 8.972 + *uvptr++ = pos[j]; 8.973 + } 8.974 + set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1)); 8.975 + } 8.976 +} 8.977 + 8.978 +void Mesh::texcoord_gen_cylinder() 8.979 +{ 8.980 + if(!nverts) return; 8.981 + 8.982 + if(!has_attrib(MESH_ATTR_TEXCOORD)) { 8.983 + // allocate texture coordinate attribute array 8.984 + set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts); 8.985 + } 8.986 + 8.987 + for(unsigned int i=0; i<nverts; i++) { 8.988 + Vec3 pos = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 8.989 + 8.990 + float rho = sqrt(pos.x * pos.x + pos.z * pos.z); 8.991 + float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho); 8.992 + 8.993 + float u = theta / (2.0 * M_PI) + 0.5; 8.994 + float v = pos.y; 8.995 + 8.996 + set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1)); 8.997 + } 8.998 +} 8.999 + 8.1000 + 8.1001 +bool Mesh::dump(const char *fname) const 8.1002 +{ 8.1003 + FILE *fp = fopen(fname, "wb"); 8.1004 + if(fp) { 8.1005 + bool res = dump(fp); 8.1006 + fclose(fp); 8.1007 + return res; 8.1008 + } 8.1009 + return false; 8.1010 +} 8.1011 + 8.1012 +bool Mesh::dump(FILE *fp) const 8.1013 +{ 8.1014 + if(!has_attrib(MESH_ATTR_VERTEX)) { 8.1015 + return false; 8.1016 + } 8.1017 + 8.1018 + fprintf(fp, "VERTEX ATTRIBUTES\n"); 8.1019 + static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" }; 8.1020 + static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 }; 8.1021 + 8.1022 + for(int i=0; i<(int)nverts; i++) { 8.1023 + fprintf(fp, "%5u:", i); 8.1024 + for(int j=0; j<NUM_MESH_ATTR; j++) { 8.1025 + if(has_attrib(j)) { 8.1026 + Vec4 v = get_attrib(j, i); 8.1027 + int nelem = vattr[j].nelem; 8.1028 + fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w); 8.1029 + } 8.1030 + } 8.1031 + fputc('\n', fp); 8.1032 + } 8.1033 + 8.1034 + if(is_indexed()) { 8.1035 + const unsigned int *idx = get_index_data(); 8.1036 + int numidx = get_index_count(); 8.1037 + int numtri = numidx / 3; 8.1038 + assert(numidx % 3 == 0); 8.1039 + 8.1040 + fprintf(fp, "FACES\n"); 8.1041 + 8.1042 + for(int i=0; i<numtri; i++) { 8.1043 + fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]); 8.1044 + idx += 3; 8.1045 + } 8.1046 + } 8.1047 + return true; 8.1048 +} 8.1049 + 8.1050 +bool Mesh::dump_obj(const char *fname) const 8.1051 +{ 8.1052 + FILE *fp = fopen(fname, "wb"); 8.1053 + if(fp) { 8.1054 + bool res = dump_obj(fp); 8.1055 + fclose(fp); 8.1056 + return res; 8.1057 + } 8.1058 + return false; 8.1059 +} 8.1060 + 8.1061 +bool Mesh::dump_obj(FILE *fp) const 8.1062 +{ 8.1063 + if(!has_attrib(MESH_ATTR_VERTEX)) { 8.1064 + return false; 8.1065 + } 8.1066 + 8.1067 + for(int i=0; i<(int)nverts; i++) { 8.1068 + Vec4 v = get_attrib(MESH_ATTR_VERTEX, i); 8.1069 + fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z); 8.1070 + } 8.1071 + 8.1072 + if(has_attrib(MESH_ATTR_NORMAL)) { 8.1073 + for(int i=0; i<(int)nverts; i++) { 8.1074 + Vec4 v = get_attrib(MESH_ATTR_NORMAL, i); 8.1075 + fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z); 8.1076 + } 8.1077 + } 8.1078 + 8.1079 + if(has_attrib(MESH_ATTR_TEXCOORD)) { 8.1080 + for(int i=0; i<(int)nverts; i++) { 8.1081 + Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i); 8.1082 + fprintf(fp, "vt %g %g\n", v.x, v.y); 8.1083 + } 8.1084 + } 8.1085 + 8.1086 + if(is_indexed()) { 8.1087 + const unsigned int *idxptr = get_index_data(); 8.1088 + int numidx = get_index_count(); 8.1089 + int numtri = numidx / 3; 8.1090 + assert(numidx % 3 == 0); 8.1091 + 8.1092 + for(int i=0; i<numtri; i++) { 8.1093 + fputc('f', fp); 8.1094 + for(int j=0; j<3; j++) { 8.1095 + unsigned int idx = *idxptr++ + 1; 8.1096 + fprintf(fp, " %u/%u/%u", idx, idx, idx); 8.1097 + } 8.1098 + fputc('\n', fp); 8.1099 + } 8.1100 + } else { 8.1101 + int numtri = nverts / 3; 8.1102 + unsigned int idx = 1; 8.1103 + for(int i=0; i<numtri; i++) { 8.1104 + fputc('f', fp); 8.1105 + for(int j=0; j<3; j++) { 8.1106 + fprintf(fp, " %u/%u/%u", idx, idx, idx); 8.1107 + ++idx; 8.1108 + } 8.1109 + fputc('\n', fp); 8.1110 + } 8.1111 + } 8.1112 + return true; 8.1113 +} 8.1114 + 8.1115 +// ------ private member functions ------ 8.1116 + 8.1117 +void Mesh::calc_aabb() 8.1118 +{ 8.1119 + // the cast is to force calling the const version which doesn't invalidate 8.1120 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 8.1121 + return; 8.1122 + } 8.1123 + 8.1124 + aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX); 8.1125 + aabb.max = -aabb.min; 8.1126 + 8.1127 + for(unsigned int i=0; i<nverts; i++) { 8.1128 + Vec4 v = get_attrib(MESH_ATTR_VERTEX, i); 8.1129 + for(int j=0; j<3; j++) { 8.1130 + if(v[j] < aabb.min[j]) { 8.1131 + aabb.min[j] = v[j]; 8.1132 + } 8.1133 + if(v[j] > aabb.max[j]) { 8.1134 + aabb.max[j] = v[j]; 8.1135 + } 8.1136 + } 8.1137 + } 8.1138 + aabb_valid = true; 8.1139 +} 8.1140 + 8.1141 +void Mesh::calc_bsph() 8.1142 +{ 8.1143 + // the cast is to force calling the const version which doesn't invalidate 8.1144 + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { 8.1145 + return; 8.1146 + } 8.1147 + 8.1148 + Vec3 v; 8.1149 + bsph.center = Vec3(0, 0, 0); 8.1150 + 8.1151 + // first find the center 8.1152 + for(unsigned int i=0; i<nverts; i++) { 8.1153 + v = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 8.1154 + bsph.center += v; 8.1155 + } 8.1156 + bsph.center /= (float)nverts; 8.1157 + 8.1158 + bsph.radius = 0.0f; 8.1159 + for(unsigned int i=0; i<nverts; i++) { 8.1160 + v = get_attrib(MESH_ATTR_VERTEX, i).xyz(); 8.1161 + float dist_sq = length_sq(v - bsph.center); 8.1162 + if(dist_sq > bsph.radius) { 8.1163 + bsph.radius = dist_sq; 8.1164 + } 8.1165 + } 8.1166 + bsph.radius = sqrt(bsph.radius); 8.1167 + 8.1168 + bsph_valid = true; 8.1169 +} 8.1170 + 8.1171 +void Mesh::update_buffers() 8.1172 +{ 8.1173 + for(int i=0; i<NUM_MESH_ATTR; i++) { 8.1174 + if(has_attrib(i) && !vattr[i].vbo_valid) { 8.1175 + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); 8.1176 + glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW); 8.1177 + vattr[i].vbo_valid = true; 8.1178 + } 8.1179 + } 8.1180 + glBindBuffer(GL_ARRAY_BUFFER, 0); 8.1181 + 8.1182 + if(idata_valid && !ibo_valid) { 8.1183 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); 8.1184 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW); 8.1185 + ibo_valid = true; 8.1186 + } 8.1187 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 8.1188 +} 8.1189 + 8.1190 +void Mesh::update_wire_ibo() 8.1191 +{ 8.1192 + update_buffers(); 8.1193 + 8.1194 + if(wire_ibo_valid) { 8.1195 + return; 8.1196 + } 8.1197 + 8.1198 + if(!wire_ibo) { 8.1199 + glGenBuffers(1, &wire_ibo); 8.1200 + } 8.1201 + 8.1202 + unsigned int *wire_idxarr = new unsigned int[nfaces * 6]; 8.1203 + unsigned int *dest = wire_idxarr; 8.1204 + 8.1205 + if(ibo_valid) { 8.1206 + // we're dealing with an indexed mesh 8.1207 + const unsigned int *idxarr = ((const Mesh*)this)->get_index_data(); 8.1208 + 8.1209 + for(unsigned int i=0; i<nfaces; i++) { 8.1210 + *dest++ = idxarr[0]; 8.1211 + *dest++ = idxarr[1]; 8.1212 + *dest++ = idxarr[1]; 8.1213 + *dest++ = idxarr[2]; 8.1214 + *dest++ = idxarr[2]; 8.1215 + *dest++ = idxarr[0]; 8.1216 + idxarr += 3; 8.1217 + } 8.1218 + } else { 8.1219 + // not an indexed mesh ... 8.1220 + for(unsigned int i=0; i<nfaces; i++) { 8.1221 + int vidx = i * 3; 8.1222 + *dest++ = vidx; 8.1223 + *dest++ = vidx + 1; 8.1224 + *dest++ = vidx + 1; 8.1225 + *dest++ = vidx + 2; 8.1226 + *dest++ = vidx + 2; 8.1227 + *dest++ = vidx; 8.1228 + } 8.1229 + } 8.1230 + 8.1231 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); 8.1232 + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW); 8.1233 + delete [] wire_idxarr; 8.1234 + wire_ibo_valid = true; 8.1235 + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 8.1236 +} 8.1237 + 8.1238 + 8.1239 +// ------ class Triangle ------ 8.1240 +Triangle::Triangle() 8.1241 +{ 8.1242 + normal_valid = false; 8.1243 + id = -1; 8.1244 +} 8.1245 + 8.1246 +Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2) 8.1247 +{ 8.1248 + v[0] = v0; 8.1249 + v[1] = v1; 8.1250 + v[2] = v2; 8.1251 + normal_valid = false; 8.1252 + id = -1; 8.1253 +} 8.1254 + 8.1255 +Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr) 8.1256 +{ 8.1257 + if(idxarr) { 8.1258 + v[0] = varr[idxarr[n * 3]]; 8.1259 + v[1] = varr[idxarr[n * 3 + 1]]; 8.1260 + v[2] = varr[idxarr[n * 3 + 2]]; 8.1261 + } else { 8.1262 + v[0] = varr[n * 3]; 8.1263 + v[1] = varr[n * 3 + 1]; 8.1264 + v[2] = varr[n * 3 + 2]; 8.1265 + } 8.1266 + normal_valid = false; 8.1267 + id = n; 8.1268 +} 8.1269 + 8.1270 +void Triangle::calc_normal() 8.1271 +{ 8.1272 + normal = normalize(cross(v[1] - v[0], v[2] - v[0])); 8.1273 + normal_valid = true; 8.1274 +} 8.1275 + 8.1276 +const Vec3 &Triangle::get_normal() const 8.1277 +{ 8.1278 + if(!normal_valid) { 8.1279 + ((Triangle*)this)->calc_normal(); 8.1280 + } 8.1281 + return normal; 8.1282 +} 8.1283 + 8.1284 +void Triangle::transform(const Mat4 &xform) 8.1285 +{ 8.1286 + v[0] = xform * v[0]; 8.1287 + v[1] = xform * v[1]; 8.1288 + v[2] = xform * v[2]; 8.1289 + normal_valid = false; 8.1290 +} 8.1291 + 8.1292 +void Triangle::draw() const 8.1293 +{ 8.1294 + Vec3 n[3]; 8.1295 + n[0] = n[1] = n[2] = get_normal(); 8.1296 + 8.1297 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 8.1298 + int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL); 8.1299 + 8.1300 + glEnableVertexAttribArray(vloc); 8.1301 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 8.1302 + glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x); 8.1303 + 8.1304 + glDrawArrays(GL_TRIANGLES, 0, 3); 8.1305 + 8.1306 + glDisableVertexAttribArray(vloc); 8.1307 + glDisableVertexAttribArray(nloc); 8.1308 +} 8.1309 + 8.1310 +void Triangle::draw_wire() const 8.1311 +{ 8.1312 + static const int idxarr[] = {0, 1, 1, 2, 2, 0}; 8.1313 + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); 8.1314 + 8.1315 + glEnableVertexAttribArray(vloc); 8.1316 + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); 8.1317 + 8.1318 + glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr); 8.1319 + 8.1320 + glDisableVertexAttribArray(vloc); 8.1321 +} 8.1322 + 8.1323 +Vec3 Triangle::calc_barycentric(const Vec3 &pos) const 8.1324 +{ 8.1325 + Vec3 norm = get_normal(); 8.1326 + 8.1327 + float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm)); 8.1328 + if(area_sq < 1e-5) { 8.1329 + return Vec3(0, 0, 0); 8.1330 + } 8.1331 + 8.1332 + float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm)); 8.1333 + float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm)); 8.1334 + float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm)); 8.1335 + 8.1336 + return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq); 8.1337 +} 8.1338 + 8.1339 +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const 8.1340 +{ 8.1341 + Vec3 normal = get_normal(); 8.1342 + 8.1343 + float ndotdir = dot(ray.dir, normal); 8.1344 + if(fabs(ndotdir) < 1e-4) { 8.1345 + return false; 8.1346 + } 8.1347 + 8.1348 + Vec3 vertdir = v[0] - ray.origin; 8.1349 + float t = dot(normal, vertdir) / ndotdir; 8.1350 + 8.1351 + Vec3 pos = ray.origin + ray.dir * t; 8.1352 + Vec3 bary = calc_barycentric(pos); 8.1353 + 8.1354 + if(bary.x + bary.y + bary.z > 1.00001) { 8.1355 + return false; 8.1356 + } 8.1357 + 8.1358 + if(hit) { 8.1359 + hit->dist = t; 8.1360 + hit->pos = ray.origin + ray.dir * t; 8.1361 + hit->normal = normal; 8.1362 + hit->obj = this; 8.1363 + } 8.1364 + return true; 8.1365 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/mesh.h Thu Jul 27 20:36:12 2017 +0300 9.3 @@ -0,0 +1,243 @@ 9.4 +#ifndef MESH_H_ 9.5 +#define MESH_H_ 9.6 + 9.7 +#include <stdio.h> 9.8 +#include <string> 9.9 +#include <vector> 9.10 +#include <gmath/gmath.h> 9.11 +#include "geom.h" 9.12 + 9.13 +enum { 9.14 + MESH_ATTR_VERTEX, 9.15 + MESH_ATTR_NORMAL, 9.16 + MESH_ATTR_TANGENT, 9.17 + MESH_ATTR_TEXCOORD, 9.18 + MESH_ATTR_COLOR, 9.19 + MESH_ATTR_BONEWEIGHTS, 9.20 + MESH_ATTR_BONEIDX, 9.21 + 9.22 + NUM_MESH_ATTR 9.23 +}; 9.24 + 9.25 +// intersection mode flags 9.26 +enum { 9.27 + ISECT_DEFAULT = 0, // default (whole mesh, all intersections) 9.28 + ISECT_FRONT = 1, // front-faces only 9.29 + ISECT_FACE = 2, // return intersected face pointer instead of mesh 9.30 + ISECT_VERTICES = 4 // return (?) TODO 9.31 +}; 9.32 + 9.33 +//class XFormNode; 9.34 + 9.35 + 9.36 +class Triangle { 9.37 +public: 9.38 + Vec3 v[3]; 9.39 + Vec3 normal; 9.40 + bool normal_valid; 9.41 + int id; 9.42 + 9.43 + Triangle(); 9.44 + Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2); 9.45 + Triangle(int n, const Vec3 *varr, const unsigned int *idxarr = 0); 9.46 + 9.47 + /// calculate normal (quite expensive) 9.48 + void calc_normal(); 9.49 + const Vec3 &get_normal() const; 9.50 + 9.51 + void transform(const Mat4 &xform); 9.52 + 9.53 + void draw() const; 9.54 + void draw_wire() const; 9.55 + 9.56 + /// calculate barycentric coordinates of a point 9.57 + Vec3 calc_barycentric(const Vec3 &pos) const; 9.58 + 9.59 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 9.60 +}; 9.61 + 9.62 + 9.63 +class Mesh { 9.64 +private: 9.65 + std::string name; 9.66 + unsigned int nverts, nfaces; 9.67 + 9.68 + // current value for each attribute for the immedate mode 9.69 + // interface. 9.70 + Vec4 cur_val[NUM_MESH_ATTR]; 9.71 + 9.72 + unsigned int buffer_objects[NUM_MESH_ATTR + 1]; 9.73 + 9.74 + // vertex attribute data and buffer objects 9.75 + struct { 9.76 + int nelem; // number of elements per attribute range: [1, 4] 9.77 + std::vector<float> data; 9.78 + unsigned int vbo; 9.79 + mutable bool vbo_valid; // if this is false, the vbo needs updating from the data 9.80 + mutable bool data_valid; // if this is false, the data needs to be pulled from the vbo 9.81 + //int sdr_loc; 9.82 + } vattr[NUM_MESH_ATTR]; 9.83 + 9.84 + static int global_sdr_loc[NUM_MESH_ATTR]; 9.85 + 9.86 + //std::vector<XFormNode*> bones; // bones affecting this mesh 9.87 + 9.88 + // index data and buffer object 9.89 + std::vector<unsigned int> idata; 9.90 + unsigned int ibo; 9.91 + mutable bool ibo_valid; 9.92 + mutable bool idata_valid; 9.93 + 9.94 + // index buffer object for wireframe rendering (constructed on demand) 9.95 + unsigned int wire_ibo; 9.96 + mutable bool wire_ibo_valid; 9.97 + 9.98 + // axis-aligned bounding box 9.99 + mutable AABox aabb; 9.100 + mutable bool aabb_valid; 9.101 + 9.102 + // bounding sphere 9.103 + mutable Sphere bsph; 9.104 + mutable bool bsph_valid; 9.105 + 9.106 + // keeps the last intersected face 9.107 + mutable Triangle hitface; 9.108 + // keeps the last intersected vertex position 9.109 + mutable Vec3 hitvert; 9.110 + 9.111 + void calc_aabb(); 9.112 + void calc_bsph(); 9.113 + 9.114 + static unsigned int intersect_mode; 9.115 + static float vertex_sel_dist; 9.116 + 9.117 + static float vis_vecsize; 9.118 + 9.119 + /// update the VBOs after data has changed (invalid vbo/ibo) 9.120 + void update_buffers(); 9.121 + /// construct/update the wireframe index buffer (called from draw_wire). 9.122 + void update_wire_ibo(); 9.123 + 9.124 + mutable int cur_sdr; 9.125 + bool pre_draw() const; 9.126 + void post_draw() const; 9.127 + 9.128 + 9.129 +public: 9.130 + static bool use_custom_sdr_attr; 9.131 + 9.132 + Mesh(); 9.133 + ~Mesh(); 9.134 + 9.135 + Mesh(const Mesh &rhs); 9.136 + Mesh &operator =(const Mesh &rhs); 9.137 + bool clone(const Mesh &m); 9.138 + 9.139 + void set_name(const char *name); 9.140 + const char *get_name() const; 9.141 + 9.142 + bool has_attrib(int attr) const; 9.143 + bool is_indexed() const; 9.144 + 9.145 + // clears everything about this mesh, and returns to the newly constructed state 9.146 + void clear(); 9.147 + 9.148 + // access the vertex attribute data 9.149 + // if vdata == 0, space is just allocated 9.150 + float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo 9.151 + float *get_attrib_data(int attrib); // invalidates vbo 9.152 + const float *get_attrib_data(int attrib) const; 9.153 + 9.154 + // simple access to any particular attribute 9.155 + void set_attrib(int attrib, int idx, const Vec4 &v); // invalidates vbo 9.156 + Vec4 get_attrib(int attrib, int idx) const; 9.157 + 9.158 + int get_attrib_count(int attrib) const; 9.159 + 9.160 + // ... same for index data 9.161 + unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo 9.162 + unsigned int *get_index_data(); // invalidates ibo 9.163 + const unsigned int *get_index_data() const; 9.164 + 9.165 + int get_index_count() const; 9.166 + 9.167 + void append(const Mesh &mesh); 9.168 + 9.169 + // immediate-mode style mesh construction interface 9.170 + void vertex(float x, float y, float z); 9.171 + void normal(float nx, float ny, float nz); 9.172 + void tangent(float tx, float ty, float tz); 9.173 + void texcoord(float u, float v, float w); 9.174 + void boneweights(float w1, float w2, float w3, float w4); 9.175 + void boneidx(int idx1, int idx2, int idx3, int idx4); 9.176 + 9.177 + int get_poly_count() const; 9.178 + 9.179 + /* apply a transformation to the vertices and its inverse-transpose 9.180 + * to the normals and tangents. 9.181 + */ 9.182 + void apply_xform(const Mat4 &xform); 9.183 + void apply_xform(const Mat4 &xform, const Mat4 &dir_xform); 9.184 + 9.185 + void flip(); // both faces and normals 9.186 + void flip_faces(); 9.187 + void flip_normals(); 9.188 + 9.189 + // adds a bone and returns its index 9.190 + /*int add_bone(XFormNode *bone); 9.191 + const XFormNode *get_bone(int idx) const; 9.192 + int get_bones_count() const;*/ 9.193 + 9.194 + // access the shader attribute locations 9.195 + static void set_attrib_location(int attr, int loc); 9.196 + static int get_attrib_location(int attr); 9.197 + static void clear_attrib_locations(); 9.198 + 9.199 + static void set_vis_vecsize(float sz); 9.200 + static float get_vis_vecsize(); 9.201 + 9.202 + void draw() const; 9.203 + void draw_wire() const; 9.204 + void draw_vertices() const; 9.205 + void draw_normals() const; 9.206 + void draw_tangents() const; 9.207 + 9.208 + /** get the bounding box in local space. The result will be cached, and subsequent 9.209 + * calls will return the same box. The cache gets invalidated by any functions that can affect 9.210 + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). 9.211 + * @{ */ 9.212 + void get_aabbox(Vec3 *vmin, Vec3 *vmax) const; 9.213 + const AABox &get_aabbox() const; 9.214 + /// @} 9.215 + 9.216 + /** get the bounding sphere in local space. The result will be cached, and subsequent 9.217 + * calls will return the same box. The cache gets invalidated by any functions that can affect 9.218 + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). 9.219 + * @{ */ 9.220 + float get_bsphere(Vec3 *center, float *rad) const; 9.221 + const Sphere &get_bsphere() const; 9.222 + 9.223 + static void set_intersect_mode(unsigned int mode); 9.224 + static unsigned int get_intersect_mode(); 9.225 + static void set_vertex_select_distance(float dist); 9.226 + static float get_vertex_select_distance(); 9.227 + 9.228 + /** Find the intersection between the mesh and a ray. 9.229 + * XXX Brute force at the moment, not intended to be used for anything other than picking in tools. 9.230 + * If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it! 9.231 + */ 9.232 + bool intersect(const Ray &ray, HitPoint *hit = 0) const; 9.233 + 9.234 + // texture coordinate manipulation 9.235 + void texcoord_apply_xform(const Mat4 &xform); 9.236 + void texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang); 9.237 + void texcoord_gen_box(); 9.238 + void texcoord_gen_cylinder(); 9.239 + 9.240 + bool dump(const char *fname) const; 9.241 + bool dump(FILE *fp) const; 9.242 + bool dump_obj(const char *fname) const; 9.243 + bool dump_obj(FILE *fp) const; 9.244 +}; 9.245 + 9.246 +#endif // MESH_H_
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/meshgen.cc Thu Jul 27 20:36:12 2017 +0300 10.3 @@ -0,0 +1,881 @@ 10.4 +#include <stdio.h> 10.5 +#include "meshgen.h" 10.6 +#include "mesh.h" 10.7 + 10.8 +// -------- sphere -------- 10.9 + 10.10 +#define SURAD(u) ((u) * 2.0 * M_PI) 10.11 +#define SVRAD(v) ((v) * M_PI) 10.12 + 10.13 +static Vec3 sphvec(float theta, float phi) 10.14 +{ 10.15 + return Vec3(sin(theta) * sin(phi), 10.16 + cos(phi), 10.17 + cos(theta) * sin(phi)); 10.18 +} 10.19 + 10.20 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange) 10.21 +{ 10.22 + if(usub < 4) usub = 4; 10.23 + if(vsub < 2) vsub = 2; 10.24 + 10.25 + int uverts = usub + 1; 10.26 + int vverts = vsub + 1; 10.27 + 10.28 + int num_verts = uverts * vverts; 10.29 + int num_quads = usub * vsub; 10.30 + int num_tri = num_quads * 2; 10.31 + 10.32 + mesh->clear(); 10.33 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.34 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.35 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.36 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.37 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.38 + 10.39 + float du = urange / (float)(uverts - 1); 10.40 + float dv = vrange / (float)(vverts - 1); 10.41 + 10.42 + float u = 0.0; 10.43 + for(int i=0; i<uverts; i++) { 10.44 + float theta = u * 2.0 * M_PI; 10.45 + 10.46 + float v = 0.0; 10.47 + for(int j=0; j<vverts; j++) { 10.48 + float phi = v * M_PI; 10.49 + 10.50 + Vec3 pos = sphvec(theta, phi); 10.51 + 10.52 + *varr++ = pos * rad; 10.53 + *narr++ = pos; 10.54 + *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f)); 10.55 + *uvarr++ = Vec2(u * urange, v * vrange); 10.56 + 10.57 + if(i < usub && j < vsub) { 10.58 + int idx = i * vverts + j; 10.59 + *idxarr++ = idx; 10.60 + *idxarr++ = idx + 1; 10.61 + *idxarr++ = idx + vverts + 1; 10.62 + 10.63 + *idxarr++ = idx; 10.64 + *idxarr++ = idx + vverts + 1; 10.65 + *idxarr++ = idx + vverts; 10.66 + } 10.67 + 10.68 + v += dv; 10.69 + } 10.70 + u += du; 10.71 + } 10.72 +} 10.73 + 10.74 +// ------ geosphere ------ 10.75 +#define PHI 1.618034 10.76 + 10.77 +static Vec3 icosa_pt[] = { 10.78 + Vec3(PHI, 1, 0), 10.79 + Vec3(-PHI, 1, 0), 10.80 + Vec3(PHI, -1, 0), 10.81 + Vec3(-PHI, -1, 0), 10.82 + Vec3(1, 0, PHI), 10.83 + Vec3(1, 0, -PHI), 10.84 + Vec3(-1, 0, PHI), 10.85 + Vec3(-1, 0, -PHI), 10.86 + Vec3(0, PHI, 1), 10.87 + Vec3(0, -PHI, 1), 10.88 + Vec3(0, PHI, -1), 10.89 + Vec3(0, -PHI, -1) 10.90 +}; 10.91 +enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 }; 10.92 +static int icosa_idx[] = { 10.93 + P11, P31, P21, 10.94 + P11, P22, P33, 10.95 + P13, P21, P32, 10.96 + P13, P34, P22, 10.97 + P12, P23, P31, 10.98 + P12, P33, P24, 10.99 + P14, P32, P23, 10.100 + P14, P24, P34, 10.101 + 10.102 + P11, P33, P31, 10.103 + P12, P31, P33, 10.104 + P13, P32, P34, 10.105 + P14, P34, P32, 10.106 + 10.107 + P21, P13, P11, 10.108 + P22, P11, P13, 10.109 + P23, P12, P14, 10.110 + P24, P14, P12, 10.111 + 10.112 + P31, P23, P21, 10.113 + P32, P21, P23, 10.114 + P33, P22, P24, 10.115 + P34, P24, P22 10.116 +}; 10.117 + 10.118 +static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter) 10.119 +{ 10.120 + if(!iter) { 10.121 + verts->push_back(v1); 10.122 + verts->push_back(v2); 10.123 + verts->push_back(v3); 10.124 + return; 10.125 + } 10.126 + 10.127 + Vec3 v12 = normalize(v1 + v2); 10.128 + Vec3 v23 = normalize(v2 + v3); 10.129 + Vec3 v31 = normalize(v3 + v1); 10.130 + 10.131 + geosphere(verts, v1, v12, v31, iter - 1); 10.132 + geosphere(verts, v2, v23, v12, iter - 1); 10.133 + geosphere(verts, v3, v31, v23, iter - 1); 10.134 + geosphere(verts, v12, v23, v31, iter - 1); 10.135 +} 10.136 + 10.137 +void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi) 10.138 +{ 10.139 + int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3; 10.140 + 10.141 + std::vector<Vec3> verts; 10.142 + for(int i=0; i<num_tri; i++) { 10.143 + Vec3 v[3]; 10.144 + 10.145 + for(int j=0; j<3; j++) { 10.146 + int vidx = icosa_idx[i * 3 + j]; 10.147 + v[j] = normalize(icosa_pt[vidx]); 10.148 + } 10.149 + 10.150 + if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) { 10.151 + continue; 10.152 + } 10.153 + 10.154 + geosphere(&verts, v[0], v[1], v[2], subdiv); 10.155 + } 10.156 + 10.157 + int num_verts = (int)verts.size(); 10.158 + 10.159 + mesh->clear(); 10.160 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.161 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.162 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.163 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.164 + 10.165 + for(int i=0; i<num_verts; i++) { 10.166 + *varr++ = verts[i] * rad; 10.167 + *narr++ = verts[i]; 10.168 + 10.169 + float theta = atan2(verts[i].z, verts[i].x); 10.170 + float phi = acos(verts[i].y); 10.171 + 10.172 + *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f)); 10.173 + 10.174 + float u = 0.5 * theta / M_PI + 0.5; 10.175 + float v = phi / M_PI; 10.176 + *uvarr++ = Vec2(u, v); 10.177 + } 10.178 +} 10.179 + 10.180 +// -------- torus ----------- 10.181 +static Vec3 torusvec(float theta, float phi, float mr, float rr) 10.182 +{ 10.183 + theta = -theta; 10.184 + 10.185 + float rx = -cos(phi) * rr + mr; 10.186 + float ry = sin(phi) * rr; 10.187 + float rz = 0.0; 10.188 + 10.189 + float x = rx * sin(theta) + rz * cos(theta); 10.190 + float y = ry; 10.191 + float z = -rx * cos(theta) + rz * sin(theta); 10.192 + 10.193 + return Vec3(x, y, z); 10.194 +} 10.195 + 10.196 +void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange) 10.197 +{ 10.198 + if(usub < 4) usub = 4; 10.199 + if(vsub < 2) vsub = 2; 10.200 + 10.201 + int uverts = usub + 1; 10.202 + int vverts = vsub + 1; 10.203 + 10.204 + int num_verts = uverts * vverts; 10.205 + int num_quads = usub * vsub; 10.206 + int num_tri = num_quads * 2; 10.207 + 10.208 + mesh->clear(); 10.209 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.210 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.211 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.212 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.213 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.214 + 10.215 + float du = urange / (float)(uverts - 1); 10.216 + float dv = vrange / (float)(vverts - 1); 10.217 + 10.218 + float u = 0.0; 10.219 + for(int i=0; i<uverts; i++) { 10.220 + float theta = u * 2.0 * M_PI; 10.221 + 10.222 + float v = 0.0; 10.223 + for(int j=0; j<vverts; j++) { 10.224 + float phi = v * 2.0 * M_PI; 10.225 + 10.226 + Vec3 pos = torusvec(theta, phi, mainrad, ringrad); 10.227 + Vec3 cent = torusvec(theta, phi, mainrad, 0.0); 10.228 + 10.229 + *varr++ = pos; 10.230 + *narr++ = (pos - cent) / ringrad; 10.231 + 10.232 + Vec3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad); 10.233 + Vec3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad); 10.234 + 10.235 + *tarr++ = normalize(pnext - pprev); 10.236 + *uvarr++ = Vec2(u * urange, v * vrange); 10.237 + 10.238 + if(i < usub && j < vsub) { 10.239 + int idx = i * vverts + j; 10.240 + *idxarr++ = idx; 10.241 + *idxarr++ = idx + 1; 10.242 + *idxarr++ = idx + vverts + 1; 10.243 + 10.244 + *idxarr++ = idx; 10.245 + *idxarr++ = idx + vverts + 1; 10.246 + *idxarr++ = idx + vverts; 10.247 + } 10.248 + 10.249 + v += dv; 10.250 + } 10.251 + u += du; 10.252 + } 10.253 +} 10.254 + 10.255 + 10.256 +// -------- cylinder -------- 10.257 + 10.258 +static Vec3 cylvec(float theta, float height) 10.259 +{ 10.260 + return Vec3(sin(theta), height, cos(theta)); 10.261 +} 10.262 + 10.263 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange) 10.264 +{ 10.265 + if(usub < 4) usub = 4; 10.266 + if(vsub < 1) vsub = 1; 10.267 + 10.268 + int uverts = usub + 1; 10.269 + int vverts = vsub + 1; 10.270 + 10.271 + int num_body_verts = uverts * vverts; 10.272 + int num_body_quads = usub * vsub; 10.273 + int num_body_tri = num_body_quads * 2; 10.274 + 10.275 + int capvverts = capsub ? capsub + 1 : 0; 10.276 + int num_cap_verts = uverts * capvverts; 10.277 + int num_cap_quads = usub * capsub; 10.278 + int num_cap_tri = num_cap_quads * 2; 10.279 + 10.280 + int num_verts = num_body_verts + num_cap_verts * 2; 10.281 + int num_tri = num_body_tri + num_cap_tri * 2; 10.282 + 10.283 + mesh->clear(); 10.284 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.285 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.286 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.287 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.288 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.289 + 10.290 + float du = urange / (float)(uverts - 1); 10.291 + float dv = vrange / (float)(vverts - 1); 10.292 + 10.293 + float u = 0.0; 10.294 + for(int i=0; i<uverts; i++) { 10.295 + float theta = SURAD(u); 10.296 + 10.297 + float v = 0.0; 10.298 + for(int j=0; j<vverts; j++) { 10.299 + float y = (v - 0.5) * height; 10.300 + Vec3 pos = cylvec(theta, y); 10.301 + 10.302 + *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad); 10.303 + *narr++ = Vec3(pos.x, 0.0, pos.z); 10.304 + *tarr++ = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)); 10.305 + *uvarr++ = Vec2(u * urange, v * vrange); 10.306 + 10.307 + if(i < usub && j < vsub) { 10.308 + int idx = i * vverts + j; 10.309 + 10.310 + *idxarr++ = idx; 10.311 + *idxarr++ = idx + vverts + 1; 10.312 + *idxarr++ = idx + 1; 10.313 + 10.314 + *idxarr++ = idx; 10.315 + *idxarr++ = idx + vverts; 10.316 + *idxarr++ = idx + vverts + 1; 10.317 + } 10.318 + 10.319 + v += dv; 10.320 + } 10.321 + u += du; 10.322 + } 10.323 + 10.324 + 10.325 + // now the cap! 10.326 + if(!capsub) { 10.327 + return; 10.328 + } 10.329 + 10.330 + dv = 1.0 / (float)(capvverts - 1); 10.331 + 10.332 + u = 0.0; 10.333 + for(int i=0; i<uverts; i++) { 10.334 + float theta = SURAD(u); 10.335 + 10.336 + float v = 0.0; 10.337 + for(int j=0; j<capvverts; j++) { 10.338 + float r = v * rad; 10.339 + 10.340 + Vec3 pos = cylvec(theta, height / 2.0) * r; 10.341 + pos.y = height / 2.0; 10.342 + Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)); 10.343 + 10.344 + *varr++ = pos; 10.345 + *narr++ = Vec3(0, 1, 0); 10.346 + *tarr++ = tang; 10.347 + *uvarr++ = Vec2(u * urange, v); 10.348 + 10.349 + pos.y = -height / 2.0; 10.350 + *varr++ = pos; 10.351 + *narr++ = Vec3(0, -1, 0); 10.352 + *tarr++ = -tang; 10.353 + *uvarr++ = Vec2(u * urange, v); 10.354 + 10.355 + if(i < usub && j < capsub) { 10.356 + unsigned int idx = num_body_verts + (i * capvverts + j) * 2; 10.357 + 10.358 + unsigned int vidx[4] = { 10.359 + idx, 10.360 + idx + capvverts * 2, 10.361 + idx + (capvverts + 1) * 2, 10.362 + idx + 2 10.363 + }; 10.364 + 10.365 + *idxarr++ = vidx[0]; 10.366 + *idxarr++ = vidx[2]; 10.367 + *idxarr++ = vidx[1]; 10.368 + *idxarr++ = vidx[0]; 10.369 + *idxarr++ = vidx[3]; 10.370 + *idxarr++ = vidx[2]; 10.371 + 10.372 + *idxarr++ = vidx[0] + 1; 10.373 + *idxarr++ = vidx[1] + 1; 10.374 + *idxarr++ = vidx[2] + 1; 10.375 + *idxarr++ = vidx[0] + 1; 10.376 + *idxarr++ = vidx[2] + 1; 10.377 + *idxarr++ = vidx[3] + 1; 10.378 + } 10.379 + 10.380 + v += dv; 10.381 + } 10.382 + u += du; 10.383 + } 10.384 +} 10.385 + 10.386 +// -------- cone -------- 10.387 + 10.388 +static Vec3 conevec(float theta, float y, float height) 10.389 +{ 10.390 + float scale = 1.0 - y / height; 10.391 + return Vec3(sin(theta) * scale, y, cos(theta) * scale); 10.392 +} 10.393 + 10.394 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange) 10.395 +{ 10.396 + if(usub < 4) usub = 4; 10.397 + if(vsub < 1) vsub = 1; 10.398 + 10.399 + int uverts = usub + 1; 10.400 + int vverts = vsub + 1; 10.401 + 10.402 + int num_body_verts = uverts * vverts; 10.403 + int num_body_quads = usub * vsub; 10.404 + int num_body_tri = num_body_quads * 2; 10.405 + 10.406 + int capvverts = capsub ? capsub + 1 : 0; 10.407 + int num_cap_verts = uverts * capvverts; 10.408 + int num_cap_quads = usub * capsub; 10.409 + int num_cap_tri = num_cap_quads * 2; 10.410 + 10.411 + int num_verts = num_body_verts + num_cap_verts; 10.412 + int num_tri = num_body_tri + num_cap_tri; 10.413 + 10.414 + mesh->clear(); 10.415 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.416 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.417 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.418 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.419 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.420 + 10.421 + float du = urange / (float)(uverts - 1); 10.422 + float dv = vrange / (float)(vverts - 1); 10.423 + 10.424 + float u = 0.0; 10.425 + for(int i=0; i<uverts; i++) { 10.426 + float theta = SURAD(u); 10.427 + 10.428 + float v = 0.0; 10.429 + for(int j=0; j<vverts; j++) { 10.430 + float y = v * height; 10.431 + Vec3 pos = conevec(theta, y, height); 10.432 + 10.433 + Vec3 tang = normalize(conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height)); 10.434 + Vec3 bitang = normalize(conevec(theta, y + 0.1, height) - pos); 10.435 + 10.436 + *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad); 10.437 + *narr++ = cross(tang, bitang); 10.438 + *tarr++ = tang; 10.439 + *uvarr++ = Vec2(u * urange, v * vrange); 10.440 + 10.441 + if(i < usub && j < vsub) { 10.442 + int idx = i * vverts + j; 10.443 + 10.444 + *idxarr++ = idx; 10.445 + *idxarr++ = idx + vverts + 1; 10.446 + *idxarr++ = idx + 1; 10.447 + 10.448 + *idxarr++ = idx; 10.449 + *idxarr++ = idx + vverts; 10.450 + *idxarr++ = idx + vverts + 1; 10.451 + } 10.452 + 10.453 + v += dv; 10.454 + } 10.455 + u += du; 10.456 + } 10.457 + 10.458 + 10.459 + // now the bottom cap! 10.460 + if(!capsub) { 10.461 + return; 10.462 + } 10.463 + 10.464 + dv = 1.0 / (float)(capvverts - 1); 10.465 + 10.466 + u = 0.0; 10.467 + for(int i=0; i<uverts; i++) { 10.468 + float theta = SURAD(u); 10.469 + 10.470 + float v = 0.0; 10.471 + for(int j=0; j<capvverts; j++) { 10.472 + float r = v * rad; 10.473 + 10.474 + Vec3 pos = conevec(theta, 0.0, height) * r; 10.475 + Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0)); 10.476 + 10.477 + *varr++ = pos; 10.478 + *narr++ = Vec3(0, -1, 0); 10.479 + *tarr++ = tang; 10.480 + *uvarr++ = Vec2(u * urange, v); 10.481 + 10.482 + if(i < usub && j < capsub) { 10.483 + unsigned int idx = num_body_verts + i * capvverts + j; 10.484 + 10.485 + unsigned int vidx[4] = { 10.486 + idx, 10.487 + idx + capvverts, 10.488 + idx + (capvverts + 1), 10.489 + idx + 1 10.490 + }; 10.491 + 10.492 + *idxarr++ = vidx[0]; 10.493 + *idxarr++ = vidx[1]; 10.494 + *idxarr++ = vidx[2]; 10.495 + *idxarr++ = vidx[0]; 10.496 + *idxarr++ = vidx[2]; 10.497 + *idxarr++ = vidx[3]; 10.498 + } 10.499 + 10.500 + v += dv; 10.501 + } 10.502 + u += du; 10.503 + } 10.504 +} 10.505 + 10.506 + 10.507 +// -------- plane -------- 10.508 + 10.509 +void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub) 10.510 +{ 10.511 + gen_heightmap(mesh, width, height, usub, vsub, 0); 10.512 +} 10.513 + 10.514 + 10.515 +// ----- heightmap ------ 10.516 + 10.517 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata) 10.518 +{ 10.519 + if(usub < 1) usub = 1; 10.520 + if(vsub < 1) vsub = 1; 10.521 + 10.522 + mesh->clear(); 10.523 + 10.524 + int uverts = usub + 1; 10.525 + int vverts = vsub + 1; 10.526 + int num_verts = uverts * vverts; 10.527 + 10.528 + int num_quads = usub * vsub; 10.529 + int num_tri = num_quads * 2; 10.530 + 10.531 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.532 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.533 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.534 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.535 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.536 + 10.537 + float du = 1.0 / (float)usub; 10.538 + float dv = 1.0 / (float)vsub; 10.539 + 10.540 + float u = 0.0; 10.541 + for(int i=0; i<uverts; i++) { 10.542 + float v = 0.0; 10.543 + for(int j=0; j<vverts; j++) { 10.544 + float x = (u - 0.5) * width; 10.545 + float y = (v - 0.5) * height; 10.546 + float z = hf ? hf(u, v, hfdata) : 0.0; 10.547 + 10.548 + Vec3 normal = Vec3(0, 0, 1); 10.549 + if(hf) { 10.550 + float u1z = hf(u + du, v, hfdata); 10.551 + float v1z = hf(u, v + dv, hfdata); 10.552 + 10.553 + Vec3 tang = Vec3(du * width, 0, u1z - z); 10.554 + Vec3 bitan = Vec3(0, dv * height, v1z - z); 10.555 + normal = normalize(cross(tang, bitan)); 10.556 + } 10.557 + 10.558 + *varr++ = Vec3(x, y, z); 10.559 + *narr++ = normal; 10.560 + *tarr++ = Vec3(1, 0, 0); 10.561 + *uvarr++ = Vec2(u, v); 10.562 + 10.563 + if(i < usub && j < vsub) { 10.564 + int idx = i * vverts + j; 10.565 + 10.566 + *idxarr++ = idx; 10.567 + *idxarr++ = idx + vverts + 1; 10.568 + *idxarr++ = idx + 1; 10.569 + 10.570 + *idxarr++ = idx; 10.571 + *idxarr++ = idx + vverts; 10.572 + *idxarr++ = idx + vverts + 1; 10.573 + } 10.574 + 10.575 + v += dv; 10.576 + } 10.577 + u += du; 10.578 + } 10.579 +} 10.580 + 10.581 +// ----- box ------ 10.582 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub) 10.583 +{ 10.584 + static const float face_angles[][2] = { 10.585 + {0, 0}, 10.586 + {M_PI / 2.0, 0}, 10.587 + {M_PI, 0}, 10.588 + {3.0 * M_PI / 2.0, 0}, 10.589 + {0, M_PI / 2.0}, 10.590 + {0, -M_PI / 2.0} 10.591 + }; 10.592 + 10.593 + if(usub < 1) usub = 1; 10.594 + if(vsub < 1) vsub = 1; 10.595 + 10.596 + mesh->clear(); 10.597 + 10.598 + for(int i=0; i<6; i++) { 10.599 + Mat4 xform, dir_xform; 10.600 + Mesh m; 10.601 + 10.602 + gen_plane(&m, 1, 1, usub, vsub); 10.603 + xform.rotate(Vec3(face_angles[i][1], face_angles[i][0], 0)); 10.604 + dir_xform = xform; 10.605 + xform.translate(Vec3(0, 0, 0.5)); 10.606 + m.apply_xform(xform, dir_xform); 10.607 + 10.608 + mesh->append(m); 10.609 + } 10.610 + 10.611 + Mat4 scale; 10.612 + scale.scaling(xsz, ysz, zsz); 10.613 + mesh->apply_xform(scale, Mat4::identity); 10.614 +} 10.615 + 10.616 +/* 10.617 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz) 10.618 +{ 10.619 + mesh->clear(); 10.620 + 10.621 + const int num_faces = 6; 10.622 + int num_verts = num_faces * 4; 10.623 + int num_tri = num_faces * 2; 10.624 + 10.625 + float x = xsz / 2.0; 10.626 + float y = ysz / 2.0; 10.627 + float z = zsz / 2.0; 10.628 + 10.629 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.630 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.631 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.632 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.633 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.634 + 10.635 + static const Vec2 uv[] = { Vec2(0, 0), Vec2(1, 0), Vec2(1, 1), Vec2(0, 1) }; 10.636 + 10.637 + // front 10.638 + for(int i=0; i<4; i++) { 10.639 + *narr++ = Vec3(0, 0, 1); 10.640 + *tarr++ = Vec3(1, 0, 0); 10.641 + *uvarr++ = uv[i]; 10.642 + } 10.643 + *varr++ = Vec3(-x, -y, z); 10.644 + *varr++ = Vec3(x, -y, z); 10.645 + *varr++ = Vec3(x, y, z); 10.646 + *varr++ = Vec3(-x, y, z); 10.647 + // right 10.648 + for(int i=0; i<4; i++) { 10.649 + *narr++ = Vec3(1, 0, 0); 10.650 + *tarr++ = Vec3(0, 0, -1); 10.651 + *uvarr++ = uv[i]; 10.652 + } 10.653 + *varr++ = Vec3(x, -y, z); 10.654 + *varr++ = Vec3(x, -y, -z); 10.655 + *varr++ = Vec3(x, y, -z); 10.656 + *varr++ = Vec3(x, y, z); 10.657 + // back 10.658 + for(int i=0; i<4; i++) { 10.659 + *narr++ = Vec3(0, 0, -1); 10.660 + *tarr++ = Vec3(-1, 0, 0); 10.661 + *uvarr++ = uv[i]; 10.662 + } 10.663 + *varr++ = Vec3(x, -y, -z); 10.664 + *varr++ = Vec3(-x, -y, -z); 10.665 + *varr++ = Vec3(-x, y, -z); 10.666 + *varr++ = Vec3(x, y, -z); 10.667 + // left 10.668 + for(int i=0; i<4; i++) { 10.669 + *narr++ = Vec3(-1, 0, 0); 10.670 + *tarr++ = Vec3(0, 0, 1); 10.671 + *uvarr++ = uv[i]; 10.672 + } 10.673 + *varr++ = Vec3(-x, -y, -z); 10.674 + *varr++ = Vec3(-x, -y, z); 10.675 + *varr++ = Vec3(-x, y, z); 10.676 + *varr++ = Vec3(-x, y, -z); 10.677 + // top 10.678 + for(int i=0; i<4; i++) { 10.679 + *narr++ = Vec3(0, 1, 0); 10.680 + *tarr++ = Vec3(1, 0, 0); 10.681 + *uvarr++ = uv[i]; 10.682 + } 10.683 + *varr++ = Vec3(-x, y, z); 10.684 + *varr++ = Vec3(x, y, z); 10.685 + *varr++ = Vec3(x, y, -z); 10.686 + *varr++ = Vec3(-x, y, -z); 10.687 + // bottom 10.688 + for(int i=0; i<4; i++) { 10.689 + *narr++ = Vec3(0, -1, 0); 10.690 + *tarr++ = Vec3(1, 0, 0); 10.691 + *uvarr++ = uv[i]; 10.692 + } 10.693 + *varr++ = Vec3(-x, -y, -z); 10.694 + *varr++ = Vec3(x, -y, -z); 10.695 + *varr++ = Vec3(x, -y, z); 10.696 + *varr++ = Vec3(-x, -y, z); 10.697 + 10.698 + // index array 10.699 + static const int faceidx[] = {0, 1, 2, 0, 2, 3}; 10.700 + for(int i=0; i<num_faces; i++) { 10.701 + for(int j=0; j<6; j++) { 10.702 + *idxarr++ = faceidx[j] + i * 4; 10.703 + } 10.704 + } 10.705 +} 10.706 +*/ 10.707 + 10.708 +static inline Vec3 rev_vert(float u, float v, Vec2 (*rf)(float, float, void*), void *cls) 10.709 +{ 10.710 + Vec2 pos = rf(u, v, cls); 10.711 + 10.712 + float angle = u * 2.0 * M_PI; 10.713 + float x = pos.x * cos(angle); 10.714 + float y = pos.y; 10.715 + float z = pos.x * sin(angle); 10.716 + 10.717 + return Vec3(x, y, z); 10.718 +} 10.719 + 10.720 +// ------ surface of revolution ------- 10.721 +void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), void *cls) 10.722 +{ 10.723 + gen_revol(mesh, usub, vsub, rfunc, 0, cls); 10.724 +} 10.725 + 10.726 +void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), 10.727 + Vec2 (*nfunc)(float, float, void*), void *cls) 10.728 +{ 10.729 + if(!rfunc) return; 10.730 + if(usub < 3) usub = 3; 10.731 + if(vsub < 1) vsub = 1; 10.732 + 10.733 + mesh->clear(); 10.734 + 10.735 + int uverts = usub + 1; 10.736 + int vverts = vsub + 1; 10.737 + int num_verts = uverts * vverts; 10.738 + 10.739 + int num_quads = usub * vsub; 10.740 + int num_tri = num_quads * 2; 10.741 + 10.742 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.743 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.744 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.745 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.746 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.747 + 10.748 + float du = 1.0 / (float)(uverts - 1); 10.749 + float dv = 1.0 / (float)(vverts - 1); 10.750 + 10.751 + float u = 0.0; 10.752 + for(int i=0; i<uverts; i++) { 10.753 + float v = 0.0; 10.754 + for(int j=0; j<vverts; j++) { 10.755 + Vec3 pos = rev_vert(u, v, rfunc, cls); 10.756 + 10.757 + Vec3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls); 10.758 + Vec3 tang = nextu - pos; 10.759 + if(length_sq(tang) < 1e-6) { 10.760 + float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25; 10.761 + nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls); 10.762 + tang = nextu - pos; 10.763 + } 10.764 + 10.765 + Vec3 normal; 10.766 + if(nfunc) { 10.767 + normal = rev_vert(u, v, nfunc, cls); 10.768 + } else { 10.769 + Vec3 nextv = rev_vert(u, v + dv, rfunc, cls); 10.770 + Vec3 bitan = nextv - pos; 10.771 + if(length_sq(bitan) < 1e-6) { 10.772 + nextv = rev_vert(u, v - dv, rfunc, cls); 10.773 + bitan = pos - nextv; 10.774 + } 10.775 + 10.776 + normal = cross(tang, bitan); 10.777 + } 10.778 + 10.779 + *varr++ = pos; 10.780 + *narr++ = normalize(normal); 10.781 + *tarr++ = normalize(tang); 10.782 + *uvarr++ = Vec2(u, v); 10.783 + 10.784 + if(i < usub && j < vsub) { 10.785 + int idx = i * vverts + j; 10.786 + 10.787 + *idxarr++ = idx; 10.788 + *idxarr++ = idx + vverts + 1; 10.789 + *idxarr++ = idx + 1; 10.790 + 10.791 + *idxarr++ = idx; 10.792 + *idxarr++ = idx + vverts; 10.793 + *idxarr++ = idx + vverts + 1; 10.794 + } 10.795 + 10.796 + v += dv; 10.797 + } 10.798 + u += du; 10.799 + } 10.800 +} 10.801 + 10.802 + 10.803 +static inline Vec3 sweep_vert(float u, float v, float height, Vec2 (*sf)(float, float, void*), void *cls) 10.804 +{ 10.805 + Vec2 pos = sf(u, v, cls); 10.806 + 10.807 + float x = pos.x; 10.808 + float y = v * height; 10.809 + float z = pos.y; 10.810 + 10.811 + return Vec3(x, y, z); 10.812 +} 10.813 + 10.814 +// ---- sweep shape along a path ---- 10.815 +void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls) 10.816 +{ 10.817 + if(!sfunc) return; 10.818 + if(usub < 3) usub = 3; 10.819 + if(vsub < 1) vsub = 1; 10.820 + 10.821 + mesh->clear(); 10.822 + 10.823 + int uverts = usub + 1; 10.824 + int vverts = vsub + 1; 10.825 + int num_verts = uverts * vverts; 10.826 + 10.827 + int num_quads = usub * vsub; 10.828 + int num_tri = num_quads * 2; 10.829 + 10.830 + Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); 10.831 + Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); 10.832 + Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); 10.833 + Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); 10.834 + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); 10.835 + 10.836 + float du = 1.0 / (float)(uverts - 1); 10.837 + float dv = 1.0 / (float)(vverts - 1); 10.838 + 10.839 + float u = 0.0; 10.840 + for(int i=0; i<uverts; i++) { 10.841 + float v = 0.0; 10.842 + for(int j=0; j<vverts; j++) { 10.843 + Vec3 pos = sweep_vert(u, v, height, sfunc, cls); 10.844 + 10.845 + Vec3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls); 10.846 + Vec3 tang = nextu - pos; 10.847 + if(length_sq(tang) < 1e-6) { 10.848 + float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25; 10.849 + nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls); 10.850 + tang = nextu - pos; 10.851 + } 10.852 + 10.853 + Vec3 normal; 10.854 + Vec3 nextv = sweep_vert(u, v + dv, height, sfunc, cls); 10.855 + Vec3 bitan = nextv - pos; 10.856 + if(length_sq(bitan) < 1e-6) { 10.857 + nextv = sweep_vert(u, v - dv, height, sfunc, cls); 10.858 + bitan = pos - nextv; 10.859 + } 10.860 + 10.861 + normal = cross(tang, bitan); 10.862 + 10.863 + *varr++ = pos; 10.864 + *narr++ = normalize(normal); 10.865 + *tarr++ = normalize(tang); 10.866 + *uvarr++ = Vec2(u, v); 10.867 + 10.868 + if(i < usub && j < vsub) { 10.869 + int idx = i * vverts + j; 10.870 + 10.871 + *idxarr++ = idx; 10.872 + *idxarr++ = idx + vverts + 1; 10.873 + *idxarr++ = idx + 1; 10.874 + 10.875 + *idxarr++ = idx; 10.876 + *idxarr++ = idx + vverts; 10.877 + *idxarr++ = idx + vverts + 1; 10.878 + } 10.879 + 10.880 + v += dv; 10.881 + } 10.882 + u += du; 10.883 + } 10.884 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/meshgen.h Thu Jul 27 20:36:12 2017 +0300 11.3 @@ -0,0 +1,23 @@ 11.4 +#ifndef MESHGEN_H_ 11.5 +#define MESHGEN_H_ 11.6 + 11.7 +#include <gmath/gmath.h> 11.8 + 11.9 +class Mesh; 11.10 + 11.11 +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange = 1.0, float vrange = 1.0); 11.12 +void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi = false); 11.13 +void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange = 1.0, float vrange = 1.0); 11.14 +void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0); 11.15 +void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub = 0, float urange = 1.0, float vrange = 1.0); 11.16 +void gen_plane(Mesh *mesh, float width, float height, int usub = 1, int vsub = 1); 11.17 +void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata = 0); 11.18 +void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub = 1, int vsub = 1); 11.19 + 11.20 +void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), void *cls = 0); 11.21 +void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), Vec2 (*nfunc)(float, float, void*), void *cls); 11.22 + 11.23 +/* callback args: (float u, float v, void *cls) -> Vec2 XZ offset u,v in [0, 1] */ 11.24 +void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls = 0); 11.25 + 11.26 +#endif // MESHGEN_H_
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/opengl.cc Thu Jul 27 20:36:12 2017 +0300 12.3 @@ -0,0 +1,8 @@ 12.4 +#include <string.h> 12.5 +#include "opengl.h" 12.6 + 12.7 +bool init_opengl() 12.8 +{ 12.9 + glewInit(); 12.10 + return true; 12.11 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/src/opengl.h Thu Jul 27 20:36:12 2017 +0300 13.3 @@ -0,0 +1,20 @@ 13.4 +#ifndef OPENGL_H_ 13.5 +#define OPENGL_H_ 13.6 + 13.7 +#ifdef WIN32 13.8 +#include <windows.h> 13.9 +#endif 13.10 + 13.11 +#include <GL/glew.h> 13.12 + 13.13 +#ifdef __APPLE__ 13.14 +#include <OpenGL/gl.h> 13.15 +#else 13.16 +#define GL_GLEXT_PROTOTYPES 1 13.17 +#include <GL/gl.h> 13.18 +#include <GL/glu.h> 13.19 +#endif 13.20 + 13.21 +bool init_opengl(); 13.22 + 13.23 +#endif // OPENGL_H_
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/texture.cc Thu Jul 27 20:36:12 2017 +0300 14.3 @@ -0,0 +1,103 @@ 14.4 +#include <stdio.h> 14.5 +#include <imago2.h> 14.6 +#include "texture.h" 14.7 +#include "opengl.h" 14.8 + 14.9 +Texture::Texture() 14.10 +{ 14.11 + width = height = tex_width = tex_height = 0; 14.12 + tex = 0; 14.13 +} 14.14 + 14.15 +Texture::~Texture() 14.16 +{ 14.17 + if(tex) { 14.18 + glDeleteTextures(1, &tex); 14.19 + } 14.20 +} 14.21 + 14.22 +static unsigned int next_pow2(unsigned int x) 14.23 +{ 14.24 + --x; 14.25 + x |= x >> 1; 14.26 + x |= x >> 2; 14.27 + x |= x >> 4; 14.28 + x |= x >> 8; 14.29 + x |= x >> 16; 14.30 + return x + 1; 14.31 +} 14.32 + 14.33 +bool Texture::load(const char *fname) 14.34 +{ 14.35 + img_pixmap img; 14.36 + img_init(&img); 14.37 + if(img_load(&img, fname) == -1) { 14.38 + fprintf(stderr, "failed to load texture: %s\n", fname); 14.39 + img_destroy(&img); 14.40 + return false; 14.41 + } 14.42 + 14.43 + unsigned int intfmt = img_glintfmt(&img); 14.44 + unsigned int pixfmt = img_glfmt(&img); 14.45 + unsigned int pixtype = img_gltype(&img); 14.46 + 14.47 + // if we have the sRGB extension, change the internal formats to sRGB 14.48 + if(GLEW_EXT_texture_sRGB) { 14.49 + switch(intfmt) { 14.50 + case 3: 14.51 + case GL_RGB: 14.52 + intfmt = GL_SRGB_EXT; 14.53 + break; 14.54 + case 4: 14.55 + case GL_RGBA: 14.56 + intfmt = GL_SRGB_ALPHA; 14.57 + break; 14.58 + case 1: 14.59 + case GL_LUMINANCE: 14.60 + intfmt = GL_SLUMINANCE; 14.61 + break; 14.62 + default: 14.63 + break; 14.64 + } 14.65 + } 14.66 + 14.67 + width = img.width; 14.68 + height = img.height; 14.69 + tex_width = next_pow2(width); 14.70 + tex_height = next_pow2(height); 14.71 + 14.72 + if(!tex) { 14.73 + glGenTextures(1, &tex); 14.74 + } 14.75 + glBindTexture(GL_TEXTURE_2D, tex); 14.76 + 14.77 + if(GLEW_SGIS_generate_mipmap) { 14.78 + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); 14.79 + } else { 14.80 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 14.81 + } 14.82 + 14.83 + glTexImage2D(GL_TEXTURE_2D, 0, intfmt, tex_width, tex_height, 0, pixfmt, pixtype, 0); 14.84 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, pixfmt, pixtype, img.pixels); 14.85 + 14.86 + tmat.scaling((float)width / (float)tex_width, (float)height / (float)tex_height, 1); 14.87 + return true; 14.88 +} 14.89 + 14.90 +const Mat4 &Texture::texture_matrix() const 14.91 +{ 14.92 + return tmat; 14.93 +} 14.94 + 14.95 +void Texture::bind(bool loadmat) const 14.96 +{ 14.97 + if(!tex) return; 14.98 + 14.99 + if(loadmat) { 14.100 + glMatrixMode(GL_TEXTURE); 14.101 + glLoadMatrixf(tmat[0]); 14.102 + glMatrixMode(GL_MODELVIEW); 14.103 + } 14.104 + 14.105 + glBindTexture(GL_TEXTURE_2D, tex); 14.106 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/src/texture.h Thu Jul 27 20:36:12 2017 +0300 15.3 @@ -0,0 +1,23 @@ 15.4 +#ifndef TEXTURE_H_ 15.5 +#define TEXTURE_H_ 15.6 + 15.7 +#include <gmath/gmath.h> 15.8 + 15.9 +class Texture { 15.10 +private: 15.11 + int width, height; 15.12 + int tex_width, tex_height; 15.13 + unsigned int tex; 15.14 + Mat4 tmat; 15.15 + 15.16 +public: 15.17 + Texture(); 15.18 + ~Texture(); 15.19 + 15.20 + bool load(const char *fname); 15.21 + 15.22 + const Mat4 &texture_matrix() const; 15.23 + void bind(bool loadmat = true) const; 15.24 +}; 15.25 + 15.26 +#endif // TEXTURE_H_