/* $Id$ This file is part of libmspgl Copyright © 2010 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace Msp; class Viewer: public Application { private: Graphics::SimpleGLWindow window; GL::Object *object; GL::Mesh *mesh; GL::Light light; GL::Lighting lighting; GL::Camera camera; float yaw; float pitch; float distance; float light_yaw; float light_pitch; unsigned dragging; int pointer_x; int pointer_y; static Application::RegApp reg; public: Viewer(int, char **); ~Viewer(); virtual int main(); private: virtual void tick(); void button_press(int, int, unsigned, unsigned); void button_release(int, int, unsigned, unsigned); void pointer_motion(int, int); void key_press(unsigned, unsigned, wchar_t); void update_camera(); void update_light(); public: static void usage(const char *, const char *, bool); }; Application::RegApp Viewer::reg; Viewer::Viewer(int argc, char **argv): window(1024, 768, false), object(0), mesh(0), yaw(0), pitch(0), distance(10), light_yaw(0), light_pitch(0), dragging(0), pointer_x(0), pointer_y(0) { if(argc<2) throw UsageError("Filename must be provided"); string fn = argv[1]; string ext = FS::extpart(fn); if(ext==".mesh") { mesh = new GL::Mesh; DataFile::load(*mesh, fn); } else if(ext==".object") { object = new GL::Object; DataFile::load(*object, fn); } else throw UsageError("Don't know how to view this file"); window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0)); window.signal_button_press.connect(sigc::mem_fun(this, &Viewer::button_press)); window.signal_button_release.connect(sigc::mem_fun(this, &Viewer::button_release)); window.signal_pointer_motion.connect(sigc::mem_fun(this, &Viewer::pointer_motion)); window.signal_key_press.connect(sigc::mem_fun(this, &Viewer::key_press)); light.set_position(GL::Vector4(0, 0, 1, 0)); lighting.attach(0, light); camera.set_up_direction(GL::Vector3(0, 0, 1)); update_camera(); } Viewer::~Viewer() { delete object; delete mesh; } int Viewer::main() { window.show(); return Application::main(); } void Viewer::tick() { window.tick(); GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT); camera.apply(); GL::Bind bind_lighting(lighting); GL::Bind bind_depth(GL::DepthTest::lequal()); GL::Bind bind_blend(GL::Blend::alpha()); if(object) object->render(); else if(mesh) mesh->draw(); window.swap_buffers(); } void Viewer::usage(const char *err, const char *argv0, bool) { if(err) IO::print("%s\n", err); IO::print("Usage: %s \n", argv0); } void Viewer::button_press(int x, int y, unsigned btn, unsigned) { if(btn==1) { dragging = 1; pointer_x = x; pointer_y = y; } else if(btn==3) { dragging = 3; pointer_motion(x, y); } else if(btn==4) { distance *= 0.9; update_camera(); } else if(btn==5) { distance *= 1.1; update_camera(); } } void Viewer::button_release(int, int, unsigned btn, unsigned) { if(btn==dragging) dragging = 0; } void Viewer::pointer_motion(int x, int y) { if(dragging==1) { int dx = x-pointer_x; int dy = pointer_y-y; yaw -= dx*M_PI*2/window.get_width(); while(yaw>M_PI) yaw -= M_PI*2; while(yaw<-M_PI) yaw += M_PI*2; pitch += dy*M_PI/window.get_height(); if(pitch>M_PI*0.49) pitch = M_PI*0.49; if(pitch<-M_PI*0.49) pitch = -M_PI*0.49; update_camera(); pointer_x = x; pointer_y = y; } else if(dragging==3) { int dx = x-window.get_width()/2; int dy = window.get_height()/2-y; light_yaw = yaw+dx*M_PI/window.get_width(); light_pitch = pitch-dy*M_PI/window.get_height(); update_light(); } } void Viewer::key_press(unsigned, unsigned, wchar_t) { } void Viewer::update_camera() { float cy = cos(yaw); float sy = sin(yaw); float cp = cos(pitch); float sp = sin(pitch); camera.set_position(GL::Vector3(-cy*cp*distance, -sy*cp*distance, -sp*distance)); camera.set_depth_clip(distance*0.02, distance*50); camera.look_at(GL::Vector3(0, 0, 0)); } void Viewer::update_light() { float cy = cos(light_yaw); float sy = sin(light_yaw); float cp = cos(light_pitch); float sp = sin(light_pitch); light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp, 0)); }