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