]> icculus.org git repositories - taylor/freespace2.git/blob - src/render/3dsetup.cpp
added copyright header
[taylor/freespace2.git] / src / render / 3dsetup.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Render/3dSetup.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code to setup matrix instancing and viewers
16  *
17  * $Log$
18  * Revision 1.2  2002/06/09 04:41:25  relnev
19  * added copyright header
20  *
21  * Revision 1.1.1.1  2002/05/03 03:28:10  root
22  * Initial import.
23  *
24  * 
25  * 2     10/07/98 10:53a Dave
26  * Initial checkin.
27  * 
28  * 1     10/07/98 10:51a Dave
29  * 
30  * 23    5/24/98 11:32a John
31  * safely handled null vector being passed to start_user_clip_plane.
32  * 
33  * 22    3/18/98 4:53p John
34  * Fixed some bugs with docked ships warping out
35  * 
36  * 21    3/18/98 4:33p John
37  * Called vm_vec_normalize_safe to prevent assert from bogus docked
38  * objects.
39  * 
40  * 20    3/16/98 5:02p John
41  * Better comments
42  * 
43  * 19    3/16/98 4:51p John
44  * Added low-level code to clip all polygons against an arbritary plane.
45  * Took out all old model_interp_zclip and used this new method instead.  
46  * 
47  * 18    3/10/98 4:19p John
48  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
49  * & Glide have popups and print screen.  Took out all >8bpp software
50  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
51  * support Fred.  Made zbuffering key off of functions rather than one
52  * global variable.
53  * 
54  * 17    1/19/98 6:15p John
55  * Fixed all my Optimized Build compiler warnings
56  * 
57  * 16    11/24/97 12:04p John
58  * 
59  * 15    11/07/97 7:24p John
60  * changed lighting to take two ranges.
61  * In textest, added test code to draw nebulas
62  * 
63  * 14    10/29/97 5:05p John
64  * Changed dynamic lighting to only rotate and calculate lighting for
65  * point lights that are close to an object.  Changed lower framerate cap
66  * from 4 to .5.
67  * 
68  * 13    4/29/97 12:24p Adam
69  * JAS:   Added code for delayed point to vec.   Fixed some FRED
70  * sequencing problems with g3_start_frame / g3_end_frame.
71  * 
72  * 12    4/29/97 9:55a John
73  * 
74  * 11    4/08/97 5:18p John
75  * First rev of decent (dynamic, correct) lighting in FreeSpace.
76  * 
77  * 10    3/24/97 3:26p John
78  * Cleaned up and restructured model_collide code and fvi code.  In fvi
79  * made code that finds uvs work..  Added bm_get_pixel to BmpMan.
80  * 
81  * 9     3/10/97 2:25p John
82  * Made pofview zbuffer.   Made textest work with new model code.  Took
83  * out some unnecessary Asserts in the 3d clipper.
84  * 
85  * 
86  * 8     2/17/97 5:18p John
87  * Added a bunch of RCS headers to a bunch of old files that don't have
88  * them.
89  *
90  * $NoKeywords: $
91  */
92
93
94 #include "3dinternal.h"
95 #include "tmapper.h"
96 #include "2d.h"                 // Needed for w,h,aspect of canvas
97 #include "lighting.h"
98
99
100 matrix          View_matrix;            // The matrix to convert local coordinates to screen
101 vector          View_position;          // The offset to convert local coordinates to screen
102 matrix          Unscaled_matrix;        // View_matrix before scaling
103
104 matrix          Light_matrix;           // Used to rotate world points into current local coordinates
105 vector          Light_base;                     // Used to rotate world points into current local coordinates
106
107 matrix          Eye_matrix;                     // Where the viewer's eye is pointing in World coordinates
108 vector          Eye_position;           // Where the viewer's eye is at in World coordinates
109
110 float                   View_zoom;                      // The zoom factor
111
112 vector          Window_scale;           // Scaling for window aspect
113 vector          Matrix_scale;           // How the matrix is scaled, window_scale * zoom
114
115 int                     Canvas_width;           // The actual width
116 int                     Canvas_height;          // The actual height
117
118 float                   Canv_w2;                                // Canvas_width / 2
119 float                   Canv_h2;                                // Canvas_height / 2
120
121 //vertex buffers for polygon drawing and clipping
122 vertex * Vbuf0[TMAP_MAX_VERTS];
123 vertex * Vbuf1[TMAP_MAX_VERTS];
124
125 #define MAX_INSTANCE_DEPTH      5
126
127 struct instance_context {
128         matrix m;
129         vector p;
130         matrix lm;
131         vector lb;
132 } instance_stack[MAX_INSTANCE_DEPTH];
133
134 int instance_depth = 0;
135
136 int G3_count = 0;
137 int G3_frame_count = 0;
138
139 //start the frame
140 // Pass true for zbuffer_flag to turn on zbuffering
141 void g3_start_frame_func(int zbuffer_flag, char * filename, int lineno)
142 {
143         float s;
144         int width, height;
145         float aspect;
146
147 //Uncomment this to figure out who called g3_start_frame without calling g3_end_frame.
148 //      mprintf(( "g3_start_frame called from %s, line %d\n", filename, lineno ));
149
150         Assert( G3_count == 0 );
151         G3_count++;
152
153         // Clear any user-defined clip planes
154         g3_stop_user_clip_plane();
155
156         // Get the values from the 2d...
157         width = gr_screen.clip_width;
158         height = gr_screen.clip_height;
159         aspect = gr_screen.aspect;
160
161         //set int w,h & fixed-point w,h/2
162         Canvas_width = width;
163         Canv_w2 = (float)width / 2.0f;
164         Canvas_height = height;
165         Canv_h2 = (float)height / 2.0f;
166         
167         //compute aspect ratio for this canvas
168
169         s = aspect*(float)Canvas_height/(float)Canvas_width;
170
171         if (s <= 0) {           //scale x
172                 Window_scale.x = s;
173                 Window_scale.y = 1.0f;
174         }
175         else {
176                 Window_scale.y = 1.0f / s;
177                 Window_scale.x = 1.0f;
178         }
179         
180         Window_scale.z = 1.0f;          //always 1
181
182         init_free_points();
183
184         if (zbuffer_flag)       {
185                 gr_zbuffer_clear(TRUE);
186         } else {
187                 gr_zbuffer_clear(FALSE);
188         }
189
190         G3_frame_count++;
191
192         //init_interface_vars_to_assembler();           //for the texture-mapper
193
194 }
195
196 //this doesn't do anything, but is here for completeness
197 void g3_end_frame(void)
198 {
199         G3_count--;
200         Assert( G3_count == 0 );
201
202         free_point_num = 0;
203 //      Assert(free_point_num==0);
204 }
205
206
207 void scale_matrix(void);
208
209 //set view from x,y,z, viewer matrix, and zoom.  Must call one of g3_set_view_*()
210 void g3_set_view_matrix(vector *view_pos,matrix *view_matrix,float zoom)
211 {
212         Assert( G3_count == 1 );
213
214         View_zoom = zoom;
215         View_position = *view_pos;
216
217         View_matrix = *view_matrix;
218
219         Eye_matrix = View_matrix;
220         Eye_position = *view_pos;
221
222         scale_matrix();
223
224         Light_matrix = vmd_identity_matrix;
225         Light_base.x = 0.0f;
226         Light_base.y = 0.0f;
227         Light_base.z = 0.0f;
228
229 }
230
231
232 //set view from x,y,z & p,b,h, zoom.  Must call one of g3_set_view_*()
233 void g3_set_view_angles(vector *view_pos,angles *view_orient,float zoom)
234 {
235         matrix tmp;
236
237         Assert( G3_count == 1 );
238
239         vm_angles_2_matrix(&tmp,view_orient);
240         g3_set_view_matrix(view_pos,&tmp,zoom);
241 }
242
243
244 //performs aspect scaling on global view matrix
245 void scale_matrix(void)
246 {
247         Unscaled_matrix = View_matrix;          //so we can use unscaled if we want
248
249         Matrix_scale = Window_scale;
250
251         if (View_zoom <= 1.0)           //zoom in by scaling z
252
253                 Matrix_scale.z =  Matrix_scale.z*View_zoom;
254
255         else {                  //zoom out by scaling x&y
256
257                 float s = (float)1.0 / View_zoom;
258
259                 Matrix_scale.x = Matrix_scale.x*s;
260                 Matrix_scale.y = Matrix_scale.y*s;
261         }
262
263         //now scale matrix elements
264
265         vm_vec_scale(&View_matrix.rvec,Matrix_scale.x);
266         vm_vec_scale(&View_matrix.uvec,Matrix_scale.y);
267         vm_vec_scale(&View_matrix.fvec,Matrix_scale.z);
268
269 }
270
271 ubyte g3_rotate_vertex_popped(vertex *dest,vector *src)
272 {
273         vector tempv;
274
275         Assert( G3_count == 1 );
276
277         Assert( instance_depth > 0 );
278
279         vm_vec_sub(&tempv,src,&instance_stack[0].p);
280         vm_vec_rotate( (vector *)&dest->x, &tempv, &instance_stack[0].m );
281         dest->flags = 0;        //not projected
282         return g3_code_vertex(dest);
283 }       
284
285
286 //instance at specified point with specified orientation
287 //if matrix==NULL, don't modify matrix.  This will be like doing an offset   
288 //if pos==NULL, no position change
289 void g3_start_instance_matrix(vector *pos,matrix *orient)
290 {
291         vector tempv;
292         matrix tempm,tempm2;
293
294         Assert( G3_count == 1 );
295
296         Assert(instance_depth<MAX_INSTANCE_DEPTH);
297
298         instance_stack[instance_depth].m = View_matrix;
299         instance_stack[instance_depth].p = View_position;
300         instance_stack[instance_depth].lm = Light_matrix;
301         instance_stack[instance_depth].lb = Light_base;
302         instance_depth++;
303
304         // Make sure orient is valid
305         if (!orient) {
306                 orient = &vmd_identity_matrix;          // Assume no change in orient
307         }
308
309         if ( pos )      {
310                 //step 1: subtract object position from view position
311                 vm_vec_sub2(&View_position,pos);
312
313                 //step 2: rotate view vector through object matrix
314                 vm_vec_rotate(&tempv,&View_position,orient);
315                 View_position = tempv;
316         } else {
317                 // No movement, leave View_position alone
318         }
319
320         //step 3: rotate object matrix through view_matrix (vm = ob * vm)
321         vm_copy_transpose_matrix(&tempm2,orient);
322
323         vm_matrix_x_matrix(&tempm,&tempm2,&View_matrix);
324         View_matrix = tempm;
325
326
327         // Update the lighting matrix
328         matrix saved_orient = Light_matrix;
329         vector saved_base = Light_base;
330         
331         if ( pos )      {
332                 vm_vec_unrotate(&Light_base,pos,&saved_orient );
333                 vm_vec_add2(&Light_base, &saved_base );
334         } else {
335                 // No movement, light_base doesn't change.
336         }
337
338         vm_matrix_x_matrix(&Light_matrix,&saved_orient, orient);
339
340 }
341
342
343 //instance at specified point with specified orientation
344 //if angles==NULL, don't modify matrix.  This will be like doing an offset
345 void g3_start_instance_angles(vector *pos,angles *orient)
346 {
347         matrix tm;
348
349         Assert( G3_count == 1 );
350
351         if (orient==NULL) {
352                 g3_start_instance_matrix(pos,NULL);
353                 return;
354         }
355
356         vm_angles_2_matrix(&tm,orient);
357
358         g3_start_instance_matrix(pos,&tm);
359
360 }
361
362
363 //pops the old context
364 void g3_done_instance()
365 {
366         Assert( G3_count == 1 );
367
368         instance_depth--;
369
370         Assert(instance_depth >= 0);
371
372         View_position = instance_stack[instance_depth].p;
373         View_matrix = instance_stack[instance_depth].m;
374         Light_matrix = instance_stack[instance_depth].lm;
375         Light_base = instance_stack[instance_depth].lb;
376
377 }
378
379 int G3_user_clip = 0;
380 vector G3_user_clip_normal;
381 vector G3_user_clip_point;
382
383 // Enables clipping with an arbritary plane.   This will be on
384 // until g3_stop_clip_plane is called or until next frame.
385 // The points passed should be relative to the instance.  Probably
386 // that means world coordinates.
387 /*
388   This works like any other clip plane... if this is enabled and you
389 rotate a point, the CC_OFF_USER bit will be set in the clipping codes.
390 It is completely handled by most g3_draw primitives, except maybe lines.
391
392   As far as performance, when enabled, it will slow down each point
393 rotation (or g3_code_vertex call) by a vector subtraction and dot
394 product.   It won't slow anything down for polys that are completely
395 clipped on or off by the plane, and will slow each clipped polygon by
396 not much more than any other clipping we do.
397 */
398 void g3_start_user_clip_plane( vector *plane_point, vector *plane_normal )
399 {
400         float mag = vm_vec_mag( plane_normal );
401         if ( (mag < 0.1f) || (mag > 1.5f ) )    {
402                 // Invalid plane_normal passed in.  Get Allender (since it is
403                 // probably a ship warp in bug:) or John.   
404                 Int3();                 
405                 return;
406         }
407
408         G3_user_clip = 1;
409 //      G3_user_clip_normal = *plane_normal;
410 //      G3_user_clip_point = *plane_point;
411 //      return;
412
413         vm_vec_rotate(&G3_user_clip_normal, plane_normal, &View_matrix );
414         vm_vec_normalize(&G3_user_clip_normal);
415
416         vector tempv;
417         vm_vec_sub(&tempv,plane_point,&View_position);
418         vm_vec_rotate(&G3_user_clip_point,&tempv,&View_matrix );
419 }
420
421 // Stops arbritary plane clipping
422 void g3_stop_user_clip_plane()
423 {
424         G3_user_clip = 0;
425 }
426
427 // Returns TRUE if point is behind user plane
428 int g3_point_behind_user_plane( vector *pnt )
429 {
430         if ( G3_user_clip ) {
431                 vector tmp;
432                 vm_vec_sub( &tmp, pnt, &G3_user_clip_point );
433                 if ( vm_vec_dot( &tmp, &G3_user_clip_normal ) <= 0.0f ) {
434                         return 1;
435                 }
436         }
437
438         return 0;
439 }
440
441
442
443