]> git.tdb.fi Git - libs/gl.git/blob - tools/viewer.cpp
Make builtins const
[libs/gl.git] / tools / viewer.cpp
1 #include <cmath>
2 #include <msp/core/application.h>
3 #include <msp/core/getopt.h>
4 #include <msp/datafile/directorysource.h>
5 #include <msp/datafile/packsource.h>
6 #include <msp/fs/stat.h>
7 #include <msp/fs/utils.h>
8 #include <msp/graphics/simplewindow.h>
9 #include <msp/gl/animatedobject.h>
10 #include <msp/gl/animation.h>
11 #include <msp/gl/animationplayer.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/pipeline.h>
20 #include <msp/gl/renderer.h>
21 #include <msp/gl/resources.h>
22 #include <msp/gl/simplescene.h>
23 #include <msp/gl/technique.h>
24 #include <msp/gl/tests.h>
25 #include <msp/gl/windowview.h>
26 #include <msp/input/mouse.h>
27 #include <msp/io/print.h>
28 #include <msp/time/timestamp.h>
29 #include <msp/time/utils.h>
30
31 using namespace std;
32 using namespace Msp;
33
34 class Viewer: public RegisteredApplication<Viewer>
35 {
36 private:
37         class Resources: public GL::Resources
38         {
39         private:
40                 DataFile::DirectorySource dir_source;
41                 DataFile::PackSource pack_source;
42
43         public:
44                 Resources();
45
46                 void add_directory(const string &);
47                 void add_pack(const string &);
48         };
49
50         Graphics::SimpleGLWindow window;
51         Input::Mouse mouse;
52         Resources resources;
53         GL::WindowView view;
54         GL::Pipeline pipeline;
55         GL::Renderable *renderable;
56         GL::AnimatedObject *anim_object;
57         GL::AnimationPlayer *anim_player;
58         GL::Light light;
59         GL::Lighting lighting;
60         GL::Camera camera;
61         float yaw;
62         float pitch;
63         float distance;
64         float light_yaw;
65         float light_pitch;
66         unsigned dragging;
67         Time::TimeStamp last_tick;
68
69 public:
70         Viewer(int, char **);
71 private:
72         template<typename T>
73         T *load(const string &);
74 public:
75         ~Viewer();
76
77         virtual int main();
78 private:
79         virtual void tick();
80
81         void button_press(unsigned);
82         void button_release(unsigned);
83         void axis_motion(unsigned, float, float);
84
85         void update_camera();
86         void update_light();
87 };
88
89
90 Viewer::Viewer(int argc, char **argv):
91         window(1024, 768, false),
92         mouse(window),
93         view(window, window.get_gl_context()),
94         pipeline(view),
95         renderable(0),
96         anim_object(0),
97         anim_player(0),
98         yaw(0),
99         pitch(0),
100         distance(10),
101         light_yaw(0),
102         light_pitch(0),
103         dragging(0)
104 {
105         list<string> resource_locations;
106         string animation_name;
107         string renderable_name;
108         GetOpt getopt;
109         getopt.add_option('r', "resources", resource_locations, GetOpt::REQUIRED_ARG);
110         getopt.add_option('a', "animation", animation_name, GetOpt::REQUIRED_ARG);
111         getopt.add_argument("renderable", renderable_name);
112         getopt(argc, argv);
113
114         for(list<string>::const_iterator i=resource_locations.begin(); i!=resource_locations.end(); ++i)
115         {
116                 if(FS::is_dir(*i))
117                         resources.add_directory(*i);
118                 else
119                 {
120                         string ext = FS::extpart(*i);
121                         if(ext==".mdp")
122                                 resources.add_pack(*i);
123                         else
124                                 DataFile::load(resources, *i);
125                 }
126         }
127
128         GL::Object *object = 0;
129
130         string ext = FS::extpart(renderable_name);
131         if(ext==".mesh")
132         {
133                 GL::Mesh *mesh = 0;
134                 if(FS::exists(renderable_name))
135                 {
136                         mesh = new GL::Mesh;
137                         DataFile::load(*mesh, renderable_name);
138                         resources.add("__"+renderable_name, mesh);
139                 }
140                 else
141                         mesh = &resources.get<GL::Mesh>(renderable_name);
142
143                 object = new GL::Object;
144                 GL::Technique *tech = new GL::Technique;
145                 tech->add_pass(0);
146                 object->set_mesh(mesh);
147                 object->set_technique(tech);
148                 renderable = object;
149
150                 resources.add("__.tech", tech);
151                 resources.add("__.object", object);
152         }
153         else if(ext==".object")
154                 renderable = load<GL::Object>(renderable_name);
155         else if(ext==".scene")
156         {
157                 GL::SimpleScene *scene = new GL::SimpleScene;
158                 DataFile::load(*scene, renderable_name, resources);
159                 renderable = scene;
160         }
161         else
162                 throw usage_error("Unknown renderable type");
163
164         if(!animation_name.empty())
165         {
166                 if(!object)
167                         throw usage_error("Must have an object to animate");
168
169                 GL::Animation *anim = load<GL::Animation>(animation_name);
170                 anim_player = new GL::AnimationPlayer;
171                 anim_object = new GL::AnimatedObject(*object);
172                 anim_player->play(*anim_object, *anim);
173                 renderable = anim_object;
174         }
175
176         window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0));
177         mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_press), false));
178         mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_release), false));
179         mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::axis_motion), false));
180
181         light.set_position(GL::Vector4(0, 0, 1, 0));
182         lighting.attach(0, light);
183
184         camera.set_up_direction(GL::Vector3(0, 0, 1));
185         update_camera();
186
187         GL::Pipeline::Pass &pass = pipeline.add_pass(0, *renderable);
188         pass.set_lighting(&lighting);
189         pass.set_depth_test(&GL::DepthTest::lequal());
190         pass.set_blend(&GL::Blend::alpha());
191
192         view.set_content(&pipeline);
193         view.set_camera(&camera);
194 }
195
196 template<typename T>
197 T *Viewer::load(const string &name)
198 {
199         if(FS::exists(name))
200         {
201                 T *thing = new T;
202                 DataFile::load(*thing, name, resources);
203                 resources.add("__"+name, thing);
204                 return thing;
205         }
206         else
207                 return &resources.get<T>(name);
208 }
209
210 Viewer::~Viewer()
211 {
212         delete anim_player;
213         delete anim_object;
214 }
215
216 int Viewer::main()
217 {
218         window.show();
219         return Application::main();
220 }
221
222 void Viewer::tick()
223 {
224         if(anim_player)
225         {
226                 Time::TimeStamp t = Time::now();
227                 Time::TimeDelta dt;
228                 if(last_tick)
229                         dt = t-last_tick;
230                 last_tick = t;
231
232                 anim_player->tick(dt);
233         }
234
235         window.tick();
236         view.render();
237 }
238
239 void Viewer::button_press(unsigned btn)
240 {
241         if(btn==1)
242         {
243                 dragging = 1;
244         }
245         else if(btn==3)
246         {
247                 dragging = 3;
248                 axis_motion(0, 0, 0);
249         }
250         else if(btn==4)
251         {
252                 distance *= 0.9;
253                 update_camera();
254         }
255         else if(btn==5)
256         {
257                 distance *= 1.1;
258                 update_camera();
259         }
260 }
261
262 void Viewer::button_release(unsigned btn)
263 {
264         if(btn==dragging)
265                 dragging = 0;
266 }
267
268 void Viewer::axis_motion(unsigned axis, float, float delta)
269 {
270         if(dragging==1)
271         {
272                 float dx = (axis==0 ? delta : 0);
273                 float dy = (axis==1 ? delta : 0);
274
275                 yaw -= dx*M_PI*2;
276                 while(yaw>M_PI)
277                         yaw -= M_PI*2;
278                 while(yaw<-M_PI)
279                         yaw += M_PI*2;
280
281                 pitch += dy*M_PI;
282                 if(pitch>M_PI*0.49)
283                         pitch = M_PI*0.49;
284                 if(pitch<-M_PI*0.49)
285                         pitch = -M_PI*0.49;
286
287                 update_camera();
288         }
289         else if(dragging==3)
290         {
291                 float x = mouse.get_axis_value(0);
292                 float y = mouse.get_axis_value(1);
293
294                 light_yaw = yaw+x*M_PI;
295                 light_pitch = pitch-y*M_PI;
296
297                 update_light();
298         }
299 }
300
301 void Viewer::update_camera()
302 {
303         float cy = cos(yaw);
304         float sy = sin(yaw);
305         float cp = cos(pitch);
306         float sp = sin(pitch);
307         camera.set_position(GL::Vector3(-cy*cp*distance, -sy*cp*distance, -sp*distance));
308         camera.set_depth_clip(distance*0.02, distance*50);
309         camera.look_at(GL::Vector3(0, 0, 0));
310 }
311
312 void Viewer::update_light()
313 {
314         float cy = cos(light_yaw);
315         float sy = sin(light_yaw);
316         float cp = cos(light_pitch);
317         float sp = sin(light_pitch);
318         light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp, 0));
319 }
320
321
322 Viewer::Resources::Resources()
323 {
324         add_source(dir_source);
325         add_source(pack_source);
326 }
327
328 void Viewer::Resources::add_directory(const string &dir)
329 {
330         dir_source.add_directory(dir);
331 }
332
333 void Viewer::Resources::add_pack(const string &pack)
334 {
335         pack_source.add_pack_file(pack);
336 }