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     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 #if !defined(__amigaos4__)
01588         format = GL_BGRA;
01589         dataType = GL_UNSIGNED_INT_8_8_8_8;
01590 #else
01591         // AmigaOS' MiniGL does not understand GL_UNSIGNED_INT_8_8_8_8 yet.
01592         format = GL_BGRA;
01593         dataType = GL_UNSIGNED_BYTE;
01594 #endif
01595     } else if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0)) {
01596         format = GL_BGRA;
01597         dataType = GL_UNSIGNED_INT_8_8_8_8_REV;
01598     } else if (frame->format == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
01599         format = GL_RGB;
01600         dataType = GL_UNSIGNED_SHORT_5_6_5;
01601     } else {
01602         error("Unknown pixelformat: Bpp: %d RBits: %d GBits: %d BBits: %d ABits: %d RShift: %d GShift: %d BShift: %d AShift: %d",
01603             frame->format.bytesPerPixel,
01604             -(frame->format.rLoss - 8),
01605             -(frame->format.gLoss - 8),
01606             -(frame->format.bLoss - 8),
01607             -(frame->format.aLoss - 8),
01608             frame->format.rShift,
01609             frame->format.gShift,
01610             frame->format.bShift,
01611             frame->format.aShift);
01612     }
01613 
01614     // remove if already exist
01615     if (_smushNumTex > 0) {
01616         glDeleteTextures(_smushNumTex, _smushTexIds);
01617         delete[] _smushTexIds;
01618         _smushNumTex = 0;
01619     }
01620 
01621     // create texture
01622     _smushNumTex = ((width + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE) *
01623                    ((height + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE);
01624     _smushTexIds = new GLuint[_smushNumTex];
01625     glGenTextures(_smushNumTex, _smushTexIds);
01626     for (int i = 0; i < _smushNumTex; i++) {
01627         glBindTexture(GL_TEXTURE_2D, _smushTexIds[i]);
01628         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01629         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01630         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
01631         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
01632         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, format, dataType, nullptr);
01633     }
01634 
01635     glPixelStorei(GL_UNPACK_ALIGNMENT, bytesPerPixel); // 16 bit RGB 565 bitmap/32 bit BGR
01636     glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
01637 
01638     int curTexIdx = 0;
01639     for (int y = 0; y < height; y += BITMAP_TEXTURE_SIZE) {
01640         for (int x = 0; x < width; x += BITMAP_TEXTURE_SIZE) {
01641             int t_width = (x + BITMAP_TEXTURE_SIZE >= width) ? (width - x) : BITMAP_TEXTURE_SIZE;
01642             int t_height = (y + BITMAP_TEXTURE_SIZE >= height) ? (height - y) : BITMAP_TEXTURE_SIZE;
01643             glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
01644             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, format, dataType, bitmap + (y * bytesPerPixel * width) + (bytesPerPixel * x));
01645             curTexIdx++;
01646         }
01647     }
01648     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01649     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
01650     _smushWidth = (int)(width * _scaleW);
01651     _smushHeight = (int)(height * _scaleH);
01652 }
01653 
01654 void GfxOpenGL::drawMovieFrame(int offsetX, int offsetY) {
01655     // prepare view
01656     glMatrixMode(GL_PROJECTION);
01657     glLoadIdentity();
01658     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01659     glMatrixMode(GL_MODELVIEW);
01660     glLoadIdentity();
01661     glMatrixMode(GL_TEXTURE);
01662     glLoadIdentity();
01663     // A lot more may need to be put there : disabling Alpha test, blending, ...
01664     // For now, just keep this here :-)
01665 
01666     glDisable(GL_LIGHTING);
01667     glEnable(GL_TEXTURE_2D);
01668     // draw
01669     glDisable(GL_DEPTH_TEST);
01670     glDepthMask(GL_FALSE);
01671     glEnable(GL_SCISSOR_TEST);
01672 
01673     offsetX = (int)(offsetX * _scaleW);
01674     offsetY = (int)(offsetY * _scaleH);
01675 
01676     glScissor(offsetX, _screenHeight - (offsetY + _smushHeight), _smushWidth, _smushHeight);
01677 
01678     int curTexIdx = 0;
01679     for (int y = 0; y < _smushHeight; y += (int)(BITMAP_TEXTURE_SIZE * _scaleH)) {
01680         for (int x = 0; x < _smushWidth; x += (int)(BITMAP_TEXTURE_SIZE * _scaleW)) {
01681             glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
01682             glBegin(GL_QUADS);
01683             glTexCoord2f(0, 0);
01684             glVertex2f(x + offsetX, y + offsetY);
01685             glTexCoord2f(1.0f, 0.0f);
01686             glVertex2f(x + offsetX + BITMAP_TEXTURE_SIZE * _scaleW, y + offsetY);
01687             glTexCoord2f(1.0f, 1.0f);
01688             glVertex2f(x + offsetX + BITMAP_TEXTURE_SIZE * _scaleW, y + offsetY + BITMAP_TEXTURE_SIZE * _scaleH);
01689             glTexCoord2f(0.0f, 1.0f);
01690             glVertex2f(x + offsetX, y + offsetY + BITMAP_TEXTURE_SIZE * _scaleH);
01691             glEnd();
01692             curTexIdx++;
01693         }
01694     }
01695 
01696     glDisable(GL_SCISSOR_TEST);
01697     glDisable(GL_TEXTURE_2D);
01698     glDepthMask(GL_TRUE);
01699     glEnable(GL_DEPTH_TEST);
01700     glEnable(GL_LIGHTING);
01701 }
01702 
01703 void GfxOpenGL::releaseMovieFrame() {
01704     if (_smushNumTex > 0) {
01705         glDeleteTextures(_smushNumTex, _smushTexIds);
01706         delete[] _smushTexIds;
01707         _smushNumTex = 0;
01708     }
01709 }
01710 
01711 void GfxOpenGL::loadEmergFont() {
01712     glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 8 bit font bitmaps
01713 
01714     _emergFont = glGenLists(128);
01715     for (int i = 32; i < 127; i++) {
01716         glNewList(_emergFont + i, GL_COMPILE);
01717         glBitmap(8, 13, 0, 2, 10, 0, Font::emerFont[i - 32]);
01718         glEndList();
01719     }
01720 }
01721 
01722 void GfxOpenGL::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
01723     glMatrixMode(GL_PROJECTION);
01724     glPushMatrix();
01725     glLoadIdentity();
01726     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01727 
01728     glMatrixMode(GL_MODELVIEW);
01729     glLoadIdentity();
01730     glDisable(GL_DEPTH_TEST);
01731     glDisable(GL_LIGHTING);
01732 
01733     glRasterPos2i(x, y);
01734     glColor3f(1.0f, 1.0f, 1.0f);
01735 
01736     glListBase(_emergFont);
01737     glCallLists(strlen(text), GL_UNSIGNED_BYTE, (const GLubyte *)text);
01738 
01739     glEnable(GL_LIGHTING);
01740 
01741     glMatrixMode(GL_PROJECTION);
01742     glPopMatrix();
01743 }
01744 
01745 Bitmap *GfxOpenGL::getScreenshot(int w, int h, bool useStored) {
01746     Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
01747     if (useStored) {
01748         memcpy(src.getRawBuffer(), _storedDisplay, _screenWidth * _screenHeight * 4);
01749     } else {
01750         glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, src.getRawBuffer());
01751     }
01752     return createScreenshotBitmap(src, w, h, false);
01753 }
01754 
01755 void GfxOpenGL::storeDisplay() {
01756     glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, _storedDisplay);
01757 }
01758 
01759 void GfxOpenGL::copyStoredToDisplay() {
01760     glMatrixMode(GL_PROJECTION);
01761     glLoadIdentity();
01762     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01763     glMatrixMode(GL_MODELVIEW);
01764     glLoadIdentity();
01765 
01766     glDisable(GL_LIGHTING);
01767     glDisable(GL_DEPTH_TEST);
01768     glDepthMask(GL_FALSE);
01769 
01770     glRasterPos2i(0, _screenHeight - 1);
01771     glBitmap(0, 0, 0, 0, 0, -1, nullptr);
01772     glDrawPixels(_screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, _storedDisplay);
01773 
01774     glDepthMask(GL_TRUE);
01775     glEnable(GL_DEPTH_TEST);
01776     glEnable(GL_LIGHTING);
01777 }
01778 
01779 void GfxOpenGL::dimScreen() {
01780     uint32 *data = (uint32 *)_storedDisplay;
01781     for (int l = 0; l < _screenWidth * _screenHeight; l++) {
01782         uint32 pixel = data[l];
01783         uint8 r = (pixel & 0xFF0000) >> 16;
01784         uint8 g = (pixel & 0x00FF00) >> 8;
01785         uint8 b = (pixel & 0x0000FF);
01786         uint32 color = (r + g + b) / 10;
01787         data[l] = ((color & 0xFF) << 16) | ((color & 0xFF) << 8) | (color & 0xFF);
01788     }
01789 }
01790 
01791 void GfxOpenGL::dimRegion(int x, int yReal, int w, int h, float level) {
01792     x = (int)(x * _scaleW);
01793     yReal = (int)(yReal * _scaleH);
01794     w = (int)(w * _scaleW);
01795     h = (int)(h * _scaleH);
01796     int y = _screenHeight - yReal - h;
01797 
01798 #ifdef GL_ARB_fragment_program
01799     if (_useDimShader) {
01800         GLuint texture;
01801         glGenTextures(1, &texture);
01802         glBindTexture(GL_TEXTURE_2D, texture);
01803 
01804         glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
01805         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01806         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01807 
01808         glViewport(0, 0, _screenWidth, _screenHeight);
01809 
01810         // copy the data over to the texture
01811         glBindTexture(GL_TEXTURE_2D, texture);
01812         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, w, h, 0);
01813 
01814         glMatrixMode(GL_PROJECTION);
01815         glLoadIdentity();
01816         glOrtho(0, _screenWidth, 0, _screenHeight, 0, 1);
01817         glMatrixMode(GL_MODELVIEW);
01818         glLoadIdentity();
01819         glMatrixMode(GL_TEXTURE);
01820         glLoadIdentity();
01821 
01822         glDisable(GL_LIGHTING);
01823         glDisable(GL_DEPTH_TEST);
01824         glDisable(GL_ALPHA_TEST);
01825         glDepthMask(GL_FALSE);
01826         glEnable(GL_SCISSOR_TEST);
01827 
01828         glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _dimFragProgram);
01829         glEnable(GL_FRAGMENT_PROGRAM_ARB);
01830         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, level, 0, 0, 0);
01831 
01832         glEnable(GL_TEXTURE_2D);
01833         glBindTexture(GL_TEXTURE_2D, texture);
01834 
01835         glBegin(GL_QUADS);
01836         glTexCoord2f(0, 0);
01837         glVertex2f(x, y);
01838         glTexCoord2f(1.0f, 0.0f);
01839         glVertex2f(x + w, y);
01840         glTexCoord2f(1.0f, 1.0f);
01841         glVertex2f(x + w, y + h);
01842         glTexCoord2f(0.0f, 1.0f);
01843         glVertex2f(x, y + h);
01844         glEnd();
01845 
01846         glDisable(GL_FRAGMENT_PROGRAM_ARB);
01847 
01848         glDeleteTextures(1, &texture);
01849 
01850         return;
01851     }
01852 #endif
01853 
01854     uint32 *data = new uint32[w * h];
01855     y = _screenHeight - yReal;
01856 
01857     // collect the requested area and generate the dimmed version
01858     glReadPixels(x, y - h, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
01859     for (int ly = 0; ly < h; ly++) {
01860         for (int lx = 0; lx < w; lx++) {
01861             uint32 pixel = data[ly * w + lx];
01862             uint8 r = (pixel & 0xFF0000) >> 16;
01863             uint8 g = (pixel & 0x00FF00) >> 8;
01864             uint8 b = (pixel & 0x0000FF);
01865             uint32 color = (uint32)(((r + g + b) / 3) * level);
01866             data[ly * w + lx] = ((color & 0xFF) << 16) | ((color & 0xFF) << 8) | (color & 0xFF);
01867         }
01868     }
01869 
01870     glMatrixMode(GL_PROJECTION);
01871     glLoadIdentity();
01872     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01873     glMatrixMode(GL_MODELVIEW);
01874     glLoadIdentity();
01875 
01876     glDisable(GL_LIGHTING);
01877     glDisable(GL_DEPTH_TEST);
01878     glDepthMask(GL_FALSE);
01879 
01880     // Set the raster position and draw the bitmap
01881     glRasterPos2i(x, yReal + h);
01882     glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
01883 
01884     glDepthMask(GL_TRUE);
01885     glEnable(GL_DEPTH_TEST);
01886     glEnable(GL_LIGHTING);
01887 
01888     delete[] data;
01889 }
01890 
01891 void GfxOpenGL::irisAroundRegion(int x1, int y1, int x2, int y2) {
01892     glMatrixMode(GL_PROJECTION);
01893     glLoadIdentity();
01894     glOrtho(0.0, _screenWidth, _screenHeight, 0.0, 0.0, 1.0);
01895     glMatrixMode(GL_MODELVIEW);
01896     glLoadIdentity();
01897 
01898     glDisable(GL_DEPTH_TEST);
01899     glDisable(GL_TEXTURE_2D);
01900     glDisable(GL_BLEND);
01901     glDisable(GL_LIGHTING);
01902     glDepthMask(GL_FALSE);
01903 
01904     glColor3f(0.0f, 0.0f, 0.0f);
01905 
01906     //Explicitly cast to avoid problems with C++11
01907     float fx1 = x1;
01908     float fx2 = x2;
01909     float fy1 = y1;
01910     float fy2 = y2;
01911     float width = _screenWidth;
01912     float height = _screenHeight;
01913     float points[20] = {
01914         0.0f, 0.0f,
01915         0.0f, fy1,
01916         width, 0.0f,
01917         fx2, fy1,
01918         width, height,
01919         fx2, fy2,
01920         0.0f, height,
01921         fx1, fy2,
01922         0.0f, fy1,
01923         fx1, fy1
01924     };
01925 
01926     glBegin(GL_TRIANGLE_STRIP);
01927     for (int i = 0 ;i < 10; ++i) {
01928         glVertex2fv(points+2*i);
01929     }
01930     glEnd();
01931 
01932     glColor3f(1.0f, 1.0f, 1.0f);
01933     glEnable(GL_DEPTH_TEST);
01934     glEnable(GL_LIGHTING);
01935     glDepthMask(GL_TRUE);
01936 }
01937 
01938 void GfxOpenGL::drawRectangle(const PrimitiveObject *primitive) {
01939     float x1 = primitive->getP1().x * _scaleW;
01940     float y1 = primitive->getP1().y * _scaleH;
01941     float x2 = primitive->getP2().x * _scaleW;
01942     float y2 = primitive->getP2().y * _scaleH;
01943     const Color color(primitive->getColor());
01944 
01945     glMatrixMode(GL_PROJECTION);
01946     glLoadIdentity();
01947     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01948     glMatrixMode(GL_MODELVIEW);
01949     glLoadIdentity();
01950 
01951     glDisable(GL_LIGHTING);
01952     glDisable(GL_DEPTH_TEST);
01953     glDepthMask(GL_FALSE);
01954 
01955     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
01956 
01957     if (primitive->isFilled()) {
01958         glBegin(GL_QUADS);
01959         glVertex2f(x1, y1);
01960         glVertex2f(x2 + 1, y1);
01961         glVertex2f(x2 + 1, y2 + 1);
01962         glVertex2f(x1, y2 + 1);
01963         glEnd();
01964     } else {
01965         glLineWidth(_scaleW);
01966         glBegin(GL_LINE_LOOP);
01967         glVertex2f(x1, y1);
01968         glVertex2f(x2 + 1, y1);
01969         glVertex2f(x2 + 1, y2 + 1);
01970         glVertex2f(x1, y2 + 1);
01971         glEnd();
01972     }
01973 
01974     glColor3f(1.0f, 1.0f, 1.0f);
01975 
01976     glDepthMask(GL_TRUE);
01977     glEnable(GL_DEPTH_TEST);
01978     glEnable(GL_LIGHTING);
01979 }
01980 
01981 void GfxOpenGL::drawLine(const PrimitiveObject *primitive) {
01982     float x1 = primitive->getP1().x * _scaleW;
01983     float y1 = primitive->getP1().y * _scaleH;
01984     float x2 = primitive->getP2().x * _scaleW;
01985     float y2 = primitive->getP2().y * _scaleH;
01986 
01987     const Color &color = primitive->getColor();
01988 
01989     glMatrixMode(GL_PROJECTION);
01990     glLoadIdentity();
01991     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
01992     glMatrixMode(GL_MODELVIEW);
01993     glLoadIdentity();
01994 
01995     glDisable(GL_LIGHTING);
01996     glDisable(GL_DEPTH_TEST);
01997     glDepthMask(GL_FALSE);
01998 
01999     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
02000 
02001     glLineWidth(_scaleW);
02002 
02003     glBegin(GL_LINES);
02004     glVertex2f(x1, y1);
02005     glVertex2f(x2, y2);
02006     glEnd();
02007 
02008     glColor3f(1.0f, 1.0f, 1.0f);
02009 
02010     glDepthMask(GL_TRUE);
02011     glEnable(GL_DEPTH_TEST);
02012     glEnable(GL_LIGHTING);
02013 }
02014 
02015 void GfxOpenGL::drawDimPlane() {
02016     if (_dimLevel == 0.0f) return;
02017 
02018     glMatrixMode(GL_PROJECTION);
02019     glLoadIdentity();
02020     glOrtho(0, 1.0, 1.0, 0, 0, 1);
02021     glMatrixMode(GL_MODELVIEW);
02022     glLoadIdentity();
02023 
02024     glDisable(GL_DEPTH_TEST);
02025     glDepthMask(GL_FALSE);
02026 
02027     glDisable(GL_LIGHTING);
02028     glEnable(GL_BLEND);
02029     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02030 
02031     glColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
02032 
02033     glBegin(GL_QUADS);
02034     glVertex2f(0, 0);
02035     glVertex2f(1.0, 0);
02036     glVertex2f(1.0, 1.0);
02037     glVertex2f(0, 1.0);
02038     glEnd();
02039 
02040     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
02041 
02042     glDisable(GL_BLEND);
02043     glDepthMask(GL_TRUE);
02044     glEnable(GL_DEPTH_TEST);
02045     glEnable(GL_LIGHTING);
02046 }
02047 
02048 void GfxOpenGL::drawPolygon(const PrimitiveObject *primitive) {
02049     float x1 = primitive->getP1().x * _scaleW;
02050     float y1 = primitive->getP1().y * _scaleH;
02051     float x2 = primitive->getP2().x * _scaleW;
02052     float y2 = primitive->getP2().y * _scaleH;
02053     float x3 = primitive->getP3().x * _scaleW;
02054     float y3 = primitive->getP3().y * _scaleH;
02055     float x4 = primitive->getP4().x * _scaleW;
02056     float y4 = primitive->getP4().y * _scaleH;
02057 
02058     const Color &color = primitive->getColor();
02059 
02060     glMatrixMode(GL_PROJECTION);
02061     glLoadIdentity();
02062     glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
02063     glMatrixMode(GL_MODELVIEW);
02064     glLoadIdentity();
02065 
02066 #if !defined(__amigaos4__)
02067     glDisable(GL_MULTISAMPLE);
02068 #endif
02069     glDisable(GL_LIGHTING);
02070     glDisable(GL_DEPTH_TEST);
02071     glDepthMask(GL_FALSE);
02072 
02073     glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
02074 
02075     glBegin(GL_LINES);
02076     glVertex2f(x1, y1);
02077     glVertex2f(x2 + 1, y2 + 1);
02078     glVertex2f(x3, y3 + 1);
02079     glVertex2f(x4 + 1, y4);
02080     glEnd();
02081 
02082     glColor3f(1.0f, 1.0f, 1.0f);
02083 
02084     glDepthMask(GL_TRUE);
02085     glEnable(GL_DEPTH_TEST);
02086     glEnable(GL_LIGHTING);
02087 #if !defined(__amigaos4__)
02088     glEnable(GL_MULTISAMPLE);
02089 #endif
02090 }
02091 
02092 void GfxOpenGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
02093     uint8 *p = buffer;
02094     for (int i = y; i < y + height; i++) {
02095         glReadPixels(x, _screenHeight - 1 - i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, p);
02096         p += width * 4;
02097     }
02098 }
02099 
02100 void GfxOpenGL::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
02101     readPixels(x, y, width, height, data);
02102     createSpecialtyTexture(id, data, width, height);
02103 }
02104 
02105 void GfxOpenGL::setBlendMode(bool additive) {
02106     if (additive) {
02107         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
02108     } else {
02109         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02110     }
02111 }
02112 
02113 } // end of namespace Grim
02114 
02115 #endif


Generated on Sat Oct 19 2019 05:01:02 for ResidualVM by doxygen 1.7.1
curved edge   curved edge