Files
fs2open.github.com/code/render/3dsetup.cpp
T

604 lines
17 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
/*
* $Logfile: /Freespace2/code/Render/3dSetup.cpp $
* $Revision: 2.22.2.1 $
* $Date: 2006-10-01 19:31:19 $
* $Author: taylor $
*
* Code to setup matrix instancing and viewers
*
* $Log: not supported by cvs2svn $
* Revision 2.22 2006/05/13 07:09:25 taylor
* minor cleanup and a couple extra error checks
* get rid of some wasteful math from the gr_set_proj_matrix() calls
*
* Revision 2.21 2006/03/18 10:23:46 taylor
* make the main vital TMAP_MAX_VERTS stuff dynamic, should handle the major non-HTL related crashes
*
* Revision 2.20 2005/04/05 05:53:24 taylor
* s/vector/vec3d/g, better support for different compilers (Jens Granseuer)
*
* Revision 2.19 2005/01/28 11:06:22 Goober5000
* changed a bunch of transpose-rotate sequences to use unrotate instead
* --Goober5000
*
* Revision 2.18 2004/10/09 17:54:32 taylor
* better debugging for g3_end_frame() - mostly for FRED2
*
* Revision 2.17 2004/07/26 20:47:50 Kazan
* remove MCD complete
*
* Revision 2.16 2004/07/12 16:33:04 Kazan
* MCD - define _MCD_CHECK to use memory tracking
*
* Revision 2.15 2004/02/13 04:17:14 randomtiger
* Turned off fog in OGL for Fred.
* Simulated speech doesn't say tags marked by $ now.
* The following are fixes to issues that came up testing TBP in fs2_open and fred2_open:
* Changed vm_vec_mag and parse_tmap to fail gracefully on bad data.
* Error now given on missing briefing icon and bad ship normal data.
* Solved more species divide by zero error.
* Fixed neb cube crash.
*
* Revision 2.14 2004/01/17 21:59:54 randomtiger
* Some small changes to the main codebase that allow Fred_open OGL to compile.
*
* Revision 2.13 2003/11/16 04:09:27 Goober5000
* language
*
* Revision 2.12 2003/11/11 18:04:06 phreak
* made g3_done_instance take a parameter that decides wether to pop the matrix stack.
* without it, underflows would have been caused
*
* Revision 2.11 2003/11/11 03:56:12 bobboau
* lots of bug fixing, much of it in nebula and bitmap drawing
*
* Revision 2.10 2003/11/06 22:49:22 phreak
* fixed up some of the matrix functions that were causing problems
* bob: i there is an important change here. i don't know if its going to cause any d3d problems
*
* Revision 2.9 2003/11/01 21:59:22 bobboau
* new matrix handeling code, and fixed some problems with 3D lit verts,
* several other small fixes
*
* Revision 2.8 2003/10/25 06:56:06 bobboau
* adding FOF stuff,
* and fixed a small error in the matrix code,
* I told you it was indeed suposed to be gr_start_instance_matrix
* in g3_done_instance,
* g3_start_instance_angles needs to have an gr_ API abstraction version of it made
*
* Revision 2.7 2003/10/25 03:27:21 phreak
* fixed some old bugs that reappeared after RT committed his texture code
*
* Revision 2.6 2003/10/23 18:03:24 randomtiger
* Bobs changes (take 2)
*
* Revision 2.5 2003/10/14 17:39:18 randomtiger
* Implemented hardware fog for the HT&L code path.
* It doesn't use the backgrounds anymore but it's still an improvement.
* Currently it fogs to a brighter colour than it should because of Bob specular code.
* I will fix this after discussing it with Bob.
*
* Also tided up some D3D stuff, a cmdline variable name and changed a small bit of
* the htl code to use the existing D3D engine instead of work around it.
* And added extra information in version number on bottom left of frontend screen.
*
* Revision 2.4 2003/10/10 03:59:41 matt
* Added -nohtl command line param to disable HT&L, nothing is IFDEFd
* out now. -Sticks
*
* Revision 2.3 2003/09/26 14:37:15 bobboau
* commiting Hardware T&L code, everything is ifdefed out with the compile flag HTL
* still needs a lot of work, ubt the frame rates were getting with it are incredable
* the biggest problem it still has is a bad lightmanegment system, and the zbuffer
* doesn't work well with things still getting rendered useing the sofware pipeline, like thrusters,
* and weapons, I think these should be modifyed to be sent through hardware,
* it would be slightly faster and it would likely fix the problem
*
* also the thruster glow/particle stuff I did is now in.
*
* Revision 2.2 2003/08/09 06:07:24 bobboau
* slightly better implementation of the new zbuffer thing, it now checks only three diferent formats defalting to the 16 bit if neither the 24 or 32 bit versions are suported
*
* Revision 2.1 2002/08/01 01:41:09 penguin
* The big include file move
*
* Revision 2.0 2002/06/03 04:02:28 penguin
* Warpcore CVS sync
*
* Revision 1.2 2002/05/04 04:52:22 mharris
* 1st draft at porting
*
* Revision 1.1 2002/05/02 18:03:12 mharris
* Initial checkin - converted filenames and includes to lower case
*
*
* 2 10/07/98 10:53a Dave
* Initial checkin.
*
* 1 10/07/98 10:51a Dave
*
* 23 5/24/98 11:32a John
* safely handled null vector being passed to start_user_clip_plane.
*
* 22 3/18/98 4:53p John
* Fixed some bugs with docked ships warping out
*
* 21 3/18/98 4:33p John
* Called vm_vec_normalize_safe to prevent assert from bogus docked
* objects.
*
* 20 3/16/98 5:02p John
* Better comments
*
* 19 3/16/98 4:51p John
* Added low-level code to clip all polygons against an arbritary plane.
* Took out all old model_interp_zclip and used this new method instead.
*
* 18 3/10/98 4:19p John
* Cleaned up graphics lib. Took out most unused gr functions. Made D3D
* & Glide have popups and print screen. Took out all >8bpp software
* support. Made Fred zbuffer. Made zbuffer allocate dynamically to
* support Fred. Made zbuffering key off of functions rather than one
* global variable.
*
* 17 1/19/98 6:15p John
* Fixed all my Optimized Build compiler warnings
*
* 16 11/24/97 12:04p John
*
* 15 11/07/97 7:24p John
* changed lighting to take two ranges.
* In textest, added test code to draw nebulas
*
* 14 10/29/97 5:05p John
* Changed dynamic lighting to only rotate and calculate lighting for
* point lights that are close to an object. Changed lower framerate cap
* from 4 to .5.
*
* 13 4/29/97 12:24p Adam
* JAS: Added code for delayed point to vec. Fixed some FRED
* sequencing problems with g3_start_frame / g3_end_frame.
*
* 12 4/29/97 9:55a John
*
* 11 4/08/97 5:18p John
* First rev of decent (dynamic, correct) lighting in FreeSpace.
*
* 10 3/24/97 3:26p John
* Cleaned up and restructured model_collide code and fvi code. In fvi
* made code that finds uvs work.. Added bm_get_pixel to BmpMan.
*
* 9 3/10/97 2:25p John
* Made pofview zbuffer. Made textest work with new model code. Took
* out some unnecessary Asserts in the 3d clipper.
*
*
* 8 2/17/97 5:18p John
* Added a bunch of RCS headers to a bunch of old files that don't have
* them.
*
* $NoKeywords: $
*/
#include "render/3dinternal.h"
#include "graphics/tmapper.h"
#include "graphics/2d.h" // Needed for w,h,aspect of canvas
#include "lighting/lighting.h"
matrix View_matrix; // The matrix to convert local coordinates to screen
vec3d View_position; // The offset to convert local coordinates to screen
matrix Unscaled_matrix; // View_matrix before scaling
matrix Light_matrix; // Used to rotate world points into current local coordinates
vec3d Light_base; // Used to rotate world points into current local coordinates
matrix Eye_matrix; // Where the viewer's eye is pointing in World coordinates
vec3d Eye_position; // Where the viewer's eye is at in World coordinates
float Eye_fov; // What the viewer's FOV is
float View_zoom; // The zoom factor
float Proj_fov; // The fov (for HTL projection matrix)
vec3d Window_scale; // Scaling for window aspect
vec3d Matrix_scale; // How the matrix is scaled, window_scale * zoom
int Canvas_width; // The actual width
int Canvas_height; // The actual height
float Canv_w2; // Canvas_width / 2
float Canv_h2; // Canvas_height / 2
vec3d Object_position;
matrix Object_matrix; // Where the opject is pointing in World coordinates
#define MAX_INSTANCE_DEPTH 5
struct instance_context {
matrix m;
vec3d p;
matrix lm;
vec3d lb;
matrix om;
vec3d op;
} instance_stack[MAX_INSTANCE_DEPTH];
int instance_depth = 0;
int G3_count = 0;
int G3_frame_count = 0;
extern int Cmdline_nohtl;
// check if in frame
int g3_in_frame()
{
return G3_count;
}
//start the frame
// Pass true for zbuffer_flag to turn on zbuffering
void g3_start_frame_func(int zbuffer_flag, char * filename, int lineno)
{
float s;
int width, height;
float aspect;
//Uncomment this to figure out who called g3_start_frame without calling g3_end_frame.
// mprintf(( "g3_start_frame called from %s, line %d\n", filename, lineno ));
Assert( G3_count == 0 );
G3_count++;
// Clear any user-defined clip planes
g3_stop_user_clip_plane();
// Get the values from the 2d...
width = gr_screen.clip_width;
height = gr_screen.clip_height;
aspect = gr_screen.aspect;
//set int w,h & fixed-point w,h/2
Canvas_width = width;
Canv_w2 = (float)width / 2.0f;
Canvas_height = height;
Canv_h2 = (float)height / 2.0f;
//compute aspect ratio for this canvas
s = aspect*(float)Canvas_height/(float)Canvas_width;
if ( !Cmdline_nohtl || (s <= 0.0f) ) { //scale x
Window_scale.xyz.x = s;
Window_scale.xyz.y = 1.0f;
}
else {
Window_scale.xyz.y = 1.0f / s;
Window_scale.xyz.x = 1.0f;
}
Window_scale.xyz.z = 1.0f; //always 1
init_free_points();
if (zbuffer_flag) {
gr_zbuffer_clear(TRUE);
} else {
gr_zbuffer_clear(FALSE);
}
G3_frame_count++;
//init_interface_vars_to_assembler(); //for the texture-mapper
}
//this doesn't do anything, but is here for completeness
void g3_end_frame_func(char *filename, int lineno)
{
// mprintf(( "g3_end_frame called from %s, line %d\n", filename, lineno ));
G3_count--;
Assert( G3_count == 0 );
free_point_num = 0;
// Assert(free_point_num==0);
}
void scale_matrix(void);
void g3_set_view(camera *cam)
{
vec3d pos;
matrix ori;
cam->get_info(&pos, &ori);
if(Sexp_fov <= 0.0f)
g3_set_view_matrix(&pos, &ori, cam->get_fov());
else
g3_set_view_matrix(&pos, &ori, Sexp_fov);
}
//set view from x,y,z, viewer matrix, and zoom. Must call one of g3_set_view_*()
void g3_set_view_matrix(vec3d *view_pos,matrix *view_matrix,float zoom)
{
Assert( G3_count == 1 );
View_zoom = zoom;
View_position = *view_pos;
View_matrix = *view_matrix;
// Proj_fov = (4.0f/9.0f) * PI * View_zoom;
Proj_fov = 1.39626348f * View_zoom;
Eye_matrix = View_matrix;
Eye_position = *view_pos;
Eye_fov = zoom;
scale_matrix();
Light_matrix = vmd_identity_matrix;
Light_base.xyz.x = 0.0f;
Light_base.xyz.y = 0.0f;
Light_base.xyz.z = 0.0f;
vm_vec_zero(&Object_position);
Object_matrix = vmd_identity_matrix;
}
//set view from x,y,z & p,b,h, zoom. Must call one of g3_set_view_*()
void g3_set_view_angles(vec3d *view_pos,angles *view_orient,float zoom)
{
matrix tmp;
Assert( G3_count == 1 );
vm_angles_2_matrix(&tmp,view_orient);
g3_set_view_matrix(view_pos,&tmp,zoom);
}
//performs aspect scaling on global view matrix
void scale_matrix(void)
{
Unscaled_matrix = View_matrix; //so we can use unscaled if we want
Matrix_scale = Window_scale;
float s = 1.0f;
if (Cmdline_nohtl) {
if (View_zoom <= 1.0f) { //zoom in by scaling z
Matrix_scale.xyz.z = Matrix_scale.xyz.z*View_zoom;
} else { //zoom out by scaling x&y
s = 1.0f / View_zoom;
Matrix_scale.xyz.x *= s;
Matrix_scale.xyz.y *= s;
}
} else {
s = 1.0f / tanf(Proj_fov * 0.5f);
Matrix_scale.xyz.x *= s;
Matrix_scale.xyz.y *= s;
}
//now scale matrix elements
vm_vec_scale(&View_matrix.vec.rvec,Matrix_scale.xyz.x );
vm_vec_scale(&View_matrix.vec.uvec,Matrix_scale.xyz.y );
vm_vec_scale(&View_matrix.vec.fvec,Matrix_scale.xyz.z );
}
ubyte g3_rotate_vertex_popped(vertex *dest,vec3d *src)
{
vec3d tempv;
Assert( G3_count == 1 );
Assert( instance_depth > 0 );
vm_vec_sub(&tempv,src,&instance_stack[0].p);
vm_vec_rotate( (vec3d *)&dest->x, &tempv, &instance_stack[0].m );
dest->flags = 0; //not projected
return g3_code_vertex(dest);
}
//instance at specified point with specified orientation
//if matrix==NULL, don't modify matrix. This will be like doing an offset
//if pos==NULL, no position change
void g3_start_instance_matrix(vec3d *pos,matrix *orient, bool set_api)
{
vec3d tempv;
matrix tempm,tempm2;
Assert( G3_count == 1 );
Assert(instance_depth<MAX_INSTANCE_DEPTH);
instance_stack[instance_depth].m = View_matrix;
instance_stack[instance_depth].p = View_position;
instance_stack[instance_depth].lm = Light_matrix;
instance_stack[instance_depth].lb = Light_base;
instance_stack[instance_depth].om = Object_matrix;
instance_stack[instance_depth].op = Object_position;
instance_depth++;
// Make sure orient is valid
if (!orient) {
orient = &vmd_identity_matrix; // Assume no change in orient
}
if ( pos ) {
//step 1: subtract object position from view position
vm_vec_sub2(&View_position,pos);
//step 2: rotate view vector through object matrix
vm_vec_rotate(&tempv,&View_position,orient);
View_position = tempv;
vm_vec_unrotate(&tempv,pos,&Object_matrix);
vm_vec_add2(&Object_position, &tempv);
} else {
// No movement, leave View_position alone
}
//step 3: rotate object matrix through view_matrix (vm = ob * vm)
vm_copy_transpose_matrix(&tempm2,orient);
vm_matrix_x_matrix(&tempm,&tempm2,&View_matrix);
View_matrix = tempm;
vm_matrix_x_matrix(&Object_matrix,orient,&instance_stack[instance_depth-1].om);
// Object_matrix = tempm;
// Update the lighting matrix
matrix saved_orient = Light_matrix;
vec3d saved_base = Light_base;
if ( pos ) {
vm_vec_unrotate(&Light_base,pos,&saved_orient );
vm_vec_add2(&Light_base, &saved_base );
} else {
// No movement, light_base doesn't change.
}
vm_matrix_x_matrix(&Light_matrix,&saved_orient, orient);
if(!Cmdline_nohtl && set_api)
gr_start_instance_matrix(pos,orient);
}
//instance at specified point with specified orientation
//if angles==NULL, don't modify matrix. This will be like doing an offset
void g3_start_instance_angles(vec3d *pos,angles *orient)
{
matrix tm;
Assert( G3_count == 1 );
if (orient==NULL) {
g3_start_instance_matrix(pos,NULL);
return;
}
vm_angles_2_matrix(&tm,orient);
g3_start_instance_matrix(pos,&tm, false);
if(!Cmdline_nohtl)gr_start_angles_instance_matrix(pos, orient);
}
//pops the old context
void g3_done_instance(bool use_api)
{
Assert( G3_count == 1 );
instance_depth--;
Assert(instance_depth >= 0);
View_position = instance_stack[instance_depth].p;
View_matrix = instance_stack[instance_depth].m;
Light_matrix = instance_stack[instance_depth].lm;
Light_base = instance_stack[instance_depth].lb;
Object_matrix = instance_stack[instance_depth].om;
Object_position = instance_stack[instance_depth].op;
if (!Cmdline_nohtl && use_api)
gr_end_instance_matrix();
}
int G3_user_clip = 0;
vec3d G3_user_clip_normal;
vec3d G3_user_clip_point;
// Enables clipping with an arbritary plane. This will be on
// until g3_stop_clip_plane is called or until next frame.
// The points passed should be relative to the instance. Probably
// that means world coordinates.
/*
This works like any other clip plane... if this is enabled and you
rotate a point, the CC_OFF_USER bit will be set in the clipping codes.
It is completely handled by most g3_draw primitives, except maybe lines.
As far as performance, when enabled, it will slow down each point
rotation (or g3_code_vertex call) by a vec3d subtraction and dot
product. It won't slow anything down for polys that are completely
clipped on or off by the plane, and will slow each clipped polygon by
not much more than any other clipping we do.
*/
void g3_start_user_clip_plane( vec3d *plane_point, vec3d *plane_normal )
{
float mag = vm_vec_mag( plane_normal );
if ( (mag < 0.1f) || (mag > 1.5f ) ) {
// Invalid plane_normal passed in. Get Allender (since it is
// probably a ship warp in bug:) or John.
Int3();
return;
}
G3_user_clip = 1;
if(!Cmdline_nohtl) {
G3_user_clip_normal = *plane_normal;
G3_user_clip_point = *plane_point;
// return;
gr_start_clip();
}
vm_vec_rotate(&G3_user_clip_normal, plane_normal, &View_matrix );
vm_vec_normalize(&G3_user_clip_normal);
vec3d tempv;
vm_vec_sub(&tempv,plane_point,&View_position);
vm_vec_rotate(&G3_user_clip_point,&tempv,&View_matrix );
}
// Stops arbritary plane clipping
void g3_stop_user_clip_plane()
{
G3_user_clip = 0;
if(!Cmdline_nohtl) {
gr_end_clip();
}
}
// Returns TRUE if point is behind user plane
int g3_point_behind_user_plane( vec3d *pnt )
{
if ( G3_user_clip ) {
vec3d tmp;
vm_vec_sub( &tmp, pnt, &G3_user_clip_point );
if ( vm_vec_dot( &tmp, &G3_user_clip_normal ) <= 0.0f ) {
return 1;
}
}
return 0;
}