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