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