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