ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

grim/gfx_opengl.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #if defined(WIN32)
00024 #include <windows.h>
00025 // winnt.h defines ARRAYSIZE, but we want our own one...
00026 #undef ARRAYSIZE
00027 #endif
00028 
00029 #include "common/endian.h"
00030 #include "common/system.h"
00031 #include "common/config-manager.h"
00032 
00033 #if defined(USE_OPENGL) && !defined(USE_GLES2)
00034 
00035 #include "graphics/surface.h"
00036 #include "graphics/pixelbuffer.h"
00037 
00038 #include "math/glmath.h"
00039 
00040 #include "engines/grim/actor.h"
00041 #include "engines/grim/colormap.h"
00042 #include "engines/grim/font.h"
00043 #include "engines/grim/material.h"
00044 #include "engines/grim/gfx_opengl.h"
00045 #include "engines/grim/grim.h"
00046 #include "engines/grim/bitmap.h"
00047 #include "engines/grim/primitives.h"
00048 #include "engines/grim/sprite.h"
00049 #include "engines/grim/model.h"
00050 #include "engines/grim/set.h"
00051 #include "engines/grim/emi/modelemi.h"
00052 #include "engines/grim/registry.h"
00053 
00054 
00055 #if defined (SDL_BACKEND) && defined(GL_ARB_fragment_program) && !defined(USE_GLEW)
00056 
00057 // We need SDL.h for SDL_GL_GetProcAddress.
00058 #include "backends/platform/sdl/sdl-sys.h"
00059 
00060 // Extension functions needed for fragment programs.
00061 PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
00062 PFNGLBINDPROGRAMARBPROC glBindProgramARB;
00063 PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
00064 PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
00065 PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB;
00066 
00067 #endif
00068 
00069 namespace Grim {
00070 
00071 GfxBase *CreateGfxOpenGL() {
00072     return new GfxOpenGL();
00073 }
00074 
00075 // Simple ARB fragment program that writes the value from a texture to the Z-buffer.
00076 static char fragSrc[] =
00077     "!!ARBfp1.0\n\
00078     TEMP d;\n\
00079     TEX d, fragment.texcoord[0], texture[0], 2D;\n\
00080     MOV result.depth, d.r;\n\
00081     END\n";
00082 
00083 static char dimFragSrc[] =
00084     "!!ARBfp1.0\n\
00085     PARAM level = program.local[0];\n\
00086     TEMP color;\n\
00087     TEMP d;\n\
00088     TEX d, fragment.texcoord[0], texture[0], 2D;\n\
00089     TEMP sum;\n\
00090     MOV sum, d.r;\n\
00091     ADD sum, sum, d.g;\n\
00092     ADD sum, sum, d.b;\n\
00093     MUL sum, sum, 0.33;\n\
00094     MUL sum, sum, level.x;\n\
00095     MOV result.color.r, sum;\n\
00096     MOV result.color.g, sum;\n\
00097     MOV result.color.b, sum;\n\
00098     END\n";
00099 
00100 GfxOpenGL::GfxOpenGL() : _smushNumTex(0),
00101         _smushTexIds(nullptr), _smushWidth(0), _smushHeight(0),
00102         _useDepthShader(false), _fragmentProgram(0), _useDimShader(0),
00103         _dimFragProgram(0), _maxLights(0), _storedDisplay(nullptr), 
00104         _emergFont(0), _alpha(1.f) {
00105     // GL_LEQUAL as glDepthFunc ensures that subsequent drawing attempts for
00106     // the same triangles are not ignored by the depth test.
00107     // That's necessary for EMI where some models have multiple faces which
00108     // refer to the same vertices. The first face is usually using the
00109     // color map and the following are using textures.
00110     _depthFunc = (g_grim->getGameType() == GType_MONKEY4) ? GL_LEQUAL : GL_LESS;
00111 }
00112 
00113 GfxOpenGL::~GfxOpenGL() {
00114     delete[] _storedDisplay;
00115 
00116     if (_emergFont && glIsList(_emergFont))
00117         glDeleteLists(_emergFont, 128);
00118 
00119 #ifdef GL_ARB_fragment_program
00120     if (_useDepthShader)
00121         glDeleteProgramsARB(1, &_fragmentProgram);
00122 
00123     if (_useDimShader)
00124         glDeleteProgramsARB(1, &_dimFragProgram);
00125 #endif
00126     for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
00127         destroyTexture(&_specialtyTextures[i]);
00128     }
00129 }
00130 
00131 byte *GfxOpenGL::setupScreen(int screenW, int screenH, bool fullscreen) {
00132     _screenWidth = screenW;
00133     _screenHeight = screenH;
00134     _scaleW = _screenWidth / (float)_gameWidth;
00135     _scaleH = _screenHeight / (float)_gameHeight;
00136 
00137     _useDepthShader = false;
00138     _useDimShader = false;
00139 
00140     g_system->showMouse(!fullscreen);
00141 
00142     g_system->setWindowCaption("ResidualVM: OpenGL Renderer");
00143 
00144     int screenSize = _screenWidth * _screenHeight * 4;
00145     _storedDisplay = new byte[screenSize];
00146     memset(_storedDisplay, 0, screenSize);
00147     _smushNumTex = 0;
00148 
00149     _currentShadowArray = nullptr;
00150     glViewport(0, 0, _screenWidth, _screenHeight);
00151 
00152     GLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f };
00153     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientSource);
00154     GLfloat diffuseReflectance[] = { 1.0f, 1.0f, 1.0f, 1.0f };
00155     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseReflectance);
00156 
00157     if (g_grim->getGameType() == GType_GRIM) {
00158         glPolygonOffset(-6.0, -6.0);
00159     }
00160 
00161     initExtensions();
00162     glGetIntegerv(GL_MAX_LIGHTS, &_maxLights);
00163 
00164     return nullptr;
00165 }
00166 
00167 void GfxOpenGL::initExtensions() {
00168     if (!ConfMan.getBool("use_arb_shaders")) {
00169         return;
00170     }
00171 
00172 #if defined (SDL_BACKEND) && defined(GL_ARB_fragment_program)
00173 #ifndef USE_GLEW
00174     union {
00175         void *obj_ptr;
00176         void (APIENTRY *func_ptr)();
00177     } u;
00178     // We're casting from an object pointer to a function pointer, the
00179     // sizes need to be the same for this to work.
00180     assert(sizeof(u.obj_ptr) == sizeof(u.func_ptr));
00181     u.obj_ptr = SDL_GL_GetProcAddress("glGenProgramsARB");
00182     glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)u.func_ptr;
00183     u.obj_ptr = SDL_GL_GetProcAddress("glBindProgramARB");
00184     glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)u.func_ptr;
00185     u.obj_ptr = SDL_GL_GetProcAddress("glProgramStringARB");
00186     glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)u.func_ptr;
00187     u.obj_ptr = SDL_GL_GetProcAddress("glDeleteProgramsARB");
00188     glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)u.func_ptr;
00189     u.obj_ptr = SDL_GL_GetProcAddress("glProgramLocalParameter4fARB");
00190     glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)u.func_ptr;
00191 #endif
00192 
00193     const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
00194     if (extensions && strstr(extensions, "ARB_fragment_program")) {
00195         _useDepthShader = true;
00196         _useDimShader = true;
00197     }
00198 
00199     if (_useDepthShader) {
00200         glGenProgramsARB(1, &_fragmentProgram);
00201         glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _fragmentProgram);
00202 
00203         GLint errorPos;
00204         glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragSrc), fragSrc);
00205         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
00206         if (errorPos != -1) {
00207             warning("Error compiling depth fragment program:\n%s", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
00208             _useDepthShader = false;
00209         }
00210 
00211 
00212         glGenProgramsARB(1, &_dimFragProgram);
00213         glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _dimFragProgram);
00214 
00215         glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dimFragSrc), dimFragSrc);
00216         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
00217         if (errorPos != -1) {
00218             warning("Error compiling dim fragment program:\n%s", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
00219             _useDimShader = false;
00220         }
00221     }
00222 #endif
00223 }
00224 
00225 const char *GfxOpenGL::getVideoDeviceName() {
00226     return "OpenGL Renderer";
00227 }
00228 
00229 void GfxOpenGL::setupCameraFrustum(float fov, float nclip, float fclip) {
00230     glMatrixMode(GL_PROJECTION);
00231     glLoadIdentity();
00232 
00233     float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
00234     glFrustum(-right, right, -right * 0.75, right * 0.75, nclip, fclip);
00235 
00236     glMatrixMode(GL_MODELVIEW);
00237     glLoadIdentity();
00238 }
00239 
00240 void GfxOpenGL::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) {
00241     Math::Vector3d up_vec(0, 0, 1);
00242 
00243     glRotatef(roll, 0, 0, -1);
00244 
00245     if (pos.x() == interest.x() && pos.y() == interest.y())
00246         up_vec = Math::Vector3d(0, 1, 0);
00247 
00248     Math::Matrix4 lookMatrix = Math::makeLookAtMatrix(pos, interest, up_vec);
00249     glMultMatrixf(lookMatrix.getData());
00250     glTranslated(-pos.x(), -pos.y(), -pos.z());
00251 }
00252 
00253 void GfxOpenGL::positionCamera(const Math::Vector3d &pos, const Math::Matrix4 &rot) {
00254     glScaled(1, 1, -1);
00255     _currentPos = pos;
00256     _currentRot = rot;
00257 }
00258 
00259 Math::Matrix4 GfxOpenGL::getModelView() {
00260     Math::Matrix4 modelView;
00261 
00262     if (g_grim->getGameType() == GType_MONKEY4) {
00263         glMatrixMode(GL_MODELVIEW);
00264         glPushMatrix();
00265 
00266         glMultMatrixf(_currentRot.getData());
00267         glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00268 
00269         glGetFloatv(GL_MODELVIEW_MATRIX, modelView.getData());
00270 
00271         glPopMatrix();
00272     } else {
00273         glGetFloatv(GL_MODELVIEW_MATRIX, modelView.getData());
00274     }
00275 
00276     modelView.transpose();
00277     return modelView;
00278 }
00279 
00280 Math::Matrix4 GfxOpenGL::getProjection() {
00281     Math::Matrix4 projection;
00282     glGetFloatv(GL_PROJECTION_MATRIX, projection.getData());
00283     projection.transpose();
00284     return projection;
00285 }
00286 
00287 void GfxOpenGL::clearScreen() {
00288     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00289 }
00290 
00291 void GfxOpenGL::clearDepthBuffer() {
00292     glClear(GL_DEPTH_BUFFER_BIT);
00293 }
00294 
00295 void GfxOpenGL::flipBuffer() {
00296     g_system->updateScreen();
00297 }
00298 
00299 bool GfxOpenGL::isHardwareAccelerated() {
00300     return true;
00301 }
00302 
00303 bool GfxOpenGL::supportsShaders() {
00304     return false;
00305 }
00306 
00307 static void glShadowProjection(const Math::Vector3d &light, const Math::Vector3d &plane, const Math::Vector3d &normal, bool dontNegate) {
00308     // Based on GPL shadow projection example by
00309     // (c) 2002-2003 Phaetos <phaetos@gaffga.de>
00310     float d, c;
00311     float mat[16];
00312     float nx, ny, nz, lx, ly, lz, px, py, pz;
00313 
00314     nx = normal.x();
00315     ny = normal.y();
00316     nz = normal.z();
00317     // for some unknown for me reason normal need negation
00318     if (!dontNegate) {
00319         nx = -nx;
00320         ny = -ny;
00321         nz = -nz;
00322     }
00323     lx = light.x();
00324     ly = light.y();
00325     lz = light.z();
00326     px = plane.x();
00327     py = plane.y();
00328     pz = plane.z();
00329 
00330     d = nx * lx + ny * ly + nz * lz;
00331     c = px * nx + py * ny + pz * nz - d;
00332 
00333     mat[0] = lx * nx + c;
00334     mat[4] = ny * lx;
00335     mat[8] = nz * lx;
00336     mat[12] = -lx * c - lx * d;
00337 
00338     mat[1] = nx * ly;
00339     mat[5] = ly * ny + c;
00340     mat[9] = nz * ly;
00341     mat[13] = -ly * c - ly * d;
00342 
00343     mat[2] = nx * lz;
00344     mat[6] = ny * lz;
00345     mat[10] = lz * nz + c;
00346     mat[14] = -lz * c - lz * d;
00347 
00348     mat[3] = nx;
00349     mat[7] = ny;
00350     mat[11] = nz;
00351     mat[15] = -d;
00352 
00353     glMultMatrixf((GLfloat *)mat);
00354 }
00355 
00356 void GfxOpenGL::getScreenBoundingBox(const Mesh *model, int *x1, int *y1, int *x2, int *y2) {
00357     if (_currentShadowArray) {
00358         *x1 = -1;
00359         *y1 = -1;
00360         *x2 = -1;
00361         *y2 = -1;
00362         return;
00363     }
00364 
00365     GLdouble top = 1000;
00366     GLdouble right = -1000;
00367     GLdouble left = 1000;
00368     GLdouble bottom = -1000;
00369 
00370     for (int i = 0; i < model->_numFaces; i++) {
00371         Math::Vector3d obj;
00372         float *pVertices;
00373 
00374         for (int j = 0; j < model->_faces[i].getNumVertices(); j++) {
00375             GLdouble modelView[16], projection[16];
00376             GLint viewPort[4];
00377 
00378             glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
00379             glGetDoublev(GL_PROJECTION_MATRIX, projection);
00380             glGetIntegerv(GL_VIEWPORT, viewPort);
00381 
00382             pVertices = model->_vertices + 3 * model->_faces[i].getVertex(j);
00383 
00384             obj.set(*(pVertices), *(pVertices + 1), *(pVertices + 2));
00385 
00386             Math::Vector3d win;
00387             Math::gluMathProject<GLdouble, GLint>(obj, modelView, projection, viewPort, win);
00388 
00389             if (win.x() > right)
00390                 right = win.x();
00391             if (win.x() < left)
00392                 left = win.x();
00393             if (win.y() < top)
00394                 top = win.y();
00395             if (win.y() > bottom)
00396                 bottom = win.y();
00397         }
00398     }
00399 
00400     double t = bottom;
00401     bottom = _gameHeight - top;
00402     top = _gameHeight - t;
00403 
00404     if (left < 0)
00405         left = 0;
00406     if (right >= _gameWidth)
00407         right = _gameWidth - 1;
00408     if (top < 0)
00409         top = 0;
00410     if (bottom >= _gameHeight)
00411         bottom = _gameHeight - 1;
00412 
00413     if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
00414         *x1 = -1;
00415         *y1 = -1;
00416         *x2 = -1;
00417         *y2 = -1;
00418         return;
00419     }
00420 
00421     *x1 = (int)left;
00422     *y1 = (int)top;
00423     *x2 = (int)right;
00424     *y2 = (int)bottom;
00425 }
00426 
00427 void GfxOpenGL::getScreenBoundingBox(const EMIModel *model, int *x1, int *y1, int *x2, int *y2) {
00428     if (_currentShadowArray) {
00429         *x1 = -1;
00430         *y1 = -1;
00431         *x2 = -1;
00432         *y2 = -1;
00433         return;
00434     }
00435 
00436     GLdouble top = 1000;
00437     GLdouble right = -1000;
00438     GLdouble left = 1000;
00439     GLdouble bottom = -1000;
00440 
00441     GLdouble modelView[16], projection[16];
00442     GLint viewPort[4];
00443 
00444     glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
00445     glGetDoublev(GL_PROJECTION_MATRIX, projection);
00446     glGetIntegerv(GL_VIEWPORT, viewPort);
00447 
00448     for (uint i = 0; i < model->_numFaces; i++) {
00449         int *indices = (int *)model->_faces[i]._indexes;
00450 
00451         for (uint j = 0; j < model->_faces[i]._faceLength * 3; j++) {
00452             int index = indices[j];
00453             Math::Vector3d obj = model->_drawVertices[index];
00454             Math::Vector3d win;
00455             Math::gluMathProject<GLdouble, GLint>(obj, modelView, projection, viewPort, win);
00456 
00457             if (win.x() > right)
00458                 right = win.x();
00459             if (win.x() < left)
00460                 left = win.x();
00461             if (win.y() < top)
00462                 top = win.y();
00463             if (win.y() > bottom)
00464                 bottom = win.y();
00465         }
00466     }
00467 
00468     double t = bottom;
00469     bottom = _gameHeight - top;
00470     top = _gameHeight - t;
00471     
00472     if (left < 0)
00473         left = 0;
00474     if (right >= _gameWidth)
00475         right = _gameWidth - 1;
00476     if (top < 0)
00477         top = 0;
00478     if (bottom >= _gameHeight)
00479         bottom = _gameHeight - 1;
00480     
00481     if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
00482         *x1 = -1;
00483         *y1 = -1;
00484         *x2 = -1;
00485         *y2 = -1;
00486         return;
00487     }
00488     
00489     *x1 = (int)left;
00490     *y1 = (int)top;
00491     *x2 = (int)right;
00492     *y2 = (int)bottom;
00493 }
00494 
00495 void GfxOpenGL::getActorScreenBBox(const Actor *actor, Common::Point &p1, Common::Point &p2) {
00496     // Get the actor's bounding box information (describes a 3D box)
00497     Math::Vector3d bboxPos, bboxSize;
00498     actor->getBBoxInfo(bboxPos, bboxSize);
00499 
00500     // Translate the bounding box to the actor's position
00501     Math::Matrix4 m = actor->getFinalMatrix();
00502     bboxPos = bboxPos + actor->getWorldPos();
00503 
00504     // Set up the camera coordinate system
00505     glMatrixMode(GL_MODELVIEW);
00506     glPushMatrix();
00507     Math::Matrix4 worldRot = _currentRot;
00508     glMultMatrixf(worldRot.getData());
00509     glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00510 
00511     // Get the current OpenGL state
00512     GLdouble modelView[16], projection[16];
00513     GLint viewPort[4];
00514     glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
00515     glGetDoublev(GL_PROJECTION_MATRIX, projection);
00516     glGetIntegerv(GL_VIEWPORT, viewPort);
00517 
00518     // Set values outside of the screen range
00519     p1.x = 1000;
00520     p1.y = 1000;
00521     p2.x = -1000;
00522     p2.y = -1000;
00523 
00524     // Project all of the points in the 3D bounding box
00525     Math::Vector3d p, projected;
00526     for (int x = 0; x < 2; x++) {
00527         for (int y = 0; y < 2; y++) {
00528             for (int z = 0; z < 2; z++) {
00529                 Math::Vector3d added(bboxSize.x() * 0.5f * (x * 2 - 1), bboxSize.y() * 0.5f * (y * 2 - 1), bboxSize.z() * 0.5f * (z * 2 - 1));
00530                 m.transform(&added, false);
00531                 p = bboxPos + added;
00532                 Math::gluMathProject<GLdouble, GLint>(p, modelView, projection, viewPort, projected);
00533 
00534                 // Find the points
00535                 if (projected.x() < p1.x)
00536                     p1.x = projected.x();
00537                 if (projected.y() < p1.y)
00538                     p1.y = projected.y();
00539                 if (projected.x() > p2.x)
00540                     p2.x = projected.x();
00541                 if (projected.y() > p2.y)
00542                     p2.y = projected.y();
00543             }
00544         }
00545     }
00546 
00547     // Swap the p1/p2 y coorindates
00548     int16 tmp = p1.y;
00549     p1.y = 480 - p2.y;
00550     p2.y = 480 - tmp;
00551 
00552     // Restore the state
00553     glPopMatrix();
00554 }
00555 
00556 void GfxOpenGL::startActorDraw(const Actor *actor) {
00557     _currentActor = actor;
00558     glEnable(GL_TEXTURE_2D);
00559     glEnable(GL_LIGHTING);
00560     glMatrixMode(GL_PROJECTION);
00561     glPushMatrix();
00562     glMatrixMode(GL_MODELVIEW);
00563     glPushMatrix();
00564 
00565     if (g_grim->getGameType() == GType_MONKEY4 && !actor->isInOverworld()) {
00566         // Apply the view transform.
00567         glMultMatrixf(_currentRot.getData());
00568         glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00569     }
00570 
00571     if (_currentShadowArray) {
00572         // TODO find out why shadowMask at device in woods is null
00573         if (!_currentShadowArray->shadowMask) {
00574             _currentShadowArray->shadowMask = new byte[_screenWidth * _screenHeight];
00575             _currentShadowArray->shadowMaskSize = _screenWidth * _screenHeight;
00576         }
00577         Sector *shadowSector = _currentShadowArray->planeList.front().sector;
00578         glDepthMask(GL_FALSE);
00579         glEnable(GL_POLYGON_OFFSET_FILL);
00580         glDisable(GL_LIGHTING);
00581         glDisable(GL_TEXTURE_2D);
00582 //      glColor3f(0.0f, 1.0f, 0.0f); // debug draw color
00583         if (g_grim->getGameType() == GType_GRIM) {
00584             glColor3ub(_shadowColorR, _shadowColorG, _shadowColorB);
00585         } else {
00586             glColor3ub(_currentShadowArray->color.getRed(), _currentShadowArray->color.getGreen(), _currentShadowArray->color.getBlue());
00587         }
00588         glShadowProjection(_currentShadowArray->pos, shadowSector->getVertices()[0], shadowSector->getNormal(), _currentShadowArray->dontNegate);
00589     }
00590 
00591     const float alpha = actor->getEffectiveAlpha();
00592     if (alpha < 1.f) {
00593         _alpha = alpha;
00594         glEnable(GL_BLEND);
00595         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00596     }
00597 
00598     if (g_grim->getGameType() == GType_MONKEY4) {
00599         glEnable(GL_CULL_FACE);
00600         glFrontFace(GL_CW);
00601 
00602         if (actor->isInOverworld()) {
00603             const Math::Vector3d &pos = actor->getWorldPos();
00604             const Math::Quaternion &quat = actor->getRotationQuat();
00605             // At distance 3.2, a 6.4x4.8 actor fills the screen.
00606             glMatrixMode(GL_PROJECTION);
00607             glLoadIdentity();
00608             float right = 1;
00609             float top = right * 0.75;
00610             float div = 6.0f;
00611             glFrustum(-right / div, right / div, -top / div, top / div, 1.0f / div, 3276.8f);
00612             glMatrixMode(GL_MODELVIEW);
00613             glLoadIdentity();
00614             glScalef(1.0, 1.0, -1.0);
00615             glTranslatef(pos.x(), pos.y(), pos.z());
00616             glMultMatrixf(quat.toMatrix().getData());
00617         } else {
00618             Math::Matrix4 m = actor->getFinalMatrix();
00619             m.transpose();
00620             glMultMatrixf(m.getData());
00621         }
00622     } else {
00623         // Grim
00624         Math::Vector3d pos = actor->getWorldPos();
00625         const Math::Quaternion &quat = actor->getRotationQuat();
00626         const float &scale = actor->getScale();
00627 
00628         glTranslatef(pos.x(), pos.y(), pos.z());
00629         glScalef(scale, scale, scale);
00630         glMultMatrixf(quat.toMatrix().getData());
00631     }
00632 }
00633 
00634 void GfxOpenGL::finishActorDraw() {
00635     glMatrixMode(GL_MODELVIEW);
00636     glPopMatrix();
00637     glMatrixMode(GL_PROJECTION);
00638     glPopMatrix();
00639     glMatrixMode(GL_MODELVIEW);
00640 
00641     glDisable(GL_TEXTURE_2D);
00642     if (_alpha < 1.f) {
00643         glDisable(GL_BLEND);
00644         _alpha = 1.f;
00645     }
00646 
00647     if (_currentShadowArray) {
00648         glEnable(GL_LIGHTING);
00649         glColor3f(1.0f, 1.0f, 1.0f);
00650         glDisable(GL_POLYGON_OFFSET_FILL);
00651     }
00652 
00653     if (g_grim->getGameType() == GType_MONKEY4) {
00654         glDisable(GL_CULL_FACE);
00655     }
00656 
00657     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00658     _currentActor = nullptr;
00659 }
00660 
00661 void GfxOpenGL::setShadow(Shadow *shadow) {
00662     _currentShadowArray = shadow;
00663 }
00664 
00665 void GfxOpenGL::drawShadowPlanes() {
00666 /*  glColor3f(1.0f, 1.0f, 1.0f);
00667     _currentShadowArray->planeList.begin();
00668     for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); i++) {
00669         Sector *shadowSector = i->sector;
00670         glBegin(GL_POLYGON);
00671         for (int k = 0; k < shadowSector->getNumVertices(); k++) {
00672             glVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
00673         }
00674         glEnd();
00675     }
00676 */
00677 
00678     glPushMatrix();
00679 
00680     if (g_grim->getGameType() == GType_MONKEY4) {
00681         // Apply the view transform.
00682         glMultMatrixf(_currentRot.getData());
00683         glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
00684     }
00685 
00686 
00687     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00688     glDepthMask(GL_FALSE);
00689     glClearStencil(~0);
00690     glClear(GL_STENCIL_BUFFER_BIT);
00691 
00692     glEnable(GL_STENCIL_TEST);
00693     glStencilFunc(GL_ALWAYS, 1, (GLuint)~0);
00694     glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
00695     glDisable(GL_LIGHTING);
00696     glDisable(GL_TEXTURE_2D);
00697     glColor4f(1, 1, 1, 1);
00698     for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); ++i) {
00699         Sector *shadowSector = i->sector;
00700         glBegin(GL_POLYGON);
00701         for (int k = 0; k < shadowSector->getNumVertices(); k++) {
00702             glVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
00703         }
00704         glEnd();
00705     }
00706     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00707 
00708     glStencilFunc(GL_EQUAL, 1, (GLuint)~0);
00709     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00710 
00711     glPopMatrix();
00712 }
00713 
00714 void GfxOpenGL::setShadowMode() {
00715     GfxBase::setShadowMode();
00716 }
00717 
00718 void GfxOpenGL::clearShadowMode() {
00719     GfxBase::clearShadowMode();
00720 
00721     glDisable(GL_STENCIL_TEST);
00722     glDepthMask(GL_TRUE);
00723 }
00724 
00725 void GfxOpenGL::setShadowColor(byte r, byte g, byte b) {
00726     _shadowColorR = r;
00727     _shadowColorG = g;
00728     _shadowColorB = b;
00729 }
00730 
00731 void GfxOpenGL::getShadowColor(byte *r, byte *g, byte *b) {
00732     *r = _shadowColorR;
00733     *g = _shadowColorG;
00734     *b = _shadowColorB;
00735 }
00736 
00737 void GfxOpenGL::set3DMode() {
00738     glMatrixMode(GL_MODELVIEW);
00739     glEnable(GL_DEPTH_TEST);
00740     glDepthFunc(_depthFunc);
00741 }
00742 
00743 void GfxOpenGL::drawEMIModelFace(const EMIModel *model, const EMIMeshFace *face) {
00744     int *indices = (int *)face->_indexes;
00745 
00746     glEnable(GL_DEPTH_TEST);
00747     glDisable(GL_ALPHA_TEST);
00748     glDisable(GL_LIGHTING);
00749     if (!_currentShadowArray && face->_hasTexture)
00750         glEnable(GL_TEXTURE_2D);
00751     else
00752         glDisable(GL_TEXTURE_2D);
00753     if (face->_flags & EMIMeshFace::kAlphaBlend || face->_flags & EMIMeshFace::kUnknownBlend || _currentActor->hasLocalAlpha() || _alpha < 1.0f)
00754         glEnable(GL_BLEND);
00755 
00756     glBegin(GL_TRIANGLES);
00757     float alpha = _alpha;
00758     if (model->_meshAlphaMode == Actor::AlphaReplace) {
00759         alpha *= model->_meshAlpha;
00760     }
00761     Math::Vector3d noLighting(1.f, 1.f, 1.f);
00762     for (uint j = 0; j < face->_faceLength * 3; j++) {
00763         int index = indices[j];
00764 
00765         if (!_currentShadowArray) {
00766             if (face->_hasTexture) {
00767                 glTexCoord2f(model->_texVerts[index].getX(), model->_texVerts[index].getY());
00768             }
00769             Math::Vector3d lighting = (face->_flags & EMIMeshFace::kNoLighting) ? noLighting : model->_lighting[index];
00770             byte r = (byte)(model->_colorMap[index].r * lighting.x());
00771             byte g = (byte)(model->_colorMap[index].g * lighting.y());
00772             byte b = (byte)(model->_colorMap[index].b * lighting.z());
00773             byte a = (int)(alpha * (model->_meshAlphaMode == Actor::AlphaReplace ? model->_colorMap[index].a * _currentActor->getLocalAlpha(index) : 255.f));
00774             glColor4ub(r, g, b, a);
00775         }
00776 
00777         Math::Vector3d normal = model->_normals[index];
00778         Math::Vector3d vertex = model->_drawVertices[index];
00779 
00780         glNormal3fv(normal.getData());
00781         glVertex3fv(vertex.getData());
00782     }
00783     glEnd();
00784 
00785     if (!_currentShadowArray) {
00786         glColor3f(1.0f, 1.0f, 1.0f);
00787     }
00788 
00789     glEnable(GL_TEXTURE_2D);
00790     glEnable(GL_DEPTH_TEST);
00791     glEnable(GL_ALPHA_TEST);
00792     glEnable(GL_LIGHTING);
00793     glDisable(GL_BLEND);
00794 
00795     if (!_currentShadowArray)
00796         glDepthMask(GL_TRUE);
00797 }
00798 
00799 void GfxOpenGL::drawModelFace(const Mesh *mesh, const MeshFace *face) {
00800     // Support transparency in actor objects, such as the message tube
00801     // in Manny's Office
00802     float *vertices = mesh->_vertices;
00803     float *vertNormals = mesh->_vertNormals;
00804     float *textureVerts = mesh->_textureVerts;
00805     glAlphaFunc(GL_GREATER, 0.5);
00806     glEnable(GL_ALPHA_TEST);
00807     glNormal3fv(face->getNormal().getData());
00808     glBegin(GL_POLYGON);
00809     for (int i = 0; i < face->getNumVertices(); i++) {
00810         glNormal3fv(vertNormals + 3 * face->getVertex(i));
00811 
00812         if (face->hasTexture())
00813             glTexCoord2fv(textureVerts + 2 * face->getTextureVertex(i));
00814 
00815         glVertex3fv(vertices + 3 * face->getVertex(i));
00816     }
00817     glEnd();
00818     // Done with transparency-capable objects
00819     glDisable(GL_ALPHA_TEST);
00820 }
00821 
00822 void GfxOpenGL::drawSprite(const Sprite *sprite) {
00823     glMatrixMode(GL_TEXTURE);
00824     glLoadIdentity();
00825     glMatrixMode(GL_MODELVIEW);
00826     glPushMatrix();
00827 
00828     if (g_grim->getGameType() == GType_MONKEY4) {
00829         GLdouble modelview[16];
00830         glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
00831         Math::Matrix4 act;
00832         act.buildAroundZ(_currentActor->getYaw());
00833         act.transpose();
00834         act(3, 0) = modelview[12];
00835         act(3, 1) = modelview[13];
00836         act(3, 2) = modelview[14];
00837         glLoadMatrixf(act.getData());
00838         glTranslatef(sprite->_pos.x(), sprite->_pos.y(), -sprite->_pos.z());
00839     } else {
00840         glTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
00841         GLdouble modelview[16];
00842         glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
00843 
00844         // We want screen-aligned sprites so reset the rotation part of the matrix.
00845         for (int i = 0; i < 3; i++) {
00846             for (int j = 0; j < 3; j++) {
00847                 if (i == j) {
00848                     modelview[i * 4 + j] = 1.0f;
00849                 } else {
00850                     modelview[i * 4 + j] = 0.0f;
00851                 }
00852             }
00853         }
00854         glLoadMatrixd(modelview);
00855     }
00856 
00857     if (sprite->_flags1 & Sprite::BlendAdditive) {
00858         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
00859     } else {
00860         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00861     }
00862 
00863     glDisable(GL_LIGHTING);
00864 
00865     if (g_grim->getGameType() == GType_GRIM) {
00866         glEnable(GL_ALPHA_TEST);
00867         glAlphaFunc(GL_GEQUAL, 0.5f);
00868     }  else if (sprite->_flags2 & Sprite::AlphaTest) {
00869         glEnable(GL_ALPHA_TEST);
00870         glAlphaFunc(GL_GEQUAL, 0.1f);
00871     } else {
00872         glDisable(GL_ALPHA_TEST);
00873     }
00874 
00875     if (sprite->_flags2 & Sprite::DepthTest) {
00876         glEnable(GL_DEPTH_TEST);
00877     } else {
00878         glDisable(GL_DEPTH_TEST);
00879     }
00880 
00881     if (g_grim->getGameType() == GType_MONKEY4) {
00882         glDepthMask(GL_TRUE);
00883 
00884         float halfWidth = sprite->_width / 2;
00885         float halfHeight = sprite->_height / 2;
00886         float vertexX[] = { -1.0f, 1.0f, 1.0f, -1.0f };
00887         float vertexY[] = { 1.0f, 1.0f, -1.0f, -1.0f };
00888 
00889         glBegin(GL_POLYGON);
00890         for (int i = 0; i < 4; ++i) {
00891             float r = sprite->_red[i] / 255.0f;
00892             float g = sprite->_green[i] / 255.0f;
00893             float b = sprite->_blue[i] / 255.0f;
00894             float a = sprite->_alpha[i] * _alpha / 255.0f;
00895 
00896             glColor4f(r, g, b, a);
00897             glTexCoord2f(sprite->_texCoordX[i], sprite->_texCoordY[i]);
00898             glVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
00899         }
00900         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00901         glEnd();
00902     } else {
00903         // In Grim, the bottom edge of the sprite is at y=0 and
00904         // the texture is flipped along the X-axis.
00905         float halfWidth = sprite->_width / 2;
00906         float height = sprite->_height;
00907 
00908         glBegin(GL_POLYGON);
00909         glTexCoord2f(0.0f, 1.0f);
00910         glVertex3f(+halfWidth, 0.0f, 0.0f);
00911         glTexCoord2f(0.0f, 0.0f);
00912         glVertex3f(+halfWidth, +height, 0.0f);
00913         glTexCoord2f(1.0f, 0.0f);
00914         glVertex3f(-halfWidth, +height, 0.0f);
00915         glTexCoord2f(1.0f, 1.0f);
00916         glVertex3f(-halfWidth, 0.0f, 0.0f);
00917         glEnd();
00918     }
00919 
00920     glEnable(GL_LIGHTING);
00921     glDisable(GL_ALPHA_TEST);
00922     glDepthMask(GL_TRUE);
00923     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00924     glDisable(GL_BLEND);
00925     glEnable(GL_DEPTH_TEST);
00926 
00927     glPopMatrix();
00928 }
00929 
00930 void GfxOpenGL::translateViewpointStart() {
00931     glMatrixMode(GL_MODELVIEW);
00932     glPushMatrix();
00933 }
00934 
00935 void GfxOpenGL::translateViewpoint(const Math::Vector3d &vec) {
00936     glTranslatef(vec.x(), vec.y(), vec.z());
00937 }
00938 
00939 void GfxOpenGL::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) {
00940     glRotatef(angle.getDegrees(), axis.x(), axis.y(), axis.z());
00941 }
00942 
00943 void GfxOpenGL::rotateViewpoint(const Math::Matrix4 &rot) {
00944     glMultMatrixf(rot.getData());
00945 }
00946 
00947 void GfxOpenGL::translateViewpointFinish() {
00948     glMatrixMode(GL_MODELVIEW);
00949     glPopMatrix();
00950 }
00951 
00952 void GfxOpenGL::enableLights() {
00953     if (!isShadowModeActive()) {
00954         glEnable(GL_LIGHTING);
00955     }
00956 }
00957 
00958 void GfxOpenGL::disableLights() {
00959     glDisable(GL_LIGHTING);
00960 }
00961 
00962 void GfxOpenGL::setupLight(Light *light, int lightId) {
00963     if (lightId >= _maxLights) {
00964         return;
00965     }
00966 
00967     glEnable(GL_LIGHTING);
00968     GLfloat lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
00969     GLfloat lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
00970     GLfloat lightDir[] = { 0.0f, 0.0f, -1.0f };
00971     GLfloat cutoff = 180.0f;
00972     GLfloat spot_exp = 0.0f;
00973     GLfloat q_attenuation = 1.0f;
00974 
00975     GLfloat intensity = light->_scaledintensity;
00976     lightColor[0] = (GLfloat)light->_color.getRed() * intensity;
00977     lightColor[1] = (GLfloat)light->_color.getGreen() * intensity;
00978     lightColor[2] = (GLfloat)light->_color.getBlue() * intensity;
00979 
00980     if (light->_type == Light::Omni) {
00981         lightPos[0] = light->_pos.x();
00982         lightPos[1] = light->_pos.y();
00983         lightPos[2] = light->_pos.z();
00984     } else if (light->_type == Light::Direct) {
00985         lightPos[0] = -light->_dir.x();
00986         lightPos[1] = -light->_dir.y();
00987         lightPos[2] = -light->_dir.z();
00988         lightPos[3] = 0;
00989     } else if (light->_type == Light::Spot) {
00990         lightPos[0] = light->_pos.x();
00991         lightPos[1] = light->_pos.y();
00992         lightPos[2] = light->_pos.z();
00993         lightDir[0] = light->_dir.x();
00994         lightDir[1] = light->_dir.y();
00995         lightDir[2] = light->_dir.z();
00996         spot_exp = 2.0f;
00997         cutoff = light->_penumbraangle;
00998         q_attenuation = 0.0f;
00999     }
01000 
01001     glDisable(GL_LIGHT0 + lightId);
01002     glLightfv(GL_LIGHT0 + lightId, GL_DIFFUSE, lightColor);
01003     glLightfv(GL_LIGHT0 + lightId, GL_POSITION, lightPos);
01004     glLightfv(GL_LIGHT0 + lightId, GL_SPOT_DIRECTION, lightDir);
01005     glLightf(GL_LIGHT0 + lightId, GL_SPOT_EXPONENT, spot_exp);
01006     glLightf(GL_LIGHT0 + lightId, GL_SPOT_CUTOFF, cutoff);
01007     glLightf(GL_LIGHT0 + lightId, GL_QUADRATIC_ATTENUATION, q_attenuation);
01008     glEnable(GL_LIGHT0 + lightId);
01009 }
01010 
01011 void GfxOpenGL::turnOffLight(int lightId) {
01012     glDisable(GL_LIGHT0 + lightId);
01013 }
01014 
01015 #define BITMAP_TEXTURE_SIZE 256
01016 
01017 void GfxOpenGL::createBitmap(BitmapData *bitmap) {
01018     GLuint *textures;
01019 
01020     if (bitmap->_format != 1) {
01021         for (int pic = 0; pic < bitmap->_numImages; pic++) {
01022             uint16 *zbufPtr = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
01023             for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
01024                 uint16 val = READ_LE_UINT16(zbufPtr + i);
01025                 // fix the value if it is incorrectly set to the bitmap transparency color
01026                 if (val == 0xf81f) {
01027                     val = 0;
01028                 }
01029                 zbufPtr[i] = 0xffff - ((uint32)val) * 0x10000 / 100 / (0x10000 - val);
01030             }
01031 
01032             // Flip the zbuffer image to match what GL expects
01033             if (!_useDepthShader) {
01034                 for (int y = 0; y < bitmap->_height / 2; y++) {
01035                     uint16 *ptr1 = zbufPtr + y * bitmap->_width;
01036                     uint16 *ptr2 = zbufPtr + (bitmap->_height - 1 - y) * bitmap->_width;
01037                     for (int x = 0; x < bitmap->_width; x++, ptr1++, ptr2++) {
01038                         uint16 tmp = *ptr1;
01039                         *ptr1 = *ptr2;
01040                         *ptr2 = tmp;
01041                     }
01042                 }
01043             }
01044         }
01045     }
01046     if (bitmap->_format == 1 || _useDepthShader) {
01047         bitmap->_hasTransparency = false;
01048         bitmap->_numTex = ((bitmap->_width + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE) *
01049                           ((bitmap->_height + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE);
01050         bitmap->_texIds = new GLuint[bitmap->_numTex * bitmap->_numImages];
01051         textures = (GLuint *)bitmap->_texIds;
01052         glGenTextures(bitmap->_numTex * bitmap->_numImages, textures);
01053 
01054         byte *texData = nullptr;
01055         byte *texOut = nullptr;
01056 
01057         GLint format = GL_RGBA;
01058         GLint type = GL_UNSIGNED_BYTE;
01059         int bytes = 4;
01060         if (bitmap->_format != 1) {
01061             format = GL_DEPTH_COMPONENT;
01062             type = GL_UNSIGNED_SHORT;
01063             bytes = 2;
01064         }
01065 
01066         glPixelStorei(GL_UNPACK_ALIGNMENT, bytes);
01067         glPixelStorei(GL_UNPACK_ROW_LENGTH, bitmap->_width);
01068 
01069         for (int pic = 0; pic < bitmap->_numImages; pic++) {
01070             if (bitmap->_format == 1 && bitmap->_bpp == 16 && bitmap->_colorFormat != BM_RGB1555) {
01071                 if (texData == nullptr)
01072                     texData = new byte[bytes * bitmap->_width * bitmap->_height];
01073                 // Convert data to 32-bit RGBA format
01074                 byte *texDataPtr = texData;
01075                 uint16 *bitmapData = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
01076                 for (int i = 0; i < bitmap->_width * bitmap->_height; i++, texDataPtr += bytes, bitmapData++) {
01077                     uint16 pixel = *bitmapData;
01078                     int r = pixel >> 11;
01079                     texDataPtr[0] = (r << 3) | (r >> 2);
01080                     int g = (pixel >> 5) & 0x3f;
01081                     texDataPtr[1] = (g << 2) | (g >> 4);
01082                     int b = pixel & 0x1f;
01083                     texDataPtr[2] = (b << 3) | (b >> 2);
01084                     if (pixel == 0xf81f) { // transparent
01085                         texDataPtr[3] = 0;
01086                         bitmap->_hasTransparency = true;
01087                     } else {
01088                         texDataPtr[3] = 255;
01089                     }
01090                 }
01091                 texOut = texData;
01092             } else if (bitmap->_format == 1 && bitmap->_colorFormat == BM_RGB1555) {
01093                 bitmap->convertToColorFormat(pic, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
01094                 texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
01095             } else {
01096                 texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
01097             }
01098 
01099             for (int i = 0; i < bitmap->_numTex; i++) {
01100                 glBindTexture(GL_TEXTURE_2D, textures[bitmap->_numTex * pic + i]);
01101                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01102                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01103                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
01104                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
01105                 glTexImage2D(GL_TEXTURE_2D, 0, format, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, format, type, nullptr);
01106             }
01107 
01108             int cur_tex_idx = bitmap->_numTex * pic;
01109 
01110             for (int y = 0; y < bitmap->_height; y += BITMAP_TEXTURE_SIZE) {
01111                 for (int x = 0; x < bitmap->_width; x += BITMAP_TEXTURE_SIZE) {
01112                     int width  = (x + BITMAP_TEXTURE_SIZE >= bitmap->_width) ? (bitmap->_width - x) : BITMAP_TEXTURE_SIZE;
01113                     int height = (y + BITMAP_TEXTURE_SIZE >= bitmap->_height) ? (bitmap->_height - y) : BITMAP_TEXTURE_SIZE;
01114                     glBindTexture(GL_TEXTURE_2D, textures[cur_tex_idx]);
01115                     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type,
01116                                     texOut + (y * bytes * bitmap->_width) + (bytes * x));
01117                     cur_tex_idx++;
01118                 }
01119             }
01120         }
01121 
01122         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
01123 
01124         delete[] texData;
01125         bitmap->freeData();
01126     }
01127 }
01128 
01129 void GfxOpenGL::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer) {
01130     // The PS2 version of EMI uses a TGA for it's splash-screen
01131     // avoid using the TIL-code below for that, by checking
01132     // for texture coordinates set by BitmapData::loadTile
01133     if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
01134         glMatrixMode(GL_MODELVIEW);
01135         glPushMatrix();
01136         glLoadIdentity();
01137         glMatrixMode(GL_PROJECTION);
01138         glPushMatrix();
01139         glLoadIdentity();
01140         glOrtho(-1, 1, -1, 1, 0, 1);
01141 
01142         glDisable(GL_LIGHTING);
01143         glEnable(GL_TEXTURE_2D);
01144         glEnable(GL_BLEND);
01145         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01146 
01147         glDisable(GL_DEPTH_TEST);
01148         glDepthMask(GL_FALSE);
01149 
01150             glColor3f(1.0f, 1.0f, 1.0f);
01151 
01152         BitmapData *data = bitmap->_data;
01153         GLuint *textures = (GLuint *)bitmap->getTexIds();
01154         float *texc = data->_texc;
01155 
01156         assert(layer < data->_numLayers);
01157         uint32 offset = data->_layers[layer]._offset;
01158         for (uint32 i = offset; i < offset + data->_layers[layer]._numImages; ++i) {
01159             glBindTexture(GL_TEXTURE_2D, textures[data->_verts[i]._texid]);
01160             glBegin(GL_QUADS);
01161             uint32 ntex = data->_verts[i]._pos * 4;
01162             for (uint32 x = 0; x < data->_verts[i]._verts; ++x) {
01163                 glTexCoord2f(texc[ntex + 2], texc[ntex + 3]);
01164                 glVertex2f(texc[ntex + 0], texc[ntex + 1]);
01165                 ntex += 4;
01166             }
01167             glEnd();
01168         }
01169 
01170         glColor3f(1.0f, 1.0f, 1.0f);
01171 
01172         glDisable(GL_BLEND);
01173         glDisable(GL_TEXTURE_2D);
01174         glDepthMask(GL_TRUE);
01175         glEnable(GL_DEPTH_TEST);
01176         glEnable(GL_LIGHTING);
01177 
01178         glPopMatrix();
01179         glMatrixMode(GL_MODELVIEW);
01180         glPopMatrix();
01181 
01182         return;
01183     }
01184 
01185     int format = bitmap->getFormat();
01186     if ((format == 1 && !_renderBitmaps) || (format == 5 && !_renderZBitmaps)) {
01187         return;
01188     }
01189 
01190     GLuint *textures;
01191     glMatrixMode(GL_PROJECTION);
01192     glLoadIdentity();
01193     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01194     glMatrixMode(GL_MODELVIEW);
01195     glLoadIdentity();
01196     glMatrixMode(GL_TEXTURE);
01197     glLoadIdentity();
01198     // A lot more may need to be put there : disabling Alpha test, blending, ...
01199     // For now, just keep this here :-)
01200     if (bitmap->getFormat() == 1 && bitmap->getHasTransparency()) {
01201         glEnable(GL_BLEND);
01202         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01203     } else {
01204         glDisable(GL_BLEND);
01205     }
01206     glDisable(GL_LIGHTING);
01207     glEnable(GL_TEXTURE_2D);
01208 
01209     // If drawing a Z-buffer image, but no shaders are available, fall back to the glDrawPixels method.
01210     if (bitmap->getFormat() == 5 && !_useDepthShader) {
01211         // Only draw the manual zbuffer when enabled
01212         if (bitmap->getActiveImage() - 1 < bitmap->getNumImages()) {
01213             drawDepthBitmap(dx, dy, bitmap->getWidth(), bitmap->getHeight(), (char *)bitmap->getData(bitmap->getActiveImage() - 1).getRawBuffer());
01214         } else {
01215             warning("zbuffer image has index out of bounds! %d/%d", bitmap->getActiveImage(), bitmap->getNumImages());
01216         }
01217         glEnable(GL_LIGHTING);
01218         return;
01219     }
01220 
01221     if (bitmap->getFormat() == 1) { // Normal image
01222         glDisable(GL_DEPTH_TEST);
01223         glDepthMask(GL_FALSE);
01224     } else { // ZBuffer image
01225         glEnable(GL_DEPTH_TEST);
01226         glDepthFunc(GL_ALWAYS);
01227         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
01228         glDepthMask(GL_TRUE);
01229 #ifdef GL_ARB_fragment_program
01230         glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _fragmentProgram);
01231         glEnable(GL_FRAGMENT_PROGRAM_ARB);
01232 #endif
01233     }
01234 
01235     glEnable(GL_SCISSOR_TEST);
01236     glScissor((int)(dx * _scaleW), _screenHeight - (int)(((dy + bitmap->getHeight())) * _scaleH), (int)(bitmap->getWidth() * _scaleW), (int)(bitmap->getHeight() * _scaleH));
01237     int cur_tex_idx = bitmap->getNumTex() * (bitmap->getActiveImage() - 1);
01238     for (int y = dy; y < (dy + bitmap->getHeight()); y += BITMAP_TEXTURE_SIZE) {
01239         for (int x = dx; x < (dx + bitmap->getWidth()); x += BITMAP_TEXTURE_SIZE) {
01240             textures = (GLuint *)bitmap->getTexIds();
01241             glBindTexture(GL_TEXTURE_2D, textures[cur_tex_idx]);
01242             glBegin(GL_QUADS);
01243             glTexCoord2f(0.0f, 0.0f);
01244             glVertex2f(x * _scaleW, y * _scaleH);
01245             glTexCoord2f(1.0f, 0.0f);
01246             glVertex2f((x + BITMAP_TEXTURE_SIZE) * _scaleW, y * _scaleH);
01247             glTexCoord2f(1.0f, 1.0f);
01248             glVertex2f((x + BITMAP_TEXTURE_SIZE) * _scaleW, (y + BITMAP_TEXTURE_SIZE)  * _scaleH);
01249             glTexCoord2f(0.0f, 1.0f);
01250             glVertex2f(x * _scaleW, (y + BITMAP_TEXTURE_SIZE) * _scaleH);
01251             glEnd();
01252             cur_tex_idx++;
01253         }
01254     }
01255     glDisable(GL_SCISSOR_TEST);
01256     glDisable(GL_TEXTURE_2D);
01257     glDisable(GL_BLEND);
01258     if (bitmap->getFormat() == 1) {
01259         glDepthMask(GL_TRUE);
01260         glEnable(GL_DEPTH_TEST);
01261     } else {
01262         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
01263         glDepthFunc(_depthFunc);
01264 #ifdef GL_ARB_fragment_program
01265         glDisable(GL_FRAGMENT_PROGRAM_ARB);
01266 #endif
01267     }
01268     glEnable(GL_LIGHTING);
01269 }
01270 
01271 void GfxOpenGL::destroyBitmap(BitmapData *bitmap) {
01272     GLuint *textures = (GLuint *)bitmap->_texIds;
01273     if (textures) {
01274         glDeleteTextures(bitmap->_numTex * bitmap->_numImages, textures);
01275         delete[] textures;
01276         bitmap->_texIds = nullptr;
01277     }
01278 }
01279 
01280 struct FontUserData {
01281     int size;
01282     GLuint texture;
01283 };
01284 
01285 void GfxOpenGL::createFont(Font *font) {
01286     const byte *bitmapData = font->getFontData();
01287     uint dataSize = font->getDataSize();
01288 
01289     uint8 bpp = 4;
01290     uint8 charsWide = 16;
01291     uint8 charsHigh = 16;
01292 
01293     byte *texDataPtr = new byte[dataSize * bpp];
01294     byte *data = texDataPtr;
01295 
01296     for (uint i = 0; i < dataSize; i++, texDataPtr += bpp, bitmapData++) {
01297         byte pixel = *bitmapData;
01298         if (pixel == 0x00) {
01299             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 0;
01300         } else if (pixel == 0x80) {
01301             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = 0;
01302             texDataPtr[3] = 255;
01303         } else if (pixel == 0xFF) {
01304             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 255;
01305         }
01306     }
01307     int size = 0;
01308     for (int i = 0; i < 256; ++i) {
01309         int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
01310         int m = MAX(width, height);
01311         if (m > size)
01312             size = m;
01313     }
01314     assert(size < 64);
01315     if (size < 8)
01316         size = 8;
01317     if (size < 16)
01318         size = 16;
01319     else if (size < 32)
01320         size = 32;
01321     else if (size < 64)
01322         size = 64;
01323 
01324     uint arraySize = size * size * bpp * charsWide * charsHigh;
01325     byte *temp = new byte[arraySize];
01326     if (!temp)
01327         error("Could not allocate %d bytes", arraySize);
01328 
01329     memset(temp, 0, arraySize);
01330 
01331     FontUserData *userData = new FontUserData;
01332     font->setUserData(userData);
01333     userData->texture = 0;
01334     userData->size = size;
01335 
01336     GLuint *texture = &(userData->texture);
01337     glGenTextures(1, texture);
01338 
01339     for (int i = 0, row = 0; i < 256; ++i) {
01340         int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
01341         int32 d = font->getCharOffset(i);
01342         for (int x = 0; x < height; ++x) {
01343             // a is the offset to get to the correct row.
01344             // b is the offset to get to the correct line in the character.
01345             // c is the offset of the character from the start of the row.
01346             uint a = row * size * size * bpp * charsHigh;
01347             uint b = x * size * charsWide * bpp;
01348             uint c = 0;
01349             if (i != 0)
01350                 c = ((i - 1) % 16) * size * bpp;
01351 
01352             uint pos = a + b + c;
01353             uint pos2 = d * bpp + x * width * bpp;
01354             assert(pos + width * bpp <= arraySize);
01355             assert(pos2 + width * bpp <= dataSize * bpp);
01356             memcpy(temp + pos, data + pos2, width * bpp);
01357         }
01358         if (i != 0 && i % charsWide == 0)
01359             ++row;
01360     }
01361     glBindTexture(GL_TEXTURE_2D, texture[0]);
01362     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01363     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01364     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
01365     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
01366     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size * charsWide, size * charsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
01367 
01368     delete[] data;
01369     delete[] temp;
01370 }
01371 
01372 void GfxOpenGL::destroyFont(Font *font) {
01373     const FontUserData *data = (const FontUserData *)font->getUserData();
01374     if (data) {
01375         glDeleteTextures(1, &(data->texture));
01376         delete data;
01377     }
01378 }
01379 
01380 void GfxOpenGL::createTextObject(TextObject *text) {
01381 }
01382 
01383 void GfxOpenGL::drawTextObject(const TextObject *text) {
01384     if (!text)
01385         return;
01386 
01387     glMatrixMode(GL_PROJECTION);
01388     glLoadIdentity();
01389     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01390     glMatrixMode(GL_MODELVIEW);
01391     glLoadIdentity();
01392     glMatrixMode(GL_TEXTURE);
01393     glLoadIdentity();
01394 
01395     glEnable(GL_BLEND);
01396     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01397 
01398     glDisable(GL_LIGHTING);
01399     glEnable(GL_TEXTURE_2D);
01400     glDepthMask(GL_FALSE);
01401 
01402     const Color &color = text->getFGColor();
01403     const Font *font = text->getFont();
01404 
01405     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01406     const FontUserData *userData = (const FontUserData *)font->getUserData();
01407     if (!userData)
01408         error("Could not get font userdata");
01409     float sizeW = userData->size * _scaleW;
01410     float sizeH = userData->size * _scaleH;
01411     GLuint texture = userData->texture;
01412     const Common::String *lines = text->getLines();
01413     int numLines = text->getNumLines();
01414     for (int j = 0; j < numLines; ++j) {
01415         const Common::String &line = lines[j];
01416         int x = text->getLineX(j);
01417         int y = text->getLineY(j);
01418         for (uint i = 0; i < line.size(); ++i) {
01419             uint8 character = line[i];
01420             float w = y + font->getCharStartingLine(character);
01421             if (g_grim->getGameType() == GType_GRIM)
01422                 w += font->getBaseOffsetY();
01423             float z = x + font->getCharStartingCol(character);
01424             z *= _scaleW;
01425             w *= _scaleH;
01426             glBindTexture(GL_TEXTURE_2D, texture);
01427             float width = 1 / 16.f;
01428             float cx = ((character - 1) % 16) / 16.0f;
01429             float cy = ((character - 1) / 16) / 16.0f;
01430             glBegin(GL_QUADS);
01431             glTexCoord2f(cx, cy);
01432             glVertex2f(z, w);
01433             glTexCoord2f(cx + width, cy);
01434             glVertex2f(z + sizeW, w);
01435             glTexCoord2f(cx + width, cy + width);
01436             glVertex2f(z + sizeW, w + sizeH);
01437             glTexCoord2f(cx, cy + width);
01438             glVertex2f(z, w + sizeH);
01439             glEnd();
01440             x += font->getCharKernedWidth(character);
01441         }
01442     }
01443 
01444     glColor3f(1, 1, 1);
01445 
01446     glDisable(GL_TEXTURE_2D);
01447     glDisable(GL_BLEND);
01448     glEnable(GL_DEPTH_TEST);
01449     glEnable(GL_LIGHTING);
01450     glDepthMask(GL_TRUE);
01451 }
01452 
01453 void GfxOpenGL::destroyTextObject(TextObject *text) {
01454 }
01455 
01456 void GfxOpenGL::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
01457     texture->_texture = new GLuint[1];
01458     glGenTextures(1, (GLuint *)texture->_texture);
01459     uint8 *texdata = new uint8[texture->_width * texture->_height * 4];
01460     uint8 *texdatapos = texdata;
01461 
01462     if (cmap != nullptr) { // EMI doesn't have colour-maps
01463         int bytes = 4;
01464         for (int y = 0; y < texture->_height; y++) {
01465             for (int x = 0; x < texture->_width; x++) {
01466                 uint8 col = *data;
01467                 if (col == 0) {
01468                     memset(texdatapos, 0, bytes); // transparent
01469                     if (!texture->_hasAlpha) {
01470                         texdatapos[3] = '\xff'; // fully opaque
01471                     }
01472                 } else {
01473                     memcpy(texdatapos, cmap->_colors + 3 * (col), 3);
01474                     texdatapos[3] = '\xff'; // fully opaque
01475                 }
01476                 texdatapos += bytes;
01477                 data++;
01478             }
01479         }
01480     } else {
01481 #ifdef SCUMM_BIG_ENDIAN
01482         // Copy and swap
01483         for (int y = 0; y < texture->_height; y++) {
01484             for (int x = 0; x < texture->_width; x++) {
01485                 uint32 pixel = (y * texture->_width + x) * texture->_bpp;
01486                 for (int b = 0; b < texture->_bpp; b++) {
01487                     texdata[pixel + b] = data[pixel + (texture->_bpp - 1) - b];
01488                 }
01489             }
01490         }
01491 #else
01492         memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
01493 #endif
01494     }
01495 
01496     GLuint format = 0;
01497     GLuint internalFormat = 0;
01498     if (texture->_colorFormat == BM_RGBA) {
01499         format = GL_RGBA;
01500         internalFormat = GL_RGBA;
01501     } else if (texture->_colorFormat == BM_BGRA) {
01502         format = GL_BGRA;
01503         internalFormat = GL_RGBA;
01504     } else {    // The only other colorFormat we load right now is BGR
01505         format = GL_BGR;
01506         internalFormat = GL_RGB;
01507     }
01508 
01509     GLuint *textures = (GLuint *)texture->_texture;
01510     glBindTexture(GL_TEXTURE_2D, textures[0]);
01511 
01512     //Remove darkened lines in EMI intro
01513     if (g_grim->getGameType() == GType_MONKEY4 && clamp) {
01514         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01515         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01516     } else {
01517         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
01518         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
01519     }
01520 
01521     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01522     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01523     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, texture->_width, texture->_height, 0, format, GL_UNSIGNED_BYTE, texdata);
01524     delete[] texdata;
01525 }
01526 
01527 void GfxOpenGL::selectTexture(const Texture *texture) {
01528     GLuint *textures = (GLuint *)texture->_texture;
01529     glBindTexture(GL_TEXTURE_2D, textures[0]);
01530 
01531     if (texture->_hasAlpha && g_grim->getGameType() == GType_MONKEY4) {
01532         glEnable(GL_BLEND);
01533     }
01534 
01535     // Grim has inverted tex-coords, EMI doesn't
01536     if (g_grim->getGameType() != GType_MONKEY4) {
01537         glMatrixMode(GL_TEXTURE);
01538         glLoadIdentity();
01539         glScalef(1.0f / texture->_width, 1.0f / texture->_height, 1);
01540     }
01541 }
01542 
01543 void GfxOpenGL::destroyTexture(Texture *texture) {
01544     GLuint *textures = (GLuint *)texture->_texture;
01545     if (textures) {
01546         glDeleteTextures(1, textures);
01547         delete[] textures;
01548     }
01549 }
01550 
01551 void GfxOpenGL::drawDepthBitmap(int x, int y, int w, int h, char *data) {
01552     //if (num != 0) {
01553     //  warning("Animation not handled yet in GL texture path");
01554     //}
01555 
01556     if (y + h == 480) {
01557         glRasterPos2i(x, _screenHeight - 1);
01558         glBitmap(0, 0, 0, 0, 0, -1, nullptr);
01559     } else
01560         glRasterPos2i(x, y + h);
01561 
01562     glDisable(GL_TEXTURE_2D);
01563     glEnable(GL_DEPTH_TEST);
01564     glDepthFunc(GL_ALWAYS);
01565     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
01566     glDepthMask(GL_TRUE);
01567     glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // 16 bit Z depth bitmap
01568 
01569     glDrawPixels(w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, data);
01570 
01571     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01572     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
01573     glDepthFunc(_depthFunc);
01574 }
01575 
01576 void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
01577     int height = frame->h;
01578     int width = frame->w;
01579     byte *bitmap = (byte *)frame->getPixels();
01580 
01581     GLenum format;
01582     GLenum dataType;
01583     int bytesPerPixel = frame->format.bytesPerPixel;
01584 
01585     // Aspyr Logo format
01586     if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0)) {
01587         format = GL_BGRA;
01588         dataType = GL_UNSIGNED_INT_8_8_8_8;
01589     } else if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0)) {
01590         format = GL_BGRA;
01591         dataType = GL_UNSIGNED_INT_8_8_8_8_REV;
01592     } else if (frame->format == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
01593         format = GL_RGB;
01594         dataType = GL_UNSIGNED_SHORT_5_6_5;
01595     } else {
01596         error("Unknown pixelformat: Bpp: %d RBits: %d GBits: %d BBits: %d ABits: %d RShift: %d GShift: %d BShift: %d AShift: %d",
01597             frame->format.bytesPerPixel,
01598             -(frame->format.rLoss - 8),
01599             -(frame->format.gLoss - 8),
01600             -(frame->format.bLoss - 8),
01601             -(frame->format.aLoss - 8),
01602             frame->format.rShift,
01603             frame->format.gShift,
01604             frame->format.bShift,
01605             frame->format.aShift);
01606     }
01607 
01608     // remove if already exist
01609     if (_smushNumTex > 0) {
01610         glDeleteTextures(_smushNumTex, _smushTexIds);
01611         delete[] _smushTexIds;
01612         _smushNumTex = 0;
01613     }
01614 
01615     // create texture
01616     _smushNumTex = ((width + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE) *
01617                    ((height + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE);
01618     _smushTexIds = new GLuint[_smushNumTex];
01619     glGenTextures(_smushNumTex, _smushTexIds);
01620     for (int i = 0; i < _smushNumTex; i++) {
01621         glBindTexture(GL_TEXTURE_2D, _smushTexIds[i]);
01622         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01623         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01624         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
01625         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
01626         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, format, dataType, nullptr);
01627     }
01628 
01629     glPixelStorei(GL_UNPACK_ALIGNMENT, bytesPerPixel); // 16 bit RGB 565 bitmap/32 bit BGR
01630     glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
01631 
01632     int curTexIdx = 0;
01633     for (int y = 0; y < height; y += BITMAP_TEXTURE_SIZE) {
01634         for (int x = 0; x < width; x += BITMAP_TEXTURE_SIZE) {
01635             int t_width = (x + BITMAP_TEXTURE_SIZE >= width) ? (width - x) : BITMAP_TEXTURE_SIZE;
01636             int t_height = (y + BITMAP_TEXTURE_SIZE >= height) ? (height - y) : BITMAP_TEXTURE_SIZE;
01637             glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
01638             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, format, dataType, bitmap + (y * bytesPerPixel * width) + (bytesPerPixel * x));
01639             curTexIdx++;
01640         }
01641     }
01642     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01643     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
01644     _smushWidth = (int)(width * _scaleW);
01645     _smushHeight = (int)(height * _scaleH);
01646 }
01647 
01648 void GfxOpenGL::drawMovieFrame(int offsetX, int offsetY) {
01649     // prepare view
01650     glMatrixMode(GL_PROJECTION);
01651     glLoadIdentity();
01652     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01653     glMatrixMode(GL_MODELVIEW);
01654     glLoadIdentity();
01655     glMatrixMode(GL_TEXTURE);
01656     glLoadIdentity();
01657     // A lot more may need to be put there : disabling Alpha test, blending, ...
01658     // For now, just keep this here :-)
01659 
01660     glDisable(GL_LIGHTING);
01661     glEnable(GL_TEXTURE_2D);
01662     // draw
01663     glDisable(GL_DEPTH_TEST);
01664     glDepthMask(GL_FALSE);
01665     glEnable(GL_SCISSOR_TEST);
01666 
01667     offsetX = (int)(offsetX * _scaleW);
01668     offsetY = (int)(offsetY * _scaleH);
01669 
01670     glScissor(offsetX, _screenHeight - (offsetY + _smushHeight), _smushWidth, _smushHeight);
01671 
01672     int curTexIdx = 0;
01673     for (int y = 0; y < _smushHeight; y += (int)(BITMAP_TEXTURE_SIZE * _scaleH)) {
01674         for (int x = 0; x < _smushWidth; x += (int)(BITMAP_TEXTURE_SIZE * _scaleW)) {
01675             glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
01676             glBegin(GL_QUADS);
01677             glTexCoord2f(0, 0);
01678             glVertex2f(x + offsetX, y + offsetY);
01679             glTexCoord2f(1.0f, 0.0f);
01680             glVertex2f(x + offsetX + BITMAP_TEXTURE_SIZE * _scaleW, y + offsetY);
01681             glTexCoord2f(1.0f, 1.0f);
01682             glVertex2f(x + offsetX + BITMAP_TEXTURE_SIZE * _scaleW, y + offsetY + BITMAP_TEXTURE_SIZE * _scaleH);
01683             glTexCoord2f(0.0f, 1.0f);
01684             glVertex2f(x + offsetX, y + offsetY + BITMAP_TEXTURE_SIZE * _scaleH);
01685             glEnd();
01686             curTexIdx++;
01687         }
01688     }
01689 
01690     glDisable(GL_SCISSOR_TEST);
01691     glDisable(GL_TEXTURE_2D);
01692     glDepthMask(GL_TRUE);
01693     glEnable(GL_DEPTH_TEST);
01694     glEnable(GL_LIGHTING);
01695 }
01696 
01697 void GfxOpenGL::releaseMovieFrame() {
01698     if (_smushNumTex > 0) {
01699         glDeleteTextures(_smushNumTex, _smushTexIds);
01700         delete[] _smushTexIds;
01701         _smushNumTex = 0;
01702     }
01703 }
01704 
01705 void GfxOpenGL::loadEmergFont() {
01706     glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 8 bit font bitmaps
01707 
01708     _emergFont = glGenLists(128);
01709     for (int i = 32; i < 127; i++) {
01710         glNewList(_emergFont + i, GL_COMPILE);
01711         glBitmap(8, 13, 0, 2, 10, 0, Font::emerFont[i - 32]);
01712         glEndList();
01713     }
01714 }
01715 
01716 void GfxOpenGL::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
01717     glMatrixMode(GL_PROJECTION);
01718     glPushMatrix();
01719     glLoadIdentity();
01720     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01721 
01722     glMatrixMode(GL_MODELVIEW);
01723     glLoadIdentity();
01724     glDisable(GL_DEPTH_TEST);
01725     glDisable(GL_LIGHTING);
01726 
01727     glRasterPos2i(x, y);
01728     glColor3f(1.0f, 1.0f, 1.0f);
01729 
01730     glListBase(_emergFont);
01731     glCallLists(strlen(text), GL_UNSIGNED_BYTE, (const GLubyte *)text);
01732 
01733     glEnable(GL_LIGHTING);
01734 
01735     glMatrixMode(GL_PROJECTION);
01736     glPopMatrix();
01737 }
01738 
01739 Bitmap *GfxOpenGL::getScreenshot(int w, int h, bool useStored) {
01740     Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
01741     if (useStored) {
01742         memcpy(src.getRawBuffer(), _storedDisplay, _screenWidth * _screenHeight * 4);
01743     } else {
01744         glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, src.getRawBuffer());
01745     }
01746     return createScreenshotBitmap(src, w, h, false);
01747 }
01748 
01749 void GfxOpenGL::storeDisplay() {
01750     glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, _storedDisplay);
01751 }
01752 
01753 void GfxOpenGL::copyStoredToDisplay() {
01754     glMatrixMode(GL_PROJECTION);
01755     glLoadIdentity();
01756     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01757     glMatrixMode(GL_MODELVIEW);
01758     glLoadIdentity();
01759 
01760     glDisable(GL_LIGHTING);
01761     glDisable(GL_DEPTH_TEST);
01762     glDepthMask(GL_FALSE);
01763 
01764     glRasterPos2i(0, _screenHeight - 1);
01765     glBitmap(0, 0, 0, 0, 0, -1, nullptr);
01766     glDrawPixels(_screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, _storedDisplay);
01767 
01768     glDepthMask(GL_TRUE);
01769     glEnable(GL_DEPTH_TEST);
01770     glEnable(GL_LIGHTING);
01771 }
01772 
01773 void GfxOpenGL::dimScreen() {
01774     uint32 *data = (uint32 *)_storedDisplay;
01775     for (int l = 0; l < _screenWidth * _screenHeight; l++) {
01776         uint32 pixel = data[l];
01777         uint8 r = (pixel & 0xFF0000) >> 16;
01778         uint8 g = (pixel & 0x00FF00) >> 8;
01779         uint8 b = (pixel & 0x0000FF);
01780         uint32 color = (r + g + b) / 10;
01781         data[l] = ((color & 0xFF) << 16) | ((color & 0xFF) << 8) | (color & 0xFF);
01782     }
01783 }
01784 
01785 void GfxOpenGL::dimRegion(int x, int yReal, int w, int h, float level) {
01786     x = (int)(x * _scaleW);
01787     yReal = (int)(yReal * _scaleH);
01788     w = (int)(w * _scaleW);
01789     h = (int)(h * _scaleH);
01790     int y = _screenHeight - yReal - h;
01791 
01792 #ifdef GL_ARB_fragment_program
01793     if (_useDimShader) {
01794         GLuint texture;
01795         glGenTextures(1, &texture);
01796         glBindTexture(GL_TEXTURE_2D, texture);
01797 
01798         glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
01799         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01800         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01801 
01802         glViewport(0, 0, _screenWidth, _screenHeight);
01803 
01804         // copy the data over to the texture
01805         glBindTexture(GL_TEXTURE_2D, texture);
01806         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, w, h, 0);
01807 
01808         glMatrixMode(GL_PROJECTION);
01809         glLoadIdentity();
01810         glOrtho(0, _screenWidth, 0, _screenHeight, 0, 1);
01811         glMatrixMode(GL_MODELVIEW);
01812         glLoadIdentity();
01813         glMatrixMode(GL_TEXTURE);
01814         glLoadIdentity();
01815 
01816         glDisable(GL_LIGHTING);
01817         glDisable(GL_DEPTH_TEST);
01818         glDisable(GL_ALPHA_TEST);
01819         glDepthMask(GL_FALSE);
01820         glEnable(GL_SCISSOR_TEST);
01821 
01822         glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _dimFragProgram);
01823         glEnable(GL_FRAGMENT_PROGRAM_ARB);
01824         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, level, 0, 0, 0);
01825 
01826         glEnable(GL_TEXTURE_2D);
01827         glBindTexture(GL_TEXTURE_2D, texture);
01828 
01829         glBegin(GL_QUADS);
01830         glTexCoord2f(0, 0);
01831         glVertex2f(x, y);
01832         glTexCoord2f(1.0f, 0.0f);
01833         glVertex2f(x + w, y);
01834         glTexCoord2f(1.0f, 1.0f);
01835         glVertex2f(x + w, y + h);
01836         glTexCoord2f(0.0f, 1.0f);
01837         glVertex2f(x, y + h);
01838         glEnd();
01839 
01840         glDisable(GL_FRAGMENT_PROGRAM_ARB);
01841 
01842         glDeleteTextures(1, &texture);
01843 
01844         return;
01845     }
01846 #endif
01847 
01848     uint32 *data = new uint32[w * h];
01849     y = _screenHeight - yReal;
01850 
01851     // collect the requested area and generate the dimmed version
01852     glReadPixels(x, y - h, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
01853     for (int ly = 0; ly < h; ly++) {
01854         for (int lx = 0; lx < w; lx++) {
01855             uint32 pixel = data[ly * w + lx];
01856             uint8 r = (pixel & 0xFF0000) >> 16;
01857             uint8 g = (pixel & 0x00FF00) >> 8;
01858             uint8 b = (pixel & 0x0000FF);
01859             uint32 color = (uint32)(((r + g + b) / 3) * level);
01860             data[ly * w + lx] = ((color & 0xFF) << 16) | ((color & 0xFF) << 8) | (color & 0xFF);
01861         }
01862     }
01863 
01864     glMatrixMode(GL_PROJECTION);
01865     glLoadIdentity();
01866     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01867     glMatrixMode(GL_MODELVIEW);
01868     glLoadIdentity();
01869 
01870     glDisable(GL_LIGHTING);
01871     glDisable(GL_DEPTH_TEST);
01872     glDepthMask(GL_FALSE);
01873 
01874     // Set the raster position and draw the bitmap
01875     glRasterPos2i(x, yReal + h);
01876     glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
01877 
01878     glDepthMask(GL_TRUE);
01879     glEnable(GL_DEPTH_TEST);
01880     glEnable(GL_LIGHTING);
01881 
01882     delete[] data;
01883 }
01884 
01885 void GfxOpenGL::irisAroundRegion(int x1, int y1, int x2, int y2) {
01886     glMatrixMode(GL_PROJECTION);
01887     glLoadIdentity();
01888     glOrtho(0.0, _screenWidth, _screenHeight, 0.0, 0.0, 1.0);
01889     glMatrixMode(GL_MODELVIEW);
01890     glLoadIdentity();
01891 
01892     glDisable(GL_DEPTH_TEST);
01893     glDisable(GL_TEXTURE_2D);
01894     glDisable(GL_BLEND);
01895     glDisable(GL_LIGHTING);
01896     glDepthMask(GL_FALSE);
01897 
01898     glColor3f(0.0f, 0.0f, 0.0f);
01899 
01900     //Explicitly cast to avoid problems with C++11
01901     float fx1 = x1;
01902     float fx2 = x2;
01903     float fy1 = y1;
01904     float fy2 = y2;
01905     float width = _screenWidth;
01906     float height = _screenHeight;
01907     float points[20] = {
01908         0.0f, 0.0f,
01909         0.0f, fy1,
01910         width, 0.0f,
01911         fx2, fy1,
01912         width, height,
01913         fx2, fy2,
01914         0.0f, height,
01915         fx1, fy2,
01916         0.0f, fy1,
01917         fx1, fy1
01918     };
01919 
01920     glBegin(GL_TRIANGLE_STRIP);
01921     for (int i = 0 ;i < 10; ++i) {
01922         glVertex2fv(points+2*i);
01923     }
01924     glEnd();
01925 
01926     glColor3f(1.0f, 1.0f, 1.0f);
01927     glEnable(GL_DEPTH_TEST);
01928     glEnable(GL_LIGHTING);
01929     glDepthMask(GL_TRUE);
01930 }
01931 
01932 void GfxOpenGL::drawRectangle(const PrimitiveObject *primitive) {
01933     float x1 = primitive->getP1().x * _scaleW;
01934     float y1 = primitive->getP1().y * _scaleH;
01935     float x2 = primitive->getP2().x * _scaleW;
01936     float y2 = primitive->getP2().y * _scaleH;
01937     const Color color(primitive->getColor());
01938 
01939     glMatrixMode(GL_PROJECTION);
01940     glLoadIdentity();
01941     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01942     glMatrixMode(GL_MODELVIEW);
01943     glLoadIdentity();
01944 
01945     glDisable(GL_LIGHTING);
01946     glDisable(GL_DEPTH_TEST);
01947     glDepthMask(GL_FALSE);
01948 
01949     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01950 
01951     if (primitive->isFilled()) {
01952         glBegin(GL_QUADS);
01953         glVertex2f(x1, y1);
01954         glVertex2f(x2 + 1, y1);
01955         glVertex2f(x2 + 1, y2 + 1);
01956         glVertex2f(x1, y2 + 1);
01957         glEnd();
01958     } else {
01959         glLineWidth(_scaleW);
01960         glBegin(GL_LINE_LOOP);
01961         glVertex2f(x1, y1);
01962         glVertex2f(x2 + 1, y1);
01963         glVertex2f(x2 + 1, y2 + 1);
01964         glVertex2f(x1, y2 + 1);
01965         glEnd();
01966     }
01967 
01968     glColor3f(1.0f, 1.0f, 1.0f);
01969 
01970     glDepthMask(GL_TRUE);
01971     glEnable(GL_DEPTH_TEST);
01972     glEnable(GL_LIGHTING);
01973 }
01974 
01975 void GfxOpenGL::drawLine(const PrimitiveObject *primitive) {
01976     float x1 = primitive->getP1().x * _scaleW;
01977     float y1 = primitive->getP1().y * _scaleH;
01978     float x2 = primitive->getP2().x * _scaleW;
01979     float y2 = primitive->getP2().y * _scaleH;
01980 
01981     const Color &color = primitive->getColor();
01982 
01983     glMatrixMode(GL_PROJECTION);
01984     glLoadIdentity();
01985     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01986     glMatrixMode(GL_MODELVIEW);
01987     glLoadIdentity();
01988 
01989     glDisable(GL_LIGHTING);
01990     glDisable(GL_DEPTH_TEST);
01991     glDepthMask(GL_FALSE);
01992 
01993     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01994 
01995     glLineWidth(_scaleW);
01996 
01997     glBegin(GL_LINES);
01998     glVertex2f(x1, y1);
01999     glVertex2f(x2, y2);
02000     glEnd();
02001 
02002     glColor3f(1.0f, 1.0f, 1.0f);
02003 
02004     glDepthMask(GL_TRUE);
02005     glEnable(GL_DEPTH_TEST);
02006     glEnable(GL_LIGHTING);
02007 }
02008 
02009 void GfxOpenGL::drawDimPlane() {
02010     if (_dimLevel == 0.0f) return;
02011 
02012     glMatrixMode(GL_PROJECTION);
02013     glLoadIdentity();
02014     glOrtho(0, 1.0, 1.0, 0, 0, 1);
02015     glMatrixMode(GL_MODELVIEW);
02016     glLoadIdentity();
02017 
02018     glDisable(GL_DEPTH_TEST);
02019     glDepthMask(GL_FALSE);
02020 
02021     glDisable(GL_LIGHTING);
02022     glEnable(GL_BLEND);
02023     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02024 
02025     glColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
02026 
02027     glBegin(GL_QUADS);
02028     glVertex2f(0, 0);
02029     glVertex2f(1.0, 0);
02030     glVertex2f(1.0, 1.0);
02031     glVertex2f(0, 1.0);
02032     glEnd();
02033 
02034     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
02035 
02036     glDisable(GL_BLEND);
02037     glDepthMask(GL_TRUE);
02038     glEnable(GL_DEPTH_TEST);
02039     glEnable(GL_LIGHTING);
02040 }
02041 
02042 void GfxOpenGL::drawPolygon(const PrimitiveObject *primitive) {
02043     float x1 = primitive->getP1().x * _scaleW;
02044     float y1 = primitive->getP1().y * _scaleH;
02045     float x2 = primitive->getP2().x * _scaleW;
02046     float y2 = primitive->getP2().y * _scaleH;
02047     float x3 = primitive->getP3().x * _scaleW;
02048     float y3 = primitive->getP3().y * _scaleH;
02049     float x4 = primitive->getP4().x * _scaleW;
02050     float y4 = primitive->getP4().y * _scaleH;
02051 
02052     const Color &color = primitive->getColor();
02053 
02054     glMatrixMode(GL_PROJECTION);
02055     glLoadIdentity();
02056     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
02057     glMatrixMode(GL_MODELVIEW);
02058     glLoadIdentity();
02059 
02060 #if !defined(__amigaos4__)
02061     glDisable(GL_MULTISAMPLE);
02062 #endif
02063     glDisable(GL_LIGHTING);
02064     glDisable(GL_DEPTH_TEST);
02065     glDepthMask(GL_FALSE);
02066 
02067     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
02068 
02069     glBegin(GL_LINES);
02070     glVertex2f(x1, y1);
02071     glVertex2f(x2 + 1, y2 + 1);
02072     glVertex2f(x3, y3 + 1);
02073     glVertex2f(x4 + 1, y4);
02074     glEnd();
02075 
02076     glColor3f(1.0f, 1.0f, 1.0f);
02077 
02078     glDepthMask(GL_TRUE);
02079     glEnable(GL_DEPTH_TEST);
02080     glEnable(GL_LIGHTING);
02081 #if !defined(__amigaos4__)
02082     glEnable(GL_MULTISAMPLE);
02083 #endif
02084 }
02085 
02086 void GfxOpenGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
02087     uint8 *p = buffer;
02088     for (int i = y; i < y + height; i++) {
02089         glReadPixels(x, _screenHeight - 1 - i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, p);
02090         p += width * 4;
02091     }
02092 }
02093 
02094 void GfxOpenGL::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
02095     readPixels(x, y, width, height, data);
02096     createSpecialtyTexture(id, data, width, height);
02097 }
02098 
02099 void GfxOpenGL::setBlendMode(bool additive) {
02100     if (additive) {
02101         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
02102     } else {
02103         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02104     }
02105 }
02106 
02107 } // end of namespace Grim
02108 
02109 #endif


Generated on Sat Feb 16 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge