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

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


Generated on Sat May 30 2020 05:00:45 for ResidualVM by doxygen 1.7.1
curved edge   curved edge