DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/voodoo_vogl.cpp
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <stdlib.h>
00021 #include <math.h>
00022 #include <map>
00023 
00024 #include "dosbox.h"
00025 #include "dos_inc.h"
00026 
00027 #if C_OPENGL
00028 
00029 #include "voodoo_vogl.h"
00030 
00031 /* NTS: This causes errors in Linux because MesaGL already defines these */
00032 #ifdef WIN32
00033 PFNGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB = NULL;
00034 PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB = NULL;
00035 PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
00036 #endif
00037 
00038 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
00039 PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
00040 PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
00041 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
00042 PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
00043 PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
00044 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
00045 PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL;
00046 PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
00047 PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL;
00048 PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL;
00049 PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL;
00050 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
00051 PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL;
00052 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
00053 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
00054 PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL;
00055 PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
00056 PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
00057 PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
00058 PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL;
00059 
00060 
00061 static Bit32s opengl_version = -1;
00062 
00063 static bool has_shaders = false;
00064 static bool has_stencil = false;
00065 static bool has_alpha = false;
00066 
00067 
00068 static INT32 current_begin_mode = -1;
00069 
00070 static Bit32s current_depth_mode = -1;
00071 static Bit32s current_depth_func = -1;
00072 
00073 static Bit32s current_alpha_enabled = -1;
00074 static Bit32s current_src_rgb_fac = -1;
00075 static Bit32s current_dst_rgb_fac = -1;
00076 static Bit32s current_src_alpha_fac = -1;
00077 static Bit32s current_dst_alpha_fac = -1;
00078 
00079 static bool depth_masked = false;
00080 static bool color_masked = false;
00081 static bool alpha_masked = false;
00082 
00083 // buffer read/write defaults are back-buffer for double buffered contexts
00084 static bool draw_to_front_buffer = false;
00085 static bool read_from_front_buffer = false;
00086 
00087 
00088 void VOGL_Reset(void) {
00089         opengl_version = -1;
00090         has_shaders = false;
00091         has_stencil = false;
00092         has_alpha = false;
00093 
00094         current_depth_mode=-1;
00095         current_depth_func=-1;
00096 
00097         current_alpha_enabled=-1;
00098         current_src_rgb_fac=-1;
00099         current_dst_rgb_fac=-1;
00100         current_src_alpha_fac=-1;
00101         current_dst_alpha_fac=-1;
00102 
00103         depth_masked = false;
00104         color_masked = false;
00105         alpha_masked = false;
00106 
00107         draw_to_front_buffer = false;
00108         read_from_front_buffer = false;
00109 }
00110 
00111 
00112 void VOGL_InitVersion(void) {
00113         opengl_version = -1;
00114 
00115         char gl_verstr[16];
00116         const GLubyte* gl_verstr_ub = glGetString(GL_VERSION);
00117         strncpy(gl_verstr, (const char*)gl_verstr_ub, 16);
00118         gl_verstr[15] = 0;
00119         char* gl_ver_minor = strchr(gl_verstr, '.');
00120         if (gl_ver_minor != NULL) {
00121                 gl_ver_minor++;
00122                 char* skip = strchr(gl_ver_minor, '.');
00123                 if (skip != NULL) *skip = 0;
00124         }
00125 
00126         int ogl_ver = 100;
00127         if (gl_verstr[0] != 0) {
00128                 int major = 1;
00129                 int minor = 0;
00130                 if (strchr(gl_verstr, '.') != NULL) {
00131                         if (sscanf(gl_verstr,"%d.%d", &major, &minor) != 2) major = 0;
00132                 } else {
00133                         if (sscanf(gl_verstr, "%d", &major) != 1) major = 0;
00134                 }
00135                 if (major > 0) {
00136                         ogl_ver = major*100;
00137                         if (minor >= 0) {
00138                                 if (minor < 10) ogl_ver += minor*10;
00139                                 else ogl_ver += minor;
00140                         }
00141                 }
00142         }
00143 
00144         if (ogl_ver > 0) opengl_version = ogl_ver;
00145 }
00146 
00147 void VOGL_ClearShaderFunctions(void) {
00148         glShaderSourceARB = NULL;
00149         glCompileShaderARB = NULL;
00150         glCreateProgramObjectARB = NULL;
00151         glAttachObjectARB = NULL;
00152         glLinkProgramARB = NULL;
00153         glUseProgramObjectARB = NULL;
00154         glUniform1iARB = NULL;
00155         glUniform1fARB = NULL;
00156         glUniform2fARB = NULL;
00157         glUniform3fARB = NULL;
00158         glUniform4fARB = NULL;
00159         glGetUniformLocationARB = NULL;
00160         glDetachObjectARB = NULL;
00161         glDeleteObjectARB  = NULL;
00162         glGetObjectParameterivARB = NULL;
00163         glGetInfoLogARB = NULL;
00164 }
00165 
00166 bool VOGL_Initialize(void) {
00167         VOGL_ClearShaderFunctions();
00168         
00169         VOGL_InitVersion();
00170 
00171 #ifdef WIN32
00172         glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glActiveTextureARB"));
00173         if (!glActiveTextureARB) {
00174                 LOG_MSG("opengl: glActiveTextureARB extension not supported");
00175                 return false;
00176         }
00177 
00178         glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glMultiTexCoord4fARB"));
00179         if (!glMultiTexCoord4fARB) {
00180                 LOG_MSG("opengl: glMultiTexCoord4fARB extension not supported");
00181                 return false;
00182         }
00183 
00184         glMultiTexCoord4fvARB = (PFNGLMULTITEXCOORD4FVARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glMultiTexCoord4fvARB"));
00185         if (!glMultiTexCoord4fvARB) {
00186                 LOG_MSG("opengl: glMultiTexCoord4fvARB extension not supported");
00187                 return false;
00188         }
00189 #endif
00190 
00191         glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)((uintptr_t)SDL_GL_GetProcAddress("glBlendFuncSeparateEXT"));
00192         if (!glBlendFuncSeparateEXT) {
00193                 LOG_MSG("opengl: glBlendFuncSeparateEXT extension not supported");
00194                 return false;
00195         }
00196 
00197         glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)((uintptr_t)SDL_GL_GetProcAddress("glGenerateMipmapEXT"));
00198         if (!glGenerateMipmapEXT) {
00199                 LOG_MSG("opengl: glGenerateMipmapEXT extension not supported");
00200                 return false;
00201         }
00202 
00203         if (VOGL_CheckFeature(VOGL_ATLEAST_V20)) {
00204                 const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
00205                 if (strstr(extensions, "GL_ARB_shader_objects") && strstr(extensions, "GL_ARB_vertex_shader") &&
00206                         strstr(extensions, "GL_ARB_fragment_shader")) {
00207 
00208                         glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glCreateShaderObjectARB"));
00209                         if (!glCreateShaderObjectARB) {
00210                                 LOG_MSG("opengl: shader extensions not supported. Using fixed pipeline");
00211                         } else {
00212                                 glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glShaderSourceARB"));
00213                                 if (!glShaderSourceARB) LOG_MSG("opengl: glShaderSourceARB extension not supported");
00214 
00215                                 glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glCompileShaderARB"));
00216                                 if (!glCompileShaderARB) LOG_MSG("opengl: glCompileShaderARB extension not supported");
00217 
00218                                 glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glCreateProgramObjectARB"));
00219                                 if (!glCreateProgramObjectARB) LOG_MSG("opengl: glCreateProgramObjectARB extension not supported");
00220 
00221                                 glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glAttachObjectARB"));
00222                                 if (!glAttachObjectARB) LOG_MSG("opengl: glAttachObjectARB extension not supported");
00223 
00224                                 glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glLinkProgramARB"));
00225                                 if (!glLinkProgramARB) LOG_MSG("opengl: glLinkProgramARB extension not supported");
00226 
00227                                 glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUseProgramObjectARB"));
00228                                 if (!glUseProgramObjectARB) LOG_MSG("opengl: glUseProgramObjectARB extension not supported");
00229 
00230                                 glUniform1iARB = (PFNGLUNIFORM1IARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform1iARB"));
00231                                 if (!glUniform1iARB) LOG_MSG("opengl: glUniform1iARB extension not supported");
00232 
00233                                 glUniform1fARB = (PFNGLUNIFORM1FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform1fARB"));
00234                                 if (!glUniform1fARB) LOG_MSG("opengl: glUniform1fARB extension not supported");
00235 
00236                                 glUniform2fARB = (PFNGLUNIFORM2FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform2fARB"));
00237                                 if (!glUniform2fARB) LOG_MSG("opengl: glUniform2fARB extension not supported");
00238 
00239                                 glUniform3fARB = (PFNGLUNIFORM3FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform3fARB"));
00240                                 if (!glUniform3fARB) LOG_MSG("opengl: glUniform3fARB extension not supported");
00241 
00242                                 glUniform4fARB = (PFNGLUNIFORM4FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform4fARB"));
00243                                 if (!glUniform4fARB) LOG_MSG("opengl: glUniform4fARB extension not supported");
00244 
00245                                 glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetUniformLocationARB"));
00246                                 if (!glGetUniformLocationARB) LOG_MSG("opengl: glGetUniformLocationARB extension not supported");
00247 
00248                                 glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glDetachObjectARB"));
00249                                 if (!glDetachObjectARB) LOG_MSG("opengl: glDetachObjectARB extension not supported");
00250 
00251                                 glDeleteObjectARB  = (PFNGLDELETEOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glDeleteObjectARB"));
00252                                 if (!glDeleteObjectARB) LOG_MSG("opengl: glDeleteObjectARB extension not supported");
00253 
00254                                 glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetObjectParameterivARB"));
00255                                 if (!glGetObjectParameterivARB) LOG_MSG("opengl: glGetObjectParameterivARB extension not supported");
00256 
00257                                 glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetInfoLogARB"));
00258                                 if (!glGetInfoLogARB) LOG_MSG("opengl: glGetInfoLogARB extension not supported");
00259 
00260                                 glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetAttribLocationARB"));
00261                                 if (!glGetAttribLocationARB) LOG_MSG("opengl: glGetAttribLocationARB extension not supported");
00262                         
00263                                 glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glVertexAttrib1fARB"));
00264                                 if (!glVertexAttrib1fARB) LOG_MSG("opengl: glVertexAttrib1fARB extension not supported");
00265 
00266                                 if (glShaderSourceARB && glCompileShaderARB && glCreateProgramObjectARB &&
00267                                         glAttachObjectARB && glLinkProgramARB && glUseProgramObjectARB &&
00268                                         glUniform1iARB && glUniform1fARB && glUniform2fARB && glUniform3fARB &&
00269                                         glUniform4fARB && glGetUniformLocationARB && glDetachObjectARB &&
00270                                         glDeleteObjectARB && glGetObjectParameterivARB && glGetInfoLogARB) {
00271                                                 VOGL_FlagFeature(VOGL_HAS_SHADERS);
00272 //                                              LOG_MSG("opengl: shader functionality enabled");
00273                                 } else {
00274                                         VOGL_ClearShaderFunctions();
00275                                 }
00276                         }
00277                 }
00278         }
00279 
00280         LOG_MSG("opengl: I am able to use OpenGL to emulate Voodoo graphics");
00281         return true;
00282 }
00283 
00284 
00285 bool VOGL_CheckFeature(Bit32u feat) {
00286         switch (feat) {
00287                 case VOGL_ATLEAST_V20:
00288                         if (opengl_version >= 200) return true;
00289                         break;
00290                 case VOGL_ATLEAST_V21:
00291                         if (opengl_version >= 210) return true;
00292                         break;
00293                 case VOGL_ATLEAST_V30:
00294                         if (opengl_version >= 300) return true;
00295                         break;
00296                 case VOGL_HAS_SHADERS:
00297                         if (has_shaders) return true;
00298                         break;
00299                 case VOGL_HAS_STENCIL_BUFFER:
00300                         if (has_stencil) return true;
00301                         break;
00302                 case VOGL_HAS_ALPHA_PLANE:
00303                         if (has_alpha) return true;
00304                         break;
00305                 default:
00306                         LOG_MSG("opengl: unknown feature queried: %x",feat);
00307                         break;
00308         }
00309 
00310         return false;
00311 }
00312 
00313 void VOGL_FlagFeature(Bit32u feat) {
00314         switch (feat) {
00315                 case VOGL_HAS_SHADERS:
00316                         has_shaders = true;
00317                         break;
00318                 case VOGL_HAS_STENCIL_BUFFER:
00319                         has_stencil = true;
00320                         break;
00321                 case VOGL_HAS_ALPHA_PLANE:
00322                         has_alpha = true;
00323                         break;
00324                 default:
00325                         LOG_MSG("opengl: unknown feature: %x",feat);
00326                         break;
00327         }
00328 }
00329 
00330 
00331 void VOGL_BeginMode(INT32 new_mode) {
00332         if (current_begin_mode > -1) {
00333                 if (new_mode != current_begin_mode) {
00334                         glEnd();
00335                         if (new_mode > -1) glBegin((GLenum)new_mode);
00336                         current_begin_mode = new_mode;
00337                 }
00338         } else {
00339                 if (new_mode > -1) {
00340                         glBegin((GLenum)new_mode);
00341                         current_begin_mode = new_mode;
00342                 }
00343         }
00344 }
00345 
00346 void VOGL_ClearBeginMode(void) {
00347         if (current_begin_mode > -1) {
00348                 glEnd();
00349                 current_begin_mode = -1;
00350         }
00351 }
00352 
00353 
00354 void VOGL_SetDepthMode(Bit32s mode, Bit32s func) {
00355         if (current_depth_mode!=mode) {
00356                 if (mode!=0) {
00357                         VOGL_ClearBeginMode();
00358                         glEnable(GL_DEPTH_TEST);
00359                         current_depth_mode=1;
00360                         if (current_depth_func!=func) {
00361                                 glDepthFunc((GLenum)(GL_NEVER+func));
00362                                 current_depth_func=func;
00363                         }
00364                 } else {
00365                         VOGL_ClearBeginMode();
00366                         glDisable(GL_DEPTH_TEST);
00367                         current_depth_mode=0;
00368                 }
00369         } else {
00370                 if ((mode!=0) && (current_depth_func!=func)) {
00371                         VOGL_ClearBeginMode();
00372                         glDepthFunc((GLenum)(GL_NEVER+func));
00373                         current_depth_func=func;
00374                 }
00375         }
00376 }
00377 
00378 
00379 void VOGL_SetAlphaMode(Bit32s enabled_mode,GLuint src_rgb_fac,GLuint dst_rgb_fac,
00380                                                                                         GLuint src_alpha_fac,GLuint dst_alpha_fac) {
00381         if (current_alpha_enabled!=enabled_mode) {
00382                 VOGL_ClearBeginMode();
00383                 if (enabled_mode!=0) {
00384                         glEnable(GL_BLEND);
00385                         current_alpha_enabled=1;
00386                         if ((current_src_rgb_fac!=(Bit32s)src_rgb_fac) || (current_dst_rgb_fac!=(Bit32s)dst_rgb_fac) ||
00387                                 (current_src_alpha_fac!=(Bit32s)src_alpha_fac) || (current_dst_alpha_fac!=(Bit32s)dst_alpha_fac)) {
00388                                 glBlendFuncSeparateEXT(src_rgb_fac, dst_rgb_fac, src_alpha_fac, dst_alpha_fac);
00389                                 current_src_rgb_fac=(Bit32s)src_rgb_fac;
00390                                 current_dst_rgb_fac=(Bit32s)dst_rgb_fac;
00391                                 current_src_alpha_fac=(Bit32s)src_alpha_fac;
00392                                 current_dst_alpha_fac=(Bit32s)dst_alpha_fac;
00393                         }
00394                 } else {
00395                         glDisable(GL_BLEND);
00396                         current_alpha_enabled=0;
00397                 }
00398         } else {
00399                 if (current_alpha_enabled!=0) {
00400                         if ((current_src_rgb_fac!=(Bit32s)src_rgb_fac) || (current_dst_rgb_fac!=(Bit32s)dst_rgb_fac) ||
00401                                 (current_src_alpha_fac!=(Bit32s)src_alpha_fac) || (current_dst_alpha_fac!=(Bit32s)dst_alpha_fac)) {
00402                                 VOGL_ClearBeginMode();
00403                                 glBlendFuncSeparateEXT(src_rgb_fac, dst_rgb_fac, src_alpha_fac, dst_alpha_fac);
00404                                 current_src_rgb_fac=(Bit32s)src_rgb_fac;
00405                                 current_dst_rgb_fac=(Bit32s)dst_rgb_fac;
00406                                 current_src_alpha_fac=(Bit32s)src_alpha_fac;
00407                                 current_dst_alpha_fac=(Bit32s)dst_alpha_fac;
00408                         }
00409                 }
00410         }
00411 }
00412 
00413 
00414 void VOGL_SetDepthMaskMode(bool masked) {
00415         if (depth_masked!=masked) {
00416                 VOGL_ClearBeginMode();
00417                 if (masked) {
00418                         glDepthMask(GL_TRUE);
00419                         depth_masked=true;
00420                 } else {
00421                         glDepthMask(GL_FALSE);
00422                         depth_masked=false;
00423                 }
00424         }
00425 }
00426 
00427 
00428 void VOGL_SetColorMaskMode(bool cmasked, bool amasked) {
00429         if ((color_masked!=cmasked) || (alpha_masked!=amasked)) {
00430                 color_masked=cmasked;
00431                 alpha_masked=amasked;
00432                 GLboolean cm = (color_masked ? GL_TRUE : GL_FALSE);
00433                 GLboolean am = (alpha_masked ? GL_TRUE : GL_FALSE);
00434                 glColorMask(cm,cm,cm,am);
00435         }
00436 }
00437 
00438 
00439 void VOGL_SetDrawMode(bool front_draw) {
00440         if (draw_to_front_buffer!=front_draw) {
00441                 VOGL_ClearBeginMode();
00442                 if (front_draw) glDrawBuffer(GL_FRONT);
00443                 else glDrawBuffer(GL_BACK);
00444                 draw_to_front_buffer=front_draw;
00445         }
00446 }
00447 
00448 
00449 void VOGL_SetReadMode(bool front_read) {
00450         VOGL_ClearBeginMode();
00451 
00452         if (read_from_front_buffer!=front_read) {
00453                 if (front_read) glReadBuffer(GL_FRONT);
00454                 else glReadBuffer(GL_BACK);
00455                 read_from_front_buffer=front_read;
00456         }
00457 }
00458 
00459 #endif