// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright (C) 1998-2018 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 #endif #undef GETTEXT #ifdef __GNUC__ #include #endif #include #include #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 65535 #define SCRTEX_STARTSCREENWIPE 65534 #define SCRTEX_ENDSCREENWIPE 65533 #define SCRTEX_FINALSCREENTEXTURE 65532 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 pglVertex3sv glVertex3sv #define pglNormal3f glNormal3f #define pglNormal3bv glNormal3bv #define pglColor4f glColor4f #define pglColor4fv glColor4fv #define pglTexCoord2f glTexCoord2f #define pglTexCoord2fv glTexCoord2fv #define pglVertexPointer glVertexPointer #define pglNormalPointer glNormalPointer #define pglTexCoordPointer glTexCoordPointer #define pglDrawArrays glDrawArrays #define pglDrawElements glDrawElements #define pglEnableClientState glEnableClientState #define pglDisableClientState pglDisableClientState /* 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 * PFNglVertex3sv) (const GLshort *v); static PFNglVertex3sv pglVertex3sv; typedef void (APIENTRY * PFNglNormal3f) (GLfloat x, GLfloat y, GLfloat z); static PFNglNormal3f pglNormal3f; typedef void (APIENTRY * PFNglNormal3bv)(const GLbyte *v); static PFNglNormal3bv pglNormal3bv; 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; typedef void (APIENTRY * PFNglTexCoord2fv) (const GLfloat *v); static PFNglTexCoord2fv pglTexCoord2fv; typedef void (APIENTRY * PFNglVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); static PFNglVertexPointer pglVertexPointer; typedef void (APIENTRY * PFNglNormalPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); static PFNglNormalPointer pglNormalPointer; typedef void (APIENTRY * PFNglTexCoordPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); static PFNglTexCoordPointer pglTexCoordPointer; typedef void (APIENTRY * PFNglDrawArrays) (GLenum mode, GLint first, GLsizei count); static PFNglDrawArrays pglDrawArrays; typedef void (APIENTRY * PFNglDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); static PFNglDrawElements pglDrawElements; typedef void (APIENTRY * PFNglEnableClientState) (GLenum cap); static PFNglEnableClientState pglEnableClientState; typedef void (APIENTRY * PFNglDisableClientState) (GLenum cap); static PFNglDisableClientState pglDisableClientState; /* 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(pglVertex3sv, glVertex3sv) GETOPENGLFUNC(pglNormal3f , glNormal3f) GETOPENGLFUNC(pglNormal3bv, glNomral3bv) GETOPENGLFUNC(pglColor4f , glColor4f) GETOPENGLFUNC(pglColor4fv , glColor4fv) GETOPENGLFUNC(pglTexCoord2f , glTexCoord2f) GETOPENGLFUNC(pglTexCoord2fv, glTexCoord2fv) GETOPENGLFUNC(pglVertexPointer, glVertexPointer) GETOPENGLFUNC(pglNormalPointer, glNormalPointer) GETOPENGLFUNC(pglTexCoordPointer, glTexCoordPointer) GETOPENGLFUNC(pglDrawArrays, glDrawArrays) GETOPENGLFUNC(pglDrawElements, glDrawElements) GETOPENGLFUNC(pglEnableClientState, glEnableClientState) GETOPENGLFUNC(pglDisableClientState, glDisableClientState) 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 DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, 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; scale *= 0.5f; 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); // pos->flip is if the screen is flipped too if (flipped != pos->flip) // If either are active, but not both, invert the model's culling { 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); pglScalef(scalex, scaley, scalez); boolean useTinyFrames = model->meshes[0].tinyframes != NULL; if (useTinyFrames) pglScalef(1 / 64.0f, 1 / 64.0f, 1 / 64.0f); for (int i = 0; i < model->numMeshes; i++) { mesh_t *mesh = &model->meshes[i]; if (useTinyFrames) { tinyframe_t *frame = &mesh->tinyframes[frameIndex % mesh->numFrames]; tinyframe_t *nextframe = NULL; if (nextFrameIndex != -1) nextframe = &mesh->tinyframes[nextFrameIndex % mesh->numFrames]; if (!nextframe || pol == 0.0f) { pglEnableClientState(GL_VERTEX_ARRAY); pglEnableClientState(GL_TEXTURE_COORD_ARRAY); pglEnableClientState(GL_NORMAL_ARRAY); pglVertexPointer(3, GL_SHORT, 0, frame->vertices); pglNormalPointer(GL_BYTE, 0, frame->normals); pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices); pglDisableClientState(GL_NORMAL_ARRAY); pglDisableClientState(GL_TEXTURE_COORD_ARRAY); pglDisableClientState(GL_TEXTURE_COORD_ARRAY); } else { // Dangit, I soooo want to do this in a GLSL shader... pglBegin(GL_TRIANGLES); short *buffer = malloc(mesh->numVertices * sizeof(short)); short *vertPtr = buffer; char *normBuffer = malloc(mesh->numVertices * sizeof(char)); char *normPtr = normBuffer; int j = 0; for (j = 0; j < mesh->numVertices; j++) { // Interpolate *vertPtr++ = (short)(frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j]))); *normPtr++ = (short)(frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j]))); } float *uvPtr = mesh->uvs; vertPtr = buffer; normPtr = normBuffer; for (j = 0; j < mesh->numTriangles; j++) { pglTexCoord2fv(uvPtr); pglNormal3bv(normPtr); pglVertex3sv(vertPtr); uvPtr += 2; normPtr += 3; vertPtr += 3; } free(buffer); free(normBuffer); pglEnd(); } } else { mdlframe_t *frame = &mesh->frames[frameIndex % mesh->numFrames]; mdlframe_t *nextframe = NULL; if (nextFrameIndex != -1) nextframe = &mesh->frames[nextFrameIndex % mesh->numFrames]; if (!nextframe || pol == 0.0f) { // Zoom! Take advantage of just shoving the entire arrays to the GPU. pglEnableClientState(GL_VERTEX_ARRAY); pglEnableClientState(GL_TEXTURE_COORD_ARRAY); pglEnableClientState(GL_NORMAL_ARRAY); pglVertexPointer(3, GL_FLOAT, 0, frame->vertices); pglNormalPointer(GL_FLOAT, 0, frame->normals); pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs); pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3); pglDisableClientState(GL_NORMAL_ARRAY); pglDisableClientState(GL_TEXTURE_COORD_ARRAY); pglDisableClientState(GL_TEXTURE_COORD_ARRAY); } else { // Dangit, I soooo want to do this in a GLSL shader... pglBegin(GL_TRIANGLES); int j = 0; float *uvPtr = mesh->uvs; float *frameVert = frame->vertices; float *frameNormal = frame->normals; float *nextFrameVert = nextframe->vertices; float *nextFrameNormal = frame->normals; for (j = 0; j < mesh->numTriangles; j++) { // Interpolate float px1 = *frameVert++; float px2 = *nextFrameVert++; float py1 = *frameVert++; float py2 = *nextFrameVert++; float pz1 = *frameVert++; float pz2 = *nextFrameVert++; float nx1 = *frameNormal++; float nx2 = *nextFrameNormal++; float ny1 = *frameNormal++; float ny2 = *nextFrameNormal++; float nz1 = *frameNormal++; float nz2 = *nextFrameNormal++; pglTexCoord2fv(uvPtr); 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))); uvPtr++; } pglEnd(); } } } 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(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 *color) { DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, color); } // -----------------+ // SetTransform : // -----------------+ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) { static INT32 special_splitscreen; pglLoadIdentity(); if (stransform) { // keep a trace of the transformation for md2 memcpy(&md2_transform, stransform, sizeof (md2_transform)); 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 && 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 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