]> git.tdb.fi Git - libs/gl.git/blob - viewer.cpp
d89b34bd3472a210d4167e9e75c477154e3f1259
[libs/gl.git] / viewer.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <cmath>
9 #include <msp/core/application.h>
10 #include <msp/fs/utils.h>
11 #include <msp/gbase/simplewindow.h>
12 #include <msp/gl/blend.h>
13 #include <msp/gl/camera.h>
14 #include <msp/gl/framebuffer.h>
15 #include <msp/gl/light.h>
16 #include <msp/gl/lighting.h>
17 #include <msp/gl/mesh.h>
18 #include <msp/gl/object.h>
19 #include <msp/gl/tests.h>
20 #include <msp/io/print.h>
21
22 using namespace std;
23 using namespace Msp;
24
25 class Viewer: public Application
26 {
27 private:
28         Graphics::SimpleGLWindow window;
29         GL::Object *object;
30         GL::Mesh *mesh;
31         GL::Light light;
32         GL::Lighting lighting;
33         GL::Camera camera;
34         float yaw;
35         float pitch;
36         float distance;
37         float light_yaw;
38         float light_pitch;
39         unsigned dragging;
40         int pointer_x;
41         int pointer_y;
42
43         static Application::RegApp<Viewer> reg;
44
45 public:
46         Viewer(int, char **);
47         ~Viewer();
48
49         virtual int main();
50 private:
51         virtual void tick();
52
53         void button_press(int, int, unsigned, unsigned);
54         void button_release(int, int, unsigned, unsigned);
55         void pointer_motion(int, int);
56         void key_press(unsigned, unsigned, wchar_t);
57
58         void update_camera();
59         void update_light();
60
61 public:
62         static void usage(const char *, const char *, bool);
63 };
64
65
66 Application::RegApp<Viewer> Viewer::reg;
67
68 Viewer::Viewer(int argc, char **argv):
69         window(1024, 768, false),
70         object(0),
71         mesh(0),
72         yaw(0),
73         pitch(0),
74         distance(10),
75         light_yaw(0),
76         light_pitch(0),
77         dragging(0),
78         pointer_x(0),
79         pointer_y(0)
80 {
81         if(argc<2)
82                 throw UsageError("Filename must be provided");
83
84         string fn = argv[1];
85         string ext = FS::extpart(fn);
86
87         if(ext==".mesh")
88         {
89                 mesh = new GL::Mesh;
90                 DataFile::load(*mesh, fn);
91         }
92         else if(ext==".object")
93         {
94                 object = new GL::Object;
95                 DataFile::load(*object, fn);
96         }
97         else
98                 throw UsageError("Don't know how to view this file");
99
100         window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0));
101         window.signal_button_press.connect(sigc::mem_fun(this, &Viewer::button_press));
102         window.signal_button_release.connect(sigc::mem_fun(this, &Viewer::button_release));
103         window.signal_pointer_motion.connect(sigc::mem_fun(this, &Viewer::pointer_motion));
104         window.signal_key_press.connect(sigc::mem_fun(this, &Viewer::key_press));
105
106         light.set_position(GL::Vector4(0, 0, 1, 0));
107         lighting.attach(0, light);
108
109         camera.set_up_direction(GL::Vector3(0, 0, 1));
110         update_camera();
111 }
112
113 Viewer::~Viewer()
114 {
115         delete object;
116         delete mesh;
117 }
118
119 int Viewer::main()
120 {
121         window.show();
122         return Application::main();
123 }
124
125 void Viewer::tick()
126 {
127         window.tick();
128
129         GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
130
131         camera.apply();
132
133         GL::Bind bind_lighting(lighting);
134         GL::Bind bind_depth(GL::DepthTest::lequal());
135         GL::Bind bind_blend(GL::Blend::alpha());
136         if(object)
137                 object->render();
138         else if(mesh)
139                 mesh->draw();
140
141         window.swap_buffers();
142 }
143
144 void Viewer::usage(const char *err, const char *argv0, bool)
145 {
146         if(err)
147                 IO::print("%s\n", err);
148         IO::print("Usage: %s <filename>\n", argv0);
149 }
150
151 void Viewer::button_press(int x, int y, unsigned btn, unsigned)
152 {
153         if(btn==1)
154         {
155                 dragging = 1;
156                 pointer_x = x;
157                 pointer_y = y;
158         }
159         else if(btn==3)
160         {
161                 dragging = 3;
162                 pointer_motion(x, y);
163         }
164         else if(btn==4)
165         {
166                 distance *= 0.9;
167                 update_camera();
168         }
169         else if(btn==5)
170         {
171                 distance *= 1.1;
172                 update_camera();
173         }
174 }
175
176 void Viewer::button_release(int, int, unsigned btn, unsigned)
177 {
178         if(btn==dragging)
179                 dragging = 0;
180 }
181
182 void Viewer::pointer_motion(int x, int y)
183 {
184         if(dragging==1)
185         {
186                 int dx = x-pointer_x;
187                 int dy = pointer_y-y;
188
189                 yaw -= dx*M_PI*2/window.get_width();
190                 while(yaw>M_PI)
191                         yaw -= M_PI*2;
192                 while(yaw<-M_PI)
193                         yaw += M_PI*2;
194
195                 pitch += dy*M_PI/window.get_height();
196                 if(pitch>M_PI*0.49)
197                         pitch = M_PI*0.49;
198                 if(pitch<-M_PI*0.49)
199                         pitch = -M_PI*0.49;
200
201                 update_camera();
202
203                 pointer_x = x;
204                 pointer_y = y;
205         }
206         else if(dragging==3)
207         {
208                 int dx = x-window.get_width()/2;
209                 int dy = window.get_height()/2-y;
210
211                 light_yaw = yaw+dx*M_PI/window.get_width();
212                 light_pitch = pitch-dy*M_PI/window.get_height();
213
214                 update_light();
215         }
216 }
217
218 void Viewer::key_press(unsigned, unsigned, wchar_t)
219 {
220 }
221
222 void Viewer::update_camera()
223 {
224         float cy = cos(yaw);
225         float sy = sin(yaw);
226         float cp = cos(pitch);
227         float sp = sin(pitch);
228         camera.set_position(GL::Vector3(-cy*cp*distance, -sy*cp*distance, -sp*distance));
229         camera.set_depth_clip(distance*0.02, distance*50);
230         camera.look_at(GL::Vector3(0, 0, 0));
231 }
232
233 void Viewer::update_light()
234 {
235         float cy = cos(light_yaw);
236         float sy = sin(light_yaw);
237         float cp = cos(light_pitch);
238         float sp = sin(light_pitch);
239         light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp, 0));
240 }