-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWorldWindow.cpp
323 lines (274 loc) · 7.75 KB
/
WorldWindow.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/*
* CS559 Maze Project
*
* Class file for the WorldWindow class.
*
* (c) Stephen Chenney, University of Wisconsin at Madison, 2001-2002
*
*/
#include "WorldWindow.h"
#include <Fl/math.h>
#include <Fl/gl.h>
#include <GL/glu.h>
#include <stdio.h>
const double WorldWindow::FOV_X = 45.0;
WorldWindow::WorldWindow(int x, int y, int width, int height, char *label)
: Fl_Gl_Window(x, y, width, height, label)
{
button = -1;
// Initial viewing parameters.
phi = 45.0f;
theta = 0.0f;
dist = 100.0f;
x_at = 0.0f;
y_at = 0.0f;
riding = false;
smooth = false;
}
void
WorldWindow::draw(void)
{
double eye[3];
float color[4], dir[4];
if (!valid())
{
// Stuff in here doesn't change from frame to frame, and does not
// rely on any coordinate system. It only has to be done if the
// GL context is damaged.
double fov_y;
// Sets the clear color to sky blue.
glClearColor(0.53f, 0.81f, 0.92f, 1.0);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Turn on back face culling. Faces with normals away from the viewer
// will not be drawn.
glEnable(GL_CULL_FACE);
// Enable lighting with one light.
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
// Ambient and diffuse lighting track the current color.
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
// Turn on normal vector normalization. You don't have to give unit
// normal vector, and you can scale objects.
glEnable(GL_NORMALIZE);
// Set up the viewport.
glViewport(0, 0, w(), h());
// Set up the persepctive transformation.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
fov_y = 360.0f / M_PI * atan(h() * tan(FOV_X * M_PI / 360.0) / w());
gluPerspective(fov_y, w() / (float)h(), 1.0, 1000.0);
// Do some light stuff. Diffuse color, and zero specular color
// turns off specular lighting.
color[0] = 1.0f; color[1] = 1.0f; color[2] = 1.0f; color[3] = 1.0f;
glLightfv(GL_LIGHT0, GL_DIFFUSE, color);
color[0] = 0.0f; color[1] = 0.0f; color[2] = 0.0f; color[3] = 1.0f;
glLightfv(GL_LIGHT0, GL_SPECULAR, color);
// Initialize all the objects.
ground.Initialize();
traintrack.Initialize();
building.Initialize();
sphere.Initialize();
}
// Stuff out here relies on a coordinate system or must be done on every
// frame.
// Clear the screen. Color and depth.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set up the viewing transformation. The viewer is at a distance
// dist from (x_at, y_ay, 2.0) in the direction (theta, phi) defined
// by two angles. They are looking at (x_at, y_ay, 2.0) and z is up.
if (riding) {
traintrack.Ride();
}
else {
eye[0] = x_at + dist * cos(theta * M_PI / 180.0) * cos(phi * M_PI / 180.0);
eye[1] = y_at + dist * sin(theta * M_PI / 180.0) * cos(phi * M_PI / 180.0);
eye[2] = 2.0 + dist * sin(phi * M_PI / 180.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye[0], eye[1], eye[2], x_at, y_at, 2.0, 0.0, 0.0, 1.0);
}
// Position the light source. This has to happen after the viewing
// transformation is set up, so that the light stays fixed in world
// space. This is a directional light - note the 0 in the w component.
dir[0] = 1.0; dir[1] = 1.0; dir[2] = 1.0; dir[3] = 0.0;
glLightfv(GL_LIGHT0, GL_POSITION, dir);
// Draw stuff. Everything.
ground.Draw();
traintrack.Draw();
glPushMatrix();
glTranslatef(18.5f, 0.0f, 16.0f); // Move right and into the screen
building.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f, 17.0f, 13.0f); // Move right and into the screen
building.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(-15.5f, 18.0f, 25.0f); // Move right and into the screen
building.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(4.0f, -20.0f, 14.0f); // Move right and into the screen
building.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(-13.0f, -13.0f, 3.0f); // Move right and into the screen
building.Draw();
glPopMatrix();
// flared creeper cheeks
glPushMatrix();
glTranslatef(18.5f, -1.0f, 16.0f); // Move right and into the screen
glScalef(4.5f, 0.0f, 4.5f);
sphere.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f, 17.0f, 13.0f); // Move right and into the screen
glScalef(4.5f, 0.0f, 4.5f);
sphere.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(-15.5f, 18.0f, 25.0f); // Move right and into the screen
glScalef(4.5f, 0.0f, 4.5f);
sphere.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(4.0f, -20.0f, 14.0f); // Move right and into the screen
glScalef(4.5f, 0.0f, 4.5f);
sphere.Draw();
glPopMatrix();
glPushMatrix();
glTranslatef(-13.0f, -12.0f, 3.0f); // Move right and into the screen
glScalef(4.5f, 0.0f, 4.5f);
sphere.Draw();
glPopMatrix();
//pyramids
glPushMatrix();
glTranslatef(18.5f, 0.0f, 18.0f); // Move right and into the screen
building.DrawPyramid();
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f, 17.0f, 15.0f); // Move right and into the screen
building.DrawPyramid();
glPopMatrix();
glPushMatrix();
glTranslatef(-15.5f, 18.0f, 27.0f); // Move right and into the screen
building.DrawPyramid();
glPopMatrix();
glPushMatrix();
glTranslatef(4.0f, -20.0f, 16.0f); // Move right and into the screen
building.DrawPyramid();
glPopMatrix();
glPushMatrix();
glTranslatef(-13.0f, -13.0f, 5.0f); // Move right and into the screen
building.DrawPyramid();
glPopMatrix();
}
void
WorldWindow::Drag(float dt)
{
int dx = x_down - x_last;
int dy = y_down - y_last;
static bool riding = false;
switch (button)
{
case FL_LEFT_MOUSE:
// Left button changes the direction the viewer is looking from.
theta = theta_down + 360.0f * dx / (float)w();
while (theta >= 360.0f)
theta -= 360.0f;
while (theta < 0.0f)
theta += 360.0f;
phi = phi_down + 90.0f * dy / (float)h();
if (phi > 89.0f)
phi = 89.0f;
if (phi < -5.0f)
phi = -5.0f;
break;
case FL_MIDDLE_MOUSE:
// Middle button moves the viewer in or out.
dist = dist_down - (0.5f * dist_down * dy / (float)h());
if (dist < 1.0f)
dist = 1.0f;
break;
case FL_RIGHT_MOUSE: {
// Right mouse button moves the look-at point around, so the world
// appears to move under the viewer.
float x_axis[2];
float y_axis[2];
x_axis[0] = -(float)sin(theta * M_PI / 180.0);
x_axis[1] = (float)cos(theta * M_PI / 180.0);
y_axis[0] = x_axis[1];
y_axis[1] = -x_axis[0];
x_at = x_at_down + 100.0f * (x_axis[0] * dx / (float)w()
+ y_axis[0] * dy / (float)h());
y_at = y_at_down + 100.0f * (x_axis[1] * dx / (float)w()
+ y_axis[1] * dy / (float)h());
} break;
default:;
}
}
bool
WorldWindow::Update(float dt)
{
// Update the view. This gets called once per frame before doing the
// drawing.
if (button != -1) // Only do anything if the mouse button is down.
Drag(dt);
// Animate the train.
traintrack.Update(dt);
return true;
}
int
WorldWindow::handle(int event)
{
// Event handling routine. Only looks at mouse events.
// Stores a bunch of values when the mouse goes down and keeps track
// of where the mouse is and what mouse button is down, if any.
switch (event)
{
case FL_PUSH:
button = Fl::event_button();
x_last = x_down = Fl::event_x();
y_last = y_down = Fl::event_y();
phi_down = phi;
theta_down = theta;
dist_down = dist;
x_at_down = x_at;
y_at_down = y_at;
return 1;
case FL_DRAG:
x_last = Fl::event_x();
y_last = Fl::event_y();
return 1;
case FL_RELEASE:
button = -1;
return 1;
case FL_KEYBOARD:
if (Fl::event_key() == 'q')
exit(0);
if (Fl::event_key() == 'r')
{
riding = !riding;
redraw();
return 1;
}
if (Fl::event_key() == 's')
{
sphere.Subdivide(1);
redraw();
return 1;
}
if (Fl::event_key() == 'n')
{
smooth = !smooth;
redraw();
return 1;
}
return 0;
}
// Pass any other event types on the superclass.
return Fl_Gl_Window::handle(event);
}