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/directionallight.h>
15 #include <msp/gl/framebuffer.h>
16 #include <msp/gl/lighting.h>
17 #include <msp/gl/mesh.h>
18 #include <msp/gl/object.h>
19 #include <msp/gl/sequence.h>
20 #include <msp/gl/sequencebuilder.h>
21 #include <msp/gl/sequencetemplate.h>
22 #include <msp/gl/renderer.h>
23 #include <msp/gl/resources.h>
24 #include <msp/gl/simplescene.h>
25 #include <msp/gl/technique.h>
26 #include <msp/gl/windowview.h>
27 #include <msp/input/mouse.h>
28 #include <msp/io/print.h>
29 #include <msp/strings/regex.h>
30 #include <msp/time/timestamp.h>
31 #include <msp/time/utils.h>
36 class Viewer: public RegisteredApplication<Viewer>
41 list<string> resource_locations;
42 string animation_name;
43 string renderable_name;
44 Graphics::WindowOptions wnd_opts;
45 Graphics::GLOptions gl_opts;
47 Options(int, char **);
50 class Resources: public GL::Resources
53 DataFile::DirectorySource dir_source;
54 DataFile::PackSource pack_source;
59 void add_directory(const string &);
60 void add_pack(const string &);
64 Graphics::Display display;
65 Graphics::Window window;
66 Graphics::GLContext gl_ctx;
70 GL::Sequence *sequence;
71 GL::Renderable *renderable;
72 GL::AnimatedObject *anim_object;
73 GL::AnimationPlayer *anim_player;
74 GL::DirectionalLight light;
75 GL::Lighting lighting;
83 Time::TimeStamp last_tick;
89 T *load(const string &);
97 void button_press(unsigned);
98 void button_release(unsigned);
99 void axis_motion(unsigned, float, float);
101 void update_camera();
106 Viewer::Options::Options(int argc, char **argv)
111 getopt.add_option('r', "resources", resource_locations, GetOpt::REQUIRED_ARG);
112 getopt.add_option('a', "animation", animation_name, GetOpt::REQUIRED_ARG);
113 getopt.add_option('w', "window-size", window_size, GetOpt::REQUIRED_ARG);
114 getopt.add_argument("renderable", renderable_name);
117 wnd_opts.width = 1024;
118 wnd_opts.height = 768;
119 if (!window_size.empty())
121 RegMatch m = Regex("^([1-9][0-9]*)x([1-9][0-9]*)$").match(window_size);
123 throw usage_error("Invalid window size");
125 wnd_opts.width = lexical_cast<unsigned>(m[1].str);
126 wnd_opts.height = lexical_cast<unsigned>(m[2].str);
128 gl_opts.gl_version_major = Graphics::GLOptions::LATEST_VERSION;
129 gl_opts.core_profile = true;
132 Viewer::Viewer(int argc, char **argv):
134 window(display, opts.wnd_opts),
135 gl_ctx(window, opts.gl_opts),
137 view(window, gl_ctx),
149 for(list<string>::const_iterator i=opts.resource_locations.begin(); i!=opts.resource_locations.end(); ++i)
152 resources.add_directory(*i);
155 string ext = FS::extpart(*i);
157 resources.add_pack(*i);
159 DataFile::load(resources, *i);
163 GL::Object *object = 0;
165 string ext = FS::extpart(opts.renderable_name);
169 if(FS::exists(opts.renderable_name))
172 DataFile::load(*mesh, opts.renderable_name);
173 resources.add("__"+opts.renderable_name, mesh);
176 mesh = &resources.get<GL::Mesh>(opts.renderable_name);
178 object = new GL::Object;
179 GL::Technique *tech = new GL::Technique;
181 object->set_mesh(mesh);
182 object->set_technique(tech);
185 resources.add("__.tech", tech);
186 resources.add("__.object", object);
188 else if(ext==".object")
189 renderable = load<GL::Object>(opts.renderable_name);
190 else if(ext==".scene")
192 if(FS::exists(opts.renderable_name))
194 GL::Scene::GenericLoader ldr(resources);
195 IO::BufferedFile in(opts.renderable_name);
196 DataFile::Parser parser(in, opts.renderable_name);
198 renderable = ldr.get_object();
201 renderable = &resources.get<GL::Scene>(opts.renderable_name);
205 GL::SequenceTemplate *tmpl = load<GL::SequenceTemplate>(opts.renderable_name);
206 GL::SequenceBuilder bld(*tmpl);
207 bld.set_debug_name(FS::basename(opts.renderable_name));
208 sequence = bld.build(view);
211 throw usage_error("Unknown renderable type");
213 if(!opts.animation_name.empty())
216 throw usage_error("Must have an object to animate");
218 GL::Animation *anim = load<GL::Animation>(opts.animation_name);
219 anim_player = new GL::AnimationPlayer;
220 anim_object = new GL::AnimatedObject(*object);
221 anim_player->play(*anim_object, *anim);
222 renderable = anim_object;
225 window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Viewer::exit), 0));
226 mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_press), false));
227 mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_release), false));
228 mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::axis_motion), false));
230 light.set_direction(GL::Vector3(0, 0, -1));
231 lighting.attach(light);
233 camera.set_debug_name("Camera");
234 camera.set_up_direction(GL::Vector3(0, 0, 1));
239 sequence = new GL::Sequence();
240 sequence->set_debug_name("Sequence");
241 GL::Sequence::Step &step = sequence->add_step(0, *renderable);
242 step.set_lighting(&lighting);
243 step.set_depth_test(GL::LEQUAL);
246 view.set_content(sequence);
247 view.set_camera(&camera);
251 T *Viewer::load(const string &name)
256 DataFile::load(*thing, name, resources);
257 resources.add("__"+name, thing);
261 return &resources.get<T>(name);
274 return Application::main();
281 Time::TimeStamp t = Time::now();
287 anim_player->tick(dt);
294 void Viewer::button_press(unsigned btn)
303 axis_motion(0, 0, 0);
317 void Viewer::button_release(unsigned btn)
323 void Viewer::axis_motion(unsigned axis, float, float delta)
327 float dx = (axis==0 ? delta : 0);
328 float dy = (axis==1 ? delta : 0);
346 float x = mouse.get_axis_value(0);
347 float y = mouse.get_axis_value(1);
349 light_yaw = yaw+x*M_PI;
350 light_pitch = pitch-y*M_PI;
356 void Viewer::update_camera()
360 float cp = cos(pitch);
361 float sp = sin(pitch);
362 camera.set_position(GL::Vector3(-cy*cp*distance, -sy*cp*distance, -sp*distance));
363 camera.set_depth_clip(distance*0.02, distance*50);
364 camera.look_at(GL::Vector3(0, 0, 0));
367 void Viewer::update_light()
369 float cy = cos(light_yaw);
370 float sy = sin(light_yaw);
371 float cp = cos(light_pitch);
372 float sp = sin(light_pitch);
373 light.set_direction(GL::Vector3(cy*cp, sy*cp, sp));
377 Viewer::Resources::Resources()
379 add_source(dir_source);
380 add_source(pack_source);
383 void Viewer::Resources::add_directory(const string &dir)
385 dir_source.add_directory(dir);
388 void Viewer::Resources::add_pack(const string &pack)
390 pack_source.add_pack_file(pack);