# HG changeset patch # User John Tsiombikas # Date 1405576277 -10800 # Node ID 3d3656360a821430030cdf594f23bafb58e0661c # Parent f9274bebe55e3f8d35a5730fe01e2a8080cc2fb4 rendering properly, added picking, almost done... diff -r f9274bebe55e -r 3d3656360a82 Makefile --- a/Makefile Thu Jul 17 02:35:19 2014 +0300 +++ b/Makefile Thu Jul 17 08:51:17 2014 +0300 @@ -5,7 +5,7 @@ CFLAGS = -pedantic -Wall -g CXXFLAGS = $(CFLAGS) -LDFLAGS = -lGL -lGLU -lglut -lGLEW -lX11 -lm -lpthread +LDFLAGS = -lGL -lGLU -lGLEW -lX11 -lm -lpthread $(bin): $(obj) $(CXX) -o $@ $(obj) $(LDFLAGS) diff -r f9274bebe55e -r 3d3656360a82 data/device.obj --- a/data/device.obj Thu Jul 17 02:35:19 2014 +0300 +++ b/data/device.obj Thu Jul 17 08:51:17 2014 +0300 @@ -1,7 +1,7 @@ # 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware # File Created: 14.07.2014 08:46:21 -mtllib device.mtl +mtllib data/device.mtl # # object box diff -r f9274bebe55e -r 3d3656360a82 src/bvol.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bvol.cc Thu Jul 17 08:51:17 2014 +0300 @@ -0,0 +1,62 @@ +#include +#include "bvol.h" + +BSphere::BSphere() +{ + radius = 1.0f; +} + +BSphere::BSphere(const Vector3 &c, float rad) + : center(c) +{ + radius = rad; +} + +void BSphere::set_center(const Vector3 ¢er) +{ + this->center = center; +} + +const Vector3 &BSphere::get_center() const +{ + return center; +} + +void BSphere::set_radius(float rad) +{ + radius = rad; +} + +float BSphere::get_radius() const +{ + return radius; +} + +bool BSphere::intersect(const Ray &ray, HitPoint *hit) const +{ + float a = dot(ray.dir, ray.dir); + float b = 2.0 * dot(ray.dir, ray.origin - center); + float c = dot(ray.origin, ray.origin) + dot(center, center) - + 2.0 * dot(ray.origin, center) - radius * radius; + + float disc = b * b - 4.0f * a * c; + if(disc < 1e-6) { + return false; + } + + float sqrt_disc = sqrt(disc); + float x1 = (-b + sqrt_disc) / (2.0f * a); + float x2 = (-b - sqrt_disc) / (2.0f * a); + + if(x1 < 1e-6) x1 = x2; + if(x2 < 1e-6) x2 = x1; + + float t = x1 < x2 ? x1 : x2; + if(t < 1e-6) { + return false; + } + + hit->t = t; + hit->pos = ray.origin + ray.dir * t; + return true; +} diff -r f9274bebe55e -r 3d3656360a82 src/bvol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bvol.h Thu Jul 17 08:51:17 2014 +0300 @@ -0,0 +1,36 @@ +#ifndef BVOL_H_ +#define BVOL_H_ + +#include "vmath.h" + +struct HitPoint { + float t; + Vector3 pos; +}; + +class BVolume { +public: + virtual ~BVolume() {} + + virtual bool intersect(const Ray &ray, HitPoint *hit) const = 0; +}; + +class BSphere : public BVolume { +private: + Vector3 center; + float radius; + +public: + BSphere(); + explicit BSphere(const Vector3 &c, float rad = 1.0); + + void set_center(const Vector3 ¢er); + const Vector3 &get_center() const; + + void set_radius(float rad); + float get_radius() const; + + bool intersect(const Ray &ray, HitPoint *hit) const; +}; + +#endif // BVOL_H_ diff -r f9274bebe55e -r 3d3656360a82 src/main.cc --- a/src/main.cc Thu Jul 17 02:35:19 2014 +0300 +++ b/src/main.cc Thu Jul 17 08:51:17 2014 +0300 @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,6 +9,7 @@ #include #include #include "dev.h" +#include "scene.h" static bool init(); static void cleanup(); @@ -15,6 +17,7 @@ static void keyb(int key, bool pressed); static void mouse(int bn, bool pressed, int x, int y); static void motion(int x, int y); +static Ray calc_pick_ray(int x, int y); static Window create_window(const char *title, int xsz, int ysz); static void process_events(); @@ -29,12 +32,19 @@ static int win_width, win_height; -static bool redisplay_pending; +static bool draw_pending; static bool win_mapped; static int fakefd = -1; static char *fake_devpath; +static float cam_theta, cam_phi, cam_dist = 140; +static Scene *scn; + +enum { BN_TICKET, BN_NEXT, NUM_BUTTONS }; +const char *button_names[] = { "button1", "button2" }; +static Object *button_obj[NUM_BUTTONS]; + int main(int argc, char **argv) { if(proc_args(argc, argv) == -1) { @@ -47,6 +57,9 @@ int xfd = ConnectionNumber(dpy); + // run once through pending events before going into the select loop + process_events(); + for(;;) { fd_set rd; FD_ZERO(&rd); @@ -54,9 +67,9 @@ FD_SET(xfd, &rd); FD_SET(fakefd, &rd); + struct timeval noblock = {0, 0}; int maxfd = xfd > fakefd ? xfd : fakefd; - - while(select(maxfd + 1, &rd, 0, 0, 0) == -1 && errno == EINTR); + while(select(maxfd + 1, &rd, 0, 0, draw_pending ? &noblock : 0) == -1 && errno == EINTR); if(FD_ISSET(xfd, &rd)) { process_events(); @@ -65,9 +78,9 @@ proc_dev_input(); } - if(redisplay_pending) { + if(draw_pending) { display(); - redisplay_pending = false; + draw_pending = false; } } return 0; @@ -86,15 +99,42 @@ return false; } - if(!(win = create_window("dummy equeue device", 800, 600))) { + if(!(win = create_window("equeue device emulator", 800, 600))) { return false; } + glewInit(); + + scn = new Scene; + if(!scn->load("data/device.obj")) { + fprintf(stderr, "failed to load device 3D model\n"); + return false; + } + + for(int i=0; iget_object(button_names[i]); + if(!button_obj[i]) { + fprintf(stderr, "invalid 3D model\n"); + return false; + } + BSphere &bs = button_obj[i]->get_mesh()->get_bounds(); + bs.set_radius(bs.get_radius() * 1.5); + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + glClearColor(0.1, 0.1, 0.1, 1); + return true; } static void cleanup() { + delete scn; + stop_dev(); if(!dpy) return; @@ -111,6 +151,14 @@ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + glTranslatef(0, 0, -cam_dist); + glRotatef(cam_phi, 1, 0, 0); + glRotatef(cam_theta, 0, 1, 0); + + float lpos[] = {-7, 5, 10, 0}; + glLightfv(GL_LIGHT0, GL_POSITION, lpos); + + scn->render(); glXSwapBuffers(dpy, win); assert(glGetError() == GL_NO_ERROR); @@ -122,7 +170,10 @@ glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); + gluPerspective(50.0, (float)x / (float)y, 1.0, 1000.0); + + win_width = x; + win_height = y; } static void keyb(int key, bool pressed) @@ -135,12 +186,87 @@ } } +static bool bnstate[32]; +static int prev_x, prev_y; + static void mouse(int bn, bool pressed, int x, int y) { + bnstate[bn] = pressed; + prev_x = x; + prev_y = y; + + if(bn == 0 && pressed) { + // do picking + Ray ray = calc_pick_ray(x, win_height - y); + + HitPoint minhit; + minhit.t = FLT_MAX; + int hit_found = -1; + + for(int i=0; iget_mesh()->get_bounds().intersect(ray, &hit) && hit.t < minhit.t) { + minhit = hit; + hit_found = i; + } + } + + if(hit_found != -1) { + switch(hit_found) { + case BN_TICKET: + issue_ticket(); + printf("issue ticket\n"); + break; + + case BN_NEXT: + next_customer(); + printf("next customer\n"); + break; + } + draw_pending = true; + } + } } static void motion(int x, int y) { + int dx = x - prev_x; + int dy = y - prev_y; + prev_x = x; + prev_y = y; + + 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; + draw_pending = true; + } + if(bnstate[2]) { + cam_dist += dy * 0.5; + if(cam_dist < 0.0) cam_dist = 0.0; + draw_pending = true; + } +} + +static Ray calc_pick_ray(int x, int y) +{ + double mv[16], proj[16]; + int vp[4]; + double resx, resy, resz; + Ray ray; + + glGetDoublev(GL_MODELVIEW_MATRIX, mv); + glGetDoublev(GL_PROJECTION_MATRIX, proj); + glGetIntegerv(GL_VIEWPORT, vp); + + gluUnProject(x, y, 0, mv, proj, vp, &resx, &resy, &resz); + ray.origin = Vector3(resx, resy, resz); + + gluUnProject(x, y, 1, mv, proj, vp, &resx, &resy, &resz); + ray.dir = normalize(Vector3(resx, resy, resz) - ray.origin); + + return ray; } static Window create_window(const char *title, int xsz, int ysz) @@ -231,7 +357,7 @@ case Expose: if(win_mapped && ev.xexpose.count == 0) { - redisplay_pending = 1; + draw_pending = 1; } break; diff -r f9274bebe55e -r 3d3656360a82 src/material.cc --- a/src/material.cc Thu Jul 17 02:35:19 2014 +0300 +++ b/src/material.cc Thu Jul 17 08:51:17 2014 +0300 @@ -2,7 +2,7 @@ #include "material.h" Material::Material() - : color(1, 1, 1), specular(0, 0, 0) + : diffuse(1, 1, 1), specular(0, 0, 0) { shininess = 1.0; alpha = 1.0; @@ -10,7 +10,7 @@ void Material::setup() const { - float col[] = {color.x, color.y, color.z, alpha}; + float col[] = {diffuse.x, diffuse.y, diffuse.z, alpha}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); float spec[] = {specular.x, specular.y, specular.z, 1.0}; diff -r f9274bebe55e -r 3d3656360a82 src/mesh.cc --- a/src/mesh.cc Thu Jul 17 02:35:19 2014 +0300 +++ b/src/mesh.cc Thu Jul 17 08:51:17 2014 +0300 @@ -1,5 +1,6 @@ #include #include +#include #include #include "mesh.h" @@ -8,8 +9,9 @@ Mesh::Mesh() { buf_valid = ALL_VALID; + bsph_valid = false; - for(int i=0; i max_lensq) { + max_lensq = lensq; + } + } + + bsph.set_center(center); + bsph.set_radius(sqrt(max_lensq)); + + bsph_valid = true; +} diff -r f9274bebe55e -r 3d3656360a82 src/mesh.h --- a/src/mesh.h Thu Jul 17 02:35:19 2014 +0300 +++ b/src/mesh.h Thu Jul 17 08:51:17 2014 +0300 @@ -1,6 +1,8 @@ #ifndef MESH_H_ #define MESH_H_ +#include "bvol.h" + enum { MESH_ATTR_VERTEX, MESH_ATTR_NORMAL, @@ -19,6 +21,10 @@ mutable unsigned int buf_valid; /* bitmask */ void update_buffers() const; + mutable BSphere bsph; + mutable bool bsph_valid; + void calc_bsph() const; + public: Mesh(); ~Mesh(); @@ -28,6 +34,9 @@ const float *get_attrib(int aidx) const; void draw() const; + + BSphere &get_bounds(); + const BSphere &get_bounds() const; }; #endif // MESH_H_ diff -r f9274bebe55e -r 3d3656360a82 src/object.cc --- a/src/object.cc Thu Jul 17 02:35:19 2014 +0300 +++ b/src/object.cc Thu Jul 17 08:51:17 2014 +0300 @@ -5,6 +5,16 @@ mesh = 0; } +void Object::set_name(const char *name) +{ + this->name = std::string(name); +} + +const char *Object::get_name() const +{ + return name.c_str(); +} + void Object::set_mesh(Mesh *mesh) { this->mesh = mesh; diff -r f9274bebe55e -r 3d3656360a82 src/object.h --- a/src/object.h Thu Jul 17 02:35:19 2014 +0300 +++ b/src/object.h Thu Jul 17 08:51:17 2014 +0300 @@ -1,11 +1,13 @@ #ifndef OBJECT_H_ #define OBJECT_H_ +#include #include "mesh.h" #include "material.h" class Object { private: + std::string name; Mesh *mesh; public: @@ -13,6 +15,9 @@ Object(); + void set_name(const char *name); + const char *get_name() const; + void set_mesh(Mesh *mesh); Mesh *get_mesh() const; diff -r f9274bebe55e -r 3d3656360a82 src/objfile.cc --- a/src/objfile.cc Thu Jul 17 02:35:19 2014 +0300 +++ b/src/objfile.cc Thu Jul 17 08:51:17 2014 +0300 @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -284,6 +285,9 @@ int nelem = obj->f.size() * 3; + assert(sizeof(Vector3) == 3 * sizeof(float)); + assert(sizeof(Vector2) == 2 * sizeof(float)); + try { robj = new Object; varr = new Vector3[nelem]; @@ -293,15 +297,15 @@ catch(...) { return 0; } - /*if(obj->cur_obj.length() > 0) { + if(obj->cur_obj.length() > 0) { robj->set_name(obj->cur_obj.c_str()); - }*/ + } // need at least one of each element bool added_norm = false, added_tc = false; if(obj->vn.empty()) { obj->vn.push_back(Vector3(0, 0, 0)); - added_norm = true;; + added_norm = true; } if(obj->vt.empty()) { obj->vt.push_back(Vector2(0, 0)); @@ -329,10 +333,13 @@ obj->vt.pop_back(); } - Mesh *mesh = robj->get_mesh(); + Mesh *mesh = new Mesh; mesh->set_attrib(MESH_ATTR_VERTEX, nelem, 3, &varr->x); mesh->set_attrib(MESH_ATTR_NORMAL, nelem, 3, &narr->x); mesh->set_attrib(MESH_ATTR_TEXCOORD, nelem, 2, &tarr->x); + robj->set_mesh(mesh); + + printf("loaded object %s: %d faces\n", obj->cur_obj.c_str(), nelem / 3); delete [] varr; delete [] narr; diff -r f9274bebe55e -r 3d3656360a82 src/scene.cc --- a/src/scene.cc Thu Jul 17 02:35:19 2014 +0300 +++ b/src/scene.cc Thu Jul 17 08:51:17 2014 +0300 @@ -1,5 +1,6 @@ #include #include +#include #include "scene.h" Scene::~Scene() @@ -50,6 +51,16 @@ return objects[idx]; } +Object *Scene::get_object(const char *name) const +{ + for(size_t i=0; iget_name(), name) == 0) { + return objects[i]; + } + } + return 0; +} + Mesh *Scene::get_mesh(int idx) const { return meshes[idx]; diff -r f9274bebe55e -r 3d3656360a82 src/scene.h --- a/src/scene.h Thu Jul 17 02:35:19 2014 +0300 +++ b/src/scene.h Thu Jul 17 08:51:17 2014 +0300 @@ -27,6 +27,8 @@ Object *get_object(int idx) const; Mesh *get_mesh(int idx) const; + Object *get_object(const char *name) const; + void update(long msec); void render() const; }; diff -r f9274bebe55e -r 3d3656360a82 src/vmath.h --- a/src/vmath.h Thu Jul 17 02:35:19 2014 +0300 +++ b/src/vmath.h Thu Jul 17 08:51:17 2014 +0300 @@ -1,6 +1,8 @@ #ifndef VMATH_H_ #define VMATH_H_ +#include + class Vector2 { public: float x, y; @@ -23,6 +25,40 @@ const float &operator [](int idx) const { return (&x)[idx]; } }; +inline Vector3 operator +(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x + b.x, a.y + b.y, a.z + b.z); +} + +inline Vector3 operator -(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +inline Vector3 operator *(const Vector3 &a, float s) +{ + return Vector3(a.x * s, a.y * s, a.z * s); +} + +inline float dot(const Vector3 &a, const Vector3 &b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +inline float length(const Vector3 &v) +{ + return sqrt(dot(v, v)); +} + +inline Vector3 normalize(const Vector3 &v) +{ + float len = length(v); + if(len == 0.0) { + return v; + } + return Vector3(v.x / len, v.y / len, v.z / len); +} + class Vector4 { public: float x, y, z, w; @@ -34,4 +70,12 @@ const float &operator [](int idx) const { return (&x)[idx]; } }; +class Ray { +public: + Vector3 origin, dir; + + Ray() : origin(0, 0, 0), dir(0, 0, 1) {} + Ray(const Vector3 &o, const Vector3 &d) : origin(o), dir(d) {} +}; + #endif // VMATH_H_