Files
fs2open.github.com/code/graphics/gropengltnl.cpp
T
2004-05-24 07:25:32 +00:00

549 lines
12 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/Graphics/GrOpenGLTNL.cpp $
* $Revision: 1.1 $
* $Date: 2004-05-24 07:25:32 $
* $Author: taylor $
*
* source for doing the fun TNL stuff
*
* $Log: not supported by cvs2svn $
* Revision 2.4 2004/04/26 13:05:19 taylor
* respect -glow and -spec
*
* Revision 2.3 2004/04/13 01:55:41 phreak
* put in the correct fields for the CVS comments to register
* fixed a glowmap problem that occured when rendering glowmapped and non-glowmapped ships
*
*
* $NoKeywords: $
*/
#include <windows.h>
#include "globalincs/pstypes.h"
#include "model/model.h"
#include "graphics/gl/gl.h"
#include "graphics/gl/glu.h"
#include "graphics/gl/glext.h"
#include "graphics/2d.h"
#include "graphics/grinternal.h"
#include "graphics/gropengl.h"
#include "graphics/gropenglextension.h"
#include "graphics/gropengltexture.h"
#include "graphics/gropengllight.h"
#include "graphics/gropengltnl.h"
#include "math/vecmat.h"
#include "render/3d.h"
#include "debugconsole/timerbar.h"
extern int VBO_ENABLED;
extern int GLOWMAP;
extern int CLOAKMAP;
extern int SPECMAP;
extern vector G3_user_clip_normal;
extern vector G3_user_clip_point;
extern int Interp_multitex_cloakmap;
extern int Interp_cloakmap_alpha;
int GL_modelview_matrix_depth = 1;
int GL_htl_projection_matrix_set = 0;
int GL_htl_view_matrix_set = 0;
struct opengl_vertex_buffer
{
int n_poly;
vector *vertex_array;
uv_pair *texcoord_array;
vector *normal_array;
int used;
uint vbo_vert;
uint vbo_norm;
uint vbo_tex;
};
#define MAX_SUBOBJECTS 64
#ifdef INF_BUILD
#define MAX_BUFFERS_PER_SUBMODEL 24
#else
#define MAX_BUFFERS_PER_SUBMODEL 16
#endif
#define MAX_BUFFERS MAX_POLYGON_MODELS*MAX_SUBOBJECTS*MAX_BUFFERS_PER_SUBMODEL
static opengl_vertex_buffer vertex_buffers[MAX_BUFFERS];
//zeros everything out
void opengl_init_vertex_buffers()
{
memset(vertex_buffers,0,sizeof(opengl_vertex_buffer)*MAX_BUFFERS);
}
int opengl_find_first_free_buffer()
{
for (int i=0; i < MAX_BUFFERS; i++)
{
if (!vertex_buffers[i].used)
return i;
}
return -1;
}
int opengl_check_for_errors()
{
#ifdef _DEBUG
int error=0;
if ((error=glGetError()) != GL_NO_ERROR)
{
mprintf(("!!ERROR!!: %s\n", gluErrorString(error)));
return 1;
}
#endif
return 0;
}
int opengl_mod_depth()
{
int mv;
glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mv);
return mv;
}
uint opengl_create_vbo(uint size, void** data)
{
if (!data)
return 0;
if (!*data)
return 0;
if (size == 0)
return 0;
// Kazan: A) This makes that if (buffer_name) work correctly (false = 0, true = anything not 0)
// if glGenBuffersARB() doesn't initialized it for some reason
// B) It shuts up MSVC about may be used without been initalized
uint buffer_name=0;
glGenBuffersARB(1, &buffer_name);
//make sure we have one
if (buffer_name)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer_name);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, *data, GL_STATIC_DRAW_ARB );
//just in case
if (opengl_check_for_errors())
{
return 0;
}
else
{
free(*data);
*data = NULL;
// mprintf(("VBO Created: %d\n", buffer_name));
}
}
return buffer_name;
}
int gr_opengl_make_buffer(poly_list *list)
{
int buffer_num=opengl_find_first_free_buffer();
//we have a valid buffer
if (buffer_num > -1)
{
opengl_vertex_buffer *vbp=&vertex_buffers[buffer_num];
vbp->used=1;
vbp->n_poly=list->n_poly;
vbp->texcoord_array=(uv_pair*)malloc(list->n_poly * 3 * sizeof(uv_pair));
memset(vbp->texcoord_array,0,list->n_poly*sizeof(uv_pair));
vbp->normal_array=(vector*)malloc(list->n_poly * 3 * sizeof(vector));
memset(vbp->normal_array,0,list->n_poly*sizeof(vector));
vbp->vertex_array=(vector*)malloc(list->n_poly * 3 * sizeof(vector));
memset(vbp->vertex_array,0,list->n_poly*sizeof(vector));
vector *n=vbp->normal_array;
vector *v=vbp->vertex_array;
uv_pair *t=vbp->texcoord_array;
vertex *vl;
memcpy(n,list->norm,list->n_poly*sizeof(vector)*3);
for (int i=0; i < list->n_poly*3; i++)
{
vl=&list->vert[i];
v->xyz.x=vl->x;
v->xyz.y=vl->y;
v->xyz.z=vl->z;
v++;
t->u=vl->u;
t->v=vl->v;
t++;
}
//maybe load it into a vertex buffer object
if (VBO_ENABLED)
{
vbp->vbo_vert=opengl_create_vbo(vbp->n_poly*9*sizeof(float),(void**)&vbp->vertex_array);
vbp->vbo_norm=opengl_create_vbo(vbp->n_poly*9*sizeof(float),(void**)&vbp->normal_array);
vbp->vbo_tex=opengl_create_vbo(vbp->n_poly*6*sizeof(float),(void**)&vbp->texcoord_array);
}
}
return buffer_num;
}
void gr_opengl_destroy_buffer(int idx)
{
opengl_vertex_buffer *vbp=&vertex_buffers[idx];
if (vbp->normal_array) free(vbp->normal_array);
if (vbp->texcoord_array) free(vbp->texcoord_array);
if (vbp->vertex_array) free(vbp->vertex_array);
if (vbp->vbo_norm) glDeleteBuffersARB(1,&vbp->vbo_norm);
if (vbp->vbo_vert) glDeleteBuffersARB(1,&vbp->vbo_vert);
if (vbp->vbo_tex) glDeleteBuffersARB(1,&vbp->vbo_tex);
memset(vbp,0,sizeof(opengl_vertex_buffer));
}
//#define DRAW_DEBUG_LINES
extern float Model_Interp_scale_x,Model_Interp_scale_y,Model_Interp_scale_z;
void gr_opengl_render_buffer(int idx)
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_htl_view_matrix_set);
TIMERBAR_PUSH(2);
float u_scale,v_scale;
if (glIsEnabled(GL_CULL_FACE)) glFrontFace(GL_CW);
glColor3ub(255,255,255);
opengl_vertex_buffer *vbp=&vertex_buffers[idx];
glEnableClientState(GL_VERTEX_ARRAY);
if (vbp->vbo_vert)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo_vert);
glVertexPointer(3,GL_FLOAT,0, (void*)NULL);
}
else
{
glVertexPointer(3,GL_FLOAT,0,vbp->vertex_array);
}
glEnableClientState(GL_NORMAL_ARRAY);
if (vbp->vbo_norm)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo_norm);
glNormalPointer(GL_FLOAT,0, (void*)NULL);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glNormalPointer(GL_FLOAT,0,vbp->normal_array);
}
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (vbp->vbo_tex)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo_tex);
glTexCoordPointer(2,GL_FLOAT,0,(void*)NULL);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glTexCoordPointer(2,GL_FLOAT,0,vbp->texcoord_array);
}
if (Interp_multitex_cloakmap > 0)
{
SPECMAP = -1; // don't add a spec map if we are cloaked
GLOWMAP = -1; // don't use a glowmap either, shouldn't see them
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (vbp->vbo_tex)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo_tex);
glTexCoordPointer(2,GL_FLOAT,0,(void*)NULL);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glTexCoordPointer(2,GL_FLOAT,0,vbp->texcoord_array);
}
}
if ( (GLOWMAP > -1) && !Cmdline_noglow )
{
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (vbp->vbo_tex)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo_tex);
glTexCoordPointer(2,GL_FLOAT,0,(void*)NULL);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glTexCoordPointer(2,GL_FLOAT,0,vbp->texcoord_array);
}
}
if ((SPECMAP > -1) && !Cmdline_nospec && (GL_supported_texture_units > 2))
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (vbp->vbo_tex)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo_tex);
glTexCoordPointer(2,GL_FLOAT,0,(void*)NULL);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glTexCoordPointer(2,GL_FLOAT,0,vbp->texcoord_array);
}
}
int r,g,b,a,tmap_type;
opengl_setup_render_states(r,g,b,a,tmap_type,TMAP_FLAG_TEXTURED,0);
if (gr_screen.current_bitmap==CLOAKMAP)
{
glBlendFunc(GL_ONE,GL_ONE);
r=g=b=Interp_cloakmap_alpha;
a=255;
}
gr_tcache_set(gr_screen.current_bitmap, tmap_type, &u_scale, &v_scale, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, 0);
glLockArraysEXT(0,vbp->n_poly*3);
opengl_pre_render_init_lights();
opengl_change_active_lights(0);
glDrawArrays(GL_TRIANGLES,0,vbp->n_poly*3);
if((lighting_is_enabled)&&((n_active_gl_lights-1)/max_gl_lights > 0)) {
gr_opengl_set_state( TEXTURE_SOURCE_DECAL, ALPHA_BLEND_ALPHA_ADDITIVE, ZBUFFER_TYPE_READ );
opengl_switch_arb(1,0);
opengl_switch_arb(2,0);
for(int i=1; i< (n_active_gl_lights-1)/max_gl_lights; i++)
{
opengl_change_active_lights(i);
glDrawArrays(GL_TRIANGLES,0,vbp->n_poly*3);
}
}
glUnlockArraysEXT();
TIMERBAR_POP();
if (VBO_ENABLED)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
}
#if defined(DRAW_DEBUG_LINES) && defined(_DEBUG)
glBegin(GL_LINES);
glColor3ub(255,0,0);
glVertex3d(0,0,0);
glVertex3d(20,0,0);
glColor3ub(0,255,0);
glVertex3d(0,0,0);
glVertex3d(0,20,0);
glColor3ub(0,0,255);
glVertex3d(0,0,0);
glVertex3d(0,0,20);
glEnd();
#endif
}
void gr_opengl_start_instance_matrix(vector *offset, matrix* rotation)
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_htl_view_matrix_set);
if (!offset)
offset = &vmd_zero_vector;
if (!rotation)
rotation = &vmd_identity_matrix;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
vector axis;
float ang;
vm_matrix_to_rot_axis_and_angle(rotation,&ang,&axis);
glTranslatef(offset->xyz.x,offset->xyz.y,offset->xyz.z);
glRotatef(fl_degrees(ang),axis.xyz.x,axis.xyz.y,axis.xyz.z);
GL_modelview_matrix_depth++;
}
void gr_opengl_start_instance_angles(vector *pos, angles* rotation)
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_htl_view_matrix_set);
matrix m;
vm_angles_2_matrix(&m,rotation);
gr_opengl_start_instance_matrix(pos,&m);
}
void gr_opengl_end_instance_matrix()
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_htl_view_matrix_set);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
GL_modelview_matrix_depth--;
}
//the projection matrix; fov, aspect ratio, near, far
void gr_opengl_set_projection_matrix(float fov, float aspect, float z_near, float z_far)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(fl_degrees(fov),aspect,z_near,z_far);
glMatrixMode(GL_MODELVIEW);
GL_htl_projection_matrix_set = 1;
}
void gr_opengl_end_projection_matrix()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
GL_htl_projection_matrix_set = 0;
}
void gr_opengl_set_view_matrix(vector *pos, matrix* orient)
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_modelview_matrix_depth == 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
vector fwd;
vector *uvec=&orient->vec.uvec;
vm_vec_add(&fwd, pos, &orient->vec.fvec);
gluLookAt(pos->xyz.x,pos->xyz.y,-pos->xyz.z,
fwd.xyz.x,fwd.xyz.y,-fwd.xyz.z,
uvec->xyz.x, uvec->xyz.y,-uvec->xyz.z);
glScalef(1,1,-1);
glViewport(gr_screen.offset_x,gr_screen.max_h-gr_screen.offset_y-gr_screen.clip_height,gr_screen.clip_width,gr_screen.clip_height);
GL_modelview_matrix_depth = 2;
GL_htl_view_matrix_set = 1;
}
void gr_opengl_end_view_matrix()
{
Assert(GL_modelview_matrix_depth == 2);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glLoadIdentity();
glViewport(0,0,gr_screen.max_w, gr_screen.max_h);
GL_modelview_matrix_depth = 1;
GL_htl_view_matrix_set = 0;
}
void gr_opengl_push_scale_matrix(vector *scale_factor)
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_htl_view_matrix_set);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
GL_modelview_matrix_depth++;
glScalef(scale_factor->xyz.x,scale_factor->xyz.y,scale_factor->xyz.z);
}
void gr_opengl_pop_scale_matrix()
{
Assert(GL_htl_projection_matrix_set);
Assert(GL_htl_view_matrix_set);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
GL_modelview_matrix_depth--;
}
void gr_opengl_end_clip_plane()
{
glDisable(GL_CLIP_PLANE0);
}
void gr_opengl_start_clip_plane()
{
double clip_equation[4];
vector n;
vector p;
n=G3_user_clip_normal;
p=G3_user_clip_point;
clip_equation[0]=n.xyz.x;
clip_equation[1]=n.xyz.y;
clip_equation[2]=n.xyz.z;
clip_equation[3]=-vm_vec_dot(&p, &n);
glClipPlane(GL_CLIP_PLANE0, clip_equation);
glEnable(GL_CLIP_PLANE0);
}