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