]> git.tdb.fi Git - libs/gl.git/blob - viewer.cpp
Add a simple object/mesh viewer application
[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
48         virtual int main();
49 private:
50         virtual void tick();
51
52         void button_press(int, int, unsigned, unsigned);
53         void button_release(int, int, unsigned, unsigned);
54         void pointer_motion(int, int);
55         void key_press(unsigned, unsigned, wchar_t);
56
57         void update_camera();
58         void update_light();
59
60 public:
61         static void usage(const char *, const char *, bool);
62 };
63
64
65 Application::RegApp<Viewer> Viewer::reg;
66
67 Viewer::Viewer(int argc, char **argv):
68         window(1024, 768, false),
69         object(0),
70         mesh(0),
71         yaw(0),
72         pitch(0),
73         distance(10),
74         light_yaw(0),
75         light_pitch(0),
76         dragging(0),
77         pointer_x(0),
78         pointer_y(0)
79 {
80         if(argc<2)
81                 throw UsageError("Filename must be provided");
82
83         string fn = argv[1];
84         string ext = FS::extpart(fn);
85
86         if(ext==".mesh")
87         {
88                 mesh = new GL::Mesh;
89                 DataFile::load(*mesh, fn);
90         }
91         else if(ext==".object")
92         {
93                 object = new GL::Object;
94                 DataFile::load(*object, fn);
95         }
96         else
97                 throw UsageError("Don't know how to view this file");
98
99         window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0));
100         window.signal_button_press.connect(sigc::mem_fun(this, &Viewer::button_press));
101         window.signal_button_release.connect(sigc::mem_fun(this, &Viewer::button_release));
102         window.signal_pointer_motion.connect(sigc::mem_fun(this, &Viewer::pointer_motion));
103         window.signal_key_press.connect(sigc::mem_fun(this, &Viewer::key_press));
104
105         light.set_position(GL::Vector4(0, 0, 1, 0));
106         lighting.attach(0, light);
107
108         camera.set_up_direction(GL::Vector3(0, 0, 1));
109         camera.set_position(GL::Vector3(distance, 0, 0));
110         camera.look_at(GL::Vector3(0, 0, 0));
111 }
112
113 int Viewer::main()
114 {
115         window.show();
116         return Application::main();
117 }
118
119 void Viewer::tick()
120 {
121         window.get_display().tick();
122
123         GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
124
125         camera.apply();
126
127         GL::Bind bind_lighting(lighting);
128         GL::Bind bind_depth(GL::DepthTest::lequal());
129         GL::Bind bind_blend(GL::Blend::alpha());
130         if(object)
131                 object->render();
132         else if(mesh)
133                 mesh->draw();
134
135         window.swap_buffers();
136 }
137
138 void Viewer::usage(const char *err, const char *argv0, bool)
139 {
140         if(err)
141                 IO::print("%s\n", err);
142         IO::print("Usage: %s <filename>\n", argv0);
143 }
144
145 void Viewer::button_press(int x, int y, unsigned btn, unsigned)
146 {
147         if(btn==1)
148         {
149                 dragging = 1;
150                 pointer_x = x;
151                 pointer_y = y;
152         }
153         else if(btn==3)
154         {
155                 dragging = 3;
156                 pointer_motion(x, y);
157         }
158         else if(btn==4)
159         {
160                 distance *= 0.9;
161                 update_camera();
162         }
163         else if(btn==5)
164         {
165                 distance *= 1.1;
166                 update_camera();
167         }
168 }
169
170 void Viewer::button_release(int, int, unsigned btn, unsigned)
171 {
172         if(btn==dragging)
173                 dragging = 0;
174 }
175
176 void Viewer::pointer_motion(int x, int y)
177 {
178         if(dragging==1)
179         {
180                 int dx = x-pointer_x;
181                 int dy = pointer_y-y;
182
183                 yaw -= dx*M_PI*2/window.get_width();
184                 while(yaw>M_PI)
185                         yaw -= M_PI*2;
186                 while(yaw<-M_PI)
187                         yaw += M_PI*2;
188
189                 pitch += dy*M_PI/window.get_height();
190                 if(pitch>M_PI*0.49)
191                         pitch = M_PI*0.49;
192                 if(pitch<-M_PI*0.49)
193                         pitch = -M_PI*0.49;
194
195                 update_camera();
196
197                 pointer_x = x;
198                 pointer_y = y;
199         }
200         else if(dragging==3)
201         {
202                 int dx = x-window.get_width()/2;
203                 int dy = window.get_height()/2-y;
204
205                 light_yaw = yaw+dx*M_PI/window.get_width();
206                 light_pitch = pitch-dy*M_PI/window.get_height();
207
208                 update_light();
209         }
210 }
211
212 void Viewer::key_press(unsigned, unsigned, wchar_t)
213 {
214 }
215
216 void Viewer::update_camera()
217 {
218         float cy = cos(yaw);
219         float sy = sin(yaw);
220         float cp = cos(pitch);
221         float sp = sin(pitch);
222         camera.set_position(GL::Vector3(-cy*cp*distance, -sy*cp*distance, -sp*distance));
223         camera.look_at(GL::Vector3(0, 0, 0));
224 }
225
226 void Viewer::update_light()
227 {
228         float cy = cos(light_yaw);
229         float sy = sin(light_yaw);
230         float cp = cos(light_pitch);
231         float sp = sin(light_pitch);
232         light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp));
233 }