]> git.tdb.fi Git - libs/gl.git/blob - tools/viewer.cpp
Rework loading in 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/resources.h>
20 #include <msp/gl/technique.h>
21 #include <msp/gl/tests.h>
22 #include <msp/input/mouse.h>
23 #include <msp/io/print.h>
24 #include <msp/time/timestamp.h>
25 #include <msp/time/utils.h>
26
27 using namespace std;
28 using namespace Msp;
29
30 class Viewer: public RegisteredApplication<Viewer>
31 {
32 private:
33         class Resources: public GL::Resources
34         {
35         private:
36                 DataFile::DirectorySource dir_source;
37                 DataFile::PackSource pack_source;
38
39         public:
40                 Resources();
41
42                 void add_directory(const string &);
43                 void add_pack(const string &);
44         };
45
46         Graphics::SimpleGLWindow window;
47         Input::Mouse mouse;
48         Resources resources;
49         GL::Renderable *renderable;
50         GL::AnimatedObject *anim_object;
51         GL::AnimationPlayer *anim_player;
52         GL::Light light;
53         GL::Lighting lighting;
54         GL::Camera camera;
55         float yaw;
56         float pitch;
57         float distance;
58         float light_yaw;
59         float light_pitch;
60         unsigned dragging;
61         Time::TimeStamp last_tick;
62
63 public:
64         Viewer(int, char **);
65 private:
66         template<typename T>
67         T *load(const string &);
68 public:
69         ~Viewer();
70
71         virtual int main();
72 private:
73         virtual void tick();
74
75         void button_press(unsigned);
76         void button_release(unsigned);
77         void axis_motion(unsigned, float, float);
78
79         void update_camera();
80         void update_light();
81 };
82
83
84 Viewer::Viewer(int argc, char **argv):
85         window(1024, 768, false),
86         mouse(window),
87         renderable(0),
88         anim_object(0),
89         anim_player(0),
90         yaw(0),
91         pitch(0),
92         distance(10),
93         light_yaw(0),
94         light_pitch(0),
95         dragging(0)
96 {
97         list<string> resource_locations;
98         string animation_name;
99         string renderable_name;
100         GetOpt getopt;
101         getopt.add_option('r', "resources", resource_locations, GetOpt::REQUIRED_ARG);
102         getopt.add_option('a', "animation", animation_name, GetOpt::REQUIRED_ARG);
103         getopt.add_argument("renderable", renderable_name);
104         getopt(argc, argv);
105
106         for(list<string>::const_iterator i=resource_locations.begin(); i!=resource_locations.end(); ++i)
107         {
108                 if(FS::is_dir(*i))
109                         resources.add_directory(*i);
110                 else
111                 {
112                         string ext = FS::extpart(*i);
113                         if(ext==".mdp")
114                                 resources.add_pack(*i);
115                         else
116                                 DataFile::load(resources, *i);
117                 }
118         }
119
120         GL::Object *object = 0;
121
122         string ext = FS::extpart(renderable_name);
123         if(ext==".mesh")
124         {
125                 GL::Mesh *mesh = 0;
126                 if(FS::exists(renderable_name))
127                 {
128                         mesh = new GL::Mesh;
129                         DataFile::load(*mesh, renderable_name);
130                         resources.add("__"+renderable_name, mesh);
131                 }
132                 else
133                         mesh = &resources.get<GL::Mesh>(renderable_name);
134
135                 object = new GL::Object;
136                 GL::Technique *tech = new GL::Technique;
137                 tech->add_pass(0);
138                 object->set_mesh(mesh);
139                 object->set_technique(tech);
140                 renderable = object;
141
142                 resources.add("__.tech", tech);
143                 resources.add("__.object", object);
144         }
145         else if(ext==".object")
146         {
147                 object = load<GL::Object>(renderable_name);
148                 renderable = object;
149         }
150         else
151                 throw usage_error("Unknown renderable type");
152
153         if(!animation_name.empty())
154         {
155                 if(!object)
156                         throw usage_error("Must have an object to animate");
157
158                 GL::Animation *anim = load<GL::Animation>(animation_name);
159                 anim_player = new GL::AnimationPlayer;
160                 anim_object = new GL::AnimatedObject(*object);
161                 anim_player->play(*anim_object, *anim);
162                 renderable = anim_object;
163         }
164
165         window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0));
166         mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_press), false));
167         mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_release), false));
168         mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::axis_motion), false));
169
170         light.set_position(GL::Vector4(0, 0, 1, 0));
171         lighting.attach(0, light);
172
173         camera.set_up_direction(GL::Vector3(0, 0, 1));
174         update_camera();
175 }
176
177 template<typename T>
178 T *Viewer::load(const string &name)
179 {
180         if(FS::exists(name))
181         {
182                 T *thing = new T;
183                 DataFile::load(*thing, name, resources);
184                 resources.add("__"+name, thing);
185                 return thing;
186         }
187         else
188                 return &resources.get<T>(name);
189 }
190
191 Viewer::~Viewer()
192 {
193         delete anim_player;
194         delete anim_object;
195 }
196
197 int Viewer::main()
198 {
199         window.show();
200         return Application::main();
201 }
202
203 void Viewer::tick()
204 {
205         if(anim_player)
206         {
207                 Time::TimeStamp t = Time::now();
208                 Time::TimeDelta dt;
209                 if(last_tick)
210                         dt = t-last_tick;
211                 last_tick = t;
212
213                 anim_player->tick(dt);
214         }
215
216         window.tick();
217
218         GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
219
220         camera.apply();
221
222         GL::Bind bind_lighting(lighting);
223         GL::Bind bind_depth(GL::DepthTest::lequal());
224         GL::Bind bind_blend(GL::Blend::alpha());
225         renderable->render();
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 }