Starshatter_Open
Open source Starshatter engine
Main Page
Classes
Files
File List
File Members
All
Classes
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Friends
Macros
Projector.cpp
Go to the documentation of this file.
1
/* Project nGenEx
2
Destroyer Studios LLC
3
Copyright © 1997-2004. All Rights Reserved.
4
5
SUBSYSTEM: nGenEx.lib
6
FILE: Projector.cpp
7
AUTHOR: John DiCamillo
8
9
10
OVERVIEW
11
========
12
3D Projection Camera class
13
*/
14
15
#include "
MemDebug.h
"
16
#include "
Projector.h
"
17
18
// +--------------------------------------------------------------------+
19
20
static
const
float
CLIP_PLANE_EPSILON = 0.0001f;
21
static
const
double
Z_NEAR = 1.0;
22
23
void
Print
(
const
char
* fmt, ...);
24
25
// +--------------------------------------------------------------------+
26
27
static
Camera
emergency_cam;
28
29
// +--------------------------------------------------------------------+
30
31
Projector::Projector
(
Window
* window,
Camera
* cam)
32
: camera(cam), infinite(0), depth_scale(1.0f), orthogonal(false), field_of_view(2)
33
{
34
if
(!
camera
)
35
camera
= &emergency_cam;
36
37
UseWindow
(window);
38
}
39
40
Projector::~Projector
()
41
{ }
42
43
// +--------------------------------------------------------------------+
44
45
void
46
Projector::UseCamera
(
Camera
* cam)
47
{
48
if
(cam)
49
camera
= cam;
50
else
51
camera
= &emergency_cam;
52
}
53
54
void
55
Projector::UseWindow
(
Window
* win)
56
{
57
Rect
r = win->
GetRect
();
58
width
= r.
w
;
59
height
= r.
h
;
60
61
xcenter
= (
width
/ 2.0);
62
ycenter
= (
height
/ 2.0);
63
64
xclip0
= 0.0f;
65
xclip1
= (float)
width
-0.5f;
66
yclip0
= 0.0f;
67
yclip1
= (float)
height
-0.5f;
68
69
SetFieldOfView
(
field_of_view
);
70
}
71
72
void
73
Projector::SetFieldOfView
(
double
fov)
74
{
75
field_of_view
= fov;
76
77
xscreenscale
=
width
/ fov;
78
yscreenscale
=
height
/ fov;
79
80
maxscale
= max(
xscreenscale
,
yscreenscale
);
81
82
xangle
= atan(2.0/fov *
maxscale
/
xscreenscale
);
83
yangle
= atan(2.0/fov *
maxscale
/
yscreenscale
);
84
}
85
86
double
87
Projector::GetFieldOfView
()
const
88
{
89
return
field_of_view
;
90
}
91
92
void
93
Projector::SetDepthScale
(
float
scale)
94
{
95
depth_scale
= scale;
96
}
97
98
double
99
Projector::GetDepthScale
()
const
100
{
101
return
depth_scale
;
102
}
103
104
int
105
Projector::SetInfinite
(
int
i)
106
{
107
int
old =
infinite
;
108
infinite
= i;
109
return
old;
110
}
111
112
// +--------------------------------------------------------------------+
113
114
void
115
Projector::StartFrame
()
116
{
117
SetUpFrustum
();
118
SetWorldSpace
();
119
}
120
121
// +--------------------------------------------------------------------+
122
// Transform a point from worldspace to viewspace.
123
// +--------------------------------------------------------------------+
124
125
void
126
Projector::Transform
(
Vec3
& vec)
const
127
{
128
Vec3
tvert = vec;
129
130
// Translate into a viewpoint-relative coordinate
131
if
(!
infinite
)
132
tvert -=
camera
->
Pos
();
133
134
// old method:
135
vec.
x
= (tvert *
camera
->
vrt
());
136
vec.
y
= (tvert *
camera
->
vup
());
137
vec.
z
= (tvert *
camera
->
vpn
());
138
139
// Rotate into the view orientation
140
// vec = tvert * camera->Orientation();
141
}
142
143
// +--------------------------------------------------------------------+
144
// Transform a point from worldspace to viewspace.
145
// +--------------------------------------------------------------------+
146
147
void
148
Projector::Transform
(
Point
& point)
const
149
{
150
Point
tvert = point;
151
152
// Translate into a viewpoint-relative coordinate
153
if
(!
infinite
)
154
tvert -=
camera
->
Pos
();
155
156
// old method:
157
point.
x
= (tvert *
camera
->
vrt
());
158
point.
y
= (tvert *
camera
->
vup
());
159
point.
z
= (tvert *
camera
->
vpn
());
160
161
// Rotate into the view orientation
162
// point = tvert * camera->Orientation();
163
}
164
165
// +--------------------------------------------------------------------+
166
// APPARENT RADIUS OF PROJECTED OBJECT
167
// Project a viewspace point into screen coordinates.
168
// Use projected Z to determine apparent radius of object.
169
// +--------------------------------------------------------------------+
170
171
float
172
Projector::ProjectRadius
(
const
Vec3
& v,
float
radius)
const
173
{
174
return
(
float
) fabs((radius *
maxscale
) / v.
z
);
175
}
176
177
// +--------------------------------------------------------------------+
178
// IN PLACE PROJECTION OF POINT
179
// Project a viewspace point into screen coordinates.
180
// Note that the y axis goes up in worldspace and viewspace, but
181
// goes down in screenspace.
182
// +--------------------------------------------------------------------+
183
184
void
185
Projector::Project
(
Vec3
& v,
bool
clamp
)
const
186
{
187
double
zrecip;
188
189
if
(
orthogonal
) {
190
double
scale =
field_of_view
/2;
191
v.
x
= (float) (
xcenter
+ scale * v.
x
);
192
v.
y
= (float) (
height
- (
ycenter
+ scale * v.
y
));
193
v.
z
= (float) (0.0f);
194
}
195
196
else
{
197
//zrecip = 2 * (1.0e5 / (1.0e5-1)) / v.z;
198
//zrecip = 2 * 0.97 / v.z; -- what the heck was this version used for?
199
200
zrecip = 2 / v.
z
;
201
v.
x
= (float) (
xcenter
+
maxscale
* v.
x
* zrecip);
202
v.
y
= (float) (
height
- (
ycenter
+
maxscale
* v.
y
* zrecip));
203
v.
z
= (float) (1 - zrecip);
204
}
205
206
// clamp the point to the viewport:
207
if
(clamp) {
208
if
(v.
x
<
xclip0
) v.
x
=
xclip0
;
209
if
(v.
x
>
xclip1
) v.
x
=
xclip1
;
210
if
(v.
y
<
yclip0
) v.
y
=
yclip0
;
211
if
(v.
y
>
yclip1
) v.
y
=
yclip1
;
212
}
213
}
214
215
// +--------------------------------------------------------------------+
216
// IN PLACE PROJECTION OF POINT
217
// Project a viewspace point into screen coordinates.
218
// Note that the y axis goes up in worldspace and viewspace, but
219
// goes down in screenspace.
220
// +--------------------------------------------------------------------+
221
222
void
223
Projector::Project
(
Point
& v,
bool
clamp
)
const
224
{
225
double
zrecip;
226
227
if
(
orthogonal
) {
228
double
scale =
field_of_view
/2;
229
v.
x
= (
xcenter
+ scale * v.
x
);
230
v.
y
= (
height
- (
ycenter
+ scale * v.
y
));
231
v.
z
= 0;
232
}
233
234
else
{
235
zrecip = 1 / v.
z
;
236
v.
x
= (
xcenter
+ 2 *
maxscale
* v.
x
* zrecip);
237
v.
y
= (
height
- (
ycenter
+ 2 *
maxscale
* v.
y
* zrecip));
238
v.
z
= (1 - zrecip);
239
}
240
241
// clamp the point to the viewport:
242
if
(clamp) {
243
if
(v.
x
<
xclip0
) v.
x
=
xclip0
;
244
if
(v.
x
>
xclip1
) v.
x
=
xclip1
;
245
if
(v.
y
<
yclip0
) v.
y
=
yclip0
;
246
if
(v.
y
>
yclip1
) v.
y
=
yclip1
;
247
}
248
}
249
250
// +--------------------------------------------------------------------+
251
// IN PLACE UN-PROJECTION OF POINT
252
// Convert a point in screen coordinates back to viewspace.
253
// Note that the y axis goes up in worldspace and viewspace, but
254
// goes down in screenspace.
255
// +--------------------------------------------------------------------+
256
257
void
258
Projector::Unproject
(
Point
& v)
const
259
{
260
double
zrecip = 1 / v.
z
;
261
262
/***
263
* forward projection:
264
v.x = (xcenter + maxscale * v.x * zrecip);
265
v.y = (height - (ycenter + maxscale * v.y * zrecip));
266
v.z = (1 - zrecip);
267
***/
268
269
v.
x
= ( v.
x
-
xcenter
) / (
maxscale
* zrecip);
270
v.
y
= (
height
- v.
y
-
ycenter
) / (
maxscale
* zrecip);
271
}
272
273
// +--------------------------------------------------------------------+
274
// IN PLACE PROJECTION OF RECTANGLE (FOR SPRITES)
275
// Project a viewspace point into screen coordinates.
276
// Note that the y axis goes up in worldspace and viewspace, but
277
// goes down in screenspace.
278
// +--------------------------------------------------------------------+
279
280
void
281
Projector::ProjectRect
(
Point
& v,
double
& w,
double
& h)
const
282
{
283
double
zrecip;
284
285
if
(
orthogonal
) {
286
double
scale =
field_of_view
/2;
287
v.
x
= (
xcenter
+ scale * v.
x
);
288
v.
y
= (
height
- (
ycenter
+ scale * v.
y
));
289
v.
z
= 0;
290
}
291
292
else
{
293
zrecip = 1 / v.
z
;
294
v.
x
= (
xcenter
+ 2 *
maxscale
* v.
x
* zrecip);
295
v.
y
= (
height
- (
ycenter
+ 2 *
maxscale
* v.
y
* zrecip));
296
v.
z
= (1 - Z_NEAR*zrecip);
297
298
w *=
maxscale
* zrecip;
299
h *=
maxscale
* zrecip;
300
}
301
}
302
303
// +--------------------------------------------------------------------+
304
// Set up a clip plane with the specified normal.
305
// +--------------------------------------------------------------------+
306
307
void
308
Projector::SetWorldspaceClipPlane
(
Vec3
& normal,
Plane
& plane)
309
{
310
// Rotate the plane normal into worldspace
311
ViewToWorld
(normal, plane.
normal
);
312
plane.
distance
= (float) (
camera
->
Pos
() * plane.
normal
+ CLIP_PLANE_EPSILON);
313
}
314
315
// +--------------------------------------------------------------------+
316
// Set up the planes of the frustum, in worldspace coordinates.
317
// +--------------------------------------------------------------------+
318
319
void
320
Projector::SetUpFrustum
()
321
{
322
double
angle, s, c;
323
Vec3
normal;
324
325
angle =
XAngle
();
326
s = sin(angle);
327
c = cos(angle);
328
329
// Left clip plane
330
normal.
x
= (float) s;
331
normal.
y
= (float) 0;
332
normal.
z
= (float) c;
333
view_planes
[0].
normal
= normal;
334
view_planes
[0].
distance
= CLIP_PLANE_EPSILON;
335
SetWorldspaceClipPlane
(normal,
world_planes
[0]);
336
337
// Right clip plane
338
normal.
x
= (float) -s;
339
view_planes
[1].
normal
= normal;
340
view_planes
[1].
distance
= CLIP_PLANE_EPSILON;
341
SetWorldspaceClipPlane
(normal,
world_planes
[1]);
342
343
angle =
YAngle
();
344
s = sin(angle);
345
c = cos(angle);
346
347
// Bottom clip plane
348
normal.
x
= (float) 0;
349
normal.
y
= (float) s;
350
normal.
z
= (float) c;
351
view_planes
[2].
normal
= normal;
352
view_planes
[2].
distance
= CLIP_PLANE_EPSILON;
353
SetWorldspaceClipPlane
(normal,
world_planes
[2]);
354
355
// Top clip plane
356
normal.
y
= (float) -s;
357
view_planes
[3].
normal
= normal;
358
view_planes
[3].
distance
= CLIP_PLANE_EPSILON;
359
SetWorldspaceClipPlane
(normal,
world_planes
[3]);
360
}
361
362
// +--------------------------------------------------------------------+
363
// Clip the point against the frustum and return 1 if partially inside
364
// Return 2 if completely inside
365
// +--------------------------------------------------------------------+
366
367
int
368
Projector::IsVisible
(
const
Vec3
& v,
float
radius)
const
369
{
370
int
visible = 1;
371
int
complete = 1;
372
373
Plane
* plane = (
Plane
*)
frustum_planes
;
374
if
(
infinite
) {
375
complete = 0;
376
377
for
(
int
i = 0; visible && (i <
NUM_FRUSTUM_PLANES
); i++) {
378
visible = ((v * plane->
normal
) >= CLIP_PLANE_EPSILON);
379
plane++;
380
}
381
}
382
else
{
383
for
(
int
i = 0; visible && (i <
NUM_FRUSTUM_PLANES
); i++) {
384
float
dot = v * plane->
normal
;
385
visible = ((dot + radius) >= plane->
distance
);
386
complete = complete && ((dot - radius) >= plane->
distance
);
387
plane++;
388
}
389
}
390
391
return
visible + complete;
392
}
393
394
// +--------------------------------------------------------------------+
395
// Clip the bouding point against the frustum and return non zero
396
// if at least partially inside. This version is not terribly
397
// efficient as it checks all eight box corners rather than just
398
// the minimum two.
399
// +--------------------------------------------------------------------+
400
401
int
402
Projector::IsBoxVisible
(
const
Point
* p)
const
403
{
404
int
i, j, outside = 0;
405
406
// if all eight corners are outside of the same
407
// frustrum plane, then the box is not visible
408
Plane
* plane = (
Plane
*)
frustum_planes
;
409
410
if
(
infinite
) {
411
for
(i = 0; !outside && (i <
NUM_FRUSTUM_PLANES
); i++) {
412
for
(j = 0; j < 8; j++)
413
outside += (p[j] * plane->
normal
) < CLIP_PLANE_EPSILON;
414
415
if
(outside < 8)
416
outside = 0;
417
418
plane++;
419
}
420
}
421
else
{
422
for
(i = 0; !outside && (i <
NUM_FRUSTUM_PLANES
); i++) {
423
for
(j = 0; j < 8; j++)
424
outside += (p[j] * plane->
normal
) < plane->
distance
;
425
426
if
(outside < 8)
427
outside = 0;
428
429
plane++;
430
}
431
}
432
433
// if not outside, then the box is visible
434
return
!outside;
435
}
436
437
// +--------------------------------------------------------------------+
438
439
float
440
Projector::ApparentRadius
(
const
Vec3
& v,
float
radius)
const
441
{
442
Vec3
vloc = v;
443
444
Transform
(vloc);
// transform in place
445
return
ProjectRadius
(vloc, radius);
446
}
447
448
449
// +--------------------------------------------------------------------+
450
// Rotate a vector from viewspace to worldspace.
451
// +--------------------------------------------------------------------+
452
453
void
454
Projector::ViewToWorld
(
Point
& pin,
Point
& pout)
455
{
456
// Rotate into the world orientation
457
pout.
x
= pin.
x
*
camera
->
vrt
().
x
+ pin.
y
*
camera
->
vup
().
x
+ pin.
z
*
camera
->
vpn
().
x
;
458
pout.
y
= pin.
x
*
camera
->
vrt
().
y
+ pin.
y
*
camera
->
vup
().
y
+ pin.
z
*
camera
->
vpn
().
y
;
459
pout.
z
= pin.
x
*
camera
->
vrt
().
z
+ pin.
y
*
camera
->
vup
().
z
+ pin.
z
*
camera
->
vpn
().
z
;
460
}
461
462
void
463
Projector::ViewToWorld
(
Vec3
& vin,
Vec3
& vout)
464
{
465
// Rotate into the world orientation
466
vout.
x
= (float) (vin.
x
*
camera
->
vrt
().
x
+ vin.
y
*
camera
->
vup
().
x
+ vin.
z
*
camera
->
vpn
().
x
);
467
vout.
y
= (float) (vin.
x
*
camera
->
vrt
().
y
+ vin.
y
*
camera
->
vup
().
y
+ vin.
z
*
camera
->
vpn
().
y
);
468
vout.
z
= (float) (vin.
x
*
camera
->
vrt
().
z
+ vin.
y
*
camera
->
vup
().
z
+ vin.
z
*
camera
->
vpn
().
z
);
469
}
470
nGenEx
Projector.cpp
Generated on Thu May 31 2012 16:30:58 for Starshatter_Open by
1.8.1