]> git.tdb.fi Git - libs/gl.git/blob - tools/viewer.cpp
Fix event bindings
[libs/gl.git] / tools / viewer.cpp
1 #include <cmath>
2 #include <msp/core/application.h>
3 #include <msp/core/getopt.h>
4 #include <msp/fs/utils.h>
5 #include <msp/graphics/simplewindow.h>
6 #include <msp/gl/animatedobject.h>
7 #include <msp/gl/animation.h>
8 #include <msp/gl/animationplayer.h>
9 #include <msp/gl/blend.h>
10 #include <msp/gl/camera.h>
11 #include <msp/gl/framebuffer.h>
12 #include <msp/gl/light.h>
13 #include <msp/gl/lighting.h>
14 #include <msp/gl/mesh.h>
15 #include <msp/gl/object.h>
16 #include <msp/gl/tests.h>
17 #include <msp/input/mouse.h>
18 #include <msp/io/print.h>
19 #include <msp/time/timestamp.h>
20 #include <msp/time/utils.h>
21
22 using namespace std;
23 using namespace Msp;
24
25 class Viewer: public RegisteredApplication<Viewer>
26 {
27 private:
28         Graphics::SimpleGLWindow window;
29         Input::Mouse mouse;
30         GL::Object *object;
31         GL::Mesh *mesh;
32         GL::Animation *animation;
33         GL::AnimatedObject *anim_object;
34         GL::AnimationPlayer *anim_player;
35         GL::Light light;
36         GL::Lighting lighting;
37         GL::Camera camera;
38         float yaw;
39         float pitch;
40         float distance;
41         float light_yaw;
42         float light_pitch;
43         unsigned dragging;
44         Time::TimeStamp last_tick;
45
46 public:
47         Viewer(int, char **);
48         ~Viewer();
49
50         virtual int main();
51 private:
52         virtual void tick();
53
54         void button_press(unsigned);
55         void button_release(unsigned);
56         void axis_motion(unsigned, float, float);
57
58         void update_camera();
59         void update_light();
60 };
61
62
63 Viewer::Viewer(int argc, char **argv):
64         window(1024, 768, false),
65         mouse(window),
66         object(0),
67         mesh(0),
68         animation(0),
69         anim_object(0),
70         anim_player(0),
71         yaw(0),
72         pitch(0),
73         distance(10),
74         light_yaw(0),
75         light_pitch(0),
76         dragging(0)
77 {
78         if(argc<2)
79                 throw usage_error("Filename must be provided");
80
81         for(int i=1; i<argc; ++i)
82         {
83                 string fn = argv[i];
84                 string ext = FS::extpart(fn);
85
86                 if(ext==".mesh")
87                 {
88                         if(mesh || object)
89                                 throw usage_error("Only one mesh or object may be specified");
90
91                         mesh = new GL::Mesh;
92                         DataFile::load(*mesh, fn);
93                 }
94                 else if(ext==".object")
95                 {
96                         if(mesh || object)
97                                 throw usage_error("Only one mesh or object may be specified");
98
99                         object = new GL::Object;
100                         DataFile::load(*object, fn);
101                 }
102                 else if(ext==".anim")
103                 {
104                         if(!object)
105                                 throw usage_error("An object must be provided for animation");
106
107                         animation = new GL::Animation;
108                         DataFile::load(*animation, argv[2]);
109                         anim_object = new GL::AnimatedObject(*object);
110                         anim_player = new GL::AnimationPlayer;
111                         anim_player->play(*anim_object, *animation);
112                 }
113                 else
114                         throw usage_error("Don't know how to view this file");
115         }
116
117         window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0));
118         mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_press), false));
119         mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_release), false));
120         mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::axis_motion), false));
121
122         light.set_position(GL::Vector4(0, 0, 1, 0));
123         lighting.attach(0, light);
124
125         camera.set_up_direction(GL::Vector3(0, 0, 1));
126         update_camera();
127 }
128
129 Viewer::~Viewer()
130 {
131         delete object;
132         delete mesh;
133 }
134
135 int Viewer::main()
136 {
137         window.show();
138         return Application::main();
139 }
140
141 void Viewer::tick()
142 {
143         if(anim_player)
144         {
145                 Time::TimeStamp t = Time::now();
146                 Time::TimeDelta dt;
147                 if(last_tick)
148                         dt = t-last_tick;
149                 last_tick = t;
150
151                 anim_player->tick(dt);
152         }
153
154         window.tick();
155
156         GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
157
158         camera.apply();
159
160         GL::Bind bind_lighting(lighting);
161         GL::Bind bind_depth(GL::DepthTest::lequal());
162         GL::Bind bind_blend(GL::Blend::alpha());
163         if(anim_object)
164                 anim_object->render();
165         else if(object)
166                 object->render();
167         else if(mesh)
168                 mesh->draw();
169
170         window.swap_buffers();
171 }
172
173 void Viewer::button_press(unsigned btn)
174 {
175         if(btn==1)
176         {
177                 dragging = 1;
178         }
179         else if(btn==3)
180         {
181                 dragging = 3;
182                 axis_motion(0, 0, 0);
183         }
184         else if(btn==4)
185         {
186                 distance *= 0.9;
187                 update_camera();
188         }
189         else if(btn==5)
190         {
191                 distance *= 1.1;
192                 update_camera();
193         }
194 }
195
196 void Viewer::button_release(unsigned btn)
197 {
198         if(btn==dragging)
199                 dragging = 0;
200 }
201
202 void Viewer::axis_motion(unsigned axis, float, float delta)
203 {
204         if(dragging==1)
205         {
206                 float dx = (axis==0 ? delta : 0);
207                 float dy = (axis==1 ? delta : 0);
208
209                 yaw -= dx*M_PI*2;
210                 while(yaw>M_PI)
211                         yaw -= M_PI*2;
212                 while(yaw<-M_PI)
213                         yaw += M_PI*2;
214
215                 pitch += dy*M_PI;
216                 if(pitch>M_PI*0.49)
217                         pitch = M_PI*0.49;
218                 if(pitch<-M_PI*0.49)
219                         pitch = -M_PI*0.49;
220
221                 update_camera();
222         }
223         else if(dragging==3)
224         {
225                 float x = mouse.get_axis_value(0);
226                 float y = mouse.get_axis_value(1);
227
228                 light_yaw = yaw+x*M_PI;
229                 light_pitch = pitch-y*M_PI;
230
231                 update_light();
232         }
233 }
234
235 void Viewer::update_camera()
236 {
237         float cy = cos(yaw);
238         float sy = sin(yaw);
239         float cp = cos(pitch);
240         float sp = sin(pitch);
241         camera.set_position(GL::Vector3(-cy*cp*distance, -sy*cp*distance, -sp*distance));
242         camera.set_depth_clip(distance*0.02, distance*50);
243         camera.look_at(GL::Vector3(0, 0, 0));
244 }
245
246 void Viewer::update_light()
247 {
248         float cy = cos(light_yaw);
249         float sy = sin(light_yaw);
250         float cp = cos(light_pitch);
251         float sp = sin(light_pitch);
252         light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp, 0));
253 }