# HG changeset patch # User John Tsiombikas # Date 1434586350 -10800 # Node ID ac80210d5fbed34795902b018252bf8d03ae7f62 # Parent 2712c5da2e00bc7bfb64445236563d39b6232e25 preparing a pc version for easier development of non-android-specifics diff -r 2712c5da2e00 -r ac80210d5fbe Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,22 @@ +root = . +include $(root)/proj.mk + +src += $(wildcard $(root)/src/glut/*.c) +obj = $(src:.c=.o) $(ccsrc:.cc=.o) + +ifeq ($(shell uname -s), Darwin) + libgl = -framework OpenGL -framework GLUT +else + libgl = -lGL -lGLU -lglut +endif + +CXXFLAGS = -pedantic -Wall -g $(defs) -I$(root)/src/glut $(incpaths) +CFLAGS = $(CXXFLAGS) +LDFLAGS = $(libpaths) $(libs) $(libgl) + +$(bin): $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 2712c5da2e00 -r ac80210d5fbe sdr/color.p.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/color.p.glsl Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,8 @@ +precision mediump float; + +uniform vec4 color; + +void main() +{ + gl_FragColor = color; +} diff -r 2712c5da2e00 -r ac80210d5fbe sdr/normvis.p.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/normvis.p.glsl Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,10 @@ +precision mediump float; + +varying vec3 normal; + +void main() +{ + vec3 ncol = normal * 0.5 + 0.5; + gl_FragColor.rgb = ncol; + gl_FragColor.a = 1.0; +} diff -r 2712c5da2e00 -r ac80210d5fbe sdr/vertex.glsl --- a/sdr/vertex.glsl Tue Jun 16 06:17:59 2015 +0300 +++ b/sdr/vertex.glsl Thu Jun 18 03:12:30 2015 +0300 @@ -1,7 +1,9 @@ -attribute vec4 attr_vertex, attr_texcoord, attr_color; +attribute vec4 attr_vertex, attr_normal, attr_texcoord, attr_color; uniform mat4 matrix_modelview, matrix_projection, matrix_texture; +uniform mat3 matrix_normal; +varying vec3 normal; varying vec4 tex_coords, color; void main() @@ -10,4 +12,5 @@ gl_Position = mvp * attr_vertex; tex_coords = matrix_texture * attr_texcoord; color = attr_color; + normal = matrix_normal * attr_normal.xyz; } diff -r 2712c5da2e00 -r ac80210d5fbe src/android/amain.c --- a/src/android/amain.c Tue Jun 16 06:17:59 2015 +0300 +++ b/src/android/amain.c Thu Jun 18 03:12:30 2015 +0300 @@ -117,15 +117,26 @@ switch(evid) { case EVID_SENS_ACCEL: if(sens_accel) { - float accel[3]; + static double prev_sec = -1.0; + double sec, dt; + double accel[3] = {0, 0, 0}; + static double velocity[3]; + while(ASensorEventQueue_getEvents(sens_evq_accel, &sens_ev, 1) > 0) { - accel[0] = sens_ev.acceleration.x; - accel[1] = sens_ev.acceleration.y; - accel[2] = sens_ev.acceleration.z; + accel[0] += sens_ev.acceleration.x; + accel[1] += sens_ev.acceleration.y; + accel[2] += sens_ev.acceleration.z; } - // TODO: integrate over time - game_6dof_translation(accel[0], accel[1], accel[2]); + sec = get_time_sec(); + dt = prev_sec >= 0.0 ? sec - prev_sec : 0.0; + prev_sec = sec; + + velocity[0] += accel[0] * dt; + velocity[1] += accel[1] * dt; + velocity[2] += accel[2] * dt; + + game_6dof_translation(velocity[0] * dt, velocity[1] * dt, velocity[2] * dt); } break; diff -r 2712c5da2e00 -r ac80210d5fbe src/android/camera.c --- a/src/android/camera.c Tue Jun 16 06:17:59 2015 +0300 +++ b/src/android/camera.c Thu Jun 18 03:12:30 2015 +0300 @@ -4,6 +4,8 @@ #include #include "opengl.h" #include "camera.h" +#include "sdr.h" +#include "sanegl.h" static JavaVM *jvm; @@ -15,6 +17,10 @@ static jfloatArray jtex_matrix; static int capturing; +static unsigned int sdr_cam; +static int aloc_vertex, aloc_texcoord; + + int cam_init(void *platform_data) { int glerr; @@ -26,6 +32,13 @@ jtex_matrix = (*jni)->NewFloatArray(jni, 16); + // load preview shader + if(!(sdr_cam = create_program_load("sdr/vertex.glsl", "sdr/android_cam_preview.p.glsl"))) { + return -1; + } + aloc_vertex = glGetAttribLocation(sdr_cam, "attr_vertex"); + aloc_texcoord = glGetAttribLocation(sdr_cam, "attr_texcoord"); + // create the camera texture assert(glGetError() == GL_NO_ERROR); glGenTextures(1, &tex); @@ -44,6 +57,8 @@ glDeleteTextures(1, &tex); tex = 0; + free_program(sdr_cam); + if(jni) { (*jni)->DeleteGlobalRef(jni, jtex_matrix); } @@ -171,3 +186,28 @@ { return -1; // TODO } + +void cam_draw_preview(void) +{ + const float *tex_matrix = cam_texture_matrix(); + + gl_matrix_mode(GL_TEXTURE); + gl_load_matrixf(tex_matrix); + + glUseProgram(sdr_cam); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); + + gl_begin(GL_QUADS); + gl_texcoord2f(0, 0); + gl_vertex2f(-1, -1); + gl_texcoord2f(1, 0); + gl_vertex2f(1, -1); + gl_texcoord2f(1, 1); + gl_vertex2f(1, 1); + gl_texcoord2f(0, 1); + gl_vertex2f(-1, 1); + gl_end(); + + gl_matrix_mode(GL_TEXTURE); + gl_load_identity(); +} diff -r 2712c5da2e00 -r ac80210d5fbe src/camera.h --- a/src/camera.h Tue Jun 16 06:17:59 2015 +0300 +++ b/src/camera.h Thu Jun 18 03:12:30 2015 +0300 @@ -30,6 +30,8 @@ int cam_take_picture(void); +void cam_draw_preview(void); + #ifdef __cplusplus } #endif diff -r 2712c5da2e00 -r ac80210d5fbe src/game.cc --- a/src/game.cc Tue Jun 16 06:17:59 2015 +0300 +++ b/src/game.cc Thu Jun 18 03:12:30 2015 +0300 @@ -2,6 +2,7 @@ #include #include #include +#include #include "opengl.h" #include "game.h" #include "camera.h" @@ -10,8 +11,12 @@ #include "shader.h" #include "text.h" #include "vmath/vmath.h" +#include "mesh.h" +#include "meshgen.h" static void draw_quad(float hsz, float vsz); +static void draw_rotation_gizmo(); +static void draw_disc_wedge(float start, float end, int subdiv); int win_width, win_height; @@ -20,10 +25,15 @@ static float video_aspect; static struct texture *test_tex; -static SdrProg *sdr_cam, *sdr_tex; +static SdrProg *sdr_tex, *sdr_color, *sdr_debug; -static Quaternion qrot; -static Vector3 trans; +static Quaternion last_rot; +static Vector3 last_trans; + +static Quaternion rot; +static Vector3 rot_euler; + +static Mesh *mesh; extern "C" int game_init(void) { @@ -32,10 +42,13 @@ glClearColor(0.4, 0.4, 0.4, 1); - if(!(sdr_cam = get_sdrprog("sdr/vertex.glsl", "sdr/android_cam_preview.p.glsl"))) { + if(!(sdr_tex = get_sdrprog("sdr/vertex.glsl", "sdr/tex.p.glsl"))) { return -1; } - if(!(sdr_tex = get_sdrprog("sdr/vertex.glsl", "sdr/tex.p.glsl"))) { + if(!(sdr_color = get_sdrprog("sdr/vertex.glsl", "sdr/color.p.glsl"))) { + return -1; + } + if(!(sdr_debug = get_sdrprog("sdr/vertex.glsl", "sdr/normvis.p.glsl"))) { return -1; } @@ -43,6 +56,9 @@ return -1; } + mesh = new Mesh; + gen_cylinder(mesh, 0.2, 1.0, 16, 1); + cam_start_video(); cam_video_size(&video_width, &video_height); if(video_height) { @@ -58,31 +74,28 @@ extern "C" void game_shutdown(void) { cam_shutdown(); - delete sdr_cam; delete sdr_tex; } extern "C" void game_display(unsigned long msec) { unsigned int tex; - const float *tex_matrix; float xscale, yscale; cam_update(); tex = cam_texture(); - tex_matrix = cam_texture_matrix(); //float tsec = (float)msec / 1000.0f; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // draw video preview frame + gl_matrix_mode(GL_PROJECTION); + gl_push_matrix(); + gl_load_identity(); + gl_scalef((float)win_height / (float)win_width, 1, 1); gl_matrix_mode(GL_MODELVIEW); gl_load_identity(); - gl_matrix_mode(GL_TEXTURE); - gl_load_matrixf(tex_matrix); - - sdr_cam->bind(); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); if(video_aspect > win_aspect) { xscale = 1.0; @@ -91,34 +104,27 @@ xscale = video_aspect; yscale = 1.0; } - draw_quad(xscale, yscale); + gl_scalef(xscale, yscale, 1); - gl_matrix_mode(GL_TEXTURE); - gl_load_identity(); - gl_translatef(0, 1, 0); - gl_scalef(1, -1, 1); + cam_draw_preview(); + + gl_matrix_mode(GL_PROJECTION); + gl_pop_matrix(); + // done drawing preview + + gl_matrix_mode(GL_MODELVIEW); gl_load_identity(); - gl_scalef((float)test_tex->width / (float)test_tex->height, 1, 1); + gl_translatef(0, 0, -6); - sdr_tex->bind(); - glBindTexture(GL_TEXTURE_2D, test_tex->texid); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - draw_quad(0.5, 0.5); - glDisable(GL_BLEND); - - gl_matrix_mode(GL_TEXTURE); - gl_load_identity(); - + draw_rotation_gizmo(); // print the rotation quaternion text_color(1, 1, 1, 1); text_position(0, 0); - text_printf("translation (% .3f, % .3f, % .3f)", trans.x, trans.y, trans.z); + text_printf("translation (% .3f, % .3f, % .3f)", last_trans.x, last_trans.y, last_trans.z); text_position(0, 1); - text_printf("Rotation quat ([% 1.3f, % 1.3f, % 1.3f], % 1.3f)", qrot.v.x, qrot.v.y, qrot.v.z, qrot.s); + text_printf("Rotation quat ([% 1.3f, % 1.3f, % 1.3f], % 1.3f)", last_rot.v.x, last_rot.v.y, last_rot.v.z, last_rot.s); } static void draw_quad(float hsz, float vsz) @@ -147,6 +153,65 @@ gl_pop_matrix(); } +static void draw_rotation_gizmo() +{ + /*static const float axis[][3] = { + {1, 0, 0}, {0, 1, 0}, {0, 0, 1} + };*/ + + last_rot.normalize(); + Matrix4x4 rmat = last_rot.get_rotation_matrix().transposed(); + gl_matrix_mode(GL_MODELVIEW); + gl_push_matrix(); + gl_mult_matrixf(rmat[0]); + gl_apply_xform(sdr_debug->get_globj()); + + sdr_debug->bind(); + + mesh->draw(); + + gl_pop_matrix(); +} + +static void draw_disc_wedge(float start, float end, int subdiv) +{ + if(start > end) { + float tmp = start; + start = end; + end = tmp; + } + + float arc_size = end - start; + subdiv = std::max(subdiv * arc_size, 1); + int nverts = subdiv + 2; + + float *varr = (float*)alloca(nverts * 3 * sizeof *varr); + float *vptr = varr; + + // start with the center vertex + vptr[0] = vptr[1] = vptr[2] = 0; + vptr += 3; + + // then add the arc vertices in sequence + float u = start; + float du = arc_size / (float)subdiv; + for(int i=0; i +#include +#include "geom.h" + +GeomObject::~GeomObject() +{ +} + + +Sphere::Sphere() +{ + radius = 1.0; +} + +Sphere::Sphere(const Vector3 ¢, float radius) + : center(cent) +{ + this->radius = radius; +} + +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2) +{ + const Sphere *sph1 = dynamic_cast(obj1); + const Sphere *sph2 = dynamic_cast(obj2); + + if(!sph1 || !sph2) { + fprintf(stderr, "Sphere::set_union: arguments must be spheres"); + return; + } + + float dist = (sph1->center - sph2->center).length(); + float surf_dist = dist - (sph1->radius + sph2->radius); + float d1 = sph1->radius + surf_dist / 2.0; + float d2 = sph2->radius + surf_dist / 2.0; + float t = d1 / (d1 + d2); + + if(t < 0.0) t = 0.0; + if(t > 1.0) t = 1.0; + + center = sph1->center * t + sph2->center * (1.0 - t); + radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius); +} + +void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2) +{ + fprintf(stderr, "Sphere::intersection undefined\n"); +} + +bool Sphere::intersect(const Ray &ray, HitPoint *hit) const +{ + float a = dot_product(ray.dir, ray.dir); + float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) + + 2.0 * ray.dir.y * (ray.origin.y - center.y) + + 2.0 * ray.dir.z * (ray.origin.z - center.z); + float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) - + 2.0 * dot_product(ray.origin, center) - radius * radius; + + float discr = b * b - 4.0 * a * c; + if(discr < 1e-4) { + return false; + } + + float sqrt_discr = sqrt(discr); + float t0 = (-b + sqrt_discr) / (2.0 * a); + float t1 = (-b - sqrt_discr) / (2.0 * a); + + if(t0 < 1e-4) + t0 = t1; + if(t1 < 1e-4) + t1 = t0; + + float t = t0 < t1 ? t0 : t1; + if(t < 1e-4) { + return false; + } + + // fill the HitPoint structure + if(hit) { + hit->obj = this; + hit->dist = t; + hit->pos = ray.origin + ray.dir * t; + hit->normal = (hit->pos - center) / radius; + } + return true; +} + + +AABox::AABox() +{ +} + +AABox::AABox(const Vector3 &vmin, const Vector3 &vmax) + : min(vmin), max(vmax) +{ +} + +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) +{ + const AABox *box1 = dynamic_cast(obj1); + const AABox *box2 = dynamic_cast(obj2); + + if(!box1 || !box2) { + fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); + return; + } + + min.x = std::min(box1->min.x, box2->min.x); + min.y = std::min(box1->min.y, box2->min.y); + min.z = std::min(box1->min.z, box2->min.z); + + max.x = std::max(box1->max.x, box2->max.x); + max.y = std::max(box1->max.y, box2->max.y); + max.z = std::max(box1->max.z, box2->max.z); +} + +void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2) +{ + const AABox *box1 = dynamic_cast(obj1); + const AABox *box2 = dynamic_cast(obj2); + + if(!box1 || !box2) { + fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n"); + return; + } + + for(int i=0; i<3; i++) { + min[i] = std::max(box1->min[i], box2->min[i]); + max[i] = std::min(box1->max[i], box2->max[i]); + + if(max[i] < min[i]) { + max[i] = min[i]; + } + } +} + +bool AABox::intersect(const Ray &ray, HitPoint *hit) const +{ + Vector3 param[2] = {min, max}; + Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); + int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; + + float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; + float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; + float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; + float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; + + if(tmin > tymax || tymin > tmax) { + return false; + } + if(tymin > tmin) { + tmin = tymin; + } + if(tymax < tmax) { + tmax = tymax; + } + + float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; + float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; + + if(tmin > tzmax || tzmin > tmax) { + return false; + } + if(tzmin > tmin) { + tmin = tzmin; + } + if(tzmax < tmax) { + tmax = tzmax; + } + + float t = tmin < 1e-4 ? tmax : tmin; + if(t >= 1e-4) { + + if(hit) { + hit->obj = this; + hit->dist = t; + hit->pos = ray.origin + ray.dir * t; + + float min_dist = FLT_MAX; + Vector3 offs = min + (max - min) / 2.0; + Vector3 local_hit = hit->pos - offs; + + static const Vector3 axis[] = { + Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) + }; + //int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}}; + + for(int i=0; i<3; i++) { + float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i])); + if(dist < min_dist) { + min_dist = dist; + hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0); + //hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]); + } + } + } + return true; + } + return false; + +} + +Plane::Plane() + : normal(0.0, 1.0, 0.0) +{ +} + +Plane::Plane(const Vector3 &p, const Vector3 &norm) + : pt(p) +{ + normal = norm.normalized(); +} + +Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3) + : pt(p1) +{ + normal = cross_product(p2 - p1, p3 - p1).normalized(); +} + +Plane::Plane(const Vector3 &normal, float dist) +{ + this->normal = normal.normalized(); + pt = this->normal * dist; +} + +void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2) +{ + fprintf(stderr, "Plane::set_union undefined\n"); +} + +void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2) +{ + fprintf(stderr, "Plane::set_intersection undefined\n"); +} + +bool Plane::intersect(const Ray &ray, HitPoint *hit) const +{ + float ndotdir = dot_product(normal, ray.dir); + if(fabs(ndotdir) < 1e-4) { + return false; + } + + if(hit) { + Vector3 ptdir = pt - ray.origin; + float t = dot_product(normal, ptdir) / ndotdir; + + hit->pos = ray.origin + ray.dir * t; + hit->normal = normal; + hit->obj = this; + } + return true; +} diff -r 2712c5da2e00 -r ac80210d5fbe src/geom.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/geom.h Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,67 @@ +#ifndef GEOMOBJ_H_ +#define GEOMOBJ_H_ + +#include "vmath/vmath.h" + +class GeomObject; + +struct HitPoint { + float dist; //< parametric distance along the ray + Vector3 pos; //< position of intersection (orig + dir * dist) + Vector3 normal; //< normal at the point of intersection + const void *obj; //< pointer to the intersected object +}; + +class GeomObject { +public: + virtual ~GeomObject(); + + virtual void set_union(const GeomObject *obj1, const GeomObject *obj2) = 0; + virtual void set_intersection(const GeomObject *obj1, const GeomObject *obj2) = 0; + + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0; +}; + +class Sphere : public GeomObject { +public: + Vector3 center; + float radius; + + Sphere(); + Sphere(const Vector3 ¢er, float radius); + + void set_union(const GeomObject *obj1, const GeomObject *obj2); + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); + + bool intersect(const Ray &ray, HitPoint *hit = 0) const; +}; + +class AABox : public GeomObject { +public: + Vector3 min, max; + + AABox(); + AABox(const Vector3 &min, const Vector3 &max); + + void set_union(const GeomObject *obj1, const GeomObject *obj2); + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); + + bool intersect(const Ray &ray, HitPoint *hit = 0) const; +}; + +class Plane : public GeomObject { +public: + Vector3 pt, normal; + + Plane(); + Plane(const Vector3 &pt, const Vector3 &normal); + Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3); + Plane(const Vector3 &normal, float dist); + + void set_union(const GeomObject *obj1, const GeomObject *obj2); + void set_intersection(const GeomObject *obj1, const GeomObject *obj2); + + bool intersect(const Ray &ray, HitPoint *hit = 0) const; +}; + +#endif // GEOMOBJ_H_ diff -r 2712c5da2e00 -r ac80210d5fbe src/mesh.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mesh.cc Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,1190 @@ +#include +#include +#include +#include +#include "opengl.h" +#include "mesh.h" +//#include "xform_node.h" +#include "shader.h" + +int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { + (int)SDR_ATTR_VERTEX, + (int)SDR_ATTR_NORMAL, + (int)SDR_ATTR_TANGENT, + (int)SDR_ATTR_TEXCOORD, + (int)SDR_ATTR_COLOR, + -1, -1}; +unsigned int Mesh::intersect_mode = ISECT_DEFAULT; +float Mesh::vertex_sel_dist = 0.01; +float Mesh::vis_vecsize = 1.0; + +Mesh::Mesh() +{ + clear(); + + glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects); + + for(int i=0; iname = name; +} + +const char *Mesh::get_name() const +{ + return name.c_str(); +} + +bool Mesh::has_attrib(int attr) const +{ + if(attr < 0 || attr >= NUM_MESH_ATTR) { + return false; + } + + // if neither of these is valid, then nobody has set this attribute + return vattr[attr].vbo_valid || vattr[attr].data_valid; +} + +bool Mesh::is_indexed() const +{ + return ibo_valid || idata_valid; +} + +void Mesh::clear() +{ + //bones.clear(); + + for(int i=0; i= NUM_MESH_ATTR) { + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + if(nverts && num != nverts) { + fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts); + return 0; + } + nverts = num; + + vattr[attrib].data.clear(); + vattr[attrib].nelem = nelem; + vattr[attrib].data.resize(num * nelem); + + if(data) { + memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data); + } + + vattr[attrib].data_valid = true; + vattr[attrib].vbo_valid = false; + return &vattr[attrib].data[0]; +} + +float *Mesh::get_attrib_data(int attrib) +{ + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + vattr[attrib].vbo_valid = false; + return (float*)((const Mesh*)this)->get_attrib_data(attrib); +} + +const float *Mesh::get_attrib_data(int attrib) const +{ + if(attrib < 0 || attrib >= NUM_MESH_ATTR) { + fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + if(!vattr[attrib].data_valid) { +#if GL_ES_VERSION_2_0 + fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__); + return 0; +#else + if(!vattr[attrib].vbo_valid) { + fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib); + return 0; + } + + // local data copy is unavailable, grab the data from the vbo + Mesh *m = (Mesh*)this; + m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem); + + glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo); + void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); + memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float)); + glUnmapBuffer(GL_ARRAY_BUFFER); + + vattr[attrib].data_valid = true; +#endif + } + + return &vattr[attrib].data[0]; +} + +void Mesh::set_attrib(int attrib, int idx, const Vector4 &v) +{ + float *data = get_attrib_data(attrib); + if(data) { + data += idx * vattr[attrib].nelem; + for(int i=0; iget_index_data(); +} + +const unsigned int *Mesh::get_index_data() const +{ + if(!idata_valid) { +#if GL_ES_VERSION_2_0 + fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__); + return 0; +#else + if(!ibo_valid) { + fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__); + return 0; + } + + // local data copy is unavailable, gram the data from the ibo + Mesh *m = (Mesh*)this; + int nidx = nfaces * 3; + m->idata.resize(nidx); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY); + memcpy(&m->idata[0], data, nidx * sizeof(unsigned int)); + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + + idata_valid = true; +#endif + } + + return &idata[0]; +} + +int Mesh::get_index_count() const +{ + return nfaces * 3; +} + +void Mesh::append(const Mesh &mesh) +{ + unsigned int idxoffs = nverts; + + nverts += mesh.nverts; + nfaces += mesh.nfaces; + + for(int i=0; i= NUM_MESH_ATTR) { + return; + } + Mesh::global_sdr_loc[attr] = loc; +} + +/// static function +int Mesh::get_attrib_location(int attr) +{ + if(attr < 0 || attr >= NUM_MESH_ATTR) { + return -1; + } + return Mesh::global_sdr_loc[attr]; +} + +/// static function +void Mesh::clear_attrib_locations() +{ + for(int i=0; i= (int)bones.size()) { + return 0; + } + return bones[idx]; +} + +int Mesh::get_bones_count() const +{ + return (int)bones.size(); +} +*/ + +void Mesh::draw() const +{ +#ifdef GL_ES_VERSION_2_0 + if(!SdrProg::active) { + fprintf(stderr, "%s: CrippledGL ES can't draw without a shader\n", __FUNCTION__); + return; + } +#endif + + ((Mesh*)this)->update_buffers(); + + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); + return; + } + + if(SdrProg::active) { + // rendering with shaders + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); + return; + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(loc); + } + } + } else { +#ifndef GL_ES_VERSION_2_0 + // rendering with fixed-function (not available in GLES2) + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo); + glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo); + glNormalPointer(GL_FLOAT, 0, 0); + glEnableClientState(GL_NORMAL_ARRAY); + } + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo); + glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + if(vattr[MESH_ATTR_COLOR].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo); + glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0); + glEnableClientState(GL_COLOR_ARRAY); + } +#endif + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if(ibo_valid) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + glDrawArrays(GL_TRIANGLES, 0, nverts); + } + + if(SdrProg::active) { + // rendered with shaders + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glDisableVertexAttribArray(loc); + } + } + } else { +#ifndef GL_ES_VERSION_2_0 + // rendered with fixed-function + glDisableClientState(GL_VERTEX_ARRAY); + if(vattr[MESH_ATTR_NORMAL].vbo_valid) { + glDisableClientState(GL_NORMAL_ARRAY); + } + if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + if(vattr[MESH_ATTR_COLOR].vbo_valid) { + glDisableClientState(GL_COLOR_ARRAY); + } +#endif + } +} + +void Mesh::draw_wire() const +{ + ((Mesh*)this)->update_wire_ibo(); + + if(!vattr[MESH_ATTR_VERTEX].vbo_valid || !wire_ibo_valid) { + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); + return; + } + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); + return; + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(loc); + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo); + glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glDisableVertexAttribArray(loc); + } + } +} + +void Mesh::draw_vertices() const +{ + ((Mesh*)this)->update_buffers(); + + if(!vattr[MESH_ATTR_VERTEX].vbo_valid) { + fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__); + return; + } + if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { + fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); + return; + } + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo); + glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(loc); + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDrawArrays(GL_POINTS, 0, nverts); + + for(int i=0; i= 0 && vattr[i].vbo_valid) { + glDisableVertexAttribArray(loc); + } + } +} + +void Mesh::draw_normals() const +{ +#ifdef USE_OLDGL + Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); + Vector3 *norm = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); + if(!varr || !norm) { + return; + } + + glBegin(GL_LINES); + if(get_current_shader()) { + int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX]; + if(vert_loc < 0) { + glEnd(); + return; + } + + for(size_t i=0; icalc_aabb(); + } + *vmin = aabb.min; + *vmax = aabb.max; +} + +const AABox &Mesh::get_aabbox() const +{ + if(!aabb_valid) { + ((Mesh*)this)->calc_aabb(); + } + return aabb; +} + +float Mesh::get_bsphere(Vector3 *center, float *rad) const +{ + if(!bsph_valid) { + ((Mesh*)this)->calc_bsph(); + } + *center = bsph.center; + *rad = bsph.radius; + return bsph.radius; +} + +const Sphere &Mesh::get_bsphere() const +{ + if(!bsph_valid) { + ((Mesh*)this)->calc_bsph(); + } + return bsph; +} + +/// static function +void Mesh::set_intersect_mode(unsigned int mode) +{ + Mesh::intersect_mode = mode; +} + +/// static function +unsigned int Mesh::get_intersect_mode() +{ + return Mesh::intersect_mode; +} + +/// static function +void Mesh::set_vertex_select_distance(float dist) +{ + Mesh::vertex_sel_dist = dist; +} + +/// static function +float Mesh::get_vertex_select_distance() +{ + return Mesh::vertex_sel_dist; +} + +bool Mesh::intersect(const Ray &ray, HitPoint *hit) const +{ + assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE)); + + const Vector3 *varr = (Vector3*)get_attrib_data(MESH_ATTR_VERTEX); + const Vector3 *narr = (Vector3*)get_attrib_data(MESH_ATTR_NORMAL); + if(!varr) { + return false; + } + const unsigned int *idxarr = get_index_data(); + + // first test with the bounding box + AABox box; + get_aabbox(&box.min, &box.max); + if(!box.intersect(ray)) { + return false; + } + + HitPoint nearest_hit; + nearest_hit.dist = FLT_MAX; + nearest_hit.obj = 0; + + if(Mesh::intersect_mode & ISECT_VERTICES) { + // we asked for "intersections" with the vertices of the mesh + long nearest_vidx = -1; + float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist; + + for(unsigned int i=0; i 0) { + continue; + } + + // project the vertex onto the ray line + float t = dot_product(varr[i] - ray.origin, ray.dir); + Vector3 vproj = ray.origin + ray.dir * t; + + float dist_sq = (vproj - varr[i]).length_sq(); + if(dist_sq < thres_sq) { + if(!hit) { + return true; + } + if(t < nearest_hit.dist) { + nearest_hit.dist = t; + nearest_vidx = i; + } + } + } + + if(nearest_vidx != -1) { + hitvert = varr[nearest_vidx]; + nearest_hit.obj = &hitvert; + } + + } else { + // regular intersection test with polygons + + for(unsigned int i=0; i 0) { + continue; + } + + HitPoint fhit; + if(face.intersect(ray, hit ? &fhit : 0)) { + if(!hit) { + return true; + } + if(fhit.dist < nearest_hit.dist) { + nearest_hit = fhit; + hitface = face; + } + } + } + } + + if(nearest_hit.obj) { + if(hit) { + *hit = nearest_hit; + + // if we are interested in the mesh and not the faces set obj to this + if(Mesh::intersect_mode & ISECT_FACE) { + hit->obj = &hitface; + } else if(Mesh::intersect_mode & ISECT_VERTICES) { + hit->obj = &hitvert; + } else { + hit->obj = this; + } + } + return true; + } + return false; +} + + +// ------ private member functions ------ + +void Mesh::calc_aabb() +{ + // the cast is to force calling the const version which doesn't invalidate + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { + return; + } + + aabb.min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX); + aabb.max = -aabb.min; + + for(unsigned int i=0; i aabb.max[j]) { + aabb.max[j] = v[j]; + } + } + } + aabb_valid = true; +} + +void Mesh::calc_bsph() +{ + // the cast is to force calling the const version which doesn't invalidate + if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) { + return; + } + + Vector3 v; + bsph.center = Vector3(0, 0, 0); + + // first find the center + for(unsigned int i=0; i bsph.radius) { + bsph.radius = dist_sq; + } + } + bsph.radius = sqrt(bsph.radius); + + bsph_valid = true; +} + +void Mesh::update_buffers() +{ + for(int i=0; iget_index_data(); + + for(unsigned int i=0; icalc_normal(); + } + return normal; +} + +void Triangle::transform(const Matrix4x4 &xform) +{ + v[0].transform(xform); + v[1].transform(xform); + v[2].transform(xform); + normal_valid = false; +} + +void Triangle::draw() const +{ + Vector3 n[3]; + n[0] = get_normal(); + n[1] = get_normal(); + n[2] = get_normal(); + + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); + int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL); + + glEnableVertexAttribArray(vloc); + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); + glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(vloc); + glDisableVertexAttribArray(nloc); + CHECK_GLERROR; +} + +void Triangle::draw_wire() const +{ + static const int idxarr[] = {0, 1, 1, 2, 2, 0}; + int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX); + + glEnableVertexAttribArray(vloc); + glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x); + + glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr); + + glDisableVertexAttribArray(vloc); + CHECK_GLERROR; +} + +Vector3 Triangle::calc_barycentric(const Vector3 &pos) const +{ + Vector3 norm = get_normal(); + + float area_sq = fabs(dot_product(cross_product(v[1] - v[0], v[2] - v[0]), norm)); + if(area_sq < 1e-5) { + return Vector3(0, 0, 0); + } + + float asq0 = fabs(dot_product(cross_product(v[1] - pos, v[2] - pos), norm)); + float asq1 = fabs(dot_product(cross_product(v[2] - pos, v[0] - pos), norm)); + float asq2 = fabs(dot_product(cross_product(v[0] - pos, v[1] - pos), norm)); + + return Vector3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq); +} + +bool Triangle::intersect(const Ray &ray, HitPoint *hit) const +{ + Vector3 normal = get_normal(); + + float ndotdir = dot_product(ray.dir, normal); + if(fabs(ndotdir) < 1e-4) { + return false; + } + + Vector3 vertdir = v[0] - ray.origin; + float t = dot_product(normal, vertdir) / ndotdir; + + Vector3 pos = ray.origin + ray.dir * t; + Vector3 bary = calc_barycentric(pos); + + if(bary.x + bary.y + bary.z > 1.00001) { + return false; + } + + if(hit) { + hit->dist = t; + hit->pos = ray.origin + ray.dir * t; + hit->normal = normal; + hit->obj = this; + } + return true; +} diff -r 2712c5da2e00 -r ac80210d5fbe src/mesh.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mesh.h Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,225 @@ +#ifndef MESH_H_ +#define MESH_H_ + +#include +#include +#include "vmath/vmath.h" +#include "geom.h" + +enum { + MESH_ATTR_VERTEX, + MESH_ATTR_NORMAL, + MESH_ATTR_TANGENT, + MESH_ATTR_TEXCOORD, + MESH_ATTR_COLOR, + MESH_ATTR_BONEWEIGHTS, + MESH_ATTR_BONEIDX, + + NUM_MESH_ATTR +}; + +// intersection mode flags +enum { + ISECT_DEFAULT = 0, // default (whole mesh, all intersections) + ISECT_FRONT = 1, // front-faces only + ISECT_FACE = 2, // return intersected face pointer instead of mesh + ISECT_VERTICES = 4 // return (?) TODO +}; + +//class XFormNode; + + +class Triangle { +public: + Vector3 v[3]; + Vector3 normal; + bool normal_valid; + int id; + + Triangle(); + Triangle(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2); + Triangle(int n, const Vector3 *varr, const unsigned int *idxarr = 0); + + /// calculate normal (quite expensive) + void calc_normal(); + const Vector3 &get_normal() const; + + void transform(const Matrix4x4 &xform); + + void draw() const; + void draw_wire() const; + + /// calculate barycentric coordinates of a point + Vector3 calc_barycentric(const Vector3 &pos) const; + + bool intersect(const Ray &ray, HitPoint *hit = 0) const; +}; + + +class Mesh { +private: + std::string name; + unsigned int nverts, nfaces; + + // current value for each attribute for the immedate mode + // interface. + Vector4 cur_val[NUM_MESH_ATTR]; + + unsigned int buffer_objects[NUM_MESH_ATTR + 1]; + + // vertex attribute data and buffer objects + struct { + int nelem; // number of elements per attribute range: [1, 4] + std::vector data; + unsigned int vbo; + mutable bool vbo_valid; // if this is false, the vbo needs updating from the data + mutable bool data_valid; // if this is false, the data needs to be pulled from the vbo + //int sdr_loc; + } vattr[NUM_MESH_ATTR]; + + static int global_sdr_loc[NUM_MESH_ATTR]; + + //std::vector bones; // bones affecting this mesh + + // index data and buffer object + std::vector idata; + unsigned int ibo; + mutable bool ibo_valid; + mutable bool idata_valid; + + // index buffer object for wireframe rendering (constructed on demand) + unsigned int wire_ibo; + mutable bool wire_ibo_valid; + + // axis-aligned bounding box + mutable AABox aabb; + mutable bool aabb_valid; + + // bounding sphere + mutable Sphere bsph; + mutable bool bsph_valid; + + // keeps the last intersected face + mutable Triangle hitface; + // keeps the last intersected vertex position + mutable Vector3 hitvert; + + void calc_aabb(); + void calc_bsph(); + + static unsigned int intersect_mode; + static float vertex_sel_dist; + + static float vis_vecsize; + + /// update the VBOs after data has changed (invalid vbo/ibo) + void update_buffers(); + /// construct/update the wireframe index buffer (called from draw_wire). + void update_wire_ibo(); + + +public: + Mesh(); + ~Mesh(); + + Mesh(const Mesh &rhs); + Mesh &operator =(const Mesh &rhs); + bool clone(const Mesh &m); + + void set_name(const char *name); + const char *get_name() const; + + bool has_attrib(int attr) const; + bool is_indexed() const; + + // clears everything about this mesh, and returns to the newly constructed state + void clear(); + + // access the vertex attribute data + // if vdata == 0, space is just allocated + float *set_attrib_data(int attrib, int nelem, unsigned int num, const float *vdata = 0); // invalidates vbo + float *get_attrib_data(int attrib); // invalidates vbo + const float *get_attrib_data(int attrib) const; + + // simple access to any particular attribute + void set_attrib(int attrib, int idx, const Vector4 &v); // invalidates vbo + Vector4 get_attrib(int attrib, int idx) const; + + int get_attrib_count(int attrib) const; + + // ... same for index data + unsigned int *set_index_data(int num, const unsigned int *indices = 0); // invalidates ibo + unsigned int *get_index_data(); // invalidates ibo + const unsigned int *get_index_data() const; + + int get_index_count() const; + + void append(const Mesh &mesh); + + // immediate-mode style mesh construction interface + void vertex(float x, float y, float z); + void normal(float nx, float ny, float nz); + void tangent(float tx, float ty, float tz); + void texcoord(float u, float v, float w); + void boneweights(float w1, float w2, float w3, float w4); + void boneidx(int idx1, int idx2, int idx3, int idx4); + + int get_poly_count() const; + + /* apply a transformation to the vertices and its inverse-transpose + * to the normals and tangents. + */ + void apply_xform(const Matrix4x4 &xform); + void apply_xform(const Matrix4x4 &xform, const Matrix4x4 &dir_xform); + + void flip(); // both faces and normals + void flip_faces(); + void flip_normals(); + + // adds a bone and returns its index + /*int add_bone(XFormNode *bone); + const XFormNode *get_bone(int idx) const; + int get_bones_count() const;*/ + + // access the shader attribute locations + static void set_attrib_location(int attr, int loc); + static int get_attrib_location(int attr); + static void clear_attrib_locations(); + + static void set_vis_vecsize(float sz); + static float get_vis_vecsize(); + + void draw() const; + void draw_wire() const; + void draw_vertices() const; + void draw_normals() const; + void draw_tangents() const; + + /** get the bounding box in local space. The result will be cached, and subsequent + * calls will return the same box. The cache gets invalidated by any functions that can affect + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). + * @{ */ + void get_aabbox(Vector3 *vmin, Vector3 *vmax) const; + const AABox &get_aabbox() const; + /// @} + + /** get the bounding sphere in local space. The result will be cached, and subsequent + * calls will return the same box. The cache gets invalidated by any functions that can affect + * the vertex data (non-const variant of get_attrib_data(MESH_ATTR_VERTEX, ...) included). + * @{ */ + float get_bsphere(Vector3 *center, float *rad) const; + const Sphere &get_bsphere() const; + + static void set_intersect_mode(unsigned int mode); + static unsigned int get_intersect_mode(); + static void set_vertex_select_distance(float dist); + static float get_vertex_select_distance(); + + /** Find the intersection between the mesh and a ray. + * XXX Brute force at the moment, not intended to be used for anything other than picking in tools. + * If you intend to use it in a speed-critical part of the code, you'll *have* to optimize it! + */ + bool intersect(const Ray &ray, HitPoint *hit = 0) const; +}; + +#endif // MESH_H_ diff -r 2712c5da2e00 -r ac80210d5fbe src/meshgen.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/meshgen.cc Thu Jun 18 03:12:30 2015 +0300 @@ -0,0 +1,395 @@ +#include +#include "meshgen.h" +#include "mesh.h" + +// -------- sphere -------- + +#define SURAD(u) ((u) * 2.0 * M_PI) +#define SVRAD(v) ((v) * M_PI) + +static Vector3 sphvec(float theta, float phi) +{ + return Vector3(sin(theta) * sin(phi), + cos(phi), + cos(theta) * sin(phi)); +} + +void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange) +{ + if(usub < 4) usub = 4; + if(vsub < 2) vsub = 2; + + int uverts = usub + 1; + int vverts = vsub + 1; + + int num_verts = uverts * vverts; + int num_quads = usub * vsub; + int num_tri = num_quads * 2; + + mesh->clear(); + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); + + float du = urange / (float)(uverts - 1); + float dv = vrange / (float)(vverts - 1); + + float u = 0.0; + for(int i=0; iclear(); + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); + + float du = urange / (float)(uverts - 1); + float dv = vrange / (float)(vverts - 1); + + float u = 0.0; + for(int i=0; iclear(); + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); + + float du = urange / (float)(uverts - 1); + float dv = vrange / (float)(vverts - 1); + + float u = 0.0; + for(int i=0; iclear(); + + int uverts = usub + 1; + int vverts = vsub + 1; + int num_verts = uverts * vverts; + + int num_quads = usub * vsub; + int num_tri = num_quads * 2; + + Vector3 *varr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0); + Vector3 *narr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0); + Vector3 *tarr = (Vector3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0); + Vector2 *uvarr = (Vector2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0); + unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0); + + float du = 1.0 / (float)usub; + float dv = 1.0 / (float)vsub; + + float u = 0.0; + for(int i=0; i