mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 12:41:35 -10:00
381 lines
11 KiB
C++
381 lines
11 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/GrOpenGLLight.cpp $
|
|
* $Revision: 1.11 $
|
|
* $Date: 2005-02-05 00:30:49 $
|
|
* $Author: taylor $
|
|
*
|
|
* code to implement lighting in HT&L opengl
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 1.10 2005/02/04 23:29:31 taylor
|
|
* merge with Linux/OSX tree - p0204-3
|
|
*
|
|
* Revision 1.9 2005/01/21 21:12:52 taylor
|
|
* crap
|
|
*
|
|
* Revision 1.8 2005/01/21 08:29:04 taylor
|
|
* add -rlm cmdline option to switch to local viewpoint lighting calculations (OGL only for now)
|
|
*
|
|
* Revision 1.7 2005/01/07 14:00:04 argv
|
|
* Added missing #include.
|
|
*
|
|
* -- _argv[-1]
|
|
*
|
|
* Revision 1.6 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.5 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.4 2004/10/31 21:45:13 taylor
|
|
* Linux tree merge, single array for VBOs/HTL
|
|
*
|
|
* Revision 1.3 2004/07/26 20:47:32 Kazan
|
|
* remove MCD complete
|
|
*
|
|
* Revision 1.2 2004/07/12 16:32:48 Kazan
|
|
* MCD - define _MCD_CHECK to use memory tracking
|
|
*
|
|
* Revision 1.1 2004/05/24 07:25:32 taylor
|
|
* filename case change
|
|
*
|
|
* Revision 2.7 2004/05/13 00:17:20 taylor
|
|
* disable COLOR_MATERIAL, for nvidia drivers
|
|
*
|
|
* Revision 2.6 2004/05/12 23:24:35 phreak
|
|
* got rid of the color material call, nebulas should blind the player
|
|
*
|
|
* Revision 2.5 2004/05/11 19:39:29 phreak
|
|
* fixed an array bounds error that was causing debug builds to crash when
|
|
* rendering a ship
|
|
*
|
|
* Revision 2.4 2004/04/26 13:02:27 taylor
|
|
* light setup changes, support cmdline ambient value
|
|
*
|
|
* 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/gropengl.h"
|
|
#include "graphics/gropenglextension.h"
|
|
#include "graphics/gropengllight.h"
|
|
#include "graphics/2d.h"
|
|
#include "render/3d.h"
|
|
#include "cmdline/cmdline.h"
|
|
|
|
|
|
|
|
// Variables
|
|
opengl_light opengl_lights[MAX_LIGHTS];
|
|
bool active_light_list[MAX_LIGHTS];
|
|
int *currently_enabled_lights = NULL;
|
|
bool lighting_is_enabled = true;
|
|
int active_gl_lights = 0;
|
|
int n_active_gl_lights = 0;
|
|
int GL_center_alpha = 0;
|
|
|
|
extern float static_point_factor;
|
|
extern float static_light_factor;
|
|
extern float static_tube_factor;
|
|
extern double specular_exponent_value;
|
|
|
|
extern int Cmdline_rlm;
|
|
|
|
int GL_max_lights = 0;
|
|
|
|
// OGL defaults
|
|
static const float GL_light_color[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
|
|
static const float GL_light_spec[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
static const float GL_light_zero[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
static float GL_light_ambient_value = 0.47f;
|
|
static float GL_light_ambient[4] = { 0.47f, 0.47f, 0.47f, 1.0f };
|
|
|
|
|
|
void FSLight2GLLight(opengl_light *GLLight,light_data *FSLight) {
|
|
|
|
GLLight->Diffuse.r = FSLight->r;// * FSLight->intensity;
|
|
GLLight->Diffuse.g = FSLight->g;// * FSLight->intensity;
|
|
GLLight->Diffuse.b = FSLight->b;// * FSLight->intensity;
|
|
GLLight->Specular.r = FSLight->spec_r;// * FSLight->intensity;
|
|
GLLight->Specular.g = FSLight->spec_g;// * FSLight->intensity;
|
|
GLLight->Specular.b = FSLight->spec_b;// * FSLight->intensity;
|
|
GLLight->Ambient.r = 0.0f;
|
|
GLLight->Ambient.g = 0.0f;
|
|
GLLight->Ambient.b = 0.0f;
|
|
GLLight->Ambient.a = 1.0f;
|
|
GLLight->Specular.a = 1.0f;
|
|
GLLight->Diffuse.a = 1.0f;
|
|
|
|
|
|
//If the light is a directional light
|
|
if(FSLight->type == LT_DIRECTIONAL) {
|
|
GLLight->Position.x = -FSLight->vec.xyz.x;
|
|
GLLight->Position.y = -FSLight->vec.xyz.y;
|
|
GLLight->Position.z = -FSLight->vec.xyz.z;
|
|
GLLight->Position.w = 0.0f; //Directional lights in OpenGL have w set to 0 and the direction vector in the position field
|
|
|
|
GLLight->Specular.r *= static_light_factor;
|
|
GLLight->Specular.g *= static_light_factor;
|
|
GLLight->Specular.b *= static_light_factor;
|
|
}
|
|
|
|
//If the light is a point or tube type
|
|
if((FSLight->type == LT_POINT) || (FSLight->type == LT_TUBE)) {
|
|
|
|
if(FSLight->type == LT_POINT){
|
|
GLLight->Specular.r *= static_point_factor;
|
|
GLLight->Specular.g *= static_point_factor;
|
|
GLLight->Specular.b *= static_point_factor;
|
|
}else{
|
|
GLLight->Specular.r *= static_tube_factor;
|
|
GLLight->Specular.g *= static_tube_factor;
|
|
GLLight->Specular.b *= static_tube_factor;
|
|
}
|
|
|
|
GLLight->Position.x = FSLight->vec.xyz.x;
|
|
GLLight->Position.y = FSLight->vec.xyz.y;
|
|
GLLight->Position.z = FSLight->vec.xyz.z; //flipped axis for FS2
|
|
GLLight->Position.w = 1.0f;
|
|
|
|
//They also have almost no radius...
|
|
// GLLight->Range = FSLight->radb +FSLight->rada; //No range function in OpenGL that I'm aware of
|
|
GLLight->ConstantAtten = 0.0f;
|
|
GLLight->LinearAtten = 0.1f;
|
|
GLLight->QuadraticAtten = 0.0f;
|
|
}
|
|
|
|
}
|
|
|
|
void set_opengl_light(int light_num, opengl_light *light)
|
|
{
|
|
Assert(light_num < GL_max_lights);
|
|
glLightfv(GL_LIGHT0+light_num, GL_POSITION, &light->Position.x);
|
|
glLightfv(GL_LIGHT0+light_num, GL_AMBIENT, &light->Ambient.r);
|
|
glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, &light->Diffuse.r);
|
|
glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, &light->Specular.r);
|
|
glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->ConstantAtten);
|
|
glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->LinearAtten);
|
|
glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->QuadraticAtten);
|
|
}
|
|
|
|
//finds the first unocupyed light
|
|
void opengl_pre_render_init_lights(){
|
|
for(int i = 0; i<GL_max_lights; i++){
|
|
if(currently_enabled_lights[i] > -1) glDisable(GL_LIGHT0+i);
|
|
currently_enabled_lights[i] = -1;
|
|
}
|
|
}
|
|
|
|
|
|
void opengl_change_active_lights(int pos){
|
|
int k = 0;
|
|
int l = 0;
|
|
if(!lighting_is_enabled)return;
|
|
bool move = false;
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
//straight cut'n'paste out of gr_opengl_set_view_matrix, but I couldn't use that, since it messes up with the stack depth var
|
|
vector fwd;
|
|
vector *uvec=&Eye_matrix.vec.uvec;
|
|
|
|
vm_vec_add(&fwd, &Eye_position, &Eye_matrix.vec.fvec);
|
|
|
|
gluLookAt(Eye_position.xyz.x,Eye_position.xyz.y,-Eye_position.xyz.z,
|
|
fwd.xyz.x,fwd.xyz.y,-fwd.xyz.z,
|
|
uvec->xyz.x, uvec->xyz.y,-uvec->xyz.z);
|
|
|
|
glScalef(1,1,-1);
|
|
|
|
for(int i = 0; (i < GL_max_lights) && ((pos * GL_max_lights)+i < active_gl_lights); i++){
|
|
glDisable(GL_LIGHT0+i);
|
|
move = false;
|
|
for(k=0; k<MAX_LIGHTS && !move; k++){
|
|
int slot = (pos * GL_max_lights)+l;
|
|
if(active_light_list[slot]){
|
|
if(opengl_lights[slot].occupied){
|
|
set_opengl_light(i,&opengl_lights[slot]);
|
|
glEnable(GL_LIGHT0+i);
|
|
currently_enabled_lights[i] = slot;
|
|
move = true;
|
|
l++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
int gr_opengl_make_light(light_data* light, int idx, int priority)
|
|
{
|
|
//Stub
|
|
return idx;
|
|
}
|
|
|
|
void gr_opengl_modify_light(light_data* light, int idx, int priority)
|
|
{
|
|
//Stub
|
|
}
|
|
|
|
void gr_opengl_destroy_light(int idx)
|
|
{
|
|
//Stub
|
|
}
|
|
|
|
void gr_opengl_set_light(light_data *light)
|
|
{
|
|
//Init the light
|
|
FSLight2GLLight(&opengl_lights[active_gl_lights],light);
|
|
opengl_lights[active_gl_lights].occupied = true;
|
|
active_light_list[active_gl_lights++] = true;
|
|
}
|
|
|
|
// this sets up a light to be pointinf from the eye to the object,
|
|
// the point being to make the object ether center or edge alphaed with THL
|
|
// this effect is used mostly on shockwave models
|
|
// -1 == edge
|
|
// 1 == center
|
|
// 0 == none
|
|
// should be called after lighting has been set up,
|
|
// currently not designed for use with lit models
|
|
void gr_opengl_center_alpha(int type)
|
|
{
|
|
GL_center_alpha = type;
|
|
}
|
|
|
|
void gr_opengl_set_center_alpha(int type)
|
|
{
|
|
}
|
|
|
|
void gr_opengl_reset_lighting()
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i<MAX_LIGHTS; i++){
|
|
opengl_lights[i].occupied = false;
|
|
}
|
|
for(i=0; i<GL_max_lights; i++){
|
|
glDisable(GL_LIGHT0+i);
|
|
active_light_list[i] = false;
|
|
}
|
|
active_gl_lights =0;
|
|
|
|
GL_center_alpha = 0;
|
|
}
|
|
|
|
void opengl_init_light()
|
|
{
|
|
float amb_user = 0.0f;
|
|
|
|
amb_user = (float)((Cmdline_ambient_factor * 2) - 255) / 255.0f;
|
|
|
|
GL_light_ambient_value += amb_user;
|
|
|
|
if (GL_light_ambient_value > 1.0f) {
|
|
GL_light_ambient_value = 1.0f;
|
|
} else if (GL_light_ambient_value < 0.02f) {
|
|
GL_light_ambient_value = 0.02f;
|
|
}
|
|
|
|
// set the ambient light
|
|
GL_light_ambient[0] = GL_light_ambient[1] = GL_light_ambient[2] = GL_light_ambient_value;
|
|
|
|
// only on front, tends to be more believable
|
|
glMaterialf(GL_FRONT, GL_SHININESS, 80.0f );
|
|
|
|
// more realistic lighting model
|
|
if (Cmdline_rlm)
|
|
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
|
|
|
|
glGetIntegerv(GL_MAX_LIGHTS, &GL_max_lights); // Get the max number of lights supported
|
|
|
|
// allocate memory for enabled lights
|
|
Verify(GL_max_lights > 0);
|
|
currently_enabled_lights = (int*)malloc(GL_max_lights * sizeof(int));
|
|
|
|
if (currently_enabled_lights == NULL)
|
|
Error( LOCATION, "Unable to allocate memory for lights!\n");
|
|
|
|
memset( currently_enabled_lights, -1, GL_max_lights * sizeof(int) );
|
|
}
|
|
|
|
void opengl_default_light_settings(int ambient = 1, int emission = 1, int specular = 1)
|
|
{
|
|
if (!lighting_is_enabled)
|
|
return;
|
|
|
|
if (ambient) {
|
|
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, GL_light_color );
|
|
} else {
|
|
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, GL_light_zero );
|
|
}
|
|
|
|
if (emission) {
|
|
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, GL_light_ambient );
|
|
} else {
|
|
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, GL_light_zero );
|
|
}
|
|
|
|
if (specular) {
|
|
// only on front, tends to be more believable
|
|
glMaterialfv( GL_FRONT, GL_SPECULAR, GL_light_spec );
|
|
} else {
|
|
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, GL_light_zero );
|
|
}
|
|
}
|
|
|
|
void gr_opengl_set_lighting(bool set, bool state)
|
|
{
|
|
lighting_is_enabled = set;
|
|
|
|
opengl_default_light_settings();
|
|
|
|
if ( (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER) && !set ) {
|
|
float amb[4] = { gr_screen.current_alpha, gr_screen.current_alpha, gr_screen.current_alpha, gr_screen.current_alpha };
|
|
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, amb );
|
|
} else {
|
|
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, GL_light_ambient );
|
|
}
|
|
|
|
for(int i = 0; i<GL_max_lights; i++){
|
|
if(currently_enabled_lights[i] > -1)glDisable(GL_LIGHT0+i);
|
|
currently_enabled_lights[i] = -1;
|
|
}
|
|
|
|
if(state) {
|
|
glEnable(GL_LIGHTING);
|
|
} else {
|
|
glDisable(GL_LIGHTING);
|
|
}
|
|
|
|
}
|