2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Render/3dSetup.cpp $
15 * Code to setup matrix instancing and viewers
18 * Revision 1.2 2002/06/09 04:41:25 relnev
19 * added copyright header
21 * Revision 1.1.1.1 2002/05/03 03:28:10 root
25 * 2 10/07/98 10:53a Dave
28 * 1 10/07/98 10:51a Dave
30 * 23 5/24/98 11:32a John
31 * safely handled null vector being passed to start_user_clip_plane.
33 * 22 3/18/98 4:53p John
34 * Fixed some bugs with docked ships warping out
36 * 21 3/18/98 4:33p John
37 * Called vm_vec_normalize_safe to prevent assert from bogus docked
40 * 20 3/16/98 5:02p John
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.
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
54 * 17 1/19/98 6:15p John
55 * Fixed all my Optimized Build compiler warnings
57 * 16 11/24/97 12:04p John
59 * 15 11/07/97 7:24p John
60 * changed lighting to take two ranges.
61 * In textest, added test code to draw nebulas
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
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.
72 * 12 4/29/97 9:55a John
74 * 11 4/08/97 5:18p John
75 * First rev of decent (dynamic, correct) lighting in FreeSpace.
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.
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.
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
94 #include "3dinternal.h"
96 #include "2d.h" // Needed for w,h,aspect of canvas
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
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
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
110 float View_zoom; // The zoom factor
112 vector Window_scale; // Scaling for window aspect
113 vector Matrix_scale; // How the matrix is scaled, window_scale * zoom
115 int Canvas_width; // The actual width
116 int Canvas_height; // The actual height
118 float Canv_w2; // Canvas_width / 2
119 float Canv_h2; // Canvas_height / 2
121 //vertex buffers for polygon drawing and clipping
122 vertex * Vbuf0[TMAP_MAX_VERTS];
123 vertex * Vbuf1[TMAP_MAX_VERTS];
125 #define MAX_INSTANCE_DEPTH 5
127 struct instance_context {
132 } instance_stack[MAX_INSTANCE_DEPTH];
134 int instance_depth = 0;
137 int G3_frame_count = 0;
140 // Pass true for zbuffer_flag to turn on zbuffering
141 void g3_start_frame_func(int zbuffer_flag, char * filename, int lineno)
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 ));
150 Assert( G3_count == 0 );
153 // Clear any user-defined clip planes
154 g3_stop_user_clip_plane();
156 // Get the values from the 2d...
157 width = gr_screen.clip_width;
158 height = gr_screen.clip_height;
159 aspect = gr_screen.aspect;
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;
167 //compute aspect ratio for this canvas
169 s = aspect*(float)Canvas_height/(float)Canvas_width;
171 if (s <= 0) { //scale x
173 Window_scale.y = 1.0f;
176 Window_scale.y = 1.0f / s;
177 Window_scale.x = 1.0f;
180 Window_scale.z = 1.0f; //always 1
185 gr_zbuffer_clear(TRUE);
187 gr_zbuffer_clear(FALSE);
192 //init_interface_vars_to_assembler(); //for the texture-mapper
196 //this doesn't do anything, but is here for completeness
197 void g3_end_frame(void)
200 Assert( G3_count == 0 );
203 // Assert(free_point_num==0);
207 void scale_matrix(void);
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)
212 Assert( G3_count == 1 );
215 View_position = *view_pos;
217 View_matrix = *view_matrix;
219 Eye_matrix = View_matrix;
220 Eye_position = *view_pos;
224 Light_matrix = vmd_identity_matrix;
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)
237 Assert( G3_count == 1 );
239 vm_angles_2_matrix(&tmp,view_orient);
240 g3_set_view_matrix(view_pos,&tmp,zoom);
244 //performs aspect scaling on global view matrix
245 void scale_matrix(void)
247 Unscaled_matrix = View_matrix; //so we can use unscaled if we want
249 Matrix_scale = Window_scale;
251 if (View_zoom <= 1.0) //zoom in by scaling z
253 Matrix_scale.z = Matrix_scale.z*View_zoom;
255 else { //zoom out by scaling x&y
257 float s = (float)1.0 / View_zoom;
259 Matrix_scale.x = Matrix_scale.x*s;
260 Matrix_scale.y = Matrix_scale.y*s;
263 //now scale matrix elements
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);
271 ubyte g3_rotate_vertex_popped(vertex *dest,vector *src)
275 Assert( G3_count == 1 );
277 Assert( instance_depth > 0 );
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);
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)
294 Assert( G3_count == 1 );
296 Assert(instance_depth<MAX_INSTANCE_DEPTH);
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;
304 // Make sure orient is valid
306 orient = &vmd_identity_matrix; // Assume no change in orient
310 //step 1: subtract object position from view position
311 vm_vec_sub2(&View_position,pos);
313 //step 2: rotate view vector through object matrix
314 vm_vec_rotate(&tempv,&View_position,orient);
315 View_position = tempv;
317 // No movement, leave View_position alone
320 //step 3: rotate object matrix through view_matrix (vm = ob * vm)
321 vm_copy_transpose_matrix(&tempm2,orient);
323 vm_matrix_x_matrix(&tempm,&tempm2,&View_matrix);
327 // Update the lighting matrix
328 matrix saved_orient = Light_matrix;
329 vector saved_base = Light_base;
332 vm_vec_unrotate(&Light_base,pos,&saved_orient );
333 vm_vec_add2(&Light_base, &saved_base );
335 // No movement, light_base doesn't change.
338 vm_matrix_x_matrix(&Light_matrix,&saved_orient, orient);
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)
349 Assert( G3_count == 1 );
352 g3_start_instance_matrix(pos,NULL);
356 vm_angles_2_matrix(&tm,orient);
358 g3_start_instance_matrix(pos,&tm);
363 //pops the old context
364 void g3_done_instance()
366 Assert( G3_count == 1 );
370 Assert(instance_depth >= 0);
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;
379 int G3_user_clip = 0;
380 vector G3_user_clip_normal;
381 vector G3_user_clip_point;
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.
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.
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.
398 void g3_start_user_clip_plane( vector *plane_point, vector *plane_normal )
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.
409 // G3_user_clip_normal = *plane_normal;
410 // G3_user_clip_point = *plane_point;
413 vm_vec_rotate(&G3_user_clip_normal, plane_normal, &View_matrix );
414 vm_vec_normalize(&G3_user_clip_normal);
417 vm_vec_sub(&tempv,plane_point,&View_position);
418 vm_vec_rotate(&G3_user_clip_point,&tempv,&View_matrix );
421 // Stops arbritary plane clipping
422 void g3_stop_user_clip_plane()
427 // Returns TRUE if point is behind user plane
428 int g3_point_behind_user_plane( vector *pnt )
430 if ( G3_user_clip ) {
432 vm_vec_sub( &tmp, pnt, &G3_user_clip_point );
433 if ( vm_vec_dot( &tmp, &G3_user_clip_normal ) <= 0.0f ) {