mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 17:46:53 -10:00
speed up gr_opengl_flip() just a tad inverted gamma slider fix that Sticks made to D3D possible fix for ATI green screens move opengl_check_for_errors() out of gropentnl so we can use it everywhere fix logged OGL info from debug builds to be a little more readable if an extension is found but required function is not then fail try to optimize glDrawRangeElements so we are not rendering more than the card is optimized for some 2d matrix usage checks
992 lines
26 KiB
C++
992 lines
26 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.24 $
|
|
* $Date: 2005-06-19 02:37:02 $
|
|
* $Author: taylor $
|
|
*
|
|
* source for doing the fun TNL stuff
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 1.23 2005/05/12 17:43:20 taylor
|
|
* use vm_malloc(), vm_free(), vm_realloc(), vm_strdup() rather than system named macros
|
|
* fixes various problems and is past time to make the switch
|
|
* try and keep up with how much VBO data is in memory too since that takes away from texture memory
|
|
*
|
|
* Revision 1.22 2005/04/05 05:53:17 taylor
|
|
* s/vector/vec3d/g, better support for different compilers (Jens Granseuer)
|
|
*
|
|
* Revision 1.21 2005/03/27 02:59:27 wmcoolmon
|
|
* Forgot to define 'i' outside of for scope...ironically, in the OGL code.
|
|
*
|
|
* Revision 1.20 2005/03/24 23:42:21 taylor
|
|
* s/gr_ogl_/gr_opengl_/g
|
|
* add empty gr_opengl_draw_line_list() so that it's not a NULL pointer
|
|
* make gr_opengl_draw_htl_sphere() just use GLU so we don't need yet another friggin API
|
|
*
|
|
* Revision 1.19 2005/03/20 00:09:07 phreak
|
|
* Added gr_draw_htl_line and gr_draw_htl sphere
|
|
* There still needs to be D3D versions implemented, but OGL is done.
|
|
* Follow that or ask phreak about how its implemented/
|
|
*
|
|
* Revision 1.18 2005/03/19 21:03:54 wmcoolmon
|
|
* OpenGL display lists
|
|
*
|
|
* Revision 1.17 2005/03/19 18:02:34 bobboau
|
|
* added new graphic functions for state blocks
|
|
* also added a class formanageing a new effect
|
|
*
|
|
* Revision 1.16 2005/02/23 05:11:13 taylor
|
|
* more consolidation of various graphics variables
|
|
* some header cleaning
|
|
* only one tmapper_internal for OGL, don't use more than two tex/pass now
|
|
* seperate out 2d matrix mode to allow -2d_poof in OGL and maybe fix missing
|
|
* interface when set 3d matrix stuff doesn't have corresponding end
|
|
* add dump_frame stuff for OGL, mostly useless but allows trailer recording
|
|
*
|
|
* Revision 1.15 2005/02/15 00:06:27 taylor
|
|
* clean up some model related globals
|
|
* code to disable individual thruster glows
|
|
* fix issue where 1 extra OGL light pass didn't render
|
|
*
|
|
* Revision 1.14 2005/02/12 10:44:10 taylor
|
|
* fix possible crash in bm_get_section_size()
|
|
* get jpeg_read_header() working properly
|
|
* VBO fixes and minor optimizations
|
|
*
|
|
* Revision 1.13 2005/01/13 04:55:57 taylor
|
|
* plug leak from VBO crash fix
|
|
*
|
|
* Revision 1.12 2005/01/03 18:45:22 taylor
|
|
* dynamic allocation of num supported OpenGL lights
|
|
* add config option for more realistic light settings
|
|
* don't render spec maps in nebula to address lighting issue
|
|
*
|
|
* Revision 1.11 2005/01/01 11:24:23 taylor
|
|
* good OpenGL spec mapping
|
|
* fix VBO crash with multitexture using same uv coord data
|
|
* little speedup of opengl_tcache_frame()
|
|
* error message to make sure hardware supports the minimum texture size
|
|
* move OpenGL version check out of the extention printout code
|
|
* disable 2d_poof with OpenGL
|
|
*
|
|
* Revision 1.10 2004/10/31 21:45:13 taylor
|
|
* Linux tree merge, single array for VBOs/HTL
|
|
*
|
|
* Revision 1.9 2004/07/29 09:35:29 taylor
|
|
* fix NULL pointer and try to prevent in future, remove excess commands in opengl_cleanup()
|
|
*
|
|
* Revision 1.8 2004/07/26 20:47:32 Kazan
|
|
* remove MCD complete
|
|
*
|
|
* Revision 1.7 2004/07/17 18:49:57 taylor
|
|
* oops, I can't spell
|
|
*
|
|
* Revision 1.6 2004/07/17 18:40:40 taylor
|
|
* Bob say we fix OGL, so me fix OGL <grunt>
|
|
*
|
|
* Revision 1.5 2004/07/12 16:32:48 Kazan
|
|
* MCD - define _MCD_CHECK to use memory tracking
|
|
*
|
|
* Revision 1.4 2004/07/11 03:22:49 bobboau
|
|
* added the working decal code
|
|
*
|
|
* Revision 1.3 2004/07/05 05:09:19 bobboau
|
|
* FVF code, only the data that is needed is sent off to the card,,
|
|
* OGL can take advantage of this if they want but it won't break
|
|
* anything if they don't. also state block code has been implemented,
|
|
* that's totaly internal to D3D no high level code is involved.
|
|
*
|
|
* Revision 1.2 2004/06/28 02:13:07 bobboau
|
|
* high level index buffer suport and d3d implementation,
|
|
* OGL people need to get this working on your end as it's broke now
|
|
*
|
|
* Revision 1.1 2004/05/24 07:25:32 taylor
|
|
* filename case change
|
|
*
|
|
* 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: $
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "globalincs/pstypes.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 vec3d G3_user_clip_normal;
|
|
extern vec3d G3_user_clip_point;
|
|
extern int Interp_multitex_cloakmap;
|
|
extern int Interp_cloakmap_alpha;
|
|
|
|
static int GL_modelview_matrix_depth = 1;
|
|
static int GL_htl_projection_matrix_set = 0;
|
|
static int GL_htl_view_matrix_set = 0;
|
|
static int GL_htl_2d_matrix_depth = 0;
|
|
static int GL_htl_2d_matrix_set = 0;
|
|
|
|
int GL_vertex_data_in = 0;
|
|
|
|
int GL_max_elements_vertices = 4096;
|
|
int GL_max_elements_indices = 4096;
|
|
|
|
|
|
struct opengl_vertex_buffer
|
|
{
|
|
int used;
|
|
int stride; // the current stride
|
|
GLenum format; // the format passed to glInterleavedArrays()
|
|
int n_prim;
|
|
int n_verts;
|
|
float *array_list; // interleaved array
|
|
uint vbo; // buffer for VBO
|
|
uint flags; // FVF
|
|
int vbo_size;
|
|
};
|
|
|
|
|
|
static opengl_vertex_buffer vertex_buffers[MAX_BUFFERS];
|
|
static opengl_vertex_buffer *g_vbp;
|
|
|
|
//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_mod_depth()
|
|
{
|
|
int mv;
|
|
glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mv);
|
|
return mv;
|
|
}
|
|
|
|
void gr_opengl_set_buffer(int idx)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
g_vbp = &vertex_buffers[idx];
|
|
}
|
|
|
|
uint opengl_create_vbo(uint size, GLfloat *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;
|
|
|
|
#ifndef GL_NO_HTL
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
#endif // GL_NO_HTL
|
|
|
|
return buffer_name;
|
|
}
|
|
|
|
int gr_opengl_make_buffer(poly_list *list, uint flags)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return -1;
|
|
|
|
int buffer_num = -1;
|
|
|
|
#ifndef GL_NO_HTL
|
|
|
|
buffer_num = opengl_find_first_free_buffer();
|
|
|
|
//we have a valid buffer
|
|
if (buffer_num > -1) {
|
|
int arsize = 0, make_vbo = 0;
|
|
int list_size, i;
|
|
|
|
gr_opengl_set_buffer( buffer_num );
|
|
|
|
opengl_vertex_buffer *vbp = g_vbp;
|
|
|
|
// defaults
|
|
vbp->format = 0;
|
|
vbp->vbo = 0;
|
|
|
|
// don't create vbo for small stuff, performance gain
|
|
if (VBO_ENABLED && (list->n_verts >= 250))
|
|
make_vbo = 1;
|
|
|
|
// setup using flags
|
|
if ( (flags & VERTEX_FLAG_UV1) && (flags & VERTEX_FLAG_NORMAL) && (flags & VERTEX_FLAG_POSITION) ) {
|
|
vbp->stride = (8 * sizeof(float));
|
|
vbp->format = GL_T2F_N3F_V3F;
|
|
} else if ( (flags & VERTEX_FLAG_UV1) && (flags & VERTEX_FLAG_POSITION) ) {
|
|
vbp->stride = (5 * sizeof(float));
|
|
vbp->format = GL_T2F_V3F;
|
|
} else if ( (flags & VERTEX_FLAG_POSITION) ) {
|
|
vbp->stride = (3 * sizeof(float));
|
|
vbp->format = GL_V3F;
|
|
} else {
|
|
Assert( 0 );
|
|
}
|
|
|
|
// total size of data
|
|
list_size = vbp->stride * list->n_verts;
|
|
|
|
// allocate the storage list
|
|
vbp->array_list = (float*)vm_malloc(list_size);
|
|
|
|
// return invalid if we don't have the memory
|
|
if (vbp->array_list == NULL)
|
|
return -1;
|
|
|
|
memset(vbp->array_list, 0, list_size);
|
|
|
|
// generate the array
|
|
for (i=0; i<list->n_verts; i++) {
|
|
vertex *vl = &list->vert[i];
|
|
vec3d *nl = &list->norm[i];
|
|
|
|
// don't try to generate more data than what's available
|
|
Assert( int((arsize * sizeof(float)) + vbp->stride) <= list_size );
|
|
|
|
// NOTE: TEX->NORM->VERT, This array order *must* be preserved!!
|
|
|
|
// tex coords
|
|
if (flags & VERTEX_FLAG_UV1) {
|
|
vbp->array_list[arsize++] = vl->u;
|
|
vbp->array_list[arsize++] = vl->v;
|
|
}
|
|
|
|
// normals
|
|
if (flags & VERTEX_FLAG_NORMAL) {
|
|
vbp->array_list[arsize++] = nl->xyz.x;
|
|
vbp->array_list[arsize++] = nl->xyz.y;
|
|
vbp->array_list[arsize++] = nl->xyz.z;
|
|
}
|
|
|
|
// verts
|
|
if (flags & VERTEX_FLAG_POSITION) {
|
|
vbp->array_list[arsize++] = vl->x;
|
|
vbp->array_list[arsize++] = vl->y;
|
|
vbp->array_list[arsize++] = vl->z;
|
|
}
|
|
}
|
|
|
|
vbp->used = 1;
|
|
vbp->flags = flags;
|
|
|
|
vbp->n_prim = (list->n_verts / 3);
|
|
vbp->n_verts = list->n_verts;
|
|
|
|
// maybe load it into a vertex buffer object
|
|
if (make_vbo) {
|
|
vbp->vbo = opengl_create_vbo( list_size, vbp->array_list );
|
|
|
|
if (vbp->vbo) {
|
|
// figure up the size so we can know how much VBO data is in card memory
|
|
vbp->vbo_size = list_size;
|
|
GL_vertex_data_in += list_size;
|
|
vm_free(vbp->array_list);
|
|
vbp->array_list = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // GL_NO_HTL
|
|
|
|
return buffer_num;
|
|
}
|
|
|
|
void gr_opengl_destroy_buffer(int idx)
|
|
{
|
|
#ifndef GL_NO_HTL
|
|
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
if (idx > -1)
|
|
gr_opengl_set_buffer(idx);
|
|
|
|
opengl_vertex_buffer *vbp = g_vbp;
|
|
|
|
if (vbp->array_list)
|
|
vm_free(vbp->array_list);
|
|
|
|
if (vbp->vbo) {
|
|
glDeleteBuffersARB(1, &vbp->vbo);
|
|
GL_vertex_data_in -= vbp->vbo_size;
|
|
}
|
|
|
|
memset(vbp, 0, sizeof(opengl_vertex_buffer));
|
|
|
|
#endif // GL_NO_HTL
|
|
}
|
|
|
|
//#define DRAW_DEBUG_LINES
|
|
extern float Model_Interp_scale_x,Model_Interp_scale_y,Model_Interp_scale_z;
|
|
extern void opengl_default_light_settings(int amb = 1, int emi = 1, int spec = 1);
|
|
|
|
//start is the first part of the buffer to render, n_prim is the number of primitives, index_list is an index buffer, if index_list == NULL render non-indexed
|
|
void gr_opengl_render_buffer(int start, int n_prim, short* index_buffer)
|
|
{
|
|
#ifndef GL_NO_HTL
|
|
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
Assert(GL_htl_projection_matrix_set);
|
|
Assert(GL_htl_view_matrix_set);
|
|
|
|
TIMERBAR_PUSH(2);
|
|
|
|
float u_scale,v_scale;
|
|
int pass_one = 0;
|
|
int i, r, g, b, a, tmap_type;
|
|
bool use_spec = false;
|
|
|
|
int end = ((n_prim * 3) - 1);
|
|
int count = (n_prim * 3);
|
|
int start_tmp, end_tmp, count_tmp, multiple_elements = 0;
|
|
|
|
opengl_vertex_buffer *vbp = g_vbp;
|
|
|
|
|
|
// see if we need to optimize glDrawRangeElements
|
|
if ( (GL_max_elements_indices == GL_max_elements_vertices) && (count > GL_max_elements_indices) )
|
|
multiple_elements = 1;
|
|
|
|
if ( glIsEnabled(GL_CULL_FACE) )
|
|
glFrontFace(GL_CW);
|
|
|
|
// -------- Begin 1st PASS ------------------------------------------------------- //
|
|
if (gr_screen.current_bitmap == CLOAKMAP) {
|
|
glBlendFunc(GL_ONE,GL_ONE);
|
|
r = g = b = Interp_cloakmap_alpha;
|
|
a = 255;
|
|
}
|
|
|
|
opengl_setup_render_states(r, g, b, a, tmap_type, TMAP_FLAG_TEXTURED, 0);
|
|
glColor4ub( (ubyte)r, (ubyte)g, (ubyte)b, (ubyte)a );
|
|
|
|
// basic setup of all data and first texture
|
|
glClientActiveTextureARB(GL_TEXTURE0_ARB+pass_one);
|
|
if (vbp->vbo) {
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo);
|
|
glInterleavedArrays(vbp->format, 0, (void*)NULL);
|
|
} else {
|
|
glInterleavedArrays(vbp->format, 0, vbp->array_list);
|
|
}
|
|
|
|
// base texture
|
|
gr_opengl_tcache_set(gr_screen.current_bitmap, tmap_type, &u_scale, &v_scale, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, 0, pass_one);
|
|
|
|
// increment texture count for this pass
|
|
pass_one++; // bump!
|
|
|
|
if ( (Interp_multitex_cloakmap > 0) && (vbp->flags & VERTEX_FLAG_UV1) ) {
|
|
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_TEXTURE0_ARB+pass_one);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
if (vbp->vbo) {
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo);
|
|
glTexCoordPointer( 2, GL_FLOAT, vbp->stride, (void*)NULL );
|
|
} else {
|
|
glTexCoordPointer( 2, GL_FLOAT, vbp->stride, vbp->array_list );
|
|
}
|
|
|
|
gr_opengl_tcache_set(Interp_multitex_cloakmap, tmap_type, &u_scale, &v_scale, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, 0, pass_one);
|
|
|
|
pass_one++; // bump!
|
|
}
|
|
|
|
// glowmaps!
|
|
if ( (GLOWMAP > -1) && !Cmdline_noglow && (vbp->flags & VERTEX_FLAG_UV1) ) {
|
|
glClientActiveTextureARB(GL_TEXTURE0_ARB+pass_one);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
if (vbp->vbo) {
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo);
|
|
glTexCoordPointer( 2, GL_FLOAT, vbp->stride, (void*)NULL );
|
|
} else {
|
|
glTexCoordPointer( 2, GL_FLOAT, vbp->stride, vbp->array_list );
|
|
}
|
|
|
|
// set glowmap on relevant ARB
|
|
gr_opengl_tcache_set(GLOWMAP, tmap_type, &u_scale, &v_scale, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, 0, pass_one);
|
|
|
|
opengl_switch_arb(pass_one, 1);
|
|
gr_opengl_set_additive_tex_env();
|
|
|
|
pass_one++; // bump!
|
|
}
|
|
|
|
opengl_pre_render_init_lights();
|
|
opengl_change_active_lights(0);
|
|
|
|
// only change lights if we have a specmap, don't render the specmap when fog is enabled
|
|
if ( (lighting_is_enabled) && !(glIsEnabled(GL_FOG)) && (SPECMAP > -1) && !Cmdline_nospec && (vbp->flags & VERTEX_FLAG_UV1) ) {
|
|
use_spec = true;
|
|
opengl_default_light_settings(1, 1, 0); // don't render with spec lighting here
|
|
} else {
|
|
// reset to defaults
|
|
opengl_default_light_settings();
|
|
}
|
|
|
|
glLockArraysEXT( 0, vbp->n_verts);
|
|
|
|
if (index_buffer != NULL) {
|
|
if ( multiple_elements ) {
|
|
start_tmp = 0;
|
|
end_tmp = (GL_max_elements_indices - 1);
|
|
count_tmp = (end_tmp - start_tmp + 1);
|
|
|
|
glDrawRangeElements(GL_TRIANGLES, start_tmp, end_tmp, count_tmp, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start_tmp);
|
|
|
|
while (end_tmp < end) {
|
|
start_tmp += (GL_max_elements_indices - 1);
|
|
end_tmp = ( (start_tmp + (GL_max_elements_indices - 1)) > end ) ? end : (start_tmp + (GL_max_elements_indices - 1));
|
|
count_tmp = (end_tmp - start_tmp + 1);
|
|
|
|
glDrawRangeElements(GL_TRIANGLES, start_tmp, end_tmp, count_tmp, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start_tmp);
|
|
}
|
|
} else {
|
|
glDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start);
|
|
}
|
|
} else {
|
|
glDrawArrays(GL_TRIANGLES, 0, vbp->n_verts);
|
|
}
|
|
|
|
glUnlockArraysEXT();
|
|
// -------- End 1st PASS --------------------------------------------------------- //
|
|
|
|
// -------- Begin 2nd (specular) PASS -------------------------------------------- //
|
|
if ( use_spec ) {
|
|
// turn all arbs off before the specular pass
|
|
// this fixes the glowmap multitexture rendering problem - taylor
|
|
opengl_switch_arb(0, 0);
|
|
opengl_switch_arb(1, 0);
|
|
opengl_switch_arb(2, 0);
|
|
|
|
glClientActiveTextureARB(GL_TEXTURE0_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
if (vbp->vbo) {
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbp->vbo);
|
|
glTexCoordPointer( 2, GL_FLOAT, vbp->stride, (void*)NULL );
|
|
} else {
|
|
glTexCoordPointer( 2, GL_FLOAT, vbp->stride, vbp->array_list );
|
|
}
|
|
|
|
opengl_set_spec_mapping(tmap_type, &u_scale, &v_scale);
|
|
|
|
glLockArraysEXT( 0, vbp->n_verts );
|
|
|
|
if (index_buffer != NULL) {
|
|
if ( multiple_elements ) {
|
|
start_tmp = 0;
|
|
end_tmp = (GL_max_elements_indices - 1);
|
|
count_tmp = (end_tmp - start_tmp + 1);
|
|
|
|
glDrawRangeElements(GL_TRIANGLES, start_tmp, end_tmp, count_tmp, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start_tmp);
|
|
|
|
while (end_tmp < end) {
|
|
start_tmp += (GL_max_elements_indices - 1);
|
|
end_tmp = ( (start_tmp + (GL_max_elements_indices - 1)) > end ) ? end : (start_tmp + (GL_max_elements_indices - 1));
|
|
count_tmp = (end_tmp - start_tmp + 1);
|
|
|
|
glDrawRangeElements(GL_TRIANGLES, start_tmp, end_tmp, count_tmp, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start_tmp);
|
|
}
|
|
} else {
|
|
glDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start);
|
|
}
|
|
} else {
|
|
glDrawArrays(GL_TRIANGLES, 0, vbp->n_verts);
|
|
}
|
|
|
|
glUnlockArraysEXT();
|
|
|
|
opengl_reset_spec_mapping();
|
|
}
|
|
// -------- End 2nd PASS --------------------------------------------------------- //
|
|
|
|
// reset lights to default values
|
|
// opengl_default_light_settings();
|
|
|
|
if ( (lighting_is_enabled) && ((n_active_gl_lights-1)/GL_max_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);
|
|
|
|
glLockArraysEXT( 0, vbp->n_verts);
|
|
|
|
for(i=0; i< (n_active_gl_lights-1)/GL_max_lights; i++)
|
|
{
|
|
opengl_change_active_lights(i+1);
|
|
|
|
if (index_buffer != NULL) {
|
|
if ( multiple_elements ) {
|
|
start_tmp = 0;
|
|
end_tmp = (GL_max_elements_indices - 1);
|
|
count_tmp = (end_tmp - start_tmp + 1);
|
|
|
|
glDrawRangeElements(GL_TRIANGLES, start_tmp, end_tmp, count_tmp, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start_tmp);
|
|
|
|
while (end_tmp < end) {
|
|
start_tmp += (GL_max_elements_indices - 1);
|
|
end_tmp = ( (start_tmp + (GL_max_elements_indices - 1)) > end ) ? end : (start_tmp + (GL_max_elements_indices - 1));
|
|
count_tmp = (end_tmp - start_tmp + 1);
|
|
|
|
glDrawRangeElements(GL_TRIANGLES, start_tmp, end_tmp, count_tmp, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start_tmp);
|
|
}
|
|
} else {
|
|
glDrawRangeElements(GL_TRIANGLES, start, end, count, GL_UNSIGNED_SHORT, (ushort*)index_buffer + start);
|
|
}
|
|
} else {
|
|
glDrawArrays(GL_TRIANGLES, 0, vbp->n_verts);
|
|
}
|
|
}
|
|
|
|
glUnlockArraysEXT();
|
|
}
|
|
|
|
TIMERBAR_POP();
|
|
|
|
// make sure everthing gets turned back off, fixes hud issue with spec lighting and VBO crash in starfield
|
|
for (i = 0; i < 4; i++) {
|
|
opengl_switch_arb(i, 0);
|
|
|
|
glClientActiveTextureARB(GL_TEXTURE0_ARB+i);
|
|
|
|
glDisableClientState( GL_VERTEX_ARRAY );
|
|
glDisableClientState( GL_NORMAL_ARRAY );
|
|
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
|
|
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
|
|
|
|
#endif // GL_NO_HTL
|
|
}
|
|
|
|
void gr_opengl_start_instance_matrix(vec3d *offset, matrix* rotation)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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();
|
|
|
|
vec3d 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(vec3d *pos, angles* rotation)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
GL_htl_projection_matrix_set = 0;
|
|
}
|
|
|
|
void gr_opengl_set_view_matrix(vec3d *pos, matrix* orient)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
Assert(GL_htl_projection_matrix_set);
|
|
Assert(GL_modelview_matrix_depth == 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glPushMatrix();
|
|
|
|
vec3d fwd;
|
|
vec3d *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()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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;
|
|
}
|
|
|
|
// set a view and projection matrix for a 2D element
|
|
// TODO: this probably needs to accept values
|
|
void gr_opengl_set_2d_matrix(/*int x, int y, int w, int h*/)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
// don't bother with this if we aren't even going to need it
|
|
if (!GL_htl_projection_matrix_set)
|
|
return;
|
|
|
|
Assert( GL_htl_2d_matrix_set == 0 );
|
|
Assert( GL_htl_2d_matrix_depth == 0 );
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
// the top and bottom positions are reversed on purpose
|
|
glOrtho( 0, gr_screen.max_w, gr_screen.max_h, 0, 0, 1 );
|
|
|
|
glMatrixMode( GL_MODELVIEW );
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
// the viewport needs to be the full screen size since glOrtho() is relative to it
|
|
glViewport(0, 0, gr_screen.max_w, gr_screen.max_h);
|
|
|
|
GL_htl_2d_matrix_set++;
|
|
GL_htl_2d_matrix_depth++;
|
|
}
|
|
|
|
// ends a previously set 2d view and projection matrix
|
|
void gr_opengl_end_2d_matrix()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
if (!GL_htl_2d_matrix_set)
|
|
return;
|
|
|
|
Assert( GL_htl_2d_matrix_depth == 1 );
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
glPopMatrix();
|
|
glMatrixMode( GL_MODELVIEW );
|
|
glPopMatrix();
|
|
|
|
GL_htl_2d_matrix_set = 0;
|
|
GL_htl_2d_matrix_depth = 0;
|
|
}
|
|
|
|
void gr_opengl_push_scale_matrix(vec3d *scale_factor)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
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()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
glDisable(GL_CLIP_PLANE0);
|
|
}
|
|
|
|
void gr_opengl_start_clip_plane()
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
double clip_equation[4];
|
|
vec3d n;
|
|
vec3d 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);
|
|
}
|
|
|
|
//face -1 is to turn it off, the rest are right, left, up, down , front, and back
|
|
|
|
//++++++++++++++++++this isn't used anymore!!!!!
|
|
//needs to be set up in in the render-to-texture stuff
|
|
/*
|
|
void gr_opengl_render_to_env(int FACE)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
}
|
|
*/
|
|
|
|
//************************************State blocks************************************
|
|
|
|
//this is an array of reference counts for state block IDs
|
|
static GLuint *state_blocks = NULL;
|
|
static uint n_state_blocks = 0;
|
|
static GLuint current_state_block;
|
|
|
|
//this is used for places in the array that a state block ID no longer exists
|
|
#define EMPTY_STATE_BOX_REF_COUNT 0xFFFFFFFF
|
|
|
|
int opengl_get_new_state_block_internal()
|
|
{
|
|
uint i;
|
|
for(i = 0; i < n_state_blocks; i++)
|
|
if(state_blocks[i] == EMPTY_STATE_BOX_REF_COUNT) return i;
|
|
|
|
//oh crap, we need more state blocks
|
|
//"i" should be n_state_blocks + 1 since we got here.
|
|
state_blocks = (GLuint*)vm_realloc(state_blocks, i);
|
|
|
|
state_blocks[n_state_blocks]=0;
|
|
n_state_blocks++;
|
|
|
|
return n_state_blocks-1;
|
|
}
|
|
|
|
void gr_opengl_start_state_block()
|
|
{
|
|
gr_screen.recording_state_block = true;
|
|
current_state_block = opengl_get_new_state_block_internal();
|
|
glNewList(current_state_block, GL_COMPILE);
|
|
}
|
|
|
|
int gr_opengl_end_state_block()
|
|
{
|
|
//sanity check
|
|
if(!gr_screen.recording_state_block)
|
|
return -1;
|
|
|
|
//End the display list
|
|
gr_screen.recording_state_block = false;
|
|
glEndList();
|
|
|
|
//now return
|
|
return current_state_block;
|
|
}
|
|
|
|
void gr_opengl_set_state_block(int handle)
|
|
{
|
|
if(handle < 0) return;
|
|
glCallList(handle);
|
|
}
|
|
|
|
|
|
void gr_opengl_draw_htl_line(vec3d *start, vec3d* end)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
glBegin(GL_LINES);
|
|
glColor3ub(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue);
|
|
glSecondaryColor3ubvEXT(GL_zero_3ub);
|
|
glVertex3fv(start->a1d);
|
|
glVertex3fv(end->a1d);
|
|
glEnd();
|
|
}
|
|
|
|
void gr_opengl_draw_htl_sphere(float rad)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
GLUquadricObj *quad = NULL;
|
|
|
|
// FIXME: before this is used in anything other than FRED2 we need to make this creation/deletion
|
|
// stuff global so that it's not so slow (it can be reused for multiple quadratic objects)
|
|
quad = gluNewQuadric();
|
|
|
|
Assert(quad != NULL);
|
|
|
|
if (quad == NULL)
|
|
return;
|
|
|
|
glColor3ub(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue);
|
|
|
|
// FIXME: opengl_check_for_errors() needs to be modified to work with this at
|
|
// some point but for now I just don't care so it does nothing
|
|
gluQuadricCallback( quad, GLU_ERROR, NULL );
|
|
|
|
// FIXME: maybe support fill/wireframe with a future flag?
|
|
gluQuadricDrawStyle( quad, GLU_FILL );
|
|
|
|
// assuming unlit spheres, otherwise use GLU_SMOOTH so that it looks better
|
|
gluQuadricNormals( quad, GLU_NONE );
|
|
|
|
// we could set the slices/stacks at some point in the future but just use 16 now since it looks ok
|
|
gluSphere( quad, (GLdouble)rad, 16, 16 );
|
|
|
|
// FIXME: I just heard this scream "Globalize Me!!". It was really scary. I even cried.
|
|
gluDeleteQuadric( quad );
|
|
}
|