extremetuxracer/src/ogl.cpp

438 lines
12 KiB
C++

/* --------------------------------------------------------------------
EXTREME TUXRACER
Copyright (C) 1999-2001 Jasmin F. Patry (Tuxracer)
Copyright (C) 2010 Extreme Tuxracer Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
---------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include <etr_config.h>
#endif
#include "ogl.h"
#include "spx.h"
#include "winsys.h"
#include <GL/glu.h>
#include <stack>
#include <climits> // INT_MAX
static const struct {
const char* name;
GLenum value;
GLenum type;
} gl_values[] = {
{ "maximum lights", GL_MAX_LIGHTS, GL_INT },
{ "modelview stack depth", GL_MAX_MODELVIEW_STACK_DEPTH, GL_INT },
{ "projection stack depth", GL_MAX_PROJECTION_STACK_DEPTH, GL_INT },
{ "max texture size", GL_MAX_TEXTURE_SIZE, GL_INT },
{ "double buffering", GL_DOUBLEBUFFER, GL_UNSIGNED_BYTE },
{ "red bits", GL_RED_BITS, GL_INT },
{ "green bits", GL_GREEN_BITS, GL_INT },
{ "blue bits", GL_BLUE_BITS, GL_INT },
{ "alpha bits", GL_ALPHA_BITS, GL_INT },
{ "depth bits", GL_DEPTH_BITS, GL_INT },
{ "stencil bits", GL_STENCIL_BITS, GL_INT }
};
void check_gl_error() {
GLenum error = glGetError();
if (error != GL_NO_ERROR) {
const char* errstr = (const char*)gluErrorString(error);
Message("OpenGL Error: ", errstr ? errstr : "");
}
}
PFNGLLOCKARRAYSEXTPROC glLockArraysEXT_p = nullptr;
PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT_p = nullptr;
void InitOpenglExtensions() {
glLockArraysEXT_p = (PFNGLLOCKARRAYSEXTPROC)sf::Context::getFunction("glLockArraysEXT");
glUnlockArraysEXT_p = (PFNGLUNLOCKARRAYSEXTPROC)sf::Context::getFunction("glUnlockArraysEXT");
if (glLockArraysEXT_p == nullptr || glUnlockArraysEXT_p == nullptr) {
Message("GL_EXT_compiled_vertex_array extension NOT supported");
glLockArraysEXT_p = nullptr;
glUnlockArraysEXT_p = nullptr;
}
}
void PrintGLInfo() {
Message("Gl vendor: ", (char*)glGetString(GL_VENDOR));
Message("Gl renderer: ", (char*)glGetString(GL_RENDERER));
Message("Gl version: ", (char*)glGetString(GL_VERSION));
std::string extensions = (char*)glGetString(GL_EXTENSIONS);
Message("");
Message("Gl extensions:");
Message("");
std::size_t oldpos = 0;
std::size_t pos;
while ((pos = extensions.find(' ', oldpos)) != std::string::npos) {
std::string s = extensions.substr(oldpos, pos-oldpos);
Message(s);
oldpos = pos+1;
}
Message(extensions.substr(oldpos));
Message("");
for (int i=0; i<(int)(sizeof(gl_values)/sizeof(gl_values[0])); i++) {
switch (gl_values[i].type) {
case GL_INT: {
GLint int_val;
glGetIntegerv(gl_values[i].value, &int_val);
std::string ss = Int_StrN(int_val);
Message(gl_values[i].name, ss);
break;
}
case GL_FLOAT: {
GLfloat float_val;
glGetFloatv(gl_values[i].value, &float_val);
std::string ss = Float_StrN(float_val, 2);
Message(gl_values[i].name, ss);
break;
}
case GL_UNSIGNED_BYTE: {
GLboolean boolean_val;
glGetBooleanv(gl_values[i].value, &boolean_val);
std::string ss = Int_StrN(boolean_val);
Message(gl_values[i].name, ss);
break;
}
default:
Message("");
}
}
}
void set_material_diffuse(const sf::Color& diffuse_colour) {
GLint mat_amb_diff[4] = {
static_cast<GLint>(diffuse_colour.r) * (INT_MAX / 255),
static_cast<GLint>(diffuse_colour.g) * (INT_MAX / 255),
static_cast<GLint>(diffuse_colour.b) * (INT_MAX / 255),
static_cast<GLint>(diffuse_colour.a) * (INT_MAX / 255)
};
glMaterialiv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_amb_diff);
glColor(diffuse_colour);
}
void set_material(const sf::Color& diffuse_colour, const sf::Color& specular_colour, float specular_exp) {
set_material_diffuse(diffuse_colour);
GLint mat_specular[4] = {
static_cast<GLint>(specular_colour.r) * (INT_MAX / 255),
static_cast<GLint>(specular_colour.g) * (INT_MAX / 255),
static_cast<GLint>(specular_colour.b) * (INT_MAX / 255),
static_cast<GLint>(specular_colour.a) * (INT_MAX / 255)
};
glMaterialiv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, specular_exp);
}
void ClearRenderContext() {
glDepthMask(GL_TRUE);
glClearColor(colBackgr.r / 255.f, colBackgr.g / 255.f, colBackgr.b / 255.f, colBackgr.a / 255.f);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void ClearRenderContext(const sf::Color& col) {
glDepthMask(GL_TRUE);
glClearColor(col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void Setup2dScene() {
static const float offset = 0.f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Winsys.resolution.width, 0, Winsys.resolution.height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(offset, offset, -1.0);
glColor4f(1.0, 1.0, 1.0, 1.0);
}
void Reshape(int w, int h) {
glViewport(0, 0, (GLint) w, (GLint) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double far_clip_dist = param.forward_clip_distance + FAR_CLIP_FUDGE_AMOUNT;
gluPerspective(param.fov, (double)w/h, NEAR_CLIP_DIST, far_clip_dist);
glMatrixMode(GL_MODELVIEW);
}
// ====================================================================
// GL options
// ====================================================================
static TRenderMode currentMode = RM_UNINITIALIZED;
void ResetRenderMode() {
if (currentMode == GUI)
Winsys.endSFML();
currentMode = RM_UNINITIALIZED;
}
void set_gl_options(TRenderMode mode) {
if (currentMode == GUI)
Winsys.endSFML();
currentMode = mode;
switch (mode) {
case GUI:
Winsys.beginSFML();
break;
case GAUGE_BARS:
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
break;
case TEXFONT:
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
break;
case COURSE:
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LEQUAL);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
break;
case TREES:
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_NORMALIZE);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
glAlphaFunc(GL_GEQUAL, 0.5);
break;
case PARTICLES:
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
glAlphaFunc(GL_GEQUAL, 0.5);
break;
case SKY:
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_FALSE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
break;
case FOG_PLANE:
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
break;
case TUX:
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(GL_TRUE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
break;
case TUX_SHADOW:
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LESS);
#ifdef USE_STENCIL_BUFFER
glDisable(GL_CULL_FACE);
glEnable(GL_STENCIL_TEST);
glDepthMask(GL_FALSE);
glStencilFunc(GL_EQUAL, 0, ~0U);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
#else
glEnable(GL_CULL_FACE);
glDisable(GL_STENCIL_TEST);
glDepthMask(GL_TRUE);
#endif
break;
case TRACK_MARKS:
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glDisable(GL_NORMALIZE);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDepthMask(GL_FALSE);
glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LEQUAL);
break;
default:
Message("not a valid render mode");
}
}
static std::stack<TRenderMode> modestack;
void PushRenderMode(TRenderMode mode) {
if (currentMode != mode)
set_gl_options(mode);
modestack.push(mode);
}
void PopRenderMode() {
TRenderMode mode = modestack.top();
modestack.pop();
if (!modestack.empty() && modestack.top() != mode)
set_gl_options(modestack.top());
}
void glColor(const sf::Color& col) {
glColor4ub(col.r, col.g, col.b, col.a);
}
void glColor(const sf::Color& col, uint8_t alpha) {
glColor4ub(col.r, col.g, col.b, alpha);
}
void glTranslate(const TVector3d& vec) {
glTranslated(vec.x, vec.y, vec.z);
}
void glNormal3(const TVector3d& vec) {
glNormal3d(vec.x, vec.y, vec.z);
}
void glVertex3(const TVector3d& vec) {
glVertex3d(vec.x, vec.y, vec.z);
}
void glTexCoord2(const TVector2d& vec) {
glTexCoord2d(vec.x, vec.y);
}
void glLoadMatrix(const TMatrix<4, 4>& mat) {
glLoadMatrixd(mat.data());
}
void glMultMatrix(const TMatrix<4, 4>& mat) {
glMultMatrixd(mat.data());
}