1 // OGL_CAMERA.CPP
2 
3 // Copyright (C) 1998 Tommi Hassinen.
4 
5 // This package is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 
10 // This package is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 
15 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 /*################################################################################################*/
20 
21 #include "ogl_camera.h"		// config.h is here -> we get ENABLE-macros here...
22 
23 #include "base_app.h"
24 
25 #include <vector>
26 #include <algorithm>	// for WIN32...
27 #include <sstream>
28 using namespace std;
29 
30 // NOT_DEFINED is defined here the same way as in libghemical.
31 
32 #ifndef NOT_DEFINED
33 #define NOT_DEFINED -1
34 #endif	// NOT_DEFINED
35 
36 /*################################################################################################*/
37 
ogl_camera(const ogl_object_location & p1,GLfloat p2)38 ogl_camera::ogl_camera(const ogl_object_location & p1, GLfloat p2) :
39 	ogl_dummy_object(p1)
40 {
41 	focus = p2;
42 	clipping = 0.90;
43 
44 	update_vdim = true;
45 
46 	use_local_lights = true;
47 	use_global_lights = true;
48 
49 	ortho = false;
50 
51 	stereo_mode = false;
52 	stereo_relaxed = false;
53 
54 	stereo_displacement = -0.25;
55 	relaxed_separation = 0.60;
56 
57 	GetLD()->crd[2] = -focus;
58 }
59 
60 // this is partial because only ogl_camera::OrbitObject() needs this!!!
61 // this is partial because only ogl_camera::OrbitObject() needs this!!!
62 // this is partial because only ogl_camera::OrbitObject() needs this!!!
63 
ogl_camera(const ogl_camera & p1)64 ogl_camera::ogl_camera(const ogl_camera & p1) :
65 	ogl_dummy_object(* p1.ol)
66 {
67 }
68 
~ogl_camera(void)69 ogl_camera::~ogl_camera(void)
70 {
71 	if (!obj_list.empty())
72 	{
73 		cout << "liboglappth : warning!!! ogl_camera::obj_list not empty!" << endl;
74 	}
75 
76 	if (!wnd_vector.empty())
77 	{
78 		cout << "liboglappth : error!!! ogl_camera::wnd_vector not empty!" << endl;
79 		exit(EXIT_FAILURE);
80 	}
81 }
82 
RegisterClient(base_wcl * wcl)83 void ogl_camera::RegisterClient(base_wcl * wcl)
84 {
85 	vector<base_wcl *>::iterator it = find(wcl_vector.begin(), wcl_vector.end(), wcl);
86 	if (it != wcl_vector.end())
87 	{
88 		cout << "liboglappth : duplicate wcl record!" << endl;
89 		exit(EXIT_FAILURE);
90 	}
91 
92 	wcl_vector.push_back(wcl);
93 }
94 
UnregisterClient(base_wcl * wcl)95 void ogl_camera::UnregisterClient(base_wcl * wcl)
96 {
97 	vector<base_wcl *>::iterator it = find(wcl_vector.begin(), wcl_vector.end(), wcl);
98 	if (it == wcl_vector.end())
99 	{
100 		cout << "liboglappth : wcl record not found!" << endl;
101 		exit(EXIT_FAILURE);
102 	}
103 
104 	wcl_vector.erase(it);
105 }
106 
RegisterWnd(base_wnd * wnd)107 void ogl_camera::RegisterWnd(base_wnd * wnd)
108 {
109 	vector<base_wnd *>::iterator it = find(wnd_vector.begin(), wnd_vector.end(), wnd);
110 	if (it != wnd_vector.end())
111 	{
112 		cout << "liboglappth : duplicate wnd record!" << endl;
113 		exit(EXIT_FAILURE);
114 	}
115 
116 	wnd_vector.push_back(wnd);
117 }
118 
UnregisterWnd(base_wnd * wnd)119 void ogl_camera::UnregisterWnd(base_wnd * wnd)
120 {
121 	vector<base_wnd *>::iterator it = find(wnd_vector.begin(), wnd_vector.end(), wnd);
122 	if (it == wnd_vector.end())
123 	{
124 		cout << "liboglappth : wnd record not found!" << endl;
125 		exit(EXIT_FAILURE);
126 	}
127 
128 	wnd_vector.erase(it);
129 }
130 
CopySettings(const ogl_camera * p1)131 bool ogl_camera::CopySettings(const ogl_camera * p1)
132 {
133 	ogl_ol_static * ref = dynamic_cast<ogl_ol_static *>(ol);
134 	if (ref == NULL) return false;
135 
136 	// now that we have verified that we can modify the ol-object, we will copy the settings...
137 
138 	focus = p1->focus; clipping = p1->clipping;
139 	for (int n1 = 0;n1 < 3;n1++) GetLD()->crd[n1] = p1->GetSafeLD()->crd[n1];
140 	GetLD()->zdir = p1->GetSafeLD()->zdir;
141 	GetLD()->ydir = p1->GetSafeLD()->ydir;
142 
143 	// the local lights that are attached to the camera are not moved?!?!?!
144 	// the local lights that are attached to the camera are not moved?!?!?!
145 	// the local lights that are attached to the camera are not moved?!?!?!
146 
147 	return true;
148 }
149 
RenderScene(base_wnd * wnd,bool accum,bool pick,int x,int y)150 void ogl_camera::RenderScene(base_wnd * wnd, bool accum, bool pick, int x, int y)
151 {
152 	glMatrixMode(GL_PROJECTION);
153 	glLoadIdentity();
154 
155 	// projection matrix is now initialized. if this is a "pick" operation, we must do
156 	// some furter manipulations (gluPickMatrix() is used to "zoom" into the selection area).
157 
158 	if (pick)
159 	{
160 		glRenderMode(GL_SELECT);
161 		GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp);
162 
163 		// is this dependent on screen resolution or what???
164 		// there are some problems with selection in wireframe models...
165 
166 		const GLfloat region = 5.0;
167 		gluPickMatrix(x, vp[3] - y, region, region, vp);
168 	}
169 
170 	if (accum) glClear(GL_ACCUM_BUFFER_BIT);
171 	else glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
172 
173 	// the stereo-modes related stuff start here...
174 	// the stereo-modes related stuff start here...
175 	// the stereo-modes related stuff start here...
176 
177 	// the stereo modes are implemented as a loop, that is cycled either once or twice.
178 
179 	int width = wnd->GetWidth(); if (stereo_mode && stereo_relaxed) width /= 2;
180 	int height = wnd->GetHeight(); int shift = 0;
181 
182 	const GLfloat aspect = (GLfloat) width / (GLfloat) height;
183 	const GLfloat fovy = (aspect > 1.0 ? 45.0 / aspect : 45.0);
184 
185 	if (update_vdim)
186 	{
187 		wnd->GetClient()->vdim[1] = focus * tan(M_PI * fovy / 360.0);
188 		wnd->GetClient()->vdim[0] = aspect * wnd->GetClient()->vdim[1];
189 	}
190 
191 	const int stereo_count = (stereo_mode ? 2 : 1);
192 	for (int stereo_loop = 0;stereo_loop < stereo_count;stereo_loop++)
193 	{
194 		glViewport(shift, 0, width, height);
195 		if (stereo_mode && stereo_relaxed)
196 		{
197 			// this will shift our viewport right at the next round...
198 
199 			shift += width;
200 		}
201 
202 		const GLfloat nearplane = (1.0 - clipping) * focus;
203 		const GLfloat farplane = (1.0 + clipping) * focus;
204 
205 		if (!ortho)
206 		{
207 			gluPerspective(fovy, aspect, nearplane, farplane);
208 		}
209 		else
210 		{
211 			const GLfloat vdimX = wnd->GetClient()->vdim[0];
212 			const GLfloat vdimY = wnd->GetClient()->vdim[1];
213 
214 			glOrtho(-vdimX, +vdimX, -vdimY, +vdimY, nearplane, farplane);
215 		}
216 
217 		const ogl_obj_loc_data * loc1 = GetSafeLD();
218 
219 		glMatrixMode(GL_MODELVIEW); glLoadIdentity();
220 		oglv3d<GLfloat> target = oglv3d<GLfloat>(loc1->crd) + (loc1->zdir * focus);
221 
222 		const GLfloat * r1; const GLfloat * r2; const GLfloat * r3;
223 
224 		if (!stereo_mode)
225 		{
226 			// if not a stereo mode, then just use normal camera settings...
227 
228 			r1 = loc1->crd;		// eye coordinates
229 			r2 = target.data;	// target coordinates
230 			r3 = loc1->ydir.data;	// y-direction vector
231 		}
232 		else
233 		{
234 			// for all stereo modes, translate the camera along camera's x-axis.
235 			// y-direction will remain constant, but other directions won't. does it matter???
236 
237 			GLfloat displacement = stereo_displacement / 20.0;
238 			if (!stereo_loop) displacement = -displacement;
239 
240 			oglv3d<GLfloat> xdir = loc1->ydir.vpr(loc1->zdir);
241 
242 	// displace each eye coordinate using camera's x-axis -> will be independent on camera's orientation!!!
243 	// displace each eye coordinate using camera's x-axis -> will be independent on camera's orientation!!!
244 	// displace each eye coordinate using camera's x-axis -> will be independent on camera's orientation!!!
245 
246 			static GLfloat tmp_crd[3];
247 			tmp_crd[0] = loc1->crd[0] + displacement * xdir.data[0];
248 			tmp_crd[1] = loc1->crd[1] + displacement * xdir.data[1];
249 			tmp_crd[2] = loc1->crd[2] + displacement * xdir.data[2];
250 
251 			r1 = tmp_crd;		// eye coordinates
252 			r2 = target.data;	// target coordinates
253 			r3 = loc1->ydir.data;	// y-direction vector
254 
255 			if (!stereo_relaxed)
256 			{
257 				// for the red-blue stereo mode, set the color masks...
258 
259 				if (!stereo_loop) glColorMask(GL_TRUE,GL_FALSE,GL_FALSE,GL_TRUE);	// left_eye - red
260 				else glColorMask(GL_FALSE,GL_FALSE,GL_TRUE,GL_TRUE);			// right_eye - blue
261 
262 				// ...and clear the depth buffer!!!
263 
264 				glClear(GL_DEPTH_BUFFER_BIT);
265 			}
266 		}
267 
268 		gluLookAt(r1[0], r1[1], r1[2], r2[0], r2[1], r2[2], r3[0], r3[1], r3[2]);
269 
270 		if (stereo_mode && stereo_relaxed)
271 		{
272 			// this will do the "relaxed-eye stereo" separation effect.
273 
274 			// 20061005 ; this is not as good as it could be, since the
275 			// effect is not a pure displacement but also a small rotation
276 			// -> interferes with the stereo_displacement option!!!!!
277 
278 			GLfloat separation = relaxed_separation / 10.0;
279 			if (!stereo_loop) separation = -separation;
280 			else separation *= 2.0;
281 
282 			glMatrixMode(GL_PROJECTION);
283 			glTranslatef(separation, 0.0, 0.0);
284 			glMatrixMode(GL_MODELVIEW);
285 		}
286 
287 		// now, it's time to set up the lights...
288 
289 		base_app::GetAppB()->UpdateLocalLightLocations(this);
290 
291 		// here, we are finally ready to actually render the view. for simple non-stereo views, just erase the background
292 		// by calling glClear(), and then call prj->Render() to render the view. For relaxed-eye stereo views, two viewports
293 		// are used and the view is therefore rendered twice, calling glClear only once. TODO(???): there is also a hardware
294 		// stereo mode (not much supported yet, except SGI) that could be also used; that is a special graphics mode with two
295 		// color buffers, and glDrawBuffer(???) is called to determine which is active.
296 
297 		// to make things more complicated, there is the "accumulation" effect that relies on glClear() call. to make all this
298 		// work together, we must take all glClear() and glAccum() calls out from the prj->Render, and do them here.
299 
300 	// this "accumulation" stuff (used only in gt2 so far) is not tested after stereo mode changes...
301 	// this "accumulation" stuff (used only in gt2 so far) is not tested after stereo mode changes...
302 	// this "accumulation" stuff (used only in gt2 so far) is not tested after stereo mode changes...
303 
304 		glInitNames();
305 		if (ogl_transformer::transform_in_progress)
306 		{
307 			// do the "transformation" effect:
308 			// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
309 			// 1) render all non-selected parts of the scene.
310 			// 2) render the selected parts translated/rotated as told by the transformer.
311 
312 			// accumulation should be DISABLED here!!!
313 			// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
314 
315 			wnd->GetClient()->RenderGL(Transform1);
316 
317 			glPushMatrix();
318 			ogl_transformer::client->tc_object_ref->SetModelView();
319 			wnd->GetClient()->RenderGL(Transform2);
320 			glPopMatrix();
321 		}
322 		else
323 		{
324 			// just do the normal rendering...
325 
326 			wnd->GetClient()->RenderGL(Normal);
327 		}
328 
329 		if (stereo_mode && !stereo_relaxed)
330 		{
331 			// reset the color mask...
332 
333 			glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
334 		}
335 	}
336 
337 	// end of stereo-modes related stuff...
338 	// end of stereo-modes related stuff...
339 	// end of stereo-modes related stuff...
340 }
341 
342 // when rotating or translating a camera we must make all operations in reversed directions
343 // and also drag all those local lights along...
344 
OrbitObject(const GLfloat * ang,const ogl_camera & cam)345 void ogl_camera::OrbitObject(const GLfloat * ang, const ogl_camera & cam)
346 {
347 	GLfloat tmp_ang[3];
348 	for (int n1 = 0;n1 < 3;n1++)
349 	{
350 		tmp_ang[n1] = -ang[n1];
351 	}
352 
353 	base_app * app = base_app::GetAppB();
354 	for (unsigned int n1 = 0;n1 < app->light_vector.size();n1++)
355 	{
356 		if (app->light_vector[n1]->owner != this) continue;
357 		app->light_vector[n1]->OrbitObject(tmp_ang, cam);
358 	}
359 
360 	ogl_dummy_object::OrbitObject(tmp_ang, cam);
361 
362 	DoCameraEvents();
363 }
364 
365 // when rotating a camera, we must also make the local lights to orbit around the camera.
366 // dummy_object::OrbitObject() will orbit the lights around the camera's focus point, so here
367 // we must set the camera focus to zero before making the transformation...
368 
RotateObject(const GLfloat * ang,const ogl_camera & cam)369 void ogl_camera::RotateObject(const GLfloat * ang, const ogl_camera & cam)
370 {
371 	GLfloat tmp_ang[3];
372 	for (int n1 = 0;n1 < 3;n1++)
373 	{
374 		tmp_ang[n1] = -ang[n1];
375 	}
376 
377 	ogl_camera tmp_cam = cam;
378 	tmp_cam.focus = 0.0;
379 
380 	base_app * app = base_app::GetAppB();
381 	for (unsigned int n1 = 0;n1 < app->light_vector.size();n1++)
382 	{
383 		if (app->light_vector[n1]->owner != this) continue;
384 		app->light_vector[n1]->OrbitObject(tmp_ang, tmp_cam);
385 	}
386 
387 	ogl_dummy_object::RotateObject(tmp_ang, cam);
388 
389 	DoCameraEvents();
390 }
391 
TranslateObject(const GLfloat * dst,const ogl_obj_loc_data * data)392 void ogl_camera::TranslateObject(const GLfloat * dst, const ogl_obj_loc_data * data)
393 {
394 	GLfloat tmp_dst[3];
395 	for (int n1 = 0;n1 < 3;n1++)
396 	{
397 		tmp_dst[n1] = -dst[n1];
398 	}
399 
400 	base_app * app = base_app::GetAppB();
401 	for (unsigned int n1 = 0;n1 < app->light_vector.size();n1++)
402 	{
403 		if (app->light_vector[n1]->owner != this) continue;
404 		app->light_vector[n1]->TranslateObject(tmp_dst, data);
405 	}
406 
407 	ogl_dummy_object::TranslateObject(tmp_dst, data);
408 
409 	DoCameraEvents();
410 }
411 
DoCameraEvents(void)412 void ogl_camera::DoCameraEvents(void)
413 {
414 	list<ogl_smart_object *>::iterator so_it;
415 	for (so_it = obj_list.begin();so_it != obj_list.end();so_it++)
416 	{
417 cout << "liboglappth : doing a camera_event..." << endl;
418 		(* so_it)->CameraEvent(* this);
419 	}
420 }
421 
422 /*################################################################################################*/
423 
424 ogl_transformer_client * ogl_transformer::client = NULL;
425 bool ogl_transformer::transform_in_progress = false;
426 
ogl_transformer()427 ogl_transformer::ogl_transformer() :
428 	ogl_dummy_object(true)
429 {
430 }
431 
~ogl_transformer(void)432 ogl_transformer::~ogl_transformer(void)
433 {
434 }
435 
Init(ogl_transformer_client * p1)436 void ogl_transformer::Init(ogl_transformer_client * p1)
437 {
438 	client = p1;
439 
440 	ogl_obj_loc_data * data = GetLD();
441 	for (int n1 = 0;n1 < 3;n1++) data->crd[n1] = 0.0;
442 	data->zdir = oglv3d<GLfloat>(0.0, 0.0, 1.0);
443 	data->ydir = oglv3d<GLfloat>(0.0, 1.0, 0.0);
444 }
445 
GetMatrix(GLfloat * p1) const446 void ogl_transformer::GetMatrix(GLfloat * p1) const
447 {
448 	glMatrixMode(GL_MODELVIEW);
449 	glPushMatrix(); glLoadIdentity();
450 	SetModelView(); glGetFloatv(GL_MODELVIEW_MATRIX, p1);
451 	glPopMatrix();
452 }
453 
BeginTransformation(void)454 bool ogl_transformer::BeginTransformation(void)
455 {
456 	transform_in_progress = true;
457 	client->BeginClientTransformation(this);
458 	return true;
459 }
460 
EndTransformation(void)461 bool ogl_transformer::EndTransformation(void)
462 {
463 	transform_in_progress = false;
464 	client->EndClientTransformation(this);
465 	return true;
466 }
467 
OrbitObject(const GLfloat * p1,const ogl_camera & p2)468 void ogl_transformer::OrbitObject(const GLfloat * p1, const ogl_camera & p2)
469 {
470 	ogl_dummy_object::RotateObject(p1, p2);
471 }
472 
RotateObject(const GLfloat * p1,const ogl_camera & p2)473 void ogl_transformer::RotateObject(const GLfloat * p1, const ogl_camera & p2)
474 {
475 	ogl_dummy_object::OrbitObject(p1, p2);
476 }
477 
478 /*################################################################################################*/
479 
ogl_transformer_client(void)480 ogl_transformer_client::ogl_transformer_client(void)
481 {
482 	tc_object_ref = NULL;
483 }
484 
~ogl_transformer_client(void)485 ogl_transformer_client::~ogl_transformer_client(void)
486 {
487 }
488 
489 /*################################################################################################*/
490 
491 // eof
492