Kart-Public/src/hardware/r_opengl/r_opengl.c
Sryder c46efa7c41 Set the screen textures to use max higher texture IDs
This should hopefully alleviate the issue where textures overwrite the screen, or the screen overwrites the texture for now.
THIS IS NOT A FULL SOLUTION TO THE PROBLEM, but I highly doubt we'll ever be loading 4 billion textures at once, ever.
2018-11-17 15:23:12 +00:00

2585 lines
73 KiB
C

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1998-2006 by Sonic Team Junior.
//
// 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.
//
//-----------------------------------------------------------------------------
/// \file
/// \brief OpenGL API for Sonic Robo Blast 2
#if defined (_WIN32)
//#define WIN32_LEAN_AND_MEAN
#define RPC_NO_WINDOWS_H
#include <windows.h>
#endif
#undef GETTEXT
#ifdef __GNUC__
#include <unistd.h>
#endif
#include <stdarg.h>
#include <math.h>
#ifndef SHUFFLE
#ifndef KOS_GL_COMPATIBILITY
#define SHUFFLE
#endif
#endif
#include "r_opengl.h"
#if defined (HWRENDER) && !defined (NOROPENGL)
// for KOS: GL_TEXTURE_ENV, glAlphaFunc, glColorMask, glPolygonOffset, glReadPixels, GL_ALPHA_TEST, GL_POLYGON_OFFSET_FILL
struct GLRGBAFloat
{
GLfloat red;
GLfloat green;
GLfloat blue;
GLfloat alpha;
};
typedef struct GLRGBAFloat GLRGBAFloat;
// ==========================================================================
// CONSTANTS
// ==========================================================================
// With OpenGL 1.1+, the first texture should be 1
#define NOTEXTURE_NUM 1 // small white texture
#define FIRST_TEX_AVAIL (NOTEXTURE_NUM + 1)
#define N_PI_DEMI (M_PIl/2.0f) //(1.5707963268f)
#define ASPECT_RATIO (1.0f) //(320.0f/200.0f)
#define FAR_CLIPPING_PLANE 32768.0f // Draw further! Tails 01-21-2001
static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE;
// **************************************************************************
// GLOBALS
// **************************************************************************
static GLuint NextTexAvail = FIRST_TEX_AVAIL;
static GLuint tex_downloaded = 0;
static GLfloat fov = 90.0f;
static GLuint pal_col = 0;
static FRGBAFloat const_pal_col;
static FBITFIELD CurrentPolyFlags;
static FTextureInfo* gr_cachetail = NULL;
static FTextureInfo* gr_cachehead = NULL;
RGBA_t myPaletteData[256];
GLint screen_width = 0; // used by Draw2DLine()
GLint screen_height = 0;
GLbyte screen_depth = 0;
GLint textureformatGL = 0;
GLint maximumAnisotropy = 0;
#ifndef KOS_GL_COMPATIBILITY
static GLboolean MipMap = GL_FALSE;
#endif
static GLint min_filter = GL_LINEAR;
static GLint mag_filter = GL_LINEAR;
static GLint anisotropic_filter = 0;
static FTransform md2_transform;
const GLubyte *gl_extensions = NULL;
//Hurdler: 04/10/2000: added for the kick ass coronas as Boris wanted;-)
#ifndef MINI_GL_COMPATIBILITY
static GLdouble modelMatrix[16];
static GLdouble projMatrix[16];
static GLint viewport[4];
#endif
#ifdef USE_PALETTED_TEXTURE
PFNGLCOLORTABLEEXTPROC glColorTableEXT = NULL;
GLubyte palette_tex[256*3];
#endif
// Yay for arbitrary numbers! NextTexAvail is buggy for some reason.
// Sryder: NextTexAvail is broken for these because palette changes or changes to the texture filter or antialiasing
// flush all of the stored textures, leaving them unavailable at times such as between levels
// These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs
// can know when the textures aren't there, as textures are always considered resident in their virtual memory
// TODO: Store them in a more normal way
#define SCRTEX_SCREENTEXTURE 4294967295
#define SCRTEX_STARTSCREENWIPE 4294967294
#define SCRTEX_ENDSCREENWIPE 4294967293
#define SCRTEX_FINALSCREENTEXTURE 4294967292
static GLuint screentexture = 0;
static GLuint startScreenWipe = 0;
static GLuint endScreenWipe = 0;
static GLuint finalScreenTexture = 0;
#if 0
GLuint screentexture = FIRST_TEX_AVAIL;
#endif
// shortcut for ((float)1/i)
static const GLfloat byte2float[256] = {
0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f,
0.031373f, 0.035294f, 0.039216f, 0.043137f, 0.047059f, 0.050980f, 0.054902f, 0.058824f,
0.062745f, 0.066667f, 0.070588f, 0.074510f, 0.078431f, 0.082353f, 0.086275f, 0.090196f,
0.094118f, 0.098039f, 0.101961f, 0.105882f, 0.109804f, 0.113725f, 0.117647f, 0.121569f,
0.125490f, 0.129412f, 0.133333f, 0.137255f, 0.141176f, 0.145098f, 0.149020f, 0.152941f,
0.156863f, 0.160784f, 0.164706f, 0.168627f, 0.172549f, 0.176471f, 0.180392f, 0.184314f,
0.188235f, 0.192157f, 0.196078f, 0.200000f, 0.203922f, 0.207843f, 0.211765f, 0.215686f,
0.219608f, 0.223529f, 0.227451f, 0.231373f, 0.235294f, 0.239216f, 0.243137f, 0.247059f,
0.250980f, 0.254902f, 0.258824f, 0.262745f, 0.266667f, 0.270588f, 0.274510f, 0.278431f,
0.282353f, 0.286275f, 0.290196f, 0.294118f, 0.298039f, 0.301961f, 0.305882f, 0.309804f,
0.313726f, 0.317647f, 0.321569f, 0.325490f, 0.329412f, 0.333333f, 0.337255f, 0.341176f,
0.345098f, 0.349020f, 0.352941f, 0.356863f, 0.360784f, 0.364706f, 0.368627f, 0.372549f,
0.376471f, 0.380392f, 0.384314f, 0.388235f, 0.392157f, 0.396078f, 0.400000f, 0.403922f,
0.407843f, 0.411765f, 0.415686f, 0.419608f, 0.423529f, 0.427451f, 0.431373f, 0.435294f,
0.439216f, 0.443137f, 0.447059f, 0.450980f, 0.454902f, 0.458824f, 0.462745f, 0.466667f,
0.470588f, 0.474510f, 0.478431f, 0.482353f, 0.486275f, 0.490196f, 0.494118f, 0.498039f,
0.501961f, 0.505882f, 0.509804f, 0.513726f, 0.517647f, 0.521569f, 0.525490f, 0.529412f,
0.533333f, 0.537255f, 0.541177f, 0.545098f, 0.549020f, 0.552941f, 0.556863f, 0.560784f,
0.564706f, 0.568627f, 0.572549f, 0.576471f, 0.580392f, 0.584314f, 0.588235f, 0.592157f,
0.596078f, 0.600000f, 0.603922f, 0.607843f, 0.611765f, 0.615686f, 0.619608f, 0.623529f,
0.627451f, 0.631373f, 0.635294f, 0.639216f, 0.643137f, 0.647059f, 0.650980f, 0.654902f,
0.658824f, 0.662745f, 0.666667f, 0.670588f, 0.674510f, 0.678431f, 0.682353f, 0.686275f,
0.690196f, 0.694118f, 0.698039f, 0.701961f, 0.705882f, 0.709804f, 0.713726f, 0.717647f,
0.721569f, 0.725490f, 0.729412f, 0.733333f, 0.737255f, 0.741177f, 0.745098f, 0.749020f,
0.752941f, 0.756863f, 0.760784f, 0.764706f, 0.768627f, 0.772549f, 0.776471f, 0.780392f,
0.784314f, 0.788235f, 0.792157f, 0.796078f, 0.800000f, 0.803922f, 0.807843f, 0.811765f,
0.815686f, 0.819608f, 0.823529f, 0.827451f, 0.831373f, 0.835294f, 0.839216f, 0.843137f,
0.847059f, 0.850980f, 0.854902f, 0.858824f, 0.862745f, 0.866667f, 0.870588f, 0.874510f,
0.878431f, 0.882353f, 0.886275f, 0.890196f, 0.894118f, 0.898039f, 0.901961f, 0.905882f,
0.909804f, 0.913726f, 0.917647f, 0.921569f, 0.925490f, 0.929412f, 0.933333f, 0.937255f,
0.941177f, 0.945098f, 0.949020f, 0.952941f, 0.956863f, 0.960784f, 0.964706f, 0.968628f,
0.972549f, 0.976471f, 0.980392f, 0.984314f, 0.988235f, 0.992157f, 0.996078f, 1.000000f
};
float byteasfloat(UINT8 fbyte)
{
return (float)(byte2float[fbyte]*2.0f);
}
static I_Error_t I_Error_GL = NULL;
#ifndef MINI_GL_COMPATIBILITY
static boolean gl13 = false; // whether we can use opengl 1.3 functions
#endif
// -----------------+
// DBG_Printf : Output error messages to debug log if DEBUG_TO_FILE is defined,
// : else do nothing
// Returns :
// -----------------+
FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
{
#ifdef DEBUG_TO_FILE
char str[4096] = "";
va_list arglist;
va_start (arglist, lpFmt);
vsnprintf (str, 4096, lpFmt, arglist);
va_end (arglist);
if (gllogstream)
fwrite(str, strlen(str), 1, gllogstream);
#else
(void)lpFmt;
#endif
}
#ifdef STATIC_OPENGL
/* 1.0 functions */
/* Miscellaneous */
#define pglClearColor glClearColor
//glClear
#define pglColorMask glColorMask
#define pglAlphaFunc glAlphaFunc
#define pglBlendFunc glBlendFunc
#define pglCullFace glCullFace
#define pglPolygonMode glPolygonMode
#define pglPolygonOffset glPolygonOffset
#define pglScissor glScissor
#define pglEnable glEnable
#define pglDisable glDisable
#ifndef MINI_GL_COMPATIBILITY
#define pglGetDoublev glGetDoublev
#endif
//glGetIntegerv
//glGetString
#ifdef KOS_GL_COMPATIBILITY
#define pglHint glHint
#endif
/* Depth Buffer */
#define pglClearDepth glClearDepth
#define pglDepthFunc glDepthFunc
#define pglDepthMask glDepthMask
#define pglDepthRange glDepthRange
/* Transformation */
#define pglMatrixMode glMatrixMode
#define pglViewport glViewport
#define pglPushMatrix glPushMatrix
#define pglPopMatrix glPopMatrix
#define pglLoadIdentity glLoadIdentity
#ifdef MINI_GL_COMPATIBILITY
#define pglMultMatrixf glMultMatrixf
#else
#define pglMultMatrixd glMultMatrixd
#endif
#define pglRotatef glRotatef
#define pglScalef glScalef
#define pglTranslatef glTranslatef
/* Drawing Functions */
#define pglBegin glBegin
#define pglEnd glEnd
#define pglVertex3f glVertex3f
#define pglNormal3f glNormal3f
#define pglColor4f glColor4f
#define pglColor4fv glColor4fv
#define pglTexCoord2f glTexCoord2f
/* Lighting */
#define pglShadeModel glShadeModel
#define pglLightfv glLightfv
#define pglLightModelfv glLightModelfv
#define pglMaterialfv glMaterialfv
/* Raster functions */
#define pglPixelStorei glPixelStorei
#define pglReadPixels glReadPixels
/* Texture mapping */
#define pglTexEnvi glTexEnvi
#define pglTexParameteri glTexParameteri
#define pglTexImage2D glTexImage2D
/* Fog */
#define pglFogf glFogf
#define pglFogfv glFogfv
/* 1.1 functions */
/* texture objects */ //GL_EXT_texture_object
#define pglDeleteTextures glDeleteTextures
#define pglBindTexture glBindTexture
/* texture mapping */ //GL_EXT_copy_texture
#ifndef KOS_GL_COMPATIBILITY
#define pglCopyTexImage2D glCopyTexImage2D
#define pglCopyTexSubImage2D glCopyTexSubImage2D
#endif
#else //!STATIC_OPENGL
/* 1.0 functions */
/* Miscellaneous */
typedef void (APIENTRY * PFNglClearColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
static PFNglClearColor pglClearColor;
//glClear
typedef void (APIENTRY * PFNglColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
static PFNglColorMask pglColorMask;
typedef void (APIENTRY * PFNglAlphaFunc) (GLenum func, GLclampf ref);
static PFNglAlphaFunc pglAlphaFunc;
typedef void (APIENTRY * PFNglBlendFunc) (GLenum sfactor, GLenum dfactor);
static PFNglBlendFunc pglBlendFunc;
typedef void (APIENTRY * PFNglCullFace) (GLenum mode);
static PFNglCullFace pglCullFace;
typedef void (APIENTRY * PFNglPolygonMode) (GLenum face, GLenum mode);
static PFNglPolygonMode pglPolygonMode;
typedef void (APIENTRY * PFNglPolygonOffset) (GLfloat factor, GLfloat units);
static PFNglPolygonOffset pglPolygonOffset;
typedef void (APIENTRY * PFNglScissor) (GLint x, GLint y, GLsizei width, GLsizei height);
static PFNglScissor pglScissor;
typedef void (APIENTRY * PFNglEnable) (GLenum cap);
static PFNglEnable pglEnable;
typedef void (APIENTRY * PFNglDisable) (GLenum cap);
static PFNglDisable pglDisable;
#ifndef MINI_GL_COMPATIBILITY
typedef void (APIENTRY * PFNglGetDoublev) (GLenum pname, GLdouble *params);
static PFNglGetDoublev pglGetDoublev;
#endif
//glGetIntegerv
//glGetString
/* Depth Buffer */
typedef void (APIENTRY * PFNglClearDepth) (GLclampd depth);
static PFNglClearDepth pglClearDepth;
typedef void (APIENTRY * PFNglDepthFunc) (GLenum func);
static PFNglDepthFunc pglDepthFunc;
typedef void (APIENTRY * PFNglDepthMask) (GLboolean flag);
static PFNglDepthMask pglDepthMask;
typedef void (APIENTRY * PFNglDepthRange) (GLclampd near_val, GLclampd far_val);
static PFNglDepthRange pglDepthRange;
/* Transformation */
typedef void (APIENTRY * PFNglMatrixMode) (GLenum mode);
static PFNglMatrixMode pglMatrixMode;
typedef void (APIENTRY * PFNglViewport) (GLint x, GLint y, GLsizei width, GLsizei height);
static PFNglViewport pglViewport;
typedef void (APIENTRY * PFNglPushMatrix) (void);
static PFNglPushMatrix pglPushMatrix;
typedef void (APIENTRY * PFNglPopMatrix) (void);
static PFNglPopMatrix pglPopMatrix;
typedef void (APIENTRY * PFNglLoadIdentity) (void);
static PFNglLoadIdentity pglLoadIdentity;
#ifdef MINI_GL_COMPATIBILITY
typedef void (APIENTRY * PFNglMultMatrixf) (const GLfloat *m);
static PFNglMultMatrixf pglMultMatrixf;
#else
typedef void (APIENTRY * PFNglMultMatrixd) (const GLdouble *m);
static PFNglMultMatrixd pglMultMatrixd;
#endif
typedef void (APIENTRY * PFNglRotatef) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
static PFNglRotatef pglRotatef;
typedef void (APIENTRY * PFNglScalef) (GLfloat x, GLfloat y, GLfloat z);
static PFNglScalef pglScalef;
typedef void (APIENTRY * PFNglTranslatef) (GLfloat x, GLfloat y, GLfloat z);
static PFNglTranslatef pglTranslatef;
/* Drawing Functions */
typedef void (APIENTRY * PFNglBegin) (GLenum mode);
static PFNglBegin pglBegin;
typedef void (APIENTRY * PFNglEnd) (void);
static PFNglEnd pglEnd;
typedef void (APIENTRY * PFNglVertex3f) (GLfloat x, GLfloat y, GLfloat z);
static PFNglVertex3f pglVertex3f;
typedef void (APIENTRY * PFNglNormal3f) (GLfloat x, GLfloat y, GLfloat z);
static PFNglNormal3f pglNormal3f;
typedef void (APIENTRY * PFNglColor4f) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
static PFNglColor4f pglColor4f;
typedef void (APIENTRY * PFNglColor4fv) (const GLfloat *v);
static PFNglColor4fv pglColor4fv;
typedef void (APIENTRY * PFNglTexCoord2f) (GLfloat s, GLfloat t);
static PFNglTexCoord2f pglTexCoord2f;
/* Lighting */
typedef void (APIENTRY * PFNglShadeModel) (GLenum mode);
static PFNglShadeModel pglShadeModel;
typedef void (APIENTRY * PFNglLightfv) (GLenum light, GLenum pname, GLfloat *params);
static PFNglLightfv pglLightfv;
typedef void (APIENTRY * PFNglLightModelfv) (GLenum pname, GLfloat *params);
static PFNglLightModelfv pglLightModelfv;
typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *params);
static PFNglMaterialfv pglMaterialfv;
/* Raster functions */
typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
static PFNglPixelStorei pglPixelStorei;
typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
static PFNglReadPixels pglReadPixels;
/* Texture mapping */
typedef void (APIENTRY * PFNglTexEnvi) (GLenum target, GLenum pname, GLint param);
static PFNglTexEnvi pglTexEnvi;
typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param);
static PFNglTexParameteri pglTexParameteri;
typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage2D pglTexImage2D;
/* Fog */
typedef void (APIENTRY * PFNglFogf) (GLenum pname, GLfloat param);
static PFNglFogf pglFogf;
typedef void (APIENTRY * PFNglFogfv) (GLenum pname, const GLfloat *params);
static PFNglFogfv pglFogfv;
/* 1.1 functions */
/* texture objects */ //GL_EXT_texture_object
typedef void (APIENTRY * PFNglDeleteTextures) (GLsizei n, const GLuint *textures);
static PFNglDeleteTextures pglDeleteTextures;
typedef void (APIENTRY * PFNglBindTexture) (GLenum target, GLuint texture);
static PFNglBindTexture pglBindTexture;
/* texture mapping */ //GL_EXT_copy_texture
typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
static PFNglCopyTexImage2D pglCopyTexImage2D;
typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
static PFNglCopyTexSubImage2D pglCopyTexSubImage2D;
#endif
/* GLU functions */
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
#ifndef MINI_GL_COMPATIBILITY
/* 1.3 functions for multitexturing */
typedef void (APIENTRY *PFNglActiveTexture) (GLenum);
static PFNglActiveTexture pglActiveTexture;
typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
static PFNglMultiTexCoord2f pglMultiTexCoord2f;
#endif
#ifndef MINI_GL_COMPATIBILITY
/* 1.2 Parms */
/* GL_CLAMP_TO_EDGE_EXT */
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#ifndef GL_TEXTURE_MIN_LOD
#define GL_TEXTURE_MIN_LOD 0x813A
#endif
#ifndef GL_TEXTURE_MAX_LOD
#define GL_TEXTURE_MAX_LOD 0x813B
#endif
/* 1.3 GL_TEXTUREi */
#ifndef GL_TEXTURE0
#define GL_TEXTURE0 0x84C0
#endif
#ifndef GL_TEXTURE1
#define GL_TEXTURE1 0x84C1
#endif
#endif
#ifdef MINI_GL_COMPATIBILITY
#undef GL_CLAMP_TO_EDGE
#undef GL_TEXTURE_MIN_LOD
#undef GL_TEXTURE_MAX_LOD
#endif
boolean SetupGLfunc(void)
{
#ifndef STATIC_OPENGL
#define GETOPENGLFUNC(func, proc) \
func = GetGLFunc(#proc); \
if (!func) \
{ \
DBG_Printf("failed to get OpenGL function: %s", #proc); \
} \
GETOPENGLFUNC(pglClearColor, glClearColor)
GETOPENGLFUNC(pglClear , glClear)
GETOPENGLFUNC(pglColorMask , glColorMask)
GETOPENGLFUNC(pglAlphaFunc , glAlphaFunc)
GETOPENGLFUNC(pglBlendFunc , glBlendFunc)
GETOPENGLFUNC(pglCullFace , glCullFace)
GETOPENGLFUNC(pglPolygonMode , glPolygonMode)
GETOPENGLFUNC(pglPolygonOffset , glPolygonOffset)
GETOPENGLFUNC(pglScissor , glScissor)
GETOPENGLFUNC(pglEnable , glEnable)
GETOPENGLFUNC(pglDisable , glDisable)
#ifndef MINI_GL_COMPATIBILITY
GETOPENGLFUNC(pglGetDoublev , glGetDoublev)
#endif
GETOPENGLFUNC(pglGetIntegerv , glGetIntegerv)
GETOPENGLFUNC(pglGetString , glGetString)
GETOPENGLFUNC(pglClearDepth , glClearDepth)
GETOPENGLFUNC(pglDepthFunc , glDepthFunc)
GETOPENGLFUNC(pglDepthMask , glDepthMask)
GETOPENGLFUNC(pglDepthRange , glDepthRange)
GETOPENGLFUNC(pglMatrixMode , glMatrixMode)
GETOPENGLFUNC(pglViewport , glViewport)
GETOPENGLFUNC(pglPushMatrix , glPushMatrix)
GETOPENGLFUNC(pglPopMatrix , glPopMatrix)
GETOPENGLFUNC(pglLoadIdentity , glLoadIdentity)
#ifdef MINI_GL_COMPATIBILITY
GETOPENGLFUNC(pglMultMatrixf , glMultMatrixf)
#else
GETOPENGLFUNC(pglMultMatrixd , glMultMatrixd)
#endif
GETOPENGLFUNC(pglRotatef , glRotatef)
GETOPENGLFUNC(pglScalef , glScalef)
GETOPENGLFUNC(pglTranslatef , glTranslatef)
GETOPENGLFUNC(pglBegin , glBegin)
GETOPENGLFUNC(pglEnd , glEnd)
GETOPENGLFUNC(pglVertex3f , glVertex3f)
GETOPENGLFUNC(pglNormal3f , glNormal3f)
GETOPENGLFUNC(pglColor4f , glColor4f)
GETOPENGLFUNC(pglColor4fv , glColor4fv)
GETOPENGLFUNC(pglTexCoord2f , glTexCoord2f)
GETOPENGLFUNC(pglShadeModel , glShadeModel)
GETOPENGLFUNC(pglLightfv, glLightfv)
GETOPENGLFUNC(pglLightModelfv , glLightModelfv)
GETOPENGLFUNC(pglMaterialfv , glMaterialfv)
GETOPENGLFUNC(pglPixelStorei , glPixelStorei)
GETOPENGLFUNC(pglReadPixels , glReadPixels)
GETOPENGLFUNC(pglTexEnvi , glTexEnvi)
GETOPENGLFUNC(pglTexParameteri , glTexParameteri)
GETOPENGLFUNC(pglTexImage2D , glTexImage2D)
GETOPENGLFUNC(pglFogf , glFogf)
GETOPENGLFUNC(pglFogfv , glFogfv)
GETOPENGLFUNC(pglDeleteTextures , glDeleteTextures)
GETOPENGLFUNC(pglBindTexture , glBindTexture)
GETOPENGLFUNC(pglCopyTexImage2D , glCopyTexImage2D)
GETOPENGLFUNC(pglCopyTexSubImage2D , glCopyTexSubImage2D)
#undef GETOPENGLFUNC
pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps");
#endif
return true;
}
// This has to be done after the context is created so the version number can be obtained
boolean SetupGLFunc13(void)
{
#ifdef MINI_GL_COMPATIBILITY
return false;
#else
const GLubyte *version = pglGetString(GL_VERSION);
int glmajor, glminor;
gl13 = false;
// Parse the GL version
if (version != NULL)
{
if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
{
// Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
if (glmajor == 1 && glminor >= 3)
gl13 = true;
else if (glmajor > 1)
gl13 = true;
}
}
if (gl13)
{
pglActiveTexture = GetGLFunc("glActiveTexture");
pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f");
}
else if (isExtAvailable("GL_ARB_multitexture", gl_extensions))
{
// Get the functions
pglActiveTexture = GetGLFunc("glActiveTextureARB");
pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2fARB");
gl13 = true; // This is now true, so the new fade mask stuff can be done, if OpenGL version is less than 1.3, it still uses the old fade stuff.
DBG_Printf("GL_ARB_multitexture support: enabled\n");
}
else
DBG_Printf("GL_ARB_multitexture support: disabled\n");
return true;
#endif
}
// -----------------+
// SetNoTexture : Disable texture
// -----------------+
static void SetNoTexture(void)
{
// Set small white texture.
if (tex_downloaded != NOTEXTURE_NUM)
{
pglBindTexture(GL_TEXTURE_2D, NOTEXTURE_NUM);
tex_downloaded = NOTEXTURE_NUM;
}
}
static void GLPerspective(GLdouble fovy, GLdouble aspect)
{
#ifdef MINI_GL_COMPATIBILITY
GLfloat m[4][4] =
#else
GLdouble m[4][4] =
#endif
{
{ 1.0f, 0.0f, 0.0f, 0.0f},
{ 0.0f, 1.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 1.0f,-1.0f},
{ 0.0f, 0.0f, 0.0f, 0.0f},
};
const GLdouble zNear = NEAR_CLIPPING_PLANE;
const GLdouble zFar = FAR_CLIPPING_PLANE;
const GLdouble radians = (GLdouble)(fovy / 2.0f * M_PIl / 180.0f);
const GLdouble sine = sin(radians);
const GLdouble deltaZ = zFar - zNear;
GLdouble cotangent;
if ((deltaZ == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) {
return;
}
cotangent = cos(radians) / sine;
m[0][0] = cotangent / aspect;
m[1][1] = cotangent;
m[2][2] = -(zFar + zNear) / deltaZ;
m[3][2] = -2.0f * zNear * zFar / deltaZ;
#ifdef MINI_GL_COMPATIBILITY
pglMultMatrixf(&m[0][0]);
#else
pglMultMatrixd(&m[0][0]);
#endif
}
#ifndef MINI_GL_COMPATIBILITY
static void GLProject(GLdouble objX, GLdouble objY, GLdouble objZ,
GLdouble* winX, GLdouble* winY, GLdouble* winZ)
{
GLdouble in[4], out[4];
int i;
for (i=0; i<4; i++)
{
out[i] =
objX * modelMatrix[0*4+i] +
objY * modelMatrix[1*4+i] +
objZ * modelMatrix[2*4+i] +
modelMatrix[3*4+i];
}
for (i=0; i<4; i++)
{
in[i] =
out[0] * projMatrix[0*4+i] +
out[1] * projMatrix[1*4+i] +
out[2] * projMatrix[2*4+i] +
out[3] * projMatrix[3*4+i];
}
if (in[3] == 0.0f) return;
in[0] /= in[3];
in[1] /= in[3];
in[2] /= in[3];
/* Map x, y and z to range 0-1 */
in[0] = in[0] * 0.5f + 0.5f;
in[1] = in[1] * 0.5f + 0.5f;
in[2] = in[2] * 0.5f + 0.5f;
/* Map x,y to viewport */
in[0] = in[0] * viewport[2] + viewport[0];
in[1] = in[1] * viewport[3] + viewport[1];
*winX=in[0];
*winY=in[1];
*winZ=in[2];
}
#endif
// -----------------+
// SetModelView :
// -----------------+
void SetModelView(GLint w, GLint h)
{
// DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h);
// The screen textures need to be flushed if the width or height change so that they be remade for the correct size
if (screen_width != w || screen_height != h)
FlushScreenTextures();
screen_width = w;
screen_height = h;
pglViewport(0, 0, w, h);
#ifdef GL_ACCUM_BUFFER_BIT
pglClear(GL_ACCUM_BUFFER_BIT);
#endif
pglMatrixMode(GL_PROJECTION);
pglLoadIdentity();
pglMatrixMode(GL_MODELVIEW);
pglLoadIdentity();
GLPerspective(fov, ASPECT_RATIO);
//pglScalef(1.0f, 320.0f/200.0f, 1.0f); // gr_scalefrustum (ORIGINAL_ASPECT)
// added for new coronas' code (without depth buffer)
#ifndef MINI_GL_COMPATIBILITY
pglGetIntegerv(GL_VIEWPORT, viewport);
pglGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
#endif
}
// -----------------+
// SetStates : Set permanent states
// -----------------+
void SetStates(void)
{
// Bind little white RGBA texture to ID NOTEXTURE_NUM.
/*
FUINT Data[8*8];
INT32 i;
*/
#ifdef GL_LIGHT_MODEL_AMBIENT
GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
#endif
// DBG_Printf("SetStates()\n");
// Hurdler: not necessary, is it?
pglShadeModel(GL_SMOOTH); // iterate vertice colors
//pglShadeModel(GL_FLAT);
pglEnable(GL_TEXTURE_2D); // two-dimensional texturing
#ifndef KOS_GL_COMPATIBILITY
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
pglAlphaFunc(GL_NOTEQUAL, 0.0f);
#endif
//pglBlendFunc(GL_ONE, GL_ZERO); // copy pixel to frame buffer (opaque)
pglEnable(GL_BLEND); // enable color blending
#ifndef KOS_GL_COMPATIBILITY
pglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
#endif
//pglDisable(GL_DITHER); // faB: ??? (undocumented in OpenGL 1.1)
// Hurdler: yes, it is!
pglEnable(GL_DEPTH_TEST); // check the depth buffer
pglDepthMask(GL_TRUE); // enable writing to depth buffer
pglClearDepth(1.0f);
pglDepthRange(0.0f, 1.0f);
pglDepthFunc(GL_LEQUAL);
// this set CurrentPolyFlags to the acctual configuration
CurrentPolyFlags = 0xffffffff;
SetBlend(0);
/*
for (i = 0; i < 64; i++)
Data[i] = 0xffFFffFF; // white pixel
*/
tex_downloaded = (GLuint)-1;
SetNoTexture();
//pglBindTexture(GL_TEXTURE_2D, NOTEXTURE_NUM);
//tex_downloaded = NOTEXTURE_NUM;
//pglTexImage2D(GL_TEXTURE_2D, 0, 4, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, Data);
#ifndef KOS_GL_COMPATIBILITY
pglPolygonOffset(-1.0f, -1.0f);
#endif
//pglEnable(GL_CULL_FACE);
//pglCullFace(GL_FRONT);
//pglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//pglPolygonMode(GL_FRONT, GL_LINE);
//glFogi(GL_FOG_MODE, GL_EXP);
//pglHint(GL_FOG_HINT, GL_FASTEST);
//pglFogfv(GL_FOG_COLOR, fogcolor);
//pglFogf(GL_FOG_DENSITY, 0.0005f);
// Lighting for models
#ifdef GL_LIGHT_MODEL_AMBIENT
pglLightModelfv(GL_LIGHT_MODEL_AMBIENT, LightDiffuse);
pglEnable(GL_LIGHT0);
#endif
// bp : when no t&l :)
pglLoadIdentity();
pglScalef(1.0f, 1.0f, -1.0f);
#ifndef MINI_GL_COMPATIBILITY
pglGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
#endif
}
// -----------------+
// Flush : flush OpenGL textures
// : Clear list of downloaded mipmaps
// -----------------+
void Flush(void)
{
//DBG_Printf ("HWR_Flush()\n");
while (gr_cachehead)
{
// ceci n'est pas du tout necessaire vu que tu les a charger normalement et
// donc il sont dans ta liste !
#if 0
//Hurdler: 25/04/2000: now support colormap in hardware mode
FTextureInfo *tmp = gr_cachehead->nextskin;
// The memory should be freed in the main code
while (tmp)
{
pglDeleteTextures(1, &tmp->downloaded);
tmp->downloaded = 0;
tmp = tmp->nextcolormap;
}
#endif
pglDeleteTextures(1, (GLuint *)&gr_cachehead->downloaded);
gr_cachehead->downloaded = 0;
gr_cachehead = gr_cachehead->nextmipmap;
}
gr_cachetail = gr_cachehead = NULL; //Hurdler: well, gr_cachehead is already NULL
NextTexAvail = FIRST_TEX_AVAIL;
#if 0
if (screentexture != FIRST_TEX_AVAIL)
{
pglDeleteTextures(1, &screentexture);
screentexture = FIRST_TEX_AVAIL;
}
#endif
tex_downloaded = 0;
}
// -----------------+
// isExtAvailable : Look if an OpenGL extension is available
// Returns : true if extension available
// -----------------+
INT32 isExtAvailable(const char *extension, const GLubyte *start)
{
GLubyte *where, *terminator;
if (!extension || !start) return 0;
where = (GLubyte *) strchr(extension, ' ');
if (where || *extension == '\0')
return 0;
for (;;)
{
where = (GLubyte *) strstr((const char *) start, extension);
if (!where)
break;
terminator = where + strlen(extension);
if (where == start || *(where - 1) == ' ')
if (*terminator == ' ' || *terminator == '\0')
return 1;
start = terminator;
}
return 0;
}
// -----------------+
// Init : Initialise the OpenGL interface API
// Returns :
// -----------------+
EXPORT boolean HWRAPI(Init) (I_Error_t FatalErrorFunction)
{
I_Error_GL = FatalErrorFunction;
DBG_Printf ("%s %s\n", DRIVER_STRING, VERSIONSTRING);
return LoadGL();
}
// -----------------+
// ClearMipMapCache : Flush OpenGL textures from memory
// -----------------+
EXPORT void HWRAPI(ClearMipMapCache) (void)
{
// DBG_Printf ("HWR_Flush(exe)\n");
Flush();
}
// -----------------+
// ReadRect : Read a rectangle region of the truecolor framebuffer
// : store pixels as 16bit 565 RGB
// Returns : 16bit 565 RGB pixel array stored in dst_data
// -----------------+
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
INT32 dst_stride, UINT16 * dst_data)
{
#ifdef KOS_GL_COMPATIBILITY
(void)x;
(void)y;
(void)width;
(void)height;
(void)dst_stride;
(void)dst_data;
#else
INT32 i;
// DBG_Printf ("ReadRect()\n");
if (dst_stride == width*3)
{
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
GLubyte *row = malloc(dst_stride);
if (!row) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(i = 0; i < height/2; i++)
{
memcpy(row, top, dst_stride);
memcpy(top, bottom, dst_stride);
memcpy(bottom, row, dst_stride);
top += dst_stride;
bottom -= dst_stride;
}
free(row);
}
else
{
INT32 j;
GLubyte *image = malloc(width*height*3*sizeof (*image));
if (!image) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = height-1; i >= 0; i--)
{
for (j = 0; j < width; j++)
{
dst_data[(height-1-i)*width+j] =
(UINT16)(
((image[(i*width+j)*3]>>3)<<11) |
((image[(i*width+j)*3+1]>>2)<<5) |
((image[(i*width+j)*3+2]>>3)));
}
}
free(image);
}
#endif
}
// -----------------+
// GClipRect : Defines the 2D hardware clipping window
// -----------------+
EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip)
{
// DBG_Printf ("GClipRect(%d, %d, %d, %d)\n", minx, miny, maxx, maxy);
pglViewport(minx, screen_height-maxy, maxx-minx, maxy-miny);
NEAR_CLIPPING_PLANE = nearclip;
//pglScissor(minx, screen_height-maxy, maxx-minx, maxy-miny);
pglMatrixMode(GL_PROJECTION);
pglLoadIdentity();
GLPerspective(fov, ASPECT_RATIO);
pglMatrixMode(GL_MODELVIEW);
// added for new coronas' code (without depth buffer)
#ifndef MINI_GL_COMPATIBILITY
pglGetIntegerv(GL_VIEWPORT, viewport);
pglGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
#endif
}
// -----------------+
// ClearBuffer : Clear the color/alpha/depth buffer(s)
// -----------------+
EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask,
FBOOLEAN DepthMask,
FRGBAFloat * ClearColor)
{
// DBG_Printf ("ClearBuffer(%d)\n", alpha);
GLbitfield ClearMask = 0;
if (ColorMask)
{
if (ClearColor)
pglClearColor(ClearColor->red,
ClearColor->green,
ClearColor->blue,
ClearColor->alpha);
ClearMask |= GL_COLOR_BUFFER_BIT;
}
if (DepthMask)
{
pglClearDepth(1.0f); //Hurdler: all that are permanen states
pglDepthRange(0.0f, 1.0f);
pglDepthFunc(GL_LEQUAL);
ClearMask |= GL_DEPTH_BUFFER_BIT;
}
SetBlend(DepthMask ? PF_Occlude | CurrentPolyFlags : CurrentPolyFlags&~PF_Occlude);
pglClear(ClearMask);
}
// -----------------+
// HWRAPI Draw2DLine: Render a 2D line
// -----------------+
EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1,
F2DCoord * v2,
RGBA_t Color)
{
GLRGBAFloat c;
// DBG_Printf ("DrawLine() (%f %f %f) %d\n", v1->x, -v1->y, -v1->z, v1->argb);
#ifdef MINI_GL_COMPATIBILITY
GLfloat px1, px2, px3, px4;
GLfloat py1, py2, py3, py4;
GLfloat dx, dy;
GLfloat angle;
#endif
// BP: we should reflect the new state in our variable
//SetBlend(PF_Modulated|PF_NoTexture);
pglDisable(GL_TEXTURE_2D);
c.red = byte2float[Color.s.red];
c.green = byte2float[Color.s.green];
c.blue = byte2float[Color.s.blue];
c.alpha = byte2float[Color.s.alpha];
#ifndef MINI_GL_COMPATIBILITY
pglColor4fv(&c.red); // is in RGBA float format
pglBegin(GL_LINES);
pglVertex3f(v1->x, -v1->y, 1.0f);
pglVertex3f(v2->x, -v2->y, 1.0f);
pglEnd();
#else
if (v2->x != v1->x)
angle = (float)atan((v2->y-v1->y)/(v2->x-v1->x));
else
angle = N_PI_DEMI;
dx = (float)sin(angle) / (float)screen_width;
dy = (float)cos(angle) / (float)screen_height;
px1 = v1->x - dx; py1 = v1->y + dy;
px2 = v2->x - dx; py2 = v2->y + dy;
px3 = v2->x + dx; py3 = v2->y - dy;
px4 = v1->x + dx; py4 = v1->y - dy;
pglColor4f(c.red, c.green, c.blue, c.alpha);
pglBegin(GL_TRIANGLE_FAN);
pglVertex3f(px1, -py1, 1);
pglVertex3f(px2, -py2, 1);
pglVertex3f(px3, -py3, 1);
pglVertex3f(px4, -py4, 1);
pglEnd();
#endif
pglEnable(GL_TEXTURE_2D);
}
static void Clamp2D(GLenum pname)
{
pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP); // fallback clamp
#ifdef GL_CLAMP_TO_EDGE
pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP_TO_EDGE);
#endif
}
// -----------------+
// SetBlend : Set render mode
// -----------------+
// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0,
// is it faster when pixels are discarded ?
EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags)
{
FBITFIELD Xor;
Xor = CurrentPolyFlags^PolyFlags;
if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible|PF_NoAlphaTest))
{
if (Xor&(PF_Blending)) // if blending mode must be changed
{
switch (PolyFlags & PF_Blending) {
case PF_Translucent & PF_Blending:
pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_NOTEQUAL, 0.0f);
#endif
break;
case PF_Masked & PF_Blending:
// Hurdler: does that mean lighting is only made by alpha src?
// it sounds ok, but not for polygonsmooth
pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_GREATER, 0.5f);
#endif
break;
case PF_Additive & PF_Blending:
#ifdef ATI_RAGE_PRO_COMPATIBILITY
pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
#else
pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest
#endif
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_NOTEQUAL, 0.0f);
#endif
break;
case PF_Environment & PF_Blending:
pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_NOTEQUAL, 0.0f);
#endif
break;
case PF_Substractive & PF_Blending:
// good for shadow
// not realy but what else ?
pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_NOTEQUAL, 0.0f);
#endif
break;
case PF_Fog & PF_Fog:
// Sryder: Fog
// multiplies input colour by input alpha, and destination colour by input colour, then adds them
pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR);
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_NOTEQUAL, 0.0f);
#endif
break;
default : // must be 0, otherwise it's an error
// No blending
pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending
#ifndef KOS_GL_COMPATIBILITY
pglAlphaFunc(GL_GREATER, 0.5f);
#endif
break;
}
}
#ifndef KOS_GL_COMPATIBILITY
if (Xor & PF_NoAlphaTest)
{
if (PolyFlags & PF_NoAlphaTest)
pglDisable(GL_ALPHA_TEST);
else
pglEnable(GL_ALPHA_TEST); // discard 0 alpha pixels (holes in texture)
}
if (Xor & PF_Decal)
{
if (PolyFlags & PF_Decal)
pglEnable(GL_POLYGON_OFFSET_FILL);
else
pglDisable(GL_POLYGON_OFFSET_FILL);
}
#endif
if (Xor&PF_NoDepthTest)
{
if (PolyFlags & PF_NoDepthTest)
pglDepthFunc(GL_ALWAYS); //pglDisable(GL_DEPTH_TEST);
else
pglDepthFunc(GL_LEQUAL); //pglEnable(GL_DEPTH_TEST);
}
if (Xor&PF_RemoveYWrap)
{
if (PolyFlags & PF_RemoveYWrap)
Clamp2D(GL_TEXTURE_WRAP_T);
}
if (Xor&PF_ForceWrapX)
{
if (PolyFlags & PF_ForceWrapX)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
}
if (Xor&PF_ForceWrapY)
{
if (PolyFlags & PF_ForceWrapY)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
#ifdef KOS_GL_COMPATIBILITY
if (Xor&PF_Modulated && !(PolyFlags & PF_Modulated))
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
#else
if (Xor&PF_Modulated)
{
#if defined (__unix__) || defined (UNIXCOMMON)
if (oglflags & GLF_NOTEXENV)
{
if (!(PolyFlags & PF_Modulated))
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
else
#endif
if (PolyFlags & PF_Modulated)
{ // mix texture colour with Surface->FlatColor
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
else
{ // colour from texture is unchanged before blending
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
}
#endif
if (Xor & PF_Occlude) // depth test but (no) depth write
{
if (PolyFlags&PF_Occlude)
{
pglDepthMask(1);
}
else
pglDepthMask(0);
}
////Hurdler: not used if we don't define POLYSKY
if (Xor & PF_Invisible)
{
if (PolyFlags&PF_Invisible)
pglBlendFunc(GL_ZERO, GL_ONE); // transparent blending
else
{ // big hack: (TODO: manage that better)
// we test only for PF_Masked because PF_Invisible is only used
// (for now) with it (yeah, that's crappy, sorry)
if ((PolyFlags&PF_Blending)==PF_Masked)
pglBlendFunc(GL_SRC_ALPHA, GL_ZERO);
}
}
if (PolyFlags & PF_NoTexture)
{
SetNoTexture();
}
}
CurrentPolyFlags = PolyFlags;
}
// -----------------+
// SetTexture : The mipmap becomes the current texture source
// -----------------+
EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
{
if (!pTexInfo)
{
SetNoTexture();
return;
}
else if (pTexInfo->downloaded)
{
if (pTexInfo->downloaded != tex_downloaded)
{
pglBindTexture(GL_TEXTURE_2D, pTexInfo->downloaded);
tex_downloaded = pTexInfo->downloaded;
}
}
else
{
// Download a mipmap
#ifdef KOS_GL_COMPATIBILITY
static GLushort tex[2048*2048];
#else
static RGBA_t tex[2048*2048];
#endif
const GLvoid *ptex = tex;
INT32 w, h;
//DBG_Printf ("DownloadMipmap %d %x\n",NextTexAvail,pTexInfo->grInfo.data);
w = pTexInfo->width;
h = pTexInfo->height;
#ifdef USE_PALETTED_TEXTURE
if (glColorTableEXT &&
(pTexInfo->grInfo.format == GR_TEXFMT_P_8) &&
!(pTexInfo->flags & TF_CHROMAKEYED))
{
// do nothing here.
// Not a problem with MiniGL since we don't use paletted texture
}
else
#endif
#ifdef KOS_GL_COMPATIBILITY
if ((pTexInfo->grInfo.format == GR_TEXFMT_P_8) ||
(pTexInfo->grInfo.format == GR_TEXFMT_AP_88))
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
if ((*pImgData == HWR_PATCHES_CHROMAKEY_COLORINDEX) &&
(pTexInfo->flags & TF_CHROMAKEYED))
{
tex[w*j+i] = 0;
}
else
{
if (pTexInfo->grInfo.format == GR_TEXFMT_AP_88 && !(pTexInfo->flags & TF_CHROMAKEYED))
tex[w*j+i] = 0;
else
tex[w*j+i] = (myPaletteData[*pImgData].s.alpha>>4)<<12;
tex[w*j+i] |= (myPaletteData[*pImgData].s.red >>4)<<8;
tex[w*j+i] |= (myPaletteData[*pImgData].s.green>>4)<<4;
tex[w*j+i] |= (myPaletteData[*pImgData].s.blue >>4);
}
pImgData++;
if (pTexInfo->grInfo.format == GR_TEXFMT_AP_88)
{
if (!(pTexInfo->flags & TF_CHROMAKEYED))
tex[w*j+i] |= ((*pImgData)>>4)<<12;
pImgData++;
}
}
}
}
else if (pTexInfo->grInfo.format == GR_RGBA)
{
// corona test : passed as ARGB 8888, which is not in glide formats
// Hurdler: not used for coronas anymore, just for dynamic lighting
const RGBA_t *pImgData = (const RGBA_t *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
tex[w*j+i] = (pImgData->s.alpha>>4)<<12;
tex[w*j+i] |= (pImgData->s.red >>4)<<8;
tex[w*j+i] |= (pImgData->s.green>>4)<<4;
tex[w*j+i] |= (pImgData->s.blue >>4);
pImgData++;
}
}
}
else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88)
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
const GLubyte sID = (*pImgData)>>4;
tex[w*j+i] = sID<<8 | sID<<4 | sID;
pImgData++;
tex[w*j+i] |= ((*pImgData)>>4)<<12;
pImgData++;
}
}
}
else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8) // Used for fade masks
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
tex[w*j+i] = (pImgData>>4)<<12;
tex[w*j+i] |= (255>>4)<<8;
tex[w*j+i] |= (255>>4)<<4;
tex[w*j+i] |= (255>>4);
pImgData++;
}
}
}
else
DBG_Printf ("SetTexture(bad format) %ld\n", pTexInfo->grInfo.format);
#else
if ((pTexInfo->grInfo.format == GR_TEXFMT_P_8) ||
(pTexInfo->grInfo.format == GR_TEXFMT_AP_88))
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
if ((*pImgData == HWR_PATCHES_CHROMAKEY_COLORINDEX) &&
(pTexInfo->flags & TF_CHROMAKEYED))
{
tex[w*j+i].s.red = 0;
tex[w*j+i].s.green = 0;
tex[w*j+i].s.blue = 0;
tex[w*j+i].s.alpha = 0;
pTexInfo->flags |= TF_TRANSPARENT; // there is a hole in it
}
else
{
tex[w*j+i].s.red = myPaletteData[*pImgData].s.red;
tex[w*j+i].s.green = myPaletteData[*pImgData].s.green;
tex[w*j+i].s.blue = myPaletteData[*pImgData].s.blue;
tex[w*j+i].s.alpha = myPaletteData[*pImgData].s.alpha;
}
pImgData++;
if (pTexInfo->grInfo.format == GR_TEXFMT_AP_88)
{
if (!(pTexInfo->flags & TF_CHROMAKEYED))
tex[w*j+i].s.alpha = *pImgData;
pImgData++;
}
}
}
}
else if (pTexInfo->grInfo.format == GR_RGBA)
{
// corona test : passed as ARGB 8888, which is not in glide formats
// Hurdler: not used for coronas anymore, just for dynamic lighting
ptex = pTexInfo->grInfo.data;
}
else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88)
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
tex[w*j+i].s.red = *pImgData;
tex[w*j+i].s.green = *pImgData;
tex[w*j+i].s.blue = *pImgData;
pImgData++;
tex[w*j+i].s.alpha = *pImgData;
pImgData++;
}
}
}
else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8) // Used for fade masks
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->grInfo.data;
INT32 i, j;
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
tex[w*j+i].s.red = 255; // 255 because the fade mask is modulated with the screen texture, so alpha affects it while the colours don't
tex[w*j+i].s.green = 255;
tex[w*j+i].s.blue = 255;
tex[w*j+i].s.alpha = *pImgData;
pImgData++;
}
}
}
else
DBG_Printf ("SetTexture(bad format) %ld\n", pTexInfo->grInfo.format);
#endif
pTexInfo->downloaded = NextTexAvail++;
tex_downloaded = pTexInfo->downloaded;
pglBindTexture(GL_TEXTURE_2D, pTexInfo->downloaded);
// disable texture filtering on any texture that has holes so there's no dumb borders or blending issues
if (pTexInfo->flags & TF_TRANSPARENT)
{
#ifdef KOS_GL_COMPATIBILITY
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NONE);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NONE);
#else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#endif
}
else
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
}
#ifdef KOS_GL_COMPATIBILITY
pglTexImage2D(GL_TEXTURE_2D, 0, GL_ARGB4444, w, h, 0, GL_ARGB4444, GL_UNSIGNED_BYTE, ptex);
#else
#ifdef MINI_GL_COMPATIBILITY
//if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88)
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
//else
if (MipMap)
pgluBuild2DMipmaps(GL_TEXTURE_2D, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else
pglTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
#else
#ifdef USE_PALETTED_TEXTURE
//Hurdler: not really supported and not tested recently
if (glColorTableEXT &&
(pTexInfo->grInfo.format == GR_TEXFMT_P_8) &&
!(pTexInfo->flags & TF_CHROMAKEYED))
{
glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, 256, GL_RGB, GL_UNSIGNED_BYTE, palette_tex);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, w, h, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, pTexInfo->grInfo.data);
}
else
#endif
if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_INTENSITY_88)
{
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
if (MipMap)
{
pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
#ifdef GL_TEXTURE_MIN_LOD
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
#endif
#ifdef GL_TEXTURE_MAX_LOD
if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4);
#endif
//pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR);
}
else
pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
}
else if (pTexInfo->grInfo.format == GR_TEXFMT_ALPHA_8)
{
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
if (MipMap)
{
pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
#ifdef GL_TEXTURE_MIN_LOD
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
#endif
#ifdef GL_TEXTURE_MAX_LOD
if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4);
#endif
//pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR_MIPMAP_LINEAR);
}
else
pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
}
else
{
if (MipMap)
{
pgluBuild2DMipmaps(GL_TEXTURE_2D, textureformatGL, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
// Control the mipmap level of detail
#ifdef GL_TEXTURE_MIN_LOD
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail
#endif
#ifdef GL_TEXTURE_MAX_LOD
if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5);
#endif
}
else
pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
}
#endif
#endif
if (pTexInfo->flags & TF_WRAPX)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else
Clamp2D(GL_TEXTURE_WRAP_S);
if (pTexInfo->flags & TF_WRAPY)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else
Clamp2D(GL_TEXTURE_WRAP_T);
if (maximumAnisotropy)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic_filter);
pTexInfo->nextmipmap = NULL;
if (gr_cachetail)
{ // insertion en fin de liste
gr_cachetail->nextmipmap = pTexInfo;
gr_cachetail = pTexInfo;
}
else // initialisation de la liste
gr_cachetail = gr_cachehead = pTexInfo;
}
#ifdef MINI_GL_COMPATIBILITY
switch (pTexInfo->flags)
{
case 0 :
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
break;
default:
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
break;
}
#endif
}
// -----------------+
// DrawPolygon : Render a polygon, set the texture, set render mode
// -----------------+
EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf,
//FTextureInfo *pTexInfo,
FOutVector *pOutVerts,
FUINT iNumPts,
FBITFIELD PolyFlags)
{
FUINT i;
#ifndef MINI_GL_COMPATIBILITY
FUINT j;
#endif
GLRGBAFloat c = {0,0,0,0};
#ifdef MINI_GL_COMPATIBILITY
if (PolyFlags & PF_Corona)
PolyFlags &= ~PF_NoDepthTest;
#else
if ((PolyFlags & PF_Corona) && (oglflags & GLF_NOZBUFREAD))
PolyFlags &= ~(PF_NoDepthTest|PF_Corona);
#endif
SetBlend(PolyFlags); //TODO: inline (#pragma..)
// If Modulated, mix the surface colour to the texture
if ((CurrentPolyFlags & PF_Modulated) && pSurf)
{
if (pal_col)
{ // hack for non-palettized mode
c.red = (const_pal_col.red +byte2float[pSurf->FlatColor.s.red]) /2.0f;
c.green = (const_pal_col.green+byte2float[pSurf->FlatColor.s.green])/2.0f;
c.blue = (const_pal_col.blue +byte2float[pSurf->FlatColor.s.blue]) /2.0f;
c.alpha = byte2float[pSurf->FlatColor.s.alpha];
}
else
{
c.red = byte2float[pSurf->FlatColor.s.red];
c.green = byte2float[pSurf->FlatColor.s.green];
c.blue = byte2float[pSurf->FlatColor.s.blue];
c.alpha = byte2float[pSurf->FlatColor.s.alpha];
}
#ifdef MINI_GL_COMPATIBILITY
pglColor4f(c.red, c.green, c.blue, c.alpha);
#else
pglColor4fv(&c.red); // is in RGBA float format
#endif
}
// this test is added for new coronas' code (without depth buffer)
// I think I should do a separate function for drawing coronas, so it will be a little faster
#ifndef MINI_GL_COMPATIBILITY
if (PolyFlags & PF_Corona) // check to see if we need to draw the corona
{
//rem: all 8 (or 8.0f) values are hard coded: it can be changed to a higher value
GLfloat buf[8][8];
GLdouble cx, cy, cz;
GLdouble px = 0.0f, py = 0.0f, pz = -1.0f;
GLfloat scalef = 0.0f;
cx = (pOutVerts[0].x + pOutVerts[2].x) / 2.0f; // we should change the coronas' ...
cy = (pOutVerts[0].y + pOutVerts[2].y) / 2.0f; // ... code so its only done once.
cz = pOutVerts[0].z;
// I dont know if this is slow or not
GLProject(cx, cy, cz, &px, &py, &pz);
//DBG_Printf("Projection: (%f, %f, %f)\n", px, py, pz);
if ((pz < 0.0l) ||
(px < -8.0l) ||
(py < viewport[1]-8.0l) ||
(px > viewport[2]+8.0l) ||
(py > viewport[1]+viewport[3]+8.0l))
return;
// the damned slow glReadPixels functions :(
pglReadPixels((INT32)px-4, (INT32)py, 8, 8, GL_DEPTH_COMPONENT, GL_FLOAT, buf);
//DBG_Printf("DepthBuffer: %f %f\n", buf[0][0], buf[3][3]);
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
scalef += (pz > buf[i][j]+0.00005f) ? 0 : 1;
// quick test for screen border (not 100% correct, but looks ok)
if (px < 4) scalef -= (GLfloat)(8*(4-px));
if (py < viewport[1]+4) scalef -= (GLfloat)(8*(viewport[1]+4-py));
if (px > viewport[2]-4) scalef -= (GLfloat)(8*(4-(viewport[2]-px)));
if (py > viewport[1]+viewport[3]-4) scalef -= (GLfloat)(8*(4-(viewport[1]+viewport[3]-py)));
scalef /= 64;
//DBG_Printf("Scale factor: %f\n", scalef);
if (scalef < 0.05f)
return;
c.alpha *= scalef; // change the alpha value (it seems better than changing the size of the corona)
pglColor4fv(&c.red);
}
#endif
if (PolyFlags & PF_MD2)
return;
pglBegin(GL_TRIANGLE_FAN);
for (i = 0; i < iNumPts; i++)
{
pglTexCoord2f(pOutVerts[i].sow, pOutVerts[i].tow);
//Hurdler: test code: -pOutVerts[i].z => pOutVerts[i].z
pglVertex3f(pOutVerts[i].x, pOutVerts[i].y, pOutVerts[i].z);
//pglVertex3f(pOutVerts[i].x, pOutVerts[i].y, -pOutVerts[i].z);
}
pglEnd();
if (PolyFlags & PF_RemoveYWrap)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (PolyFlags & PF_ForceWrapX)
Clamp2D(GL_TEXTURE_WRAP_S);
if (PolyFlags & PF_ForceWrapY)
Clamp2D(GL_TEXTURE_WRAP_T);
}
// ==========================================================================
//
// ==========================================================================
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
{
switch (IdState)
{
#if 0
case 77:
{
//08/01/00: Hurdler this is a test for mirror
if (!Value)
ClearBuffer(false, true, 0); // clear depth buffer
break;
}
#endif
case HWD_SET_PALETTECOLOR:
{
pal_col = Value;
const_pal_col.blue = byte2float[((Value>>16)&0xff)];
const_pal_col.green = byte2float[((Value>>8)&0xff)];
const_pal_col.red = byte2float[((Value)&0xff)];
break;
}
case HWD_SET_FOG_COLOR:
{
GLfloat fogcolor[4];
fogcolor[0] = byte2float[((Value>>16)&0xff)];
fogcolor[1] = byte2float[((Value>>8)&0xff)];
fogcolor[2] = byte2float[((Value)&0xff)];
fogcolor[3] = 0x0;
pglFogfv(GL_FOG_COLOR, fogcolor);
break;
}
case HWD_SET_FOG_DENSITY:
pglFogf(GL_FOG_DENSITY, Value*1200/(500*1000000.0f));
break;
case HWD_SET_FOG_MODE:
if (Value)
{
pglEnable(GL_FOG);
// experimental code
/*
switch (Value)
{
case 1:
glFogi(GL_FOG_MODE, GL_LINEAR);
pglFogf(GL_FOG_START, -1000.0f);
pglFogf(GL_FOG_END, 2000.0f);
break;
case 2:
glFogi(GL_FOG_MODE, GL_EXP);
break;
case 3:
glFogi(GL_FOG_MODE, GL_EXP2);
break;
}
*/
}
else
pglDisable(GL_FOG);
break;
case HWD_SET_POLYGON_SMOOTH:
#ifdef KOS_GL_COMPATIBILITY // GL_POLYGON_SMOOTH_HINT
if (Value)
pglHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
else
pglHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST);
#else
if (Value)
pglEnable(GL_POLYGON_SMOOTH);
else
pglDisable(GL_POLYGON_SMOOTH);
#endif
break;
case HWD_SET_TEXTUREFILTERMODE:
switch (Value)
{
#ifdef KOS_GL_COMPATIBILITY
case HWD_SET_TEXTUREFILTER_TRILINEAR:
case HWD_SET_TEXTUREFILTER_BILINEAR:
min_filter = mag_filter = GL_FILTER_BILINEAR;
break;
case HWD_SET_TEXTUREFILTER_POINTSAMPLED:
min_filter = mag_filter = GL_FILTER_NONE;
case HWD_SET_TEXTUREFILTER_MIXED1:
min_filter = GL_FILTER_NONE;
mag_filter = GL_LINEAR;
case HWD_SET_TEXTUREFILTER_MIXED2:
min_filter = GL_LINEAR;
mag_filter = GL_FILTER_NONE;
break;
case HWD_SET_TEXTUREFILTER_MIXED3:
min_filter = GL_FILTER_BILINEAR;
mag_filter = GL_FILTER_NONE;
break;
#elif !defined (MINI_GL_COMPATIBILITY)
case HWD_SET_TEXTUREFILTER_TRILINEAR:
min_filter = GL_LINEAR_MIPMAP_LINEAR;
mag_filter = GL_LINEAR;
MipMap = GL_TRUE;
break;
case HWD_SET_TEXTUREFILTER_BILINEAR:
min_filter = mag_filter = GL_LINEAR;
MipMap = GL_FALSE;
break;
case HWD_SET_TEXTUREFILTER_POINTSAMPLED:
min_filter = mag_filter = GL_NEAREST;
MipMap = GL_FALSE;
break;
case HWD_SET_TEXTUREFILTER_MIXED1:
min_filter = GL_NEAREST;
mag_filter = GL_LINEAR;
MipMap = GL_FALSE;
break;
case HWD_SET_TEXTUREFILTER_MIXED2:
min_filter = GL_LINEAR;
mag_filter = GL_NEAREST;
MipMap = GL_FALSE;
break;
case HWD_SET_TEXTUREFILTER_MIXED3:
min_filter = GL_LINEAR_MIPMAP_LINEAR;
mag_filter = GL_NEAREST;
MipMap = GL_TRUE;
break;
#endif
default:
#ifdef KOS_GL_COMPATIBILITY
min_filter = mag_filter = GL_FILTER_NONE;
#else
mag_filter = GL_LINEAR;
min_filter = GL_NEAREST;
#endif
}
if (!pgluBuild2DMipmaps)
{
MipMap = GL_FALSE;
min_filter = GL_LINEAR;
}
Flush(); //??? if we want to change filter mode by texture, remove this
break;
case HWD_SET_TEXTUREANISOTROPICMODE:
anisotropic_filter = min(Value,maximumAnisotropy);
if (maximumAnisotropy)
Flush(); //??? if we want to change filter mode by texture, remove this
break;
default:
break;
}
}
static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, INT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{
INT32 val, count, pindex;
GLfloat s, t;
GLfloat ambient[4];
GLfloat diffuse[4];
float pol = 0.0f;
float scalex = scale, scaley = scale, scalez = scale;
// Because Otherwise, scaling the screen negatively vertically breaks the lighting
#ifndef KOS_GL_COMPATIBILITY
GLfloat LightPos[] = {0.0f, 1.0f, 0.0f, 0.0f};
#endif
if (duration != 0 && duration != -1 && tics != -1) // don't interpolate if instantaneous or infinite in length
{
UINT32 newtime = (duration - tics); // + 1;
pol = (newtime)/(float)duration;
if (pol > 1.0f)
pol = 1.0f;
if (pol < 0.0f)
pol = 0.0f;
}
if (color)
{
ambient[0] = (color[0]/255.0f);
ambient[1] = (color[1]/255.0f);
ambient[2] = (color[2]/255.0f);
ambient[3] = (color[3]/255.0f);
diffuse[0] = (color[0]/255.0f);
diffuse[1] = (color[1]/255.0f);
diffuse[2] = (color[2]/255.0f);
diffuse[3] = (color[3]/255.0f);
if (ambient[0] > 0.75f)
ambient[0] = 0.75f;
if (ambient[1] > 0.75f)
ambient[1] = 0.75f;
if (ambient[2] > 0.75f)
ambient[2] = 0.75f;
}
pglEnable(GL_CULL_FACE);
// flipped is if the object is flipped
// pos->flip is if the screen is flipped vertically
// pos->mirror is if the screen is flipped horizontally
// XOR all the flips together to figure out what culling to use!
{
boolean reversecull = (flipped ^ pos->flip ^ pos->mirror);
if (reversecull)
pglCullFace(GL_FRONT);
else
pglCullFace(GL_BACK);
}
#ifndef KOS_GL_COMPATIBILITY
pglLightfv(GL_LIGHT0, GL_POSITION, LightPos);
#endif
pglShadeModel(GL_SMOOTH);
if (color)
{
#ifdef GL_LIGHT_MODEL_AMBIENT
pglEnable(GL_LIGHTING);
pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
#endif
if (color[3] < 255)
SetBlend(PF_Translucent|PF_Modulated|PF_Clip);
else
SetBlend(PF_Masked|PF_Modulated|PF_Occlude|PF_Clip);
}
pglPushMatrix(); // should be the same as glLoadIdentity
//Hurdler: now it seems to work
pglTranslatef(pos->x, pos->z, pos->y);
if (flipped)
scaley = -scaley;
pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f);
val = *gl_cmd_buffer++;
while (val != 0)
{
if (val < 0)
{
pglBegin(GL_TRIANGLE_FAN);
count = -val;
}
else
{
pglBegin(GL_TRIANGLE_STRIP);
count = val;
}
while (count--)
{
s = *(float *) gl_cmd_buffer++;
t = *(float *) gl_cmd_buffer++;
pindex = *gl_cmd_buffer++;
pglTexCoord2f(s, t);
if (!nextframe || pol == 0.0f)
{
pglNormal3f(frame->vertices[pindex].normal[0],
frame->vertices[pindex].normal[1],
frame->vertices[pindex].normal[2]);
pglVertex3f(frame->vertices[pindex].vertex[0]*scalex/2.0f,
frame->vertices[pindex].vertex[1]*scaley/2.0f,
frame->vertices[pindex].vertex[2]*scalez/2.0f);
}
else
{
// Interpolate
float px1 = frame->vertices[pindex].vertex[0]*scalex/2.0f;
float px2 = nextframe->vertices[pindex].vertex[0]*scalex/2.0f;
float py1 = frame->vertices[pindex].vertex[1]*scaley/2.0f;
float py2 = nextframe->vertices[pindex].vertex[1]*scaley/2.0f;
float pz1 = frame->vertices[pindex].vertex[2]*scalez/2.0f;
float pz2 = nextframe->vertices[pindex].vertex[2]*scalez/2.0f;
float nx1 = frame->vertices[pindex].normal[0];
float nx2 = nextframe->vertices[pindex].normal[0];
float ny1 = frame->vertices[pindex].normal[1];
float ny2 = nextframe->vertices[pindex].normal[1];
float nz1 = frame->vertices[pindex].normal[2];
float nz2 = nextframe->vertices[pindex].normal[2];
pglNormal3f((nx1 + pol * (nx2 - nx1)),
(ny1 + pol * (ny2 - ny1)),
(nz1 + pol * (nz2 - nz1)));
pglVertex3f((px1 + pol * (px2 - px1)),
(py1 + pol * (py2 - py1)),
(pz1 + pol * (pz2 - pz1)));
}
}
pglEnd();
val = *gl_cmd_buffer++;
}
pglPopMatrix(); // should be the same as glLoadIdentity
if (color)
pglDisable(GL_LIGHTING);
pglShadeModel(GL_FLAT);
pglDisable(GL_CULL_FACE);
}
// -----------------+
// HWRAPI DrawMD2 : Draw an MD2 model with glcommands
// -----------------+
EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, INT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{
DrawMD2Ex(gl_cmd_buffer, frame, duration, tics, nextframe, pos, scale, flipped, color);
}
EXPORT void HWRAPI(DrawMD2) (INT32 *gl_cmd_buffer, md2_frame_t *frame, FTransform *pos, float scale)
{
DrawMD2Ex(gl_cmd_buffer, frame, 0, 0, NULL, pos, scale, false, NULL);
}
// -----------------+
// SetTransform :
// -----------------+
EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
{
static boolean special_splitscreen;
pglLoadIdentity();
if (stransform)
{
// keep a trace of the transformation for md2
memcpy(&md2_transform, stransform, sizeof (md2_transform));
if (stransform->mirror)
pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez);
else if (stransform->flip)
pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez);
else
pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez);
pglRotatef(stransform->anglex , 1.0f, 0.0f, 0.0f);
pglRotatef(stransform->angley+270.0f, 0.0f, 1.0f, 0.0f);
pglTranslatef(-stransform->x, -stransform->z, -stransform->y);
pglMatrixMode(GL_PROJECTION);
pglLoadIdentity();
special_splitscreen = (stransform->splitscreen == 1 && stransform->fovxangle == 90.0f);
if (special_splitscreen)
GLPerspective(53.13l, 2*ASPECT_RATIO); // 53.13 = 2*atan(0.5)
else
GLPerspective(stransform->fovxangle, ASPECT_RATIO);
#ifndef MINI_GL_COMPATIBILITY
pglGetDoublev(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer)
#endif
pglMatrixMode(GL_MODELVIEW);
}
else
{
pglScalef(1.0f, 1.0f, -1.0f);
pglMatrixMode(GL_PROJECTION);
pglLoadIdentity();
if (special_splitscreen)
GLPerspective(53.13l, 2*ASPECT_RATIO); // 53.13 = 2*atan(0.5)
else
//Hurdler: is "fov" correct?
GLPerspective(fov, ASPECT_RATIO);
#ifndef MINI_GL_COMPATIBILITY
pglGetDoublev(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer)
#endif
pglMatrixMode(GL_MODELVIEW);
}
#ifndef MINI_GL_COMPATIBILITY
pglGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
#endif
}
EXPORT INT32 HWRAPI(GetTextureUsed) (void)
{
FTextureInfo* tmp = gr_cachehead;
INT32 res = 0;
while (tmp)
{
res += tmp->height*tmp->width*(screen_depth/8);
tmp = tmp->nextmipmap;
}
return res;
}
EXPORT INT32 HWRAPI(GetRenderVersion) (void)
{
return VERSION;
}
#ifdef SHUFFLE
EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
{
INT32 x, y;
float float_x, float_y, float_nextx, float_nexty;
float xfix, yfix;
INT32 texsize = 2048;
// Use a power of two texture, dammit
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
// X/Y stretch fix for all resolutions(!)
xfix = (float)(texsize)/((float)((screen_width)/(float)(SCREENVERTS-1)));
yfix = (float)(texsize)/((float)((screen_height)/(float)(SCREENVERTS-1)));
pglDisable(GL_DEPTH_TEST);
pglDisable(GL_BLEND);
pglBegin(GL_QUADS);
// Draw a black square behind the screen texture,
// so nothing shows through the edges
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
pglVertex3f(-16.0f, -16.0f, 6.0f);
pglVertex3f(-16.0f, 16.0f, 6.0f);
pglVertex3f(16.0f, 16.0f, 6.0f);
pglVertex3f(16.0f, -16.0f, 6.0f);
for(x=0;x<SCREENVERTS-1;x++)
{
for(y=0;y<SCREENVERTS-1;y++)
{
// Used for texture coordinates
// Annoying magic numbers to scale the square texture to
// a non-square screen..
float_x = (float)(x/(xfix));
float_y = (float)(y/(yfix));
float_nextx = (float)(x+1)/(xfix);
float_nexty = (float)(y+1)/(yfix);
// Attach the squares together.
pglTexCoord2f( float_x, float_y);
pglVertex3f(points[x][y][0], points[x][y][1], 4.4f);
pglTexCoord2f( float_x, float_nexty);
pglVertex3f(points[x][y+1][0], points[x][y+1][1], 4.4f);
pglTexCoord2f( float_nextx, float_nexty);
pglVertex3f(points[x+1][y+1][0], points[x+1][y+1][1], 4.4f);
pglTexCoord2f( float_nextx, float_y);
pglVertex3f(points[x+1][y][0], points[x+1][y][1], 4.4f);
}
}
pglEnd();
pglEnable(GL_DEPTH_TEST);
pglEnable(GL_BLEND);
}
#endif //SHUFFLE
// Sryder: This needs to be called whenever the screen changes resolution in order to reset the screen textures to use
// a new size
EXPORT void HWRAPI(FlushScreenTextures) (void)
{
pglDeleteTextures(1, &screentexture);
pglDeleteTextures(1, &startScreenWipe);
pglDeleteTextures(1, &endScreenWipe);
pglDeleteTextures(1, &finalScreenTexture);
screentexture = 0;
startScreenWipe = 0;
endScreenWipe = 0;
finalScreenTexture = 0;
}
// Create Screen to fade from
EXPORT void HWRAPI(StartScreenWipe) (void)
{
INT32 texsize = 2048;
boolean firstTime = (startScreenWipe == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// Create screen texture
if (firstTime)
startScreenWipe = SCRTEX_STARTSCREENWIPE;
pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
if (firstTime)
{
#ifdef KOS_GL_COMPATIBILITY
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE);
#else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#endif
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
#endif
}
else
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
#endif
tex_downloaded = startScreenWipe;
}
// Create Screen to fade to
EXPORT void HWRAPI(EndScreenWipe)(void)
{
INT32 texsize = 2048;
boolean firstTime = (endScreenWipe == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// Create screen texture
if (firstTime)
endScreenWipe = SCRTEX_ENDSCREENWIPE;
pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
if (firstTime)
{
#ifdef KOS_GL_COMPATIBILITY
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE);
#else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#endif
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
#endif
}
else
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
#endif
tex_downloaded = endScreenWipe;
}
// Draw the last scene under the intermission
EXPORT void HWRAPI(DrawIntermissionBG)(void)
{
float xfix, yfix;
INT32 texsize = 2048;
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
xfix = 1/((float)(texsize)/((float)((screen_width))));
yfix = 1/((float)(texsize)/((float)((screen_height))));
pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
pglBindTexture(GL_TEXTURE_2D, screentexture);
pglBegin(GL_QUADS);
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Bottom left
pglTexCoord2f(0.0f, 0.0f);
pglVertex3f(-1.0f, -1.0f, 1.0f);
// Top left
pglTexCoord2f(0.0f, yfix);
pglVertex3f(-1.0f, 1.0f, 1.0f);
// Top right
pglTexCoord2f(xfix, yfix);
pglVertex3f(1.0f, 1.0f, 1.0f);
// Bottom right
pglTexCoord2f(xfix, 0.0f);
pglVertex3f(1.0f, -1.0f, 1.0f);
pglEnd();
tex_downloaded = screentexture;
}
// Do screen fades!
EXPORT void HWRAPI(DoScreenWipe)(float alpha)
{
INT32 texsize = 2048;
float xfix, yfix;
#ifndef MINI_GL_COMPATIBILITY
INT32 fademaskdownloaded = tex_downloaded; // the fade mask that has been set
#endif
// Use a power of two texture, dammit
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
xfix = 1/((float)(texsize)/((float)((screen_width))));
yfix = 1/((float)(texsize)/((float)((screen_height))));
pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
SetBlend(PF_Modulated|PF_NoDepthTest|PF_Clip|PF_NoZClip);
// Draw the original screen
pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
pglBegin(GL_QUADS);
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Bottom left
pglTexCoord2f(0.0f, 0.0f);
pglVertex3f(-1.0f, -1.0f, 1.0f);
// Top left
pglTexCoord2f(0.0f, yfix);
pglVertex3f(-1.0f, 1.0f, 1.0f);
// Top right
pglTexCoord2f(xfix, yfix);
pglVertex3f(1.0f, 1.0f, 1.0f);
// Bottom right
pglTexCoord2f(xfix, 0.0f);
pglVertex3f(1.0f, -1.0f, 1.0f);
pglEnd();
SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest|PF_Clip|PF_NoZClip);
#ifndef MINI_GL_COMPATIBILITY
if (gl13)
{
// Draw the end screen that fades in
pglActiveTexture(GL_TEXTURE0);
pglEnable(GL_TEXTURE_2D);
pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
pglActiveTexture(GL_TEXTURE1);
pglEnable(GL_TEXTURE_2D);
pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded);
pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
pglBegin(GL_QUADS);
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Bottom left
pglMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f);
pglMultiTexCoord2f(GL_TEXTURE1, 0.0f, 1.0f);
pglVertex3f(-1.0f, -1.0f, 1.0f);
// Top left
pglMultiTexCoord2f(GL_TEXTURE0, 0.0f, yfix);
pglMultiTexCoord2f(GL_TEXTURE1, 0.0f, 0.0f);
pglVertex3f(-1.0f, 1.0f, 1.0f);
// Top right
pglMultiTexCoord2f(GL_TEXTURE0, xfix, yfix);
pglMultiTexCoord2f(GL_TEXTURE1, 1.0f, 0.0f);
pglVertex3f(1.0f, 1.0f, 1.0f);
// Bottom right
pglMultiTexCoord2f(GL_TEXTURE0, xfix, 0.0f);
pglMultiTexCoord2f(GL_TEXTURE1, 1.0f, 1.0f);
pglVertex3f(1.0f, -1.0f, 1.0f);
pglEnd();
pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit
pglActiveTexture(GL_TEXTURE0);
tex_downloaded = endScreenWipe;
}
else
{
#endif
// Draw the end screen that fades in
pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
pglBegin(GL_QUADS);
pglColor4f(1.0f, 1.0f, 1.0f, alpha);
// Bottom left
pglTexCoord2f(0.0f, 0.0f);
pglVertex3f(-1.0f, -1.0f, 1.0f);
// Top left
pglTexCoord2f(0.0f, yfix);
pglVertex3f(-1.0f, 1.0f, 1.0f);
// Top right
pglTexCoord2f(xfix, yfix);
pglVertex3f(1.0f, 1.0f, 1.0f);
// Bottom right
pglTexCoord2f(xfix, 0.0f);
pglVertex3f(1.0f, -1.0f, 1.0f);
pglEnd();
tex_downloaded = endScreenWipe;
#ifndef MINI_GL_COMPATIBILITY
}
#endif
}
// Create a texture from the screen.
EXPORT void HWRAPI(MakeScreenTexture) (void)
{
INT32 texsize = 2048;
boolean firstTime = (screentexture == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// Create screen texture
if (firstTime)
screentexture = SCRTEX_SCREENTEXTURE;
pglBindTexture(GL_TEXTURE_2D, screentexture);
if (firstTime)
{
#ifdef KOS_GL_COMPATIBILITY
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE);
#else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#endif
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
#endif
}
else
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
#endif
tex_downloaded = screentexture;
}
EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
{
INT32 texsize = 2048;
boolean firstTime = (finalScreenTexture == 0);
// Use a power of two texture, dammit
if(screen_width <= 512)
texsize = 512;
else if(screen_width <= 1024)
texsize = 1024;
// Create screen texture
if (firstTime)
finalScreenTexture = SCRTEX_FINALSCREENTEXTURE;
pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
if (firstTime)
{
#ifdef KOS_GL_COMPATIBILITY
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE);
#else
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#endif
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
#endif
}
else
#ifndef KOS_GL_COMPATIBILITY
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
#endif
tex_downloaded = finalScreenTexture;
}
EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
{
float xfix, yfix;
float origaspect, newaspect;
float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen
FRGBAFloat clearColour;
INT32 texsize = 2048;
if(screen_width <= 1024)
texsize = 1024;
if(screen_width <= 512)
texsize = 512;
xfix = 1/((float)(texsize)/((float)((screen_width))));
yfix = 1/((float)(texsize)/((float)((screen_height))));
origaspect = (float)screen_width / screen_height;
newaspect = (float)width / height;
if (origaspect < newaspect)
{
xoff = origaspect / newaspect;
yoff = 1;
}
else if (origaspect > newaspect)
{
xoff = 1;
yoff = newaspect / origaspect;
}
pglViewport(0, 0, width, height);
clearColour.red = clearColour.green = clearColour.blue = 0;
clearColour.alpha = 1;
ClearBuffer(true, false, &clearColour);
pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
pglBegin(GL_QUADS);
pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Bottom left
pglTexCoord2f(0.0f, 0.0f);
pglVertex3f(-xoff, -yoff, 1.0f);
// Top left
pglTexCoord2f(0.0f, yfix);
pglVertex3f(-xoff, yoff, 1.0f);
// Top right
pglTexCoord2f(xfix, yfix);
pglVertex3f(xoff, yoff, 1.0f);
// Bottom right
pglTexCoord2f(xfix, 0.0f);
pglVertex3f(xoff, -yoff, 1.0f);
pglEnd();
tex_downloaded = finalScreenTexture;
}
#endif //HWRENDER