From b7c92831285013b2a0783bccaf3d900545ebb5ba Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 29 Oct 2016 08:15:24 +0300 Subject: [PATCH] assimp --- Makefile | 2 +- src/exhibit.h | 29 ++++++ src/geom.cc | 139 ++++++++++---------------- src/geom.h | 44 ++++++--- src/main.cc | 256 ++++-------------------------------------------- src/material.cc | 19 ++++ src/material.h | 16 +++ src/mech_exhibit.h | 18 ++++ src/mesh.cc | 14 +-- src/object.cc | 37 +++++++ src/object.h | 37 +++++++ src/objmesh.cc | 32 ++++++ src/objmesh.h | 18 ++++ src/scene.cc | 63 ++++++++++++ src/scene.h | 28 ++++++ src/sceneload.cc | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sceneload.h | 8 ++ src/snode.cc | 227 +++++++++++++++++++++++++++++++++++++++++++ src/snode.h | 67 +++++++++++++ 19 files changed, 984 insertions(+), 345 deletions(-) create mode 100644 src/exhibit.h create mode 100644 src/material.cc create mode 100644 src/material.h create mode 100644 src/mech_exhibit.h create mode 100644 src/object.cc create mode 100644 src/object.h create mode 100644 src/objmesh.cc create mode 100644 src/objmesh.h create mode 100644 src/scene.cc create mode 100644 src/scene.h create mode 100644 src/sceneload.cc create mode 100644 src/sceneload.h create mode 100644 src/snode.cc create mode 100644 src/snode.h diff --git a/Makefile b/Makefile index 3c0cb0a..82b42ca 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ warn = -pedantic -Wall CFLAGS = $(warn) $(opt) $(dbg) $(incpath) CXXFLAGS = -std=c++11 $(warn) $(opt) $(dbg) $(incpath) -LDFLAGS = $(libpath) $(libgl_$(sys)) -lm -lgmath -lvmath -limago -lresman -lpthread +LDFLAGS = $(libpath) $(libgl_$(sys)) -lm -lgmath -lvmath -limago -lresman -lpthread -lassimp sys = $(shell uname -s) libgl_Linux = -lGL -lGLU -lglut -lGLEW diff --git a/src/exhibit.h b/src/exhibit.h new file mode 100644 index 0000000..c607fdb --- /dev/null +++ b/src/exhibit.h @@ -0,0 +1,29 @@ +#ifndef EXHIBIT_H_ +#define EXHIBIT_H_ + +#include +#include "object.h" +#include "geom.h" + +/* +- select me aktina kai select me sfaira, epistrefei Selection +- hover me aktina kai hover me sfaira +- move me selection, origin, direction kai rotation (?) + */ + +class Exhibit : public Object { +public: + Exhibit(); + virtual ~Exhibit() = default; + + Exhibit(const Exhibit&) = delete; + Exhibit &operator =(const Exhibit &) = delete; + + virtual void *select(const Ray &ray) const; + virtual void *select(const Sphere &sph) const; + + virtual void update(float dt = 0.0f); + virtual void draw() const; +}; + +#endif // EXHIBIT_H_ diff --git a/src/geom.cc b/src/geom.cc index a6b26e8..55cfed7 100644 --- a/src/geom.cc +++ b/src/geom.cc @@ -1,6 +1,5 @@ -#include -#include #include +#include #include "geom.h" GeomObject::~GeomObject() @@ -19,15 +18,19 @@ Sphere::Sphere(const Vec3 ¢, float radius) this->radius = radius; } -void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2) +GeomObjectType Sphere::get_type() const { - const Sphere *sph1 = dynamic_cast(obj1); - const Sphere *sph2 = dynamic_cast(obj2); + return GOBJ_SPHERE; +} - if(!sph1 || !sph2) { +void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2) +{ + if(obj1->get_type() != GOBJ_SPHERE || obj2->get_type() != GOBJ_SPHERE) { fprintf(stderr, "Sphere::set_union: arguments must be spheres"); return; } + const Sphere *sph1 = (const Sphere*)obj1; + const Sphere *sph2 = (const Sphere*)obj2; float dist = length(sph1->center - sph2->center); float surf_dist = dist - (sph1->radius + sph2->radius); @@ -85,6 +88,15 @@ bool Sphere::intersect(const Ray &ray, HitPoint *hit) const return true; } +bool Sphere::contains(const Vec3 &pt) const +{ + return length_sq(pt - center) <= radius * radius; +} + +float Sphere::distance(const Vec3 &v) const +{ + return length(v - center) - radius; +} AABox::AABox() { @@ -95,15 +107,19 @@ AABox::AABox(const Vec3 &vmin, const Vec3 &vmax) { } -void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) +GeomObjectType AABox::get_type() const { - const AABox *box1 = dynamic_cast(obj1); - const AABox *box2 = dynamic_cast(obj2); + return GOBJ_AABOX; +} - if(!box1 || !box2) { +void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) +{ + if(obj1->get_type() != GOBJ_AABOX || obj2->get_type() != GOBJ_AABOX) { fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n"); return; } + const AABox *box1 = (const AABox*)obj1; + const AABox *box2 = (const AABox*)obj2; min.x = std::min(box1->min.x, box2->min.x); min.y = std::min(box1->min.y, box2->min.y); @@ -116,13 +132,12 @@ void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2) 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) { + if(obj1->get_type() != GOBJ_AABOX || obj2->get_type() != GOBJ_AABOX) { fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n"); return; } + const AABox *box1 = (const AABox*)obj1; + const AABox *box2 = (const AABox*)obj2; for(int i=0; i<3; i++) { min[i] = std::max(box1->min[i], box2->min[i]); @@ -197,9 +212,20 @@ bool AABox::intersect(const Ray &ray, HitPoint *hit) const return true; } return false; +} + +bool AABox::contains(const Vec3 &v) const +{ + return v.x >= min.x && v.y >= min.y && v.z >= min.z && + v.x <= max.x && v.y <= max.y && v.z <= max.z; +} +float AABox::distance(const Vec3 &v) const +{ + return 0.0; // TODO } + Plane::Plane() : normal(0.0, 1.0, 0.0) { @@ -223,6 +249,11 @@ Plane::Plane(const Vec3 &normal, float dist) pt = this->normal * dist; } +GeomObjectType Plane::get_type() const +{ + return GOBJ_PLANE; +} + void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2) { fprintf(stderr, "Plane::set_union undefined\n"); @@ -252,84 +283,12 @@ bool Plane::intersect(const Ray &ray, HitPoint *hit) const return true; } -float sphere_distance(const Vec3 ¢, float rad, const Vec3 &pt) -{ - return length(pt - cent) - rad; -} - -// TODO version which takes both radii into account -float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt) +bool Plane::contains(const Vec3 &v) const { - Vec3 ab_dir = b - a; - float ab_len_sq = length_sq(ab_dir); - - if(fabs(ab_len_sq) < 1e-5) { - // if a == b, the capsule is a sphere with radius the maximum of the capsule radii - return sphere_distance(a, std::max(ra, rb), pt); - } - float ab_len = sqrt(ab_len_sq); - - Vec3 ap_dir = pt - a; - - float t = dot(ap_dir, ab_dir / ab_len) / ab_len; - if(t < 0.0) { - return sphere_distance(a, ra, pt); - } - if(t >= 1.0) { - return sphere_distance(b, rb, pt); - } - - Vec3 pproj = a + ab_dir * t; - return length(pproj - pt) - ra; + return dot(v, normal) <= 0.0; } -#if 0 -float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt) +float Plane::distance(const Vec3 &v) const { - Vec3 ab_dir = b - a; - - if(fabs(length_sq(ab_dir)) < 1e-5) { - // if a == b, the capsule is a sphere with radius the maximum of the capsule radii - return sphere_distance(a, std::max(ra, rb), pt); - } - float ab_len = length(ab_dir); - - Vec3 ap_dir = pt - a; - Vec3 rotaxis = normalize(cross(ab_dir, ap_dir)); - - Mat4 rmat; - rmat.set_rotation(rotaxis, M_PI / 2.0); - Vec3 right = rmat * ab_dir / ab_len; - - // XXX I think this check is redundant, always false, due to the cross product order - //assert(dot(right, ab_dir) >= 0.0); - if(dot(right, ab_dir) < 0.0) { - right = -right; - } - Vec3 aa = a + right * ra; - Vec3 bb = b + right * rb; - - // project pt to the line segment bb-aa, see if the projection lies within the interval [0, 1) - Vec3 aabb_dir = bb - aa; - float aabb_len = length(aabb_dir); - Vec3 aap_dir = pt - aa; - - float t = dot(aap_dir, aabb_dir / aabb_len) / aabb_len; - if(t < 0.0) { - return sphere_distance(a, ra, pt); - } - if(t >= 1.0) { - return sphere_distance(b, rb, pt); - } - - Vec3 ppt = aa + aabb_dir * t; - Vec3 norm = ppt - pt; - float dist = length(norm); - - if(dot(norm, right) < 0.0) { - // inside the cone - dist = -dist; - } - return dist; + return dot(v - pt, normal); } -#endif diff --git a/src/geom.h b/src/geom.h index aabf266..e110193 100644 --- a/src/geom.h +++ b/src/geom.h @@ -1,28 +1,38 @@ #ifndef GEOMOBJ_H_ #define GEOMOBJ_H_ -#include "gmath/gmath.h" +#include + +enum GeomObjectType { + GOBJ_UNKNOWN, + GOBJ_SPHERE, + GOBJ_AABOX, + GOBJ_PLANE +}; class GeomObject; -class SceneNode; struct HitPoint { - float dist; //< parametric distance along the ray - Vec3 pos; //< position of intersection (orig + dir * dist) - Vec3 normal; //< normal at the point of intersection - const void *obj; //< pointer to the intersected object - const SceneNode *node; - Ray ray; + float dist; // parametric distance along the ray + Vec3 pos; // position of intersection (orig + dir * dist) + Vec3 normal; // normal at the point of intersection + Ray ray, local_ray; + const GeomObject *obj; // pointer to the intersected geom-object + void *data; // place to hang extra data }; class GeomObject { public: virtual ~GeomObject(); + virtual GeomObjectType get_type() const = 0; 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; + virtual bool contains(const Vec3 &pt) const = 0; + + virtual float distance(const Vec3 &v) const = 0; }; class Sphere : public GeomObject { @@ -33,10 +43,15 @@ public: Sphere(); Sphere(const Vec3 ¢er, float radius); + GeomObjectType get_type() const; + 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; + bool contains(const Vec3 &pt) const; + + float distance(const Vec3 &v) const; }; class AABox : public GeomObject { @@ -46,10 +61,15 @@ public: AABox(); AABox(const Vec3 &min, const Vec3 &max); + GeomObjectType get_type() const; + 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; + bool contains(const Vec3 &pt) const; + + float distance(const Vec3 &v) const; }; class Plane : public GeomObject { @@ -61,13 +81,15 @@ public: Plane(const Vec3 &p1, const Vec3 &p2, const Vec3 &p3); Plane(const Vec3 &normal, float dist); + GeomObjectType get_type() const; + 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; -}; + bool contains(const Vec3 &pt) const; -float sphere_distance(const Vec3 ¢, float rad, const Vec3 &pt); -float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt); + float distance(const Vec3 &v) const; +}; #endif // GEOMOBJ_H_ diff --git a/src/main.cc b/src/main.cc index 4ef90c0..b170095 100644 --- a/src/main.cc +++ b/src/main.cc @@ -11,22 +11,19 @@ #include "sdr.h" #include "shadow.h" #include "texture.h" -#include "machine.h" +#include "mesh.h" #include "meshgen.h" -#include "mparser.h" static bool init(); static void cleanup(); static void display(); static void idle(); static void draw_scene(); -static void draw_gears(); static void reshape(int x, int y); static void keyb(unsigned char key, int x, int y); static void mouse(int bn, int st, int x, int y); static void motion(int x, int y); static void passive_motion(int x, int y); -static Gear *pick_gear(int x, int y); static int win_width, win_height; @@ -38,18 +35,8 @@ static bool bnstate[8]; static Mat4 view_matrix; static unsigned int start_time, prev_msec; -static Machine *machine; -static Gear *hover_gear, *sel_gear; -static HitPoint pick_hit; -static Vec3 sel_hit_pos; - -static unsigned int sdr_shadow_notex; -static int dbg_show_shadowmap; static TextureSet texman; -static Texture *envmap; -static Mesh *skydome; -static unsigned int sdr_skydome; int main(int argc, char **argv) @@ -88,34 +75,9 @@ static bool init() Mesh::use_custom_sdr_attr = false; - machine = new Machine; - if(!parse_machine(machine, "data/test.machine")) { - fprintf(stderr, "failed to parse machine\n"); - return false; - } - - // shadows - init_shadow(2048); - - if(!(sdr_shadow_notex = create_program_load("sdr/shadow.v.glsl", "sdr/shadow-notex.p.glsl"))) { - return false; - } - set_uniform_int(sdr_shadow_notex, "shadowmap", 1); - set_uniform_int(sdr_shadow_notex, "envmap", 2); - float ambient[] = {0.1, 0.1, 0.1, 0.0}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); - // env - envmap = texman.get_texture("data/stpeters_cross.jpg", TEX_CUBE); - - skydome = new Mesh; - gen_sphere(skydome, 1.0, 16, 8); - skydome->flip_faces(); - - if(!(sdr_skydome = create_program_load("sdr/skydome.v.glsl", "sdr/skydome.p.glsl"))) { - return false; - } glUseProgram(0); start_time = glutGet(GLUT_ELAPSED_TIME); @@ -125,19 +87,11 @@ static bool init() static void cleanup() { texman.clear(); - delete machine; } static void update(float dt) { texman.update(); - - machine->update(dt); - - if(sel_gear) { - } - - hover_gear = pick_gear(prev_mx, prev_my); } static void set_light(int idx, const Vec3 &pos, const Vec3 &color) @@ -175,72 +129,7 @@ static void display() update(dt); - // shadowmap pass - begin_shadow_pass(lpos[0], Vec3(0, 0, 0), 0.2, 100, 150); draw_scene(); - end_shadow_pass(); - - // regular pass - const Mat4 &shadow_matrix = get_shadow_matrix(); - Mat4 env_matrix = transpose(view_matrix.upper3x3()); - set_uniform_matrix4(sdr_shadow_notex, "envmap_matrix", env_matrix[0]); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, get_shadow_tex()); - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(shadow_matrix[0]); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_CUBE_MAP, envmap->get_id()); - - glActiveTexture(GL_TEXTURE0); - glMatrixMode(GL_MODELVIEW); - - draw_scene(); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - - - if(dbg_show_shadowmap) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - glPushAttrib(GL_ENABLE_BIT); - glUseProgram(0); - glBindTexture(GL_TEXTURE_2D, get_shadow_tex()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glEnable(GL_TEXTURE_2D); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glDisable(GL_BLEND); - - glBegin(GL_QUADS); - glColor4f(1, 1, 1, 1); - glTexCoord2f(0, 0); glVertex2f(-0.95, -0.95); - glTexCoord2f(1, 0); glVertex2f(-0.5, -0.95); - glTexCoord2f(1, 1); glVertex2f(-0.5, -0.5); - glTexCoord2f(0, 1); glVertex2f(-0.95, -0.5); - glEnd(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glBindTexture(GL_TEXTURE_2D, 0); - - glPopAttrib(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - glutSwapBuffers(); assert(glGetError() == GL_NO_ERROR); @@ -253,59 +142,13 @@ static void idle() static void draw_scene() { - // draw skydome - glDepthMask(0); - - Mat4 rot_view = view_matrix.upper3x3(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadMatrixf(rot_view[0]); - - bind_texture(envmap, 0); - - glUseProgram(sdr_skydome); - skydome->draw(); - glUseProgram(0); - - bind_texture(0, 0); - - glPopMatrix(); - glDepthMask(1); - - // draw mechanism - draw_gears(); -} - -static void draw_gears() -{ - /* world scale is in meters, gears are in millimeters, scale by 1/1000 */ - glPushMatrix(); - glScalef(0.001, 0.001, 0.001); - - if(!shadow_pass && (sel_gear || hover_gear)) { - glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POLYGON_BIT); - - glDisable(GL_LIGHTING); - glFrontFace(GL_CW); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glLineWidth(3.0); - - if(sel_gear) { - glColor3f(0.2, 1.0, 0.3); - sel_gear->draw(); - } else { - glColor3f(1.0, 0.75, 0.2); - hover_gear->draw(); - } - - glPopAttrib(); - } - - glUseProgram(shadow_pass ? 0 : sdr_shadow_notex); - machine->draw(); - glUseProgram(0); - - glPopMatrix(); + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-30, -10, 30); + glVertex3f(30, -10, 30); + glVertex3f(30, -10, -30); + glVertex3f(-30, -10, -30); + glEnd(); } static void reshape(int x, int y) @@ -325,16 +168,6 @@ static void keyb(unsigned char key, int x, int y) switch(key) { case 27: exit(0); - - case 'w': - opt_gear_wireframe = !opt_gear_wireframe; - glutPostRedisplay(); - break; - - case 's': - dbg_show_shadowmap = !dbg_show_shadowmap; - glutPostRedisplay(); - break; } } @@ -346,23 +179,6 @@ static void mouse(int bn, int st, int x, int y) prev_mx = x; prev_my = y; bnstate[bidx] = down; - - if(bidx == 0) { - if(down) { - sel_gear = pick_gear(x, y); - sel_hit_pos = pick_hit.pos; - } else { - sel_gear = 0; - } - } - - if(bidx == 3 || bidx == 4) { /* wheel */ - if(hover_gear) { - float dz = bidx == 4 ? 1 : -1; - hover_gear->set_position(hover_gear->get_position() + hover_gear->get_axis() * dz); - machine->invalidate_meshing(); - } - } } static void motion(int x, int y) @@ -374,28 +190,18 @@ static void motion(int x, int y) if(!dx && !dy) return; - if(sel_gear) { - float speed = 0.5; - Vec3 offs = Vec3(dx * speed, -dy * speed, 0.0); - offs = sel_gear->get_dir_matrix() * offs; - - sel_gear->set_position(sel_gear->get_position() + offs); - machine->invalidate_meshing(); - - } else { - if(bnstate[0]) { - cam_theta += dx * 0.5; - cam_phi += dy * 0.5; - - if(cam_phi < -90) cam_phi = -90; - if(cam_phi > 90) cam_phi = 90; - glutPostRedisplay(); - } - if(bnstate[2]) { - cam_dist += dy * 0.01; - if(cam_dist < 0.0) cam_dist = 0.0; - glutPostRedisplay(); - } + if(bnstate[0]) { + cam_theta += dx * 0.5; + cam_phi += dy * 0.5; + + if(cam_phi < -90) cam_phi = -90; + if(cam_phi > 90) cam_phi = 90; + glutPostRedisplay(); + } + if(bnstate[2]) { + cam_dist += dy * 0.01; + if(cam_dist < 0.0) cam_dist = 0.0; + glutPostRedisplay(); } } @@ -404,25 +210,3 @@ static void passive_motion(int x, int y) prev_mx = x; prev_my = y; } - -static Gear *pick_gear(int x, int y) -{ - double pt[3]; - double viewmat[16], projmat[16]; - int vp[4]; - Ray ray; - - y = win_height - y; - - glGetDoublev(GL_MODELVIEW_MATRIX, viewmat); - glGetDoublev(GL_PROJECTION_MATRIX, projmat); - glGetIntegerv(GL_VIEWPORT, vp); - - gluUnProject(x, y, 0, viewmat, projmat, vp, pt, pt + 1, pt + 2); - ray.origin = Vec3(pt[0], pt[1], pt[2]) * 1000.0f; - - gluUnProject(x, y, 1, viewmat, projmat, vp, pt, pt + 1, pt + 2); - ray.dir = Vec3(pt[0], pt[1], pt[2]) * 1000.0f - ray.origin; - - return machine->intersect_gear(ray, &pick_hit); -} diff --git a/src/material.cc b/src/material.cc new file mode 100644 index 0000000..962b10c --- /dev/null +++ b/src/material.cc @@ -0,0 +1,19 @@ +#include "opengl.h" +#include "material.h" + +Material::Material() + : diffuse(1.0f, 1.0f, 1.0f) +{ + shininess = 0.0f; + alpha = 1.0f; +} + +void Material::setup() const +{ + float kd[] = {diffuse.x, diffuse.y, diffuse.z, alpha}; + float ks[] = {specular.x, specular.y, specular.z, 1.0f}; + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, kd); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ks); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); +} diff --git a/src/material.h b/src/material.h new file mode 100644 index 0000000..f5c26ae --- /dev/null +++ b/src/material.h @@ -0,0 +1,16 @@ +#ifndef MATERIAL_H_ +#define MATERIAL_H_ + +#include + +class Material { +public: + Vec3 diffuse, specular; + float shininess; + float alpha; + + Material(); + void setup() const; +}; + +#endif // MATERIAL_H_ diff --git a/src/mech_exhibit.h b/src/mech_exhibit.h new file mode 100644 index 0000000..74fa613 --- /dev/null +++ b/src/mech_exhibit.h @@ -0,0 +1,18 @@ +#ifndef MECH_EXHIBIT_H_ +#define MECH_EXHIBIT_H_ + +#include "exhibit.h" +#include "machine.h" + +class MechExhibit : public Exhibit { +private: + +public: + MechExhibit(); + ~MechExhibit(); + + void update(float dt); + void draw() const; +}; + +#endif // MECH_EXHIBIT_H_ diff --git a/src/mesh.cc b/src/mesh.cc index ed4fd98..beb5b49 100644 --- a/src/mesh.cc +++ b/src/mesh.cc @@ -903,7 +903,7 @@ bool Mesh::intersect(const Ray &ray, HitPoint *hit) const HitPoint nearest_hit; nearest_hit.dist = FLT_MAX; - nearest_hit.obj = 0; + nearest_hit.data = 0; if(Mesh::intersect_mode & ISECT_VERTICES) { // we asked for "intersections" with the vertices of the mesh @@ -934,7 +934,7 @@ bool Mesh::intersect(const Ray &ray, HitPoint *hit) const if(nearest_vidx != -1) { hitvert = varr[nearest_vidx]; - nearest_hit.obj = &hitvert; + nearest_hit.data = &hitvert; } } else { @@ -961,17 +961,17 @@ bool Mesh::intersect(const Ray &ray, HitPoint *hit) const } } - if(nearest_hit.obj) { + if(nearest_hit.data) { 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; + hit->data = &hitface; } else if(Mesh::intersect_mode & ISECT_VERTICES) { - hit->obj = &hitvert; + hit->data = &hitvert; } else { - hit->obj = this; + hit->data = (void*)this; } } return true; @@ -1432,7 +1432,7 @@ bool Triangle::intersect(const Ray &ray, HitPoint *hit) const hit->dist = t; hit->pos = ray.origin + ray.dir * t; hit->normal = normal; - hit->obj = this; + hit->data = (void*)this; } return true; } diff --git a/src/object.cc b/src/object.cc new file mode 100644 index 0000000..d850d47 --- /dev/null +++ b/src/object.cc @@ -0,0 +1,37 @@ +#include "object.h" +#include "snode.h" + + +Object::Object() +{ + name = ""; + node = 0; +} + +ObjType Object::get_type() const +{ + return OBJ_NULL; +} + +void Object::set_name(const char *name) +{ + this->name = name; +} + +const char *Object::get_name() const +{ + return name.c_str(); +} + +bool Object::intersect(const Ray &ray, HitPoint *hit) const +{ + return false; +} + +void Object::update(float dt) +{ +} + +void Object::draw() const +{ +} diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..cc82d1b --- /dev/null +++ b/src/object.h @@ -0,0 +1,37 @@ +#ifndef OBJECT_H_ +#define OBJECT_H_ + +#include +#include +#include "geom.h" +#include "material.h" + +class Object; +class SceneNode; + +enum ObjType { OBJ_NULL, OBJ_MESH }; + +class Object { +private: + std::string name; + +public: + Material mtl; + //GeomObject *bvol; + SceneNode *node; + + Object(); + virtual ~Object() = default; + + virtual ObjType get_type() const; + + virtual void set_name(const char *name); + virtual const char *get_name() const; + + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; + + virtual void update(float dt = 0.0f); + virtual void draw() const; +}; + +#endif // OBJECT_H_ diff --git a/src/objmesh.cc b/src/objmesh.cc new file mode 100644 index 0000000..60fa7f9 --- /dev/null +++ b/src/objmesh.cc @@ -0,0 +1,32 @@ +#include "opengl.h" +#include "objmesh.h" +#include "snode.h" + +ObjMesh::ObjMesh() +{ + mesh = 0; +} + +ObjType ObjMesh::get_type() const +{ + return OBJ_MESH; +} + +void ObjMesh::draw() const +{ + if(!mesh) return; + + mtl.setup(); + + if(node) { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMultMatrixf(node->get_matrix()[0]); + } + + mesh->draw(); + + if(node) { + glPopMatrix(); + } +} diff --git a/src/objmesh.h b/src/objmesh.h new file mode 100644 index 0000000..811caf6 --- /dev/null +++ b/src/objmesh.h @@ -0,0 +1,18 @@ +#ifndef OBJMESH_H_ +#define OBJMESH_H_ + +#include "object.h" +#include "mesh.h" + +class ObjMesh : public Object { +public: + Mesh *mesh; + + ObjMesh(); + + ObjType get_type() const; + + void draw() const; +}; + +#endif // OBJMESH_H_ diff --git a/src/scene.cc b/src/scene.cc new file mode 100644 index 0000000..27be807 --- /dev/null +++ b/src/scene.cc @@ -0,0 +1,63 @@ +#include "scene.h" + +static void destroy_node_tree(SceneNode *n); + +Scene::Scene() +{ + nodes = 0; +} + +Scene::~Scene() +{ + destroy(); +} + +void Scene::destroy() +{ + destroy_node_tree(nodes); + nodes = 0; +} + +// Scene::load defined in sceneload.cc + +void Scene::update(float dt) +{ + if(nodes) { + nodes->update(dt); + } + + int nobj = objects.size(); + for(int i=0; inode) { + // only update objects which don't belong to a scenegraph node + // to avoid updating objects twice + objects[i]->update(dt); + } + } +} + +void Scene::draw() const +{ + if(!objects.empty()) { + int nobj = objects.size(); + for(int i=0; idraw(); + } + } else { + int nmesh = meshes.size(); + for(int i=0; idraw(); + } + } +} + +static void destroy_node_tree(SceneNode *n) +{ + if(!n) return; + + int nsub = n->get_num_children(); + for(int i=0; iget_child(i)); + } + delete n; +} diff --git a/src/scene.h b/src/scene.h new file mode 100644 index 0000000..7c30445 --- /dev/null +++ b/src/scene.h @@ -0,0 +1,28 @@ +#ifndef SCENE_H_ +#define SCENE_H_ + +#include +#include "mesh.h" +#include "snode.h" + +class Scene { +public: + std::vector meshes; + std::vector objects; + SceneNode *nodes; + + Scene(); + ~Scene(); + + Scene(const Scene &rhs) = delete; + Scene &operator =(const Scene &rhs) = delete; + + void destroy(); + + bool load(const char *fname); + + void update(float dt); + void draw() const; +}; + +#endif // SCENE_H_ diff --git a/src/sceneload.cc b/src/sceneload.cc new file mode 100644 index 0000000..b2b00eb --- /dev/null +++ b/src/sceneload.cc @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scene.h" +#include "objmesh.h" + +static bool load_material(Material *mat, const aiMaterial *aimat); +static SceneNode *load_node(const aiScene *aiscn, const aiNode *ainode); +static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh); + +/*static Vec3 assimp_vector(const aiVector3D &v); +static Quat assimp_quat(const aiQuaternion &q); +static Mat4 assimp_matrix(const aiMatrix4x4 &aim); +static long assimp_time(const aiAnimation *anim, double aitime); +static void print_hierarchy(const aiNode *node); +*/ + +static std::map node_by_name; +static std::map mesh_by_aimesh; + +bool Scene::load(const char *fname) +{ + unsigned int ppflags = aiProcess_CalcTangentSpace | + aiProcess_GenNormals | + aiProcess_JoinIdenticalVertices | + aiProcess_Triangulate | + aiProcess_SortByPType | + aiProcess_TransformUVCoords; + + const aiScene *aiscn = aiImportFile(fname, ppflags); + if(!aiscn) { + fprintf(stderr, "failed to load scene file: %s\n", fname); + return false; + } + + /* + Vec3 root_pos, root_scaling(1.0, 1.0, 1.0); + Quat root_rot; + + if(aiscn->mRootNode) { + Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation); + root_pos = root_matrix.get_translation(); + root_rot = root_matrix.get_rotation_quat(); + root_scaling = root_matrix.get_scaling(); + }*/ + + // load all meshes + for(unsigned int i=0; imNumMeshes; i++) { + aiMesh *aimesh = aiscn->mMeshes[i]; + Mesh *mesh; + + switch(aimesh->mPrimitiveTypes) { + case aiPrimitiveType_TRIANGLE: + if((mesh = load_mesh(aiscn, aimesh))) { + mesh_by_aimesh[aimesh] = mesh; + meshes.push_back(mesh); + } + break; + + default: + fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes); + break; + } + } + + SceneNode *root = new SceneNode; + + // load all the nodes recursively + for(unsigned int i=0; imRootNode->mNumChildren; i++) { + SceneNode *node = load_node(aiscn, aiscn->mRootNode->mChildren[i]); + if(node) { + root->add_child(node); + } + } + + int nnodes = root->get_num_children(); + if(nnodes <= 0) { + delete root; + } else if(nnodes == 1) { + nodes = root->get_child(0); + root->remove_child(nodes); + delete root; + } else { + nodes = root; + } + + node_by_name.clear(); + mesh_by_aimesh.clear(); + + aiReleaseImport(aiscn); + printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size()); + return true; +} + +static bool load_material(Material *mat, const aiMaterial *aimat) +{ + aiColor4D aicol; + float shin, shin_str; + + if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) { + mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]); + } + if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) { + mat->specular = Vec3(aicol[0], aicol[1], aicol[2]); + } + + unsigned int count = 1; + if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) { + shin_str = 1.0; + } + if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) { + // XXX can't remember how I came up with this... + mat->shininess = shin * shin_str * 0.0001 * 128.0; + } + + /* + // load textures + struct { int type; aiTextureType aitype; } textypes[] = { + {TEX_DIFFUSE, aiTextureType_DIFFUSE}, + {TEX_NORMAL, aiTextureType_NORMALS}, + {TEX_SPECULAR, aiTextureType_SPECULAR} + }; + + for(size_t i=0; itex[textypes[i].type] = texset.get(fname); + } + } + } + */ + + return true; +} + +static SceneNode *load_node(const aiScene *aiscn, const aiNode *ainode) +{ + SceneNode *node = new SceneNode; + node->set_name(ainode->mName.data); + + for(unsigned int i=0; imNumMeshes; i++) { + aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]]; + + Mesh *mesh = mesh_by_aimesh[aimesh]; + if(mesh) { + ObjMesh *obj = new ObjMesh; + obj->mesh = mesh; + // also grab the material of this mesh + load_material(&obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]); + + node->add_object(obj); + } + } + + /* recurse to all children */ + for(unsigned int i=0; imNumChildren; i++) { + SceneNode *child = load_node(aiscn, ainode->mChildren[i]); + if(child) { + node->add_child(child); + } + } + + node_by_name[node->get_name()] = node; + return node; +} + +static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh) +{ + Mesh *mesh = new Mesh; + + int num_verts = aimesh->mNumVertices; + int num_faces = aimesh->mNumFaces; + + mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices); + + if(aimesh->mNormals) { + mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals); + } + if(aimesh->mTangents) { + mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents); + } + if(aimesh->mTextureCoords[0]) { + mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]); + } + + unsigned int *iptr = mesh->set_index_data(num_faces * 3); + for(int i=0; imFaces[i].mIndices[j]; + } + } + + return mesh; +} + +#if 0 +static Vec3 assimp_vector(const aiVector3D &v) +{ + return Vec3(v[0], v[1], v[2]); +} + +static Quat assimp_quat(const aiQuaternion &q) +{ + return Quat(q.x, q.y, q.z, q.w); +} + +static Mat4 assimp_matrix(const aiMatrix4x4 &aim) +{ + Mat4 m; + memcpy(m[0], &aim, 16 * sizeof(float)); + m.transpose(); + return m; +} + +/* convert an assimp keyframe time (ticks) into milliseconds */ +static long assimp_time(const aiAnimation *anim, double aitime) +{ + double sec; + if(anim->mTicksPerSecond < 1e-6) { + // assume time is in frames? + sec = aitime / 30.0; + } else { + sec = aitime / anim->mTicksPerSecond; + } + return (long)(sec * 1000.0); +} + +static void print_hierarchy(const aiNode *node) +{ + static int lvl; + static int lvlopen[256]; + + for(int i=0; i= lvl - 1 ? '+' : '|'); + } else { + putchar(i >= lvl - 1 ? '+' : ' '); + } + } + printf("- \"%s\"\n", node->mName.data); + + lvlopen[lvl] = 1; + + lvl++; + for(unsigned int i=0; imNumChildren; i++) { + if(i == node->mNumChildren - 1) { + lvlopen[lvl - 1] = 0; + } + print_hierarchy(node->mChildren[i]); + } + lvl--; +} +#endif /* 0 */ diff --git a/src/sceneload.h b/src/sceneload.h new file mode 100644 index 0000000..2af093d --- /dev/null +++ b/src/sceneload.h @@ -0,0 +1,8 @@ +#ifndef SCENELOAD_H_ +#define SCENELOAD_H_ + +#include "scene.h" + +bool load_scene( + +#endif // SCENELOAD_H_ diff --git a/src/snode.cc b/src/snode.cc new file mode 100644 index 0000000..fac6c65 --- /dev/null +++ b/src/snode.cc @@ -0,0 +1,227 @@ +#include +#include +#include +#include "snode.h" + +SceneNode::SceneNode() + : scale(1, 1, 1) +{ + parent = 0; + name = 0; +} + +SceneNode::SceneNode(Object *obj) + : scale(1, 1, 1) +{ + parent = 0; + name = 0; + add_object(obj); +} + +SceneNode::~SceneNode() +{ + delete [] name; +} + +void SceneNode::set_name(const char *s) +{ + delete [] name; + name = new char[strlen(s) + 1]; + strcpy(name, s); +} + +const char *SceneNode::get_name() const +{ + return name; +} + +void SceneNode::add_child(SceneNode *node) +{ + if(node->parent) { + if(node->parent == this) { + return; + } + node->parent->remove_child(node); + } + + children.push_back(node); + node->parent = this; +} + +bool SceneNode::remove_child(SceneNode *node) +{ + auto it = std::find(children.begin(), children.end(), node); + if(it != children.end()) { + assert(node->parent == this); + node->parent = 0; + return true; + } + return false; +} + +int SceneNode::get_num_children() const +{ + return (int)children.size(); +} + +SceneNode *SceneNode::get_child(int idx) const +{ + return children[idx]; +} + +SceneNode *SceneNode::get_parent() const +{ + return parent; +} + +void SceneNode::add_object(Object *obj) +{ + if(obj->node == this) return; + + if(obj->node) { + obj->node->remove_object(obj); + } + + this->obj.push_back(obj); + obj->node = this; +} + +bool SceneNode::remove_object(Object *o) +{ + if(o->node != this) { + return false; + } + o->node = 0; + + auto it = std::find(obj.begin(), obj.end(), o); + if(it == obj.end()) { + return false; + } + obj.erase(it); + return true; +} + +int SceneNode::get_num_objects() const +{ + return (int)obj.size(); +} + +Object *SceneNode::get_object(int idx) const +{ + return obj[idx]; +} + +void SceneNode::set_position(const Vec3 &pos) +{ + this->pos = pos; +} + +void SceneNode::set_rotation(const Quat &rot) +{ + this->rot = rot; +} + +void SceneNode::set_scaling(const Vec3 &scale) +{ + this->scale = scale; +} + + +const Vec3 &SceneNode::get_node_position() const +{ + return pos; +} + +const Quat &SceneNode::get_node_rotation() const +{ + return rot; +} + +const Vec3 &SceneNode::get_node_scaling() const +{ + return scale; +} + + +Vec3 SceneNode::get_position() const +{ + return xform * Vec3(0, 0, 0); +} + +Quat SceneNode::get_rotation() const +{ + return rot; // TODO +} + +Vec3 SceneNode::get_scaling() const +{ + return scale; // TODO +} + +const Mat4 &SceneNode::get_matrix() const +{ + return xform; +} + +const Mat4 &SceneNode::get_inv_matrix() const +{ + return inv_xform; +} + + +void SceneNode::update_node(float dt) +{ + xform = Mat4::identity; + xform.pre_translate(pos); + xform.pre_rotate(rot); + xform.pre_scale(scale); + + if(parent) { + xform = parent->xform * xform; + } + inv_xform = inverse(xform); +} + +void SceneNode::update(float dt) +{ + update_node(dt); + + for(size_t i=0; iupdate(dt); + } +} + + +bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const +{ + Ray local_ray = inv_xform * ray; + + HitPoint nearest; + nearest.dist = FLT_MAX; + for(size_t i=0; iintersect(local_ray, hit)) { + if(!hit) return true; + if(hit->dist < nearest.dist) { + nearest = *hit; + nearest.data = (void*)this; + nearest.local_ray = local_ray; + } + } + } + + for(size_t i=0; iintersect(ray, hit)) { + if(!hit) return true; + if(hit->dist < nearest.dist) { + nearest = *hit; + } + } + } + + if(nearest.dist < FLT_MAX) { + *hit = nearest; + hit->ray = ray; + return true; + } + return false; +} diff --git a/src/snode.h b/src/snode.h new file mode 100644 index 0000000..21cf16d --- /dev/null +++ b/src/snode.h @@ -0,0 +1,67 @@ +#ifndef SNODE_H_ +#define SNODE_H_ + +#include +#include "object.h" +#include "gmath/gmath.h" + +class SceneNode { +private: + char *name; + + Vec3 pos; + Quat rot; + Vec3 scale; + + std::vector obj; + + SceneNode *parent; + std::vector children; + + Mat4 xform; + Mat4 inv_xform; + +public: + SceneNode(); + explicit SceneNode(Object *obj); + ~SceneNode(); + + void set_name(const char *s); + const char *get_name() const; + + void add_child(SceneNode *node); + bool remove_child(SceneNode *node); + + int get_num_children() const; + SceneNode *get_child(int idx) const; + + SceneNode *get_parent() const; + + void add_object(Object *obj); + bool remove_object(Object *obj); + + int get_num_objects() const; + Object *get_object(int idx) const; + + void set_position(const Vec3 &pos); + void set_rotation(const Quat &rot); + void set_scaling(const Vec3 &scale); + + const Vec3 &get_node_position() const; + const Quat &get_node_rotation() const; + const Vec3 &get_node_scaling() const; + + Vec3 get_position() const; + Quat get_rotation() const; + Vec3 get_scaling() const; + + const Mat4 &get_matrix() const; + const Mat4 &get_inv_matrix() const; + + void update_node(float dt = 0.0f); + void update(float dt = 0.0f); + + bool intersect(const Ray &ray, HitPoint *hit) const; +}; + +#endif // SNODE_H_ -- 1.7.10.4