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.3 2002/06/17 06:33:10 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.2 2002/06/09 04:41:25 relnev
22 * added copyright header
24 * Revision 1.1.1.1 2002/05/03 03:28:10 root
28 * 2 10/07/98 10:53a Dave
31 * 1 10/07/98 10:51a Dave
33 * 23 5/24/98 11:32a John
34 * safely handled null vector being passed to start_user_clip_plane.
36 * 22 3/18/98 4:53p John
37 * Fixed some bugs with docked ships warping out
39 * 21 3/18/98 4:33p John
40 * Called vm_vec_normalize_safe to prevent assert from bogus docked
43 * 20 3/16/98 5:02p John
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.
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
57 * 17 1/19/98 6:15p John
58 * Fixed all my Optimized Build compiler warnings
60 * 16 11/24/97 12:04p John
62 * 15 11/07/97 7:24p John
63 * changed lighting to take two ranges.
64 * In textest, added test code to draw nebulas
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
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.
75 * 12 4/29/97 9:55a John
77 * 11 4/08/97 5:18p John
78 * First rev of decent (dynamic, correct) lighting in FreeSpace.
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.
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.
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
97 #include "3dinternal.h"
99 #include "2d.h" // Needed for w,h,aspect of canvas
100 #include "lighting.h"
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
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
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
113 float View_zoom; // The zoom factor
115 vector Window_scale; // Scaling for window aspect
116 vector Matrix_scale; // How the matrix is scaled, window_scale * zoom
118 int Canvas_width; // The actual width
119 int Canvas_height; // The actual height
121 float Canv_w2; // Canvas_width / 2
122 float Canv_h2; // Canvas_height / 2
124 //vertex buffers for polygon drawing and clipping
125 vertex * Vbuf0[TMAP_MAX_VERTS];
126 vertex * Vbuf1[TMAP_MAX_VERTS];
128 #define MAX_INSTANCE_DEPTH 5
130 struct instance_context {
135 } instance_stack[MAX_INSTANCE_DEPTH];
137 int instance_depth = 0;
140 int G3_frame_count = 0;
143 // Pass true for zbuffer_flag to turn on zbuffering
144 void g3_start_frame_func(int zbuffer_flag, const char * filename, int lineno)
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 ));
153 SDL_assert( G3_count == 0 );
156 // Clear any user-defined clip planes
157 g3_stop_user_clip_plane();
159 // Get the values from the 2d...
160 width = gr_screen.clip_width;
161 height = gr_screen.clip_height;
162 aspect = gr_screen.aspect;
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;
170 //compute aspect ratio for this canvas
172 s = aspect*(float)Canvas_height/(float)Canvas_width;
174 if (s <= 0) { //scale x
175 Window_scale.xyz.x = s;
176 Window_scale.xyz.y = 1.0f;
179 Window_scale.xyz.y = 1.0f / s;
180 Window_scale.xyz.x = 1.0f;
183 Window_scale.xyz.z = 1.0f; //always 1
188 gr_zbuffer_clear(TRUE);
190 gr_zbuffer_clear(FALSE);
195 //init_interface_vars_to_assembler(); //for the texture-mapper
199 //this doesn't do anything, but is here for completeness
200 void g3_end_frame(void)
203 SDL_assert( G3_count == 0 );
206 // SDL_assert(free_point_num==0);
210 void scale_matrix(void);
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)
215 SDL_assert( G3_count == 1 );
218 View_position = *view_pos;
220 View_matrix = *view_matrix;
222 Eye_matrix = View_matrix;
223 Eye_position = *view_pos;
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;
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)
240 SDL_assert( G3_count == 1 );
242 vm_angles_2_matrix(&tmp,view_orient);
243 g3_set_view_matrix(view_pos,&tmp,zoom);
247 //performs aspect scaling on global view matrix
248 void scale_matrix(void)
250 Unscaled_matrix = View_matrix; //so we can use unscaled if we want
252 Matrix_scale = Window_scale;
254 if (View_zoom <= 1.0) //zoom in by scaling z
256 Matrix_scale.xyz.z = Matrix_scale.xyz.z*View_zoom;
258 else { //zoom out by scaling x&y
260 float s = (float)1.0 / View_zoom;
262 Matrix_scale.xyz.x = Matrix_scale.xyz.x*s;
263 Matrix_scale.xyz.y = Matrix_scale.xyz.y*s;
266 //now scale matrix elements
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);
273 ubyte g3_rotate_vertex_popped(vertex *dest,vector *src)
277 SDL_assert( G3_count == 1 );
279 SDL_assert( instance_depth > 0 );
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);
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)
296 SDL_assert( G3_count == 1 );
298 SDL_assert(instance_depth<MAX_INSTANCE_DEPTH);
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;
306 // Make sure orient is valid
308 orient = &vmd_identity_matrix; // Assume no change in orient
312 //step 1: subtract object position from view position
313 vm_vec_sub2(&View_position,pos);
315 //step 2: rotate view vector through object matrix
316 vm_vec_rotate(&tempv,&View_position,orient);
317 View_position = tempv;
319 // No movement, leave View_position alone
322 //step 3: rotate object matrix through view_matrix (vm = ob * vm)
323 vm_copy_transpose_matrix(&tempm2,orient);
325 vm_matrix_x_matrix(&tempm,&tempm2,&View_matrix);
329 // Update the lighting matrix
330 matrix saved_orient = Light_matrix;
331 vector saved_base = Light_base;
334 vm_vec_unrotate(&Light_base,pos,&saved_orient );
335 vm_vec_add2(&Light_base, &saved_base );
337 // No movement, light_base doesn't change.
340 vm_matrix_x_matrix(&Light_matrix,&saved_orient, orient);
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)
351 SDL_assert( G3_count == 1 );
354 g3_start_instance_matrix(pos,NULL);
358 vm_angles_2_matrix(&tm,orient);
360 g3_start_instance_matrix(pos,&tm);
365 //pops the old context
366 void g3_done_instance()
368 SDL_assert( G3_count == 1 );
372 SDL_assert(instance_depth >= 0);
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;
381 int G3_user_clip = 0;
382 vector G3_user_clip_normal;
383 vector G3_user_clip_point;
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.
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.
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.
400 void g3_start_user_clip_plane( vector *plane_point, vector *plane_normal )
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.
411 // G3_user_clip_normal = *plane_normal;
412 // G3_user_clip_point = *plane_point;
415 vm_vec_rotate(&G3_user_clip_normal, plane_normal, &View_matrix );
416 vm_vec_normalize(&G3_user_clip_normal);
419 vm_vec_sub(&tempv,plane_point,&View_position);
420 vm_vec_rotate(&G3_user_clip_point,&tempv,&View_matrix );
423 // Stops arbritary plane clipping
424 void g3_stop_user_clip_plane()
429 // Returns TRUE if point is behind user plane
430 int g3_point_behind_user_plane( vector *pnt )
432 if ( G3_user_clip ) {
434 vm_vec_sub( &tmp, pnt, &G3_user_clip_point );
435 if ( vm_vec_dot( &tmp, &G3_user_clip_normal ) <= 0.0f ) {