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

gfx_opengl_shaders.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 // Matrix calculations taken from the glm library
00024 // Which is covered by the MIT license
00025 // And has this additional copyright note:
00026 /* Copyright (c) 2005 - 2012 G-Truc Creation
00027  *
00028  * Permission is hereby granted, free of charge, to any person obtaining a copy
00029  * of this software and associated documentation files (the "Software"), to deal
00030  * in the Software without restriction, including without limitation the rights
00031  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00032  * copies of the Software, and to permit persons to whom the Software is
00033  * furnished to do so, subject to the following conditions:
00034  *
00035  * The above copyright notice and this permission notice shall be included in
00036  * all copies or substantial portions of the Software.
00037  */
00038 
00039 #if defined(WIN32)
00040 #include <windows.h>
00041 // winnt.h defines ARRAYSIZE, but we want our own one...
00042 #undef ARRAYSIZE
00043 #endif
00044 
00045 #include "common/endian.h"
00046 #include "common/file.h"
00047 #include "common/str.h"
00048 #include "common/system.h"
00049 #include "common/textconsole.h"
00050 
00051 #if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
00052 
00053 #include "graphics/surface.h"
00054 #include "graphics/pixelbuffer.h"
00055 
00056 #include "engines/grim/actor.h"
00057 #include "engines/grim/bitmap.h"
00058 #include "engines/grim/colormap.h"
00059 #include "engines/grim/emi/modelemi.h"
00060 #include "engines/grim/font.h"
00061 #include "engines/grim/gfx_opengl_shaders.h"
00062 #include "engines/grim/grim.h"
00063 #include "engines/grim/material.h"
00064 #include "engines/grim/model.h"
00065 #include "engines/grim/primitives.h"
00066 #include "engines/grim/set.h"
00067 #include "engines/grim/sprite.h"
00068 
00069 namespace Grim {
00070 
00071 template<class T>
00072 static T nextHigher2(T k) {
00073     if (k == 0)
00074         return 1;
00075     --k;
00076 
00077     for (uint i = 1; i < sizeof(T) * 8; i <<= 1)
00078         k = k | k >> i;
00079 
00080     return k + 1;
00081 }
00082 
00083 static float textured_quad[] = {
00084 //  X   , Y   , S   , T
00085     0.0f, 0.0f, 0.0f, 0.0f,
00086     1.0f, 0.0f, 1.0f, 0.0f,
00087     1.0f, 1.0f, 1.0f, 1.0f,
00088     0.0f, 1.0f, 0.0f, 1.0f,
00089 };
00090 
00091 static float textured_quad_centered[] = {
00092 //   X   ,  Y   , Z   , S   , T
00093     -0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
00094     -0.5f, +0.5f, 0.0f, 0.0f, 0.0f,
00095     +0.5f, +0.5f, 0.0f, 1.0f, 0.0f,
00096     +0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
00097 };
00098 
00099 static float zero_texVerts[] = { 0.0, 0.0 };
00100 
00101 struct GrimVertex {
00102     GrimVertex(const float *verts, const float *texVerts, const float *normals) {
00103         memcpy(_position, verts, 3 * sizeof(float));
00104         memcpy(_texcoord, texVerts, 2 * sizeof(float));
00105         memcpy(_normal, normals, 3 * sizeof(float));
00106     }
00107     float _position[3];
00108     float _texcoord[2];
00109     float _normal[3];
00110 };
00111 
00112 struct TextUserData {
00113     OpenGL::Shader * shader;
00114     uint32 characters;
00115     Color  color;
00116     GLuint texture;
00117 };
00118 
00119 struct FontUserData {
00120     int size;
00121     GLuint texture;
00122 };
00123 
00124 struct EMIModelUserData {
00125     OpenGL::Shader *_shader;
00126     uint32 _texCoordsVBO;
00127     uint32 _colorMapVBO;
00128     uint32 _verticesVBO;
00129     uint32 _normalsVBO;
00130 };
00131 
00132 struct ModelUserData {
00133     OpenGL::Shader *_shader;
00134     uint32 _meshInfoVBO;
00135 };
00136 
00137 struct ShadowUserData {
00138     uint32 _verticesVBO;
00139     uint32 _indicesVBO;
00140     uint32 _numTriangles;
00141 };
00142 
00143 Math::Matrix4 makeLookMatrix(const Math::Vector3d& pos, const Math::Vector3d& interest, const Math::Vector3d& up) {
00144     Math::Vector3d f = (interest - pos).getNormalized();
00145     Math::Vector3d u = up.getNormalized();
00146     Math::Vector3d s = Math::Vector3d::crossProduct(f, u).getNormalized();
00147     u = Math::Vector3d::crossProduct(s, f);
00148 
00149     Math::Matrix4 look;
00150     look(0, 0) = s.x();
00151     look(1, 0) = s.y();
00152     look(2, 0) = s.z();
00153     look(0, 1) = u.x();
00154     look(1, 1) = u.y();
00155     look(2, 1) = u.z();
00156     look(0, 2) = -f.x();
00157     look(1, 2) = -f.y();
00158     look(2, 2) = -f.z();
00159     look(3, 0) = -Math::Vector3d::dotProduct(s, pos);
00160     look(3, 1) = -Math::Vector3d::dotProduct(u, pos);
00161     look(3, 2) =  Math::Vector3d::dotProduct(f, pos);
00162 
00163     look.transpose();
00164 
00165     return look;
00166 }
00167 
00168 Math::Matrix4 makeRotationMatrix(const Math::Angle& angle, Math::Vector3d axis) {
00169     float c = angle.getCosine();
00170     float s = angle.getSine();
00171     axis.normalize();
00172     Math::Vector3d temp = (1.f - c) * axis;
00173     Math::Matrix4 rotate;
00174     rotate(0, 0) = c + temp.x() * axis.x();
00175     rotate(0, 1) = 0 + temp.x() * axis.y() + s * axis.z();
00176     rotate(0, 2) = 0 + temp.x() * axis.z() - s * axis.y();
00177     rotate(0, 3) = 0;
00178     rotate(1, 0) = 0 + temp.y() * axis.x() - s * axis.z();
00179     rotate(1, 1) = c + temp.y() * axis.y();
00180     rotate(1, 2) = 0 + temp.y() * axis.z() + s * axis.x();
00181     rotate(1, 3) = 0;
00182     rotate(2, 0) = 0 + temp.z() * axis.x() + s * axis.y();
00183     rotate(2, 1) = 0 + temp.z() * axis.y() - s * axis.x();
00184     rotate(2, 2) = c + temp.z() * axis.z();
00185     rotate(2, 3) = 0;
00186     rotate(3, 0) = 0;
00187     rotate(3, 1) = 0;
00188     rotate(3, 2) = 0;
00189     rotate(3, 3) = 1;
00190 
00191     return rotate;
00192 }
00193 
00194 Math::Matrix4 makeFrustumMatrix(double left, double right, double bottom, double top, double nclip, double fclip) {
00195     Math::Matrix4 proj;
00196     proj(0, 0) = (2.0f * nclip) / (right - left);
00197     proj(1, 1) = (2.0f * nclip) / (top - bottom);
00198     proj(2, 0) = (right + left) / (right - left);
00199     proj(2, 1) = (top + bottom) / (top - bottom);
00200     proj(2, 2) = -(fclip + nclip) / (fclip - nclip);
00201     proj(2, 3) = -1.0f;
00202     proj(3, 2) = -(2.0f * fclip * nclip) / (fclip - nclip);
00203     proj(3, 3) = 0.0f;
00204 
00205     return proj;
00206 }
00207 
00208 GfxBase *CreateGfxOpenGLShader() {
00209     return new GfxOpenGLS();
00210 }
00211 
00212 GfxOpenGLS::GfxOpenGLS() {
00213     _smushTexId = 0;
00214     _matrixStack.push(Math::Matrix4());
00215     _fov = -1.0;
00216     _nclip = -1;
00217     _fclip = -1;
00218     _selectedTexture = NULL;
00219     _emergTexture = 0;
00220     _maxLights = 8;
00221     _lights = new Light[_maxLights];
00222     _lightsEnabled = false;
00223     _hasAmbientLight = false;
00224     _backgroundProgram = nullptr;
00225     _smushProgram = nullptr;
00226     _textProgram = nullptr;
00227     _emergProgram = nullptr;
00228     _actorProgram = nullptr;
00229     _spriteProgram = nullptr;
00230     _primitiveProgram = nullptr;
00231     _irisProgram = nullptr;
00232     _shadowPlaneProgram = nullptr;
00233     _dimProgram = nullptr;
00234     _dimPlaneProgram = nullptr;
00235     _dimRegionProgram = nullptr;
00236 
00237     float div = 6.0f;
00238     _overworldProjMatrix = makeFrustumMatrix(-1.f / div, 1.f / div, -0.75f / div, 0.75f / div, 1.0f / div, 3276.8f);
00239 }
00240 
00241 GfxOpenGLS::~GfxOpenGLS() {
00242     for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
00243         destroyTexture(&_specialtyTextures[i]);
00244     }
00245     delete[] _lights;
00246 
00247     delete _backgroundProgram;
00248     delete _smushProgram;
00249     delete _textProgram;
00250     delete _emergProgram;
00251     delete _actorProgram;
00252     delete _spriteProgram;
00253     delete _primitiveProgram;
00254     delete _irisProgram;
00255     delete _shadowPlaneProgram;
00256     delete _dimProgram;
00257     delete _dimPlaneProgram;
00258     delete _dimRegionProgram;
00259     glDeleteTextures(1, &_storedDisplay);
00260     glDeleteTextures(1, &_emergTexture);
00261 }
00262 
00263 void GfxOpenGLS::setupZBuffer() {
00264     GLint format = GL_LUMINANCE_ALPHA;
00265     GLenum type = GL_UNSIGNED_BYTE;
00266     float width = _gameWidth;
00267     float height = _gameHeight;
00268 
00269     glGenTextures(1, (GLuint *)&_zBufTex);
00270     glActiveTexture(GL_TEXTURE1);
00271     glBindTexture(GL_TEXTURE_2D, _zBufTex);
00272     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00273     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00274     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00275     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00276     glTexImage2D(GL_TEXTURE_2D, 0, format, nextHigher2((int)width), nextHigher2((int)height), 0, format, type, NULL);
00277     glActiveTexture(GL_TEXTURE0);
00278 
00279     _zBufTexCrop = Math::Vector2d(width / nextHigher2((int)width), height / nextHigher2((int)height));
00280 }
00281 
00282 void GfxOpenGLS::setupQuadEBO() {
00283     // FIXME: Probably way too big...
00284     unsigned short quad_indices[6 * 1000];
00285 
00286     unsigned short start = 0;
00287     for (unsigned short *p = quad_indices; p < &quad_indices[6 * 1000]; p += 6) {
00288         p[0] = p[3] = start++;
00289         p[1] = start++;
00290         p[2] = p[4] = start++;
00291         p[5] = start++;
00292     }
00293 
00294     _quadEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_indices), quad_indices, GL_STATIC_DRAW);
00295 }
00296 
00297 void GfxOpenGLS::setupTexturedQuad() {
00298     _smushVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(textured_quad), textured_quad, GL_STATIC_DRAW);
00299     _smushProgram->enableVertexAttribute("position", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
00300     _smushProgram->enableVertexAttribute("texcoord", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
00301 
00302     _emergProgram->enableVertexAttribute("position", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
00303     _emergProgram->enableVertexAttribute("texcoord", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
00304 
00305     if (g_grim->getGameType() == GType_GRIM) {
00306         _backgroundProgram->enableVertexAttribute("position", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
00307         _backgroundProgram->enableVertexAttribute("texcoord", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
00308     } else {
00309         _dimPlaneProgram->enableVertexAttribute("position", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
00310     }
00311 }
00312 
00313 void GfxOpenGLS::setupTexturedCenteredQuad() {
00314     _spriteVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(textured_quad_centered), textured_quad_centered, GL_STATIC_DRAW);
00315     _spriteProgram->enableVertexAttribute("position", _spriteVBO, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
00316     _spriteProgram->enableVertexAttribute("texcoord", _spriteVBO, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 3 * sizeof(float));
00317     _spriteProgram->disableVertexAttribute("color", Math::Vector4d(1.0f, 1.0f, 1.0f, 1.0f));
00318 }
00319 
00320 void GfxOpenGLS::setupPrimitives() {
00321     uint32 numVBOs = ARRAYSIZE(_primitiveVBOs);
00322     glGenBuffers(numVBOs, _primitiveVBOs);
00323     _currentPrimitive = 0;
00324     for (uint32 i = 0; i < numVBOs; ++i) {
00325         glBindBuffer(GL_ARRAY_BUFFER, _primitiveVBOs[i]);
00326         glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
00327     }
00328 
00329     if (g_grim->getGameType() == GType_MONKEY4)
00330         return;
00331 
00332     glGenBuffers(1, &_irisVBO);
00333     glBindBuffer(GL_ARRAY_BUFFER, _irisVBO);
00334     glBufferData(GL_ARRAY_BUFFER, 20 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
00335 
00336     _irisProgram->enableVertexAttribute("position", _irisVBO, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
00337 
00338     glGenBuffers(1, &_dimVBO);
00339     glBindBuffer(GL_ARRAY_BUFFER, _dimVBO);
00340 
00341     float points[12] = {
00342         0.0f, 0.0f,
00343         1.0f, 0.0f,
00344         1.0f, 1.0f,
00345         1.0f, 1.0f,
00346         0.0f, 1.0f,
00347         0.0f, 0.0f,
00348     };
00349 
00350     glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), points, GL_DYNAMIC_DRAW);
00351 
00352     _dimProgram->enableVertexAttribute("position", _dimVBO, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
00353     _dimProgram->enableVertexAttribute("texcoord", _dimVBO, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
00354 
00355     glGenBuffers(1, &_dimRegionVBO);
00356     glBindBuffer(GL_ARRAY_BUFFER, _dimRegionVBO);
00357 
00358     glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
00359 
00360     _dimRegionProgram->enableVertexAttribute("position", _dimRegionVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
00361     _dimRegionProgram->enableVertexAttribute("texcoord", _dimRegionVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
00362 
00363     glBindBuffer(GL_ARRAY_BUFFER, 0);
00364 }
00365 
00366 GLuint GfxOpenGLS::nextPrimitive() {
00367     GLuint ret = _primitiveVBOs[_currentPrimitive];
00368     _currentPrimitive = (_currentPrimitive + 1) % ARRAYSIZE(_primitiveVBOs);
00369     return ret;
00370 }
00371 
00372 void GfxOpenGLS::setupShaders() {
00373     bool isEMI = g_grim->getGameType() == GType_MONKEY4;
00374 
00375     static const char* commonAttributes[] = {"position", "texcoord", NULL};
00376     _backgroundProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_background" : "grim_background", commonAttributes);
00377     _smushProgram = OpenGL::Shader::fromFiles("smush", commonAttributes);
00378     _textProgram = OpenGL::Shader::fromFiles("text", commonAttributes);
00379     _emergProgram = OpenGL::Shader::fromFiles("emerg", commonAttributes);
00380 
00381     static const char* actorAttributes[] = {"position", "texcoord", "color", "normal", NULL};
00382     _actorProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_actor" : "grim_actor", actorAttributes);
00383     _spriteProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_actor" : "grim_actor", actorAttributes);
00384 
00385     static const char* primAttributes[] = { "position", NULL };
00386     _shadowPlaneProgram = OpenGL::Shader::fromFiles("shadowplane", primAttributes);
00387     _primitiveProgram = OpenGL::Shader::fromFiles("grim_primitive", primAttributes);
00388 
00389     if (!isEMI) {
00390         _irisProgram = _primitiveProgram->clone();
00391 
00392         _dimProgram = OpenGL::Shader::fromFiles("dim", commonAttributes);
00393         _dimRegionProgram = _dimProgram->clone();
00394     } else {
00395         _dimPlaneProgram = OpenGL::Shader::fromFiles("emi_dimplane", primAttributes);
00396     }
00397 
00398     setupQuadEBO();
00399     setupTexturedQuad();
00400     setupTexturedCenteredQuad();
00401     setupPrimitives();
00402 
00403     if (!isEMI) {
00404         _blastVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, 128 * 16 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
00405     }
00406 }
00407 
00408 byte *GfxOpenGLS::setupScreen(int screenW, int screenH, bool fullscreen) {
00409     _screenWidth = screenW;
00410     _screenHeight = screenH;
00411     _scaleW = _screenWidth / (float)_gameWidth;
00412     _scaleH = _screenHeight / (float)_gameHeight;
00413 
00414     g_system->showMouse(false);
00415 
00416     g_system->setWindowCaption("ResidualVM: OpenGL Renderer with shaders");
00417 
00418     setupZBuffer();
00419     setupShaders();
00420 
00421     glViewport(0, 0, _screenWidth, _screenHeight);
00422 
00423     glGenTextures(1, &_storedDisplay);
00424 
00425     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00426     if (g_grim->getGameType() == GType_MONKEY4) {
00427         // GL_LEQUAL as glDepthFunc ensures that subsequent drawing attempts for
00428         // the same triangles are not ignored by the depth test.
00429         // That's necessary for EMI where some models have multiple faces which
00430         // refer to the same vertices. The first face is usually using the
00431         // color map and the following are using textures.
00432         glDepthFunc(GL_LEQUAL);
00433     }
00434     return NULL;
00435 }
00436 
00437 void GfxOpenGLS::setupCameraFrustum(float fov, float nclip, float fclip) {
00438     if (_fov == fov && _nclip == nclip && _fclip == fclip)
00439         return;
00440 
00441     _fov = fov; _nclip = nclip; _fclip = fclip;
00442 
00443     float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
00444     float top = right * 0.75;
00445 
00446     _projMatrix = makeFrustumMatrix(-right, right, -top, top, nclip, fclip);
00447 }
00448 
00449 void GfxOpenGLS::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) {
00450     Math::Matrix4 viewMatrix = makeRotationMatrix(Math::Angle(roll), Math::Vector3d(0, 0, 1));
00451     Math::Vector3d up_vec(0, 0, 1);
00452 
00453     if (pos.x() == interest.x() && pos.y() == interest.y())
00454         up_vec = Math::Vector3d(0, 1, 0);
00455 
00456     Math::Matrix4 lookMatrix = makeLookMatrix(pos, interest, up_vec);
00457 
00458     _viewMatrix = viewMatrix * lookMatrix;
00459     _viewMatrix.transpose();
00460 }
00461 
00462 void GfxOpenGLS::positionCamera(const Math::Vector3d &pos, const Math::Matrix4 &rot) {
00463     Math::Matrix4 projMatrix = _projMatrix;
00464     projMatrix.transpose();
00465 
00466     _currentPos = pos;
00467     _currentRot = rot;
00468 
00469     Math::Matrix4 invertZ;
00470     invertZ(2, 2) = -1.0f;
00471 
00472     Math::Matrix4 viewMatrix = _currentRot;
00473     viewMatrix.transpose();
00474 
00475     Math::Matrix4 camPos;
00476     camPos(0, 3) = -_currentPos.x();
00477     camPos(1, 3) = -_currentPos.y();
00478     camPos(2, 3) = -_currentPos.z();
00479 
00480     _viewMatrix = invertZ * viewMatrix * camPos;
00481     _mvpMatrix = projMatrix * _viewMatrix;
00482     _viewMatrix.transpose();
00483 }
00484 
00485 
00486 Math::Matrix4 GfxOpenGLS::getModelView() {
00487     if (g_grim->getGameType() == GType_MONKEY4) {
00488         Math::Matrix4 invertZ;
00489         invertZ(2, 2) = -1.0f;
00490 
00491         Math::Matrix4 viewMatrix = _currentRot;
00492         viewMatrix.transpose();
00493 
00494         Math::Matrix4 camPos;
00495         camPos(0, 3) = -_currentPos.x();
00496         camPos(1, 3) = -_currentPos.y();
00497         camPos(2, 3) = -_currentPos.z();
00498 
00499         Math::Matrix4 modelView = invertZ * viewMatrix * camPos;
00500         return modelView;
00501     } else {
00502         return _mvpMatrix;
00503     }
00504 }
00505 
00506 Math::Matrix4 GfxOpenGLS::getProjection() {
00507     Math::Matrix4 proj = _projMatrix;
00508     proj.transpose();
00509     return proj;
00510 }
00511 
00512 void GfxOpenGLS::clearScreen() {
00513     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00514 }
00515 
00516 void GfxOpenGLS::clearDepthBuffer() {
00517     glClear(GL_DEPTH_BUFFER_BIT);
00518 }
00519 
00520 void GfxOpenGLS::flipBuffer() {
00521     g_system->updateScreen();
00522 }
00523 
00524 void GfxOpenGLS::getScreenBoundingBox(const Mesh *mesh, int *x1, int *y1, int *x2, int *y2) {
00525 
00526 }
00527 
00528 void GfxOpenGLS::getScreenBoundingBox(const EMIModel *model, int *x1, int *y1, int *x2, int *y2) {
00529     if (_currentShadowArray) {
00530         *x1 = -1;
00531         *y1 = -1;
00532         *x2 = -1;
00533         *y2 = -1;
00534         return;
00535     }
00536 
00537     Math::Matrix4 modelMatrix = _currentActor->getFinalMatrix();
00538     Math::Matrix4 mvpMatrix = _mvpMatrix * modelMatrix;
00539 
00540     double top = 1000;
00541     double right = -1000;
00542     double left = 1000;
00543     double bottom = -1000;
00544 
00545     for (uint i = 0; i < model->_numFaces; i++) {
00546         int *indices = (int *)model->_faces[i]._indexes;
00547 
00548         for (uint j = 0; j < model->_faces[i]._faceLength * 3; j++) {
00549             int index = indices[j];
00550             const Math::Vector3d &dv = model->_drawVertices[index];
00551 
00552             Math::Vector4d v = Math::Vector4d(dv.x(), dv.y(), dv.z(), 1.0f);
00553             v = mvpMatrix * v;
00554             v /= v.w();
00555 
00556             double winX = (1 + v.x()) / 2.0f * _gameWidth;
00557             double winY = (1 + v.y()) / 2.0f * _gameHeight;
00558 
00559             if (winX > right)
00560                 right = winX;
00561             if (winX < left)
00562                 left = winX;
00563             if (winY < top)
00564                 top = winY;
00565             if (winY > bottom)
00566                 bottom = winY;
00567         }
00568     }
00569 
00570     double t = bottom;
00571     bottom = _gameHeight - top;
00572     top = _gameHeight - t;
00573 
00574     if (left < 0)
00575         left = 0;
00576     if (right >= _gameWidth)
00577         right = _gameWidth - 1;
00578     if (top < 0)
00579         top = 0;
00580     if (bottom >= _gameHeight)
00581         bottom = _gameHeight - 1;
00582 
00583     if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
00584         *x1 = -1;
00585         *y1 = -1;
00586         *x2 = -1;
00587         *y2 = -1;
00588         return;
00589     }
00590 
00591     *x1 = (int)left;
00592     *y1 = (int)(_gameHeight - bottom);
00593     *x2 = (int)right;
00594     *y2 = (int)(_gameHeight - top);
00595 }
00596 
00597 void GfxOpenGLS::getActorScreenBBox(const Actor *actor, Common::Point &p1, Common::Point &p2) {
00598     // Get the actor's bounding box information (describes a 3D box)
00599     Math::Vector3d bboxPos, bboxSize;
00600     actor->getBBoxInfo(bboxPos, bboxSize);
00601 
00602     // Translate the bounding box to the actor's position
00603     Math::Matrix4 m = actor->getFinalMatrix();
00604     bboxPos = bboxPos + actor->getWorldPos();
00605 
00606     // Set up the camera coordinate system
00607     Math::Matrix4 modelView = _currentRot;
00608     Math::Matrix4 zScale;
00609     zScale.setValue(2, 2, -1.0);
00610     modelView = modelView * zScale;
00611     modelView.transpose();
00612     modelView.translate(-_currentPos);
00613     modelView.transpose();
00614 
00615     // Set values outside of the screen range
00616     p1.x = 1000;
00617     p1.y = 1000;
00618     p2.x = -1000;
00619     p2.y = -1000;
00620 
00621     // Project all of the points in the 3D bounding box
00622     Math::Vector3d p, projected;
00623     for (int x = 0; x < 2; x++) {
00624         for (int y = 0; y < 2; y++) {
00625             for (int z = 0; z < 2; z++) {
00626                 Math::Vector3d added(bboxSize.x() * 0.5f * (x * 2 - 1), bboxSize.y() * 0.5f * (y * 2 - 1), bboxSize.z() * 0.5f * (z * 2 - 1));
00627                 m.transform(&added, false);
00628                 p = bboxPos + added;
00629 
00630                 Math::Vector4d v = Math::Vector4d(p.x(), p.y(), p.z(), 1.0f);
00631                 v = _projMatrix.transform(modelView.transform(v));
00632                 if (v.w() == 0.0)
00633                     return;
00634                 v /= v.w();
00635 
00636                 double winX = (1 + v.x()) / 2.0f * _gameWidth;
00637                 double winY = (1 + v.y()) / 2.0f * _gameHeight;
00638 
00639                 // Find the points
00640                 if (winX < p1.x)
00641                     p1.x = winX;
00642                 if (winY < p1.y)
00643                     p1.y = winY;
00644                 if (winX > p2.x)
00645                     p2.x = winX;
00646                 if (winY > p2.y)
00647                     p2.y = winY;
00648             }
00649         }
00650     }
00651 
00652     // Swap the p1/p2 y coorindates
00653     int16 tmp = p1.y;
00654     p1.y = 480 - p2.y;
00655     p2.y = 480 - tmp;
00656 }
00657 
00658 
00659 void GfxOpenGLS::startActorDraw(const Actor *actor) {
00660     _currentActor = actor;
00661     _actorProgram->use();
00662     glEnable(GL_DEPTH_TEST);
00663 
00664     const Math::Vector3d &pos = actor->getWorldPos();
00665     const Math::Quaternion &quat = actor->getRotationQuat();
00666     //const float scale = actor->getScale();
00667 
00668     Math::Matrix4 viewMatrix = _viewMatrix;
00669     viewMatrix.transpose();
00670 
00671     if (g_grim->getGameType() == GType_MONKEY4) {
00672         glEnable(GL_CULL_FACE);
00673         glFrontFace(GL_CW);
00674 
00675         if (actor->isInOverworld())
00676             viewMatrix = Math::Matrix4();
00677 
00678         Math::Vector4d color(1.0f, 1.0f, 1.0f, actor->getEffectiveAlpha());
00679 
00680         const Math::Matrix4 &viewRot = _currentRot;
00681         Math::Matrix4 modelMatrix = actor->getFinalMatrix();
00682 
00683         Math::Matrix4 normalMatrix = viewMatrix * modelMatrix;
00684         normalMatrix.invertAffineOrthonormal();
00685         modelMatrix.transpose();
00686 
00687         _actorProgram->setUniform("modelMatrix", modelMatrix);
00688         if (actor->isInOverworld()) {
00689             _actorProgram->setUniform("viewMatrix", viewMatrix);
00690             _actorProgram->setUniform("projMatrix", _overworldProjMatrix);
00691             _actorProgram->setUniform("cameraPos", Math::Vector3d(0,0,0));
00692         } else {
00693             _actorProgram->setUniform("viewMatrix", viewRot);
00694             _actorProgram->setUniform("projMatrix", _projMatrix);
00695             _actorProgram->setUniform("cameraPos", _currentPos);
00696         }
00697         _actorProgram->setUniform("normalMatrix", normalMatrix);
00698 
00699         _actorProgram->setUniform("isBillboard", GL_FALSE);
00700         _actorProgram->setUniform("useVertexAlpha", GL_FALSE);
00701         _actorProgram->setUniform("uniformColor", color);
00702         _actorProgram->setUniform1f("alphaRef", 0.0f);
00703         _actorProgram->setUniform1f("meshAlpha", 1.0f);
00704 
00705         // set the uniform parameter for _spriteProgram
00706         // since they are needed by emi_actor.{fragment,vertex}
00707         // in drawSprite()
00708         _spriteProgram->use();
00709         _spriteProgram->setUniform("modelMatrix", modelMatrix);
00710         if (actor->isInOverworld()) {
00711             _spriteProgram->setUniform("viewMatrix", viewMatrix);
00712             _spriteProgram->setUniform("projMatrix", _overworldProjMatrix);
00713             _spriteProgram->setUniform("cameraPos", Math::Vector3d(0,0,0));
00714         } else {
00715             _spriteProgram->setUniform("viewMatrix", viewRot);
00716             _spriteProgram->setUniform("projMatrix", _projMatrix);
00717             _spriteProgram->setUniform("cameraPos", _currentPos);
00718         }
00719         _spriteProgram->setUniform("normalMatrix", normalMatrix);
00720 
00721         _spriteProgram->setUniform("actorPos", pos);
00722         _spriteProgram->setUniform("isBillboard", GL_FALSE);
00723         _spriteProgram->setUniform("useVertexAlpha", GL_FALSE);
00724         _spriteProgram->setUniform("uniformColor", color);
00725         _spriteProgram->setUniform1f("alphaRef", 0.0f);
00726         _spriteProgram->setUniform1f("meshAlpha", 1.0f);
00727 
00728         _actorProgram->use();
00729     } else {
00730         Math::Matrix4 modelMatrix = quat.toMatrix();
00731         bool hasZBuffer = g_grim->getCurrSet()->getCurrSetup()->_bkgndZBm;
00732         Math::Matrix4 extraMatrix;
00733 
00734         modelMatrix.transpose();
00735         modelMatrix.setPosition(pos);
00736         modelMatrix.transpose();
00737 
00738         _actorProgram->setUniform("modelMatrix", modelMatrix);
00739         _actorProgram->setUniform("viewMatrix", _viewMatrix);
00740         _actorProgram->setUniform("projMatrix", _projMatrix);
00741         _actorProgram->setUniform("extraMatrix", extraMatrix);
00742         _actorProgram->setUniform("tex", 0);
00743         _actorProgram->setUniform("texZBuf", 1);
00744         _actorProgram->setUniform("hasZBuffer", hasZBuffer);
00745         _actorProgram->setUniform("texcropZBuf", _zBufTexCrop);
00746         _actorProgram->setUniform("screenSize", Math::Vector2d(_screenWidth, _screenHeight));
00747         _actorProgram->setUniform1f("alphaRef", 0.5f);
00748     }
00749 
00750     if (_currentShadowArray) {
00751         const Sector *shadowSector = _currentShadowArray->planeList.front().sector;
00752         Math::Vector3d color;
00753         if (g_grim->getGameType() == GType_GRIM) {
00754             color = Math::Vector3d(_shadowColorR, _shadowColorG, _shadowColorB) / 255.f;
00755         } else {
00756             color = Math::Vector3d(_currentShadowArray->color.getRed(), _currentShadowArray->color.getGreen(), _currentShadowArray->color.getBlue()) / 255.f;
00757         }
00758         Math::Vector3d normal = shadowSector->getNormal();
00759         if (!_currentShadowArray->dontNegate)
00760             normal = -normal;
00761 
00762         _actorProgram->setUniform("shadow._active", true);
00763         _actorProgram->setUniform("shadow._color", color);
00764         _actorProgram->setUniform("shadow._light", _currentShadowArray->pos);
00765         _actorProgram->setUniform("shadow._point", shadowSector->getVertices()[0]);
00766         _actorProgram->setUniform("shadow._normal", normal);
00767 
00768         glDepthMask(GL_FALSE);
00769         glDisable(GL_BLEND);
00770         glEnable(GL_POLYGON_OFFSET_FILL);
00771     }
00772     else {
00773         _actorProgram->setUniform("shadow._active", false);
00774     }
00775 
00776     _actorProgram->setUniform("lightsEnabled", _lightsEnabled);
00777     _actorProgram->setUniform("hasAmbient", _hasAmbientLight);
00778     if (_lightsEnabled) {
00779         for (int i = 0; i < _maxLights; ++i) {
00780             const Light &l = _lights[i];
00781             Common::String uniform;
00782             uniform = Common::String::format("lights[%u]._position", i);
00783 
00784             _actorProgram->setUniform(uniform.c_str(), viewMatrix * l._position);
00785 
00786             Math::Vector4d direction = l._direction;
00787             direction.w() = 0.0;
00788             viewMatrix.transformVector(&direction);
00789             direction.w() = l._direction.w();
00790 
00791             uniform = Common::String::format("lights[%u]._direction", i);
00792             _actorProgram->setUniform(uniform.c_str(), direction);
00793 
00794             uniform = Common::String::format("lights[%u]._color", i);
00795             _actorProgram->setUniform(uniform.c_str(), l._color);
00796 
00797             uniform = Common::String::format("lights[%u]._params", i);
00798             _actorProgram->setUniform(uniform.c_str(), l._params);
00799         }
00800     }
00801 }
00802 
00803 
00804 void GfxOpenGLS::finishActorDraw() {
00805     _currentActor = NULL;
00806     glDisable(GL_POLYGON_OFFSET_FILL);
00807     if (g_grim->getGameType() == GType_MONKEY4) {
00808         glDisable(GL_CULL_FACE);
00809     }
00810 }
00811 
00812 void GfxOpenGLS::setShadow(Shadow *shadow) {
00813     _currentShadowArray = shadow;
00814 }
00815 
00816 void GfxOpenGLS::drawShadowPlanes() {
00817     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00818     glDepthMask(GL_FALSE);
00819     glClearStencil(~0);
00820     glClear(GL_STENCIL_BUFFER_BIT);
00821 
00822     glEnable(GL_STENCIL_TEST);
00823     glStencilFunc(GL_ALWAYS, 1, (GLuint)~0);
00824     glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
00825 
00826     if (!_currentShadowArray->userData) {
00827         uint32 numVertices = 0;
00828         uint32 numTriangles = 0;
00829         for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); ++i) {
00830             numVertices += i->sector->getNumVertices();
00831             numTriangles += i->sector->getNumVertices() - 2;
00832         }
00833 
00834         float *vertBuf = new float[3 * numVertices];
00835         uint16 *idxBuf = new uint16[3 * numTriangles];
00836 
00837         float *vert = vertBuf;
00838         uint16 *idx = idxBuf;
00839 
00840         for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); ++i) {
00841             Sector *shadowSector = i->sector;
00842             memcpy(vert, shadowSector->getVertices(), 3 * shadowSector->getNumVertices() * sizeof(float));
00843             uint16 first = (vert - vertBuf) / 3;
00844             for (uint16 j = 2; j < shadowSector->getNumVertices(); ++j) {
00845                 *idx++ = first;
00846                 *idx++ = first + j - 1;
00847                 *idx++ = first + j;
00848             }
00849             vert += 3 * shadowSector->getNumVertices();
00850         }
00851 
00852         ShadowUserData *sud = new ShadowUserData;
00853         _currentShadowArray->userData = sud;
00854         sud->_numTriangles = numTriangles;
00855         sud->_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, 3 * numVertices * sizeof(float), vertBuf, GL_STATIC_DRAW);
00856         sud->_indicesVBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, 3 * numTriangles * sizeof(uint16), idxBuf, GL_STATIC_DRAW);
00857 
00858         delete[] vertBuf;
00859         delete[] idxBuf;
00860     }
00861 
00862     const ShadowUserData *sud = (ShadowUserData *)_currentShadowArray->userData;
00863     _shadowPlaneProgram->use();
00864     _shadowPlaneProgram->setUniform("projMatrix", _projMatrix);
00865     _shadowPlaneProgram->setUniform("viewMatrix", _viewMatrix);
00866 
00867     glBindBuffer(GL_ARRAY_BUFFER, sud->_verticesVBO);
00868     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sud->_indicesVBO);
00869     const uint32 attribPos = _shadowPlaneProgram->getAttribute("position")._idx;
00870     glEnableVertexAttribArray(attribPos);
00871     glVertexAttribPointer(attribPos, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(float), 0);
00872     glDrawElements(GL_TRIANGLES, 3 * sud->_numTriangles, GL_UNSIGNED_SHORT, 0);
00873 
00874     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00875 
00876     glStencilFunc(GL_EQUAL, 1, (GLuint)~0);
00877     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00878 }
00879 
00880 void GfxOpenGLS::setShadowMode() {
00881     GfxBase::setShadowMode();
00882 }
00883 
00884 void GfxOpenGLS::clearShadowMode() {
00885     GfxBase::clearShadowMode();
00886 
00887     glDisable(GL_STENCIL_TEST);
00888     glDepthMask(GL_TRUE);
00889 }
00890 
00891 bool GfxOpenGLS::isShadowModeActive() {
00892     return false;
00893 }
00894 
00895 void GfxOpenGLS::setShadowColor(byte r, byte g, byte b) {
00896     _shadowColorR = r;
00897     _shadowColorG = g;
00898     _shadowColorB = b;
00899 }
00900 
00901 void GfxOpenGLS::getShadowColor(byte *r, byte *g, byte *b) {
00902     *r = _shadowColorR;
00903     *g = _shadowColorG;
00904     *b = _shadowColorB;
00905 }
00906 
00907 void GfxOpenGLS::destroyShadow(Shadow *shadow) {
00908     ShadowUserData *sud = static_cast<ShadowUserData *>(shadow->userData);
00909     if (sud) {
00910         OpenGL::Shader::freeBuffer(sud->_verticesVBO);
00911         OpenGL::Shader::freeBuffer(sud->_indicesVBO);
00912         delete sud;
00913     }
00914 
00915     shadow->userData = nullptr;
00916 }
00917 
00918 void GfxOpenGLS::set3DMode() {
00919 
00920 }
00921 
00922 void GfxOpenGLS::translateViewpointStart() {
00923     _matrixStack.push(_matrixStack.top());
00924 }
00925 
00926 void GfxOpenGLS::translateViewpoint(const Math::Vector3d &vec) {
00927     Math::Matrix4 temp;
00928     temp.setPosition(vec);
00929     temp.transpose();
00930     _matrixStack.top() = temp * _matrixStack.top();
00931 }
00932 
00933 void GfxOpenGLS::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis_) {
00934     Math::Matrix4 temp = makeRotationMatrix(angle, axis_) * _matrixStack.top();
00935     _matrixStack.top() = temp;
00936 }
00937 
00938 void GfxOpenGLS::rotateViewpoint(const Math::Matrix4 &rot) {
00939     Math::Matrix4 temp = rot * _matrixStack.top();
00940     _matrixStack.top() = temp;
00941 }
00942 
00943 void GfxOpenGLS::translateViewpointFinish() {
00944     _matrixStack.pop();
00945 }
00946 
00947 void GfxOpenGLS::updateEMIModel(const EMIModel* model) {
00948     const EMIModelUserData *mud = (const EMIModelUserData *)model->_userData;
00949     glBindBuffer(GL_ARRAY_BUFFER, mud->_verticesVBO);
00950     glBufferSubData(GL_ARRAY_BUFFER, 0, model->_numVertices * 3 * sizeof(float), model->_drawVertices);
00951     glBindBuffer(GL_ARRAY_BUFFER, mud->_normalsVBO);
00952     glBufferSubData(GL_ARRAY_BUFFER, 0, model->_numVertices * 3 * sizeof(float), model->_drawNormals);
00953 }
00954 
00955 void GfxOpenGLS::drawEMIModelFace(const EMIModel* model, const EMIMeshFace* face) {
00956     if (face->_flags & EMIMeshFace::kAlphaBlend ||
00957         face->_flags & EMIMeshFace::kUnknownBlend)
00958         glEnable(GL_BLEND);
00959     const EMIModelUserData *mud = (const EMIModelUserData *)model->_userData;
00960     mud->_shader->use();
00961     bool textured = face->_hasTexture && !_currentShadowArray;
00962     mud->_shader->setUniform("textured", textured ? GL_TRUE : GL_FALSE);
00963     mud->_shader->setUniform("lightsEnabled", (face->_flags & EMIMeshFace::kNoLighting) ? false : _lightsEnabled);
00964     mud->_shader->setUniform("swapRandB", _selectedTexture->_colorFormat == BM_BGRA || _selectedTexture->_colorFormat == BM_BGR888);
00965     mud->_shader->setUniform("useVertexAlpha", _selectedTexture->_colorFormat == BM_BGRA);
00966     mud->_shader->setUniform1f("meshAlpha", (model->_meshAlphaMode == Actor::AlphaReplace) ? model->_meshAlpha : 1.0f);
00967 
00968     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, face->_indicesEBO);
00969 
00970     glDrawElements(GL_TRIANGLES, 3 * face->_faceLength, GL_UNSIGNED_INT, 0);
00971     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
00972 }
00973 
00974 void GfxOpenGLS::drawMesh(const Mesh *mesh) {
00975     const ModelUserData *mud = (const ModelUserData *)mesh->_userData;
00976     if (!mud)
00977         return;
00978     OpenGL::Shader *actorShader = mud->_shader;
00979 
00980     actorShader->use();
00981     actorShader->setUniform("extraMatrix", _matrixStack.top());
00982     actorShader->setUniform("lightsEnabled", _lightsEnabled && !isShadowModeActive());
00983 
00984     const Material *curMaterial = NULL;
00985     for (int i = 0; i < mesh->_numFaces;) {
00986         const MeshFace *face = &mesh->_faces[i];
00987 
00988         curMaterial = face->getMaterial();
00989         curMaterial->select();
00990 
00991         int faces = 0;
00992         for (; i < mesh->_numFaces; ++i) {
00993             if (mesh->_faces[i].getMaterial() != curMaterial)
00994                 break;
00995             faces += 3 * (mesh->_faces[i].getNumVertices() - 2);
00996         }
00997 
00998         bool textured = face->hasTexture() && !_currentShadowArray;
00999         actorShader->setUniform("textured", textured ? GL_TRUE : GL_FALSE);
01000         actorShader->setUniform("texScale", Math::Vector2d(_selectedTexture->_width, _selectedTexture->_height));
01001 
01002         glDrawArrays(GL_TRIANGLES, *(int *)face->_userData, faces);
01003     }
01004 }
01005 
01006 void GfxOpenGLS::drawDimPlane() {
01007     if (_dimLevel == 0.0f)
01008         return;
01009 
01010     glDisable(GL_DEPTH_TEST);
01011     glDepthMask(GL_FALSE);
01012     glEnable(GL_BLEND);
01013     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01014 
01015     _dimPlaneProgram->use();
01016     _dimPlaneProgram->setUniform1f("dim", _dimLevel);
01017 
01018     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01019     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01020     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01021 
01022     glEnable(GL_DEPTH_TEST);
01023     glDepthMask(GL_TRUE);
01024 }
01025 
01026 void GfxOpenGLS::drawModelFace(const Mesh *mesh, const MeshFace *face) {
01027 
01028 }
01029 
01030 void GfxOpenGLS::drawSprite(const Sprite *sprite) {
01031     if (g_grim->getGameType() == GType_MONKEY4) {
01032         glDepthMask(GL_TRUE);
01033     } else {
01034         glDepthMask(GL_FALSE);
01035     }
01036 
01037     if (sprite->_flags1 & Sprite::BlendAdditive) {
01038         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
01039     } else {
01040         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01041     }
01042 
01043     // FIXME: depth test does not work yet because final z coordinates
01044     //        for Sprites and actor textures are inconsistently calculated
01045     if (sprite->_flags2 & Sprite::DepthTest || _currentActor->isInOverworld()) {
01046         glEnable(GL_DEPTH_TEST);
01047     } else {
01048         glDisable(GL_DEPTH_TEST);
01049     }
01050 
01051     _spriteProgram->use();
01052 
01053     Math::Matrix4 rotateMatrix;
01054     rotateMatrix.buildAroundZ(_currentActor->getYaw());
01055 
01056     Math::Matrix4 extraMatrix;
01057     extraMatrix.setPosition(sprite->_pos);
01058     extraMatrix(0, 0) = sprite->_width;
01059     extraMatrix(1, 1) = sprite->_height;
01060 
01061     extraMatrix = rotateMatrix * extraMatrix;
01062     extraMatrix.transpose();
01063     _spriteProgram->setUniform("extraMatrix", extraMatrix);
01064     _spriteProgram->setUniform("textured", GL_TRUE);
01065     _spriteProgram->setUniform("swapRandB", _selectedTexture->_colorFormat == BM_BGRA || _selectedTexture->_colorFormat == BM_BGR888);
01066     _spriteProgram->setUniform("isBillboard", GL_TRUE);
01067     _spriteProgram->setUniform("lightsEnabled", false);
01068     if (g_grim->getGameType() == GType_GRIM) {
01069         _spriteProgram->setUniform1f("alphaRef", 0.5f);
01070     } else if (sprite->_flags2 & Sprite::AlphaTest) {
01071         _spriteProgram->setUniform1f("alphaRef", 0.1f);
01072     } else {
01073         _spriteProgram->setUniform1f("alphaRef", 0.0f);
01074     }
01075 
01076     // FIXME: Currently vertex-specific colors are not supported for sprites.
01077     // It is unknown at this time if this is really needed anywhere.
01078     Math::Vector4d color(sprite->_red[0] / 255.0f, sprite->_green[0] / 255.0f, sprite->_blue[0] / 255.0f, sprite->_alpha[0] / 255.0f);
01079     _spriteProgram->setUniform("uniformColor", color);
01080 
01081     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01082     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01083     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01084     glEnable(GL_DEPTH_TEST);
01085     glDepthMask(GL_TRUE);
01086     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01087 }
01088 
01089 void GfxOpenGLS::enableLights() {
01090     _lightsEnabled = true;
01091 }
01092 
01093 void GfxOpenGLS::disableLights() {
01094     _lightsEnabled = false;
01095 }
01096 
01097 void GfxOpenGLS::setupLight(Grim::Light *light, int lightId) {
01098     _lightsEnabled = true;
01099 
01100     if (lightId >= _maxLights) {
01101         return;
01102     }
01103 
01104     // Disable previous lights.
01105     if (lightId == 0) {
01106         _hasAmbientLight = false;
01107         for (int id = 0; id < _maxLights; ++id)
01108             _lights[id]._color.w() = 0.0;
01109     }
01110 
01111     Math::Vector4d &lightColor  = _lights[lightId]._color;
01112     Math::Vector4d &lightPos    = _lights[lightId]._position;
01113     Math::Vector4d &lightDir    = _lights[lightId]._direction;
01114     Math::Vector4d &lightParams = _lights[lightId]._params;
01115 
01116     lightColor.x() = (float)light->_color.getRed();
01117     lightColor.y() = (float)light->_color.getGreen();
01118     lightColor.z() = (float)light->_color.getBlue();
01119     lightColor.w() = light->_scaledintensity;
01120 
01121     if (light->_type == Grim::Light::Omni) {
01122         lightPos = Math::Vector4d(light->_pos.x(), light->_pos.y(), light->_pos.z(), 1.0f);
01123         lightDir = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01124         lightParams = Math::Vector4d(light->_falloffNear, light->_falloffFar, 0.0f, 0.0f);
01125     } else if (light->_type == Grim::Light::Direct) {
01126         lightPos = Math::Vector4d(-light->_dir.x(), -light->_dir.y(), -light->_dir.z(), 0.0f);
01127         lightDir = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01128     } else if (light->_type == Grim::Light::Spot) {
01129         lightPos = Math::Vector4d(light->_pos.x(), light->_pos.y(), light->_pos.z(), 1.0f);
01130         lightDir = Math::Vector4d(light->_dir.x(), light->_dir.y(), light->_dir.z(), 1.0f);
01131         lightParams = Math::Vector4d(light->_falloffNear, light->_falloffFar, light->_cospenumbraangle, light->_cosumbraangle);
01132     } else if (light->_type == Grim::Light::Ambient) {
01133         lightPos = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01134         lightDir = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01135         _hasAmbientLight = true;
01136     }
01137 }
01138 
01139 void GfxOpenGLS::turnOffLight(int lightId) {
01140     if (lightId >= _maxLights) {
01141         return;
01142     }
01143 
01144     _lights[lightId]._color = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
01145     _lights[lightId]._position = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
01146     _lights[lightId]._direction = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
01147 }
01148 
01149 
01150 void GfxOpenGLS::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
01151     texture->_texture = new GLuint[1];
01152     glGenTextures(1, (GLuint *)texture->_texture);
01153     char *texdata = new char[texture->_width * texture->_height * 4];
01154     char *texdatapos = texdata;
01155 
01156     if (cmap != NULL) { // EMI doesn't have colour-maps
01157         int bytes = 4;
01158         for (int y = 0; y < texture->_height; y++) {
01159             for (int x = 0; x < texture->_width; x++) {
01160                 uint8 col = *(const uint8 *)(data);
01161                 if (col == 0) {
01162                     memset(texdatapos, 0, bytes); // transparent
01163                     if (!texture->_hasAlpha) {
01164                         texdatapos[3] = '\xff'; // fully opaque
01165                     }
01166                 } else {
01167                     memcpy(texdatapos, cmap->_colors + 3 * (col), 3);
01168                     texdatapos[3] = '\xff'; // fully opaque
01169                 }
01170                 texdatapos += bytes;
01171                 data++;
01172             }
01173         }
01174     } else {
01175         memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
01176     }
01177 
01178     GLuint format = 0;
01179     GLuint internalFormat = 0;
01180     if (texture->_colorFormat == BM_RGBA) {
01181         format = GL_RGBA;
01182         internalFormat = GL_RGBA;
01183     } else if (texture->_colorFormat == BM_BGRA) {
01184 #ifdef USE_GLES2
01185         format = GL_RGBA;
01186         internalFormat = GL_RGBA;
01187 #else
01188         format = GL_BGRA;
01189         internalFormat = GL_RGBA;
01190 #endif
01191     } else { // The only other colorFormat we load right now is BGR
01192 #ifdef USE_GLES2
01193         format = GL_RGB;
01194         internalFormat = GL_RGB;
01195 #else
01196         format = GL_BGR;
01197         internalFormat = GL_RGBA;
01198 #endif
01199     }
01200 
01201     GLuint *textures = (GLuint *)texture->_texture;
01202     glBindTexture(GL_TEXTURE_2D, textures[0]);
01203 
01204     // Remove darkened lines in EMI intro
01205     if (g_grim->getGameType() == GType_MONKEY4 && clamp) {
01206         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01207         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01208     } else {
01209         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
01210         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
01211     }
01212 
01213     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01214     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01215     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, texture->_width, texture->_height, 0, format, GL_UNSIGNED_BYTE, texdata);
01216     delete[] texdata;
01217 }
01218 
01219 void GfxOpenGLS::selectTexture(const Texture *texture) {
01220     GLuint *textures = (GLuint *)texture->_texture;
01221     glBindTexture(GL_TEXTURE_2D, textures[0]);
01222 
01223     if (texture->_hasAlpha && g_grim->getGameType() == GType_MONKEY4) {
01224         glEnable(GL_BLEND);
01225     }
01226 
01227     _selectedTexture = const_cast<Texture *>(texture);
01228 }
01229 
01230 void GfxOpenGLS::destroyTexture(Texture *texture) {
01231     GLuint *textures = static_cast<GLuint *>(texture->_texture);
01232     if (textures) {
01233         glDeleteTextures(1, textures);
01234         delete[] textures;
01235     }
01236 }
01237 
01238 void GfxOpenGLS::createBitmap(BitmapData *bitmap) {
01239     if (bitmap->_format != 1) {
01240         for (int pic = 0; pic < bitmap->_numImages; pic++) {
01241             uint16 *zbufPtr = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
01242             for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
01243                 uint16 val = READ_LE_UINT16(zbufPtr + i);
01244                 // fix the value if it is incorrectly set to the bitmap transparency color
01245                 if (val == 0xf81f) {
01246                     val = 0;
01247                 }
01248                 zbufPtr[i] = 0xffff - ((uint32)val) * 0x10000 / 100 / (0x10000 - val);
01249             }
01250         }
01251     }
01252 
01253     bitmap->_hasTransparency = false;
01254     if (bitmap->_format == 1) {
01255         bitmap->_numTex = 1;
01256         GLuint *textures = new GLuint[bitmap->_numTex * bitmap->_numImages];
01257         bitmap->_texIds = textures;
01258         glGenTextures(bitmap->_numTex * bitmap->_numImages, textures);
01259 
01260         byte *texData = 0;
01261         byte *texOut = 0;
01262 
01263         GLint format = GL_RGBA;
01264         GLint type = GL_UNSIGNED_BYTE;
01265         int bytes = 4;
01266 
01267         glPixelStorei(GL_UNPACK_ALIGNMENT, bytes);
01268 
01269         for (int pic = 0; pic < bitmap->_numImages; pic++) {
01270             if (bitmap->_format == 1 && bitmap->_bpp == 16 && bitmap->_colorFormat != BM_RGB1555) {
01271                 if (texData == 0)
01272                     texData = new byte[bytes * bitmap->_width * bitmap->_height];
01273                 // Convert data to 32-bit RGBA format
01274                 byte *texDataPtr = texData;
01275                 uint16 *bitmapData = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
01276                 for (int i = 0; i < bitmap->_width * bitmap->_height; i++, texDataPtr += bytes, bitmapData++) {
01277                     uint16 pixel = *bitmapData;
01278                     int r = pixel >> 11;
01279                     texDataPtr[0] = (r << 3) | (r >> 2);
01280                     int g = (pixel >> 5) & 0x3f;
01281                     texDataPtr[1] = (g << 2) | (g >> 4);
01282                     int b = pixel & 0x1f;
01283                     texDataPtr[2] = (b << 3) | (b >> 2);
01284                     if (pixel == 0xf81f) { // transparent
01285                         texDataPtr[3] = 0;
01286                         bitmap->_hasTransparency = true;
01287                     } else {
01288                         texDataPtr[3] = 255;
01289                     }
01290                 }
01291                 texOut = texData;
01292             } else if (bitmap->_format == 1 && bitmap->_colorFormat == BM_RGB1555) {
01293                 bitmap->convertToColorFormat(pic, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
01294                 texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
01295             } else {
01296                 texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
01297             }
01298 
01299             int actualWidth = nextHigher2(bitmap->_width);
01300             int actualHeight = nextHigher2(bitmap->_height);
01301 
01302             glBindTexture(GL_TEXTURE_2D, textures[bitmap->_numTex * pic]);
01303             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01304             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01305             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01306             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01307             glTexImage2D(GL_TEXTURE_2D, 0, format, actualWidth, actualHeight, 0, format, type, NULL);
01308 
01309             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->_width, bitmap->_height, format, type, texOut);
01310         }
01311 
01312         if (texData)
01313             delete[] texData;
01314         bitmap->freeData();
01315 
01316         OpenGL::Shader *shader = _backgroundProgram->clone();
01317         bitmap->_userData = shader;
01318 
01319         if (g_grim->getGameType() == GType_MONKEY4) {
01320             GLuint vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, bitmap->_numCoords * 4 * sizeof(float), bitmap->_texc, GL_STATIC_DRAW);
01321             shader->enableVertexAttribute("position", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
01322             shader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2*sizeof(float));
01323         }
01324     } else {
01325         bitmap->_numTex = 0;
01326         bitmap->_texIds = NULL;
01327         bitmap->_userData = NULL;
01328     }
01329 }
01330 
01331 void GfxOpenGLS::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer) {
01332     if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
01333         BitmapData *data = bitmap->_data;
01334         OpenGL::Shader *shader = (OpenGL::Shader *)data->_userData;
01335         GLuint *textures = (GLuint *)bitmap->getTexIds();
01336 
01337         glDisable(GL_DEPTH_TEST);
01338 
01339         glEnable(GL_BLEND);
01340         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01341 
01342         shader->use();
01343         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01344         assert(layer < data->_numLayers);
01345         uint32 offset = data->_layers[layer]._offset;
01346         for (uint32 i = offset; i < offset + data->_layers[layer]._numImages; ++i) {
01347             glBindTexture(GL_TEXTURE_2D, textures[data->_verts[i]._texid]);
01348 
01349             unsigned short startVertex = data->_verts[i]._pos / 4 * 6;
01350             unsigned short numVertices = data->_verts[i]._verts / 4 * 6;
01351             glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_SHORT, (void *)(startVertex * sizeof(unsigned short)));
01352         }
01353         return;
01354     }
01355 
01356     int format = bitmap->getFormat();
01357     if ((format == 1 && !_renderBitmaps) || (format == 5 && !_renderZBitmaps)) {
01358         return;
01359     }
01360 
01361     if (format == 1) {
01362         GLuint *textures = (GLuint *)bitmap->getTexIds();
01363         if (bitmap->getFormat() == 1 && bitmap->getHasTransparency()) {
01364             glEnable(GL_BLEND);
01365             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01366         } else {
01367             glDisable(GL_BLEND);
01368         }
01369 
01370         OpenGL::Shader *shader = (OpenGL::Shader *)bitmap->_data->_userData;
01371         shader->use();
01372         glDisable(GL_DEPTH_TEST);
01373         glDepthMask(GL_FALSE);
01374 
01375         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01376         int cur_tex_idx = bitmap->getNumTex() * (bitmap->getActiveImage() - 1);
01377         glBindTexture(GL_TEXTURE_2D, textures[cur_tex_idx]);
01378         float width = bitmap->getWidth();
01379         float height = bitmap->getHeight();
01380         shader->setUniform("offsetXY", Math::Vector2d(float(dx) / _gameWidth, float(dy) / _gameHeight));
01381         shader->setUniform("sizeWH", Math::Vector2d(width / _gameWidth, height / _gameHeight));
01382         shader->setUniform("texcrop", Math::Vector2d(width / nextHigher2((int)width), height / nextHigher2((int)height)));
01383         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01384 
01385         glDisable(GL_BLEND);
01386         glDepthMask(GL_TRUE);
01387         glEnable(GL_DEPTH_TEST);
01388     } else {
01389         // Only draw the manual zbuffer when enabled
01390         if (bitmap->getActiveImage() - 1 < bitmap->getNumImages()) {
01391             drawDepthBitmap(dx, dy, bitmap->getWidth(), bitmap->getHeight(), (char *)bitmap->getData(bitmap->getActiveImage() - 1).getRawBuffer());
01392         } else {
01393             warning("zbuffer image has index out of bounds! %d/%d", bitmap->getActiveImage(), bitmap->getNumImages());
01394         }
01395         return;
01396     }
01397 }
01398 
01399 void GfxOpenGLS::drawDepthBitmap(int x, int y, int w, int h, char *data) {
01400     static int prevX = -1, prevY = -1;
01401     static char *prevData = NULL;
01402 
01403     if (prevX == x && prevY == y && data == prevData)
01404         return;
01405 
01406     prevX = x;
01407     prevY = y;
01408     prevData = data;
01409 
01410     glActiveTexture(GL_TEXTURE1);
01411     glBindTexture(GL_TEXTURE_2D, _zBufTex);
01412     glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // 16 bit Z depth bitmap
01413     glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
01414     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01415     glActiveTexture(GL_TEXTURE0);
01416 }
01417 
01418 void GfxOpenGLS::destroyBitmap(BitmapData *bitmap) {
01419     GLuint *textures = (GLuint *)bitmap->_texIds;
01420     if (textures) {
01421         glDeleteTextures(bitmap->_numTex * bitmap->_numImages, textures);
01422         delete[] textures;
01423         bitmap->_texIds = 0;
01424     }
01425     OpenGL::Shader *shader = (OpenGL::Shader *)bitmap->_userData;
01426     if (g_grim->getGameType() == GType_MONKEY4) {
01427         glDeleteBuffers(1, &shader->getAttributeAt(0)._vbo);
01428     }
01429     delete shader;
01430 
01431     if (bitmap->_format != 1) {
01432         bitmap->freeData();
01433     }
01434 }
01435 
01436 void GfxOpenGLS::createFont(Font *font) {
01437     const byte *bitmapData = font->getFontData();
01438     uint dataSize = font->getDataSize();
01439 
01440     uint8 bpp = 4;
01441     uint8 charsWide = 16;
01442     uint8 charsHigh = 16;
01443 
01444     byte *texDataPtr = new byte[dataSize * bpp];
01445     byte *data = texDataPtr;
01446 
01447     for (uint i = 0; i < dataSize; i++, texDataPtr += bpp, bitmapData++) {
01448         byte pixel = *bitmapData;
01449         if (pixel == 0x00) {
01450             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 0;
01451         } else if (pixel == 0x80) {
01452             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = 0;
01453             texDataPtr[3] = 255;
01454         } else if (pixel == 0xFF) {
01455             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 255;
01456         }
01457     }
01458     int size = 0;
01459     for (int i = 0; i < 256; ++i) {
01460         int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
01461         int m = MAX(width, height);
01462         if (m > size)
01463             size = m;
01464     }
01465     assert(size < 64);
01466     if (size < 8)
01467         size = 8;
01468     if (size < 16)
01469         size = 16;
01470     else if (size < 32)
01471         size = 32;
01472     else if (size < 64)
01473         size = 64;
01474 
01475     uint arraySize = size * size * bpp * charsWide * charsHigh;
01476     byte *temp = new byte[arraySize];
01477 
01478     memset(temp, 0, arraySize);
01479 
01480     FontUserData *userData = new FontUserData;
01481     font->setUserData(userData);
01482     userData->texture = 0;
01483     userData->size = size;
01484 
01485     GLuint *texture = &(userData->texture);
01486     glGenTextures(1, texture);
01487 
01488     for (int i = 0, row = 0; i < 256; ++i) {
01489         int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
01490         int32 d = font->getCharOffset(i);
01491         for (int x = 0; x < height; ++x) {
01492             // a is the offset to get to the correct row.
01493             // b is the offset to get to the correct line in the character.
01494             // c is the offset of the character from the start of the row.
01495             uint a = row * size * size * bpp * charsHigh;
01496             uint b = x * size * charsWide * bpp;
01497             uint c = 0;
01498             if (i != 0)
01499                 c = ((i - 1) % 16) * size * bpp;
01500 
01501             uint pos = a + b + c;
01502             uint pos2 = d * bpp + x * width * bpp;
01503             assert(pos + width * bpp <= arraySize);
01504             assert(pos2 + width * bpp <= dataSize * bpp);
01505             memcpy(temp + pos, data + pos2, width * bpp);
01506         }
01507         if (i != 0 && i % charsWide == 0)
01508             ++row;
01509     }
01510 
01511     glBindTexture(GL_TEXTURE_2D, texture[0]);
01512     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01513     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size * charsWide, size * charsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
01517 
01518     delete[] data;
01519     delete[] temp;
01520 }
01521 
01522 void GfxOpenGLS::destroyFont(Font *font) {
01523     const FontUserData *data = (const FontUserData *)font->getUserData();
01524     if (data) {
01525         glDeleteTextures(1, &(data->texture));
01526         delete data;
01527     }
01528 }
01529 
01530 void GfxOpenGLS::createTextObject(TextObject *text) {
01531     const Color &color = text->getFGColor();
01532     const Font *font = text->getFont();
01533 
01534     const FontUserData *userData = (const FontUserData *)font->getUserData();
01535     if (!userData)
01536         error("Could not get font userdata");
01537 
01538     float sizeW = float(userData->size) / _gameWidth;
01539     float sizeH = float(userData->size) / _gameHeight;
01540     const Common::String *lines = text->getLines();
01541     int numLines = text->getNumLines();
01542 
01543     int numCharacters = 0;
01544     for (int j = 0; j < numLines; ++j) {
01545         numCharacters += lines[j].size();
01546     }
01547 
01548     float *bufData = new float[numCharacters * 16];
01549     float *cur = bufData;
01550 
01551     for (int j = 0; j < numLines; ++j) {
01552         const Common::String &line = lines[j];
01553         int x = text->getLineX(j);
01554         int y = text->getLineY(j);
01555         for (uint i = 0; i < line.size(); ++i) {
01556             uint8 character = line[i];
01557             float w = y + font->getCharStartingLine(character);
01558             if (g_grim->getGameType() == GType_GRIM)
01559                 w += font->getBaseOffsetY();
01560             float z = x + font->getCharStartingCol(character);
01561             z /= _gameWidth;
01562             w /= _gameHeight;
01563             float width = 1 / 16.f;
01564             float cx = ((character - 1) % 16) / 16.0f;
01565             float cy = ((character - 1) / 16) / 16.0f;
01566 
01567             float charData[] = {
01568                     z, w, cx, cy,
01569                     z + sizeW, w, cx + width, cy,
01570                     z + sizeW, w + sizeH, cx + width, cy + width,
01571                     z, w + sizeH, cx, cy + width
01572             };
01573             memcpy(cur, charData, 16 * sizeof(float));
01574             cur += 16;
01575 
01576             x += font->getCharKernedWidth(character);
01577         }
01578     }
01579     GLuint vbo;
01580     if (text->isBlastDraw()) {
01581         vbo = _blastVBO;
01582         glBindBuffer(GL_ARRAY_BUFFER, vbo);
01583         glBufferSubData(GL_ARRAY_BUFFER, 0, numCharacters * 16 * sizeof(float), bufData);
01584     } else {
01585         vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, numCharacters * 16 * sizeof(float), bufData, GL_STATIC_DRAW);
01586     }
01587 
01588     OpenGL::Shader * textShader = _textProgram->clone();
01589     glBindBuffer(GL_ARRAY_BUFFER, vbo);
01590 
01591     textShader->enableVertexAttribute("position", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
01592     textShader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
01593 
01594     TextUserData * td = new TextUserData;
01595     td->characters = numCharacters;
01596     td->shader = textShader;
01597     td->color = color;
01598     td->texture = userData->texture;
01599     text->setUserData(td);
01600     delete[] bufData;
01601 }
01602 
01603 void GfxOpenGLS::drawTextObject(const TextObject *text) {
01604     glEnable(GL_BLEND);
01605     glDisable(GL_DEPTH_TEST);
01606     const TextUserData * td = (const TextUserData *) text->getUserData();
01607     assert(td);
01608     td->shader->use();
01609 
01610     Math::Vector3d colors(float(td->color.getRed()) / 255.0f,
01611                           float(td->color.getGreen()) / 255.0f,
01612                           float(td->color.getBlue()) / 255.0f);
01613     _textProgram->setUniform("color", colors);
01614     glBindTexture(GL_TEXTURE_2D, td->texture);
01615     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01616     glDrawElements(GL_TRIANGLES, td->characters * 6, GL_UNSIGNED_SHORT, 0);
01617     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01618     glEnable(GL_DEPTH_TEST);
01619 }
01620 
01621 void GfxOpenGLS::destroyTextObject(TextObject *text) {
01622     const TextUserData * td = (const TextUserData *) text->getUserData();
01623     if (!text->isBlastDraw()) {
01624         glDeleteBuffers(1, &td->shader->getAttributeAt(0)._vbo);
01625     }
01626     text->setUserData(NULL);
01627 
01628     delete td->shader;
01629     delete td;
01630 }
01631 
01632 void GfxOpenGLS::storeDisplay() {
01633     glBindTexture(GL_TEXTURE_2D, _storedDisplay);
01634     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _screenWidth, _screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
01635     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01636     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01637     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, _screenWidth, _screenHeight, 0);
01638 }
01639 
01640 void GfxOpenGLS::copyStoredToDisplay() {
01641     if (!_dimProgram)
01642         return;
01643 
01644     _dimProgram->use();
01645     _dimProgram->setUniform("scaleWH", Math::Vector2d(1.f, 1.f));
01646     _dimProgram->setUniform("tex", 0);
01647 
01648     glBindTexture(GL_TEXTURE_2D, _storedDisplay);
01649 
01650     glDisable(GL_DEPTH_TEST);
01651     glDepthMask(GL_FALSE);
01652 
01653     glDrawArrays(GL_TRIANGLES, 0, 6);
01654 
01655     glEnable(GL_DEPTH_TEST);
01656     glDepthMask(GL_TRUE);
01657 }
01658 
01659 void GfxOpenGLS::dimScreen() {
01660 
01661 }
01662 
01663 void GfxOpenGLS::dimRegion(int xin, int yReal, int w, int h, float level) {
01664     xin = (int)(xin * _scaleW);
01665     yReal = (int)(yReal * _scaleH);
01666     w = (int)(w * _scaleW);
01667     h = (int)(h * _scaleH);
01668     int yin = _screenHeight - yReal - h;
01669 
01670     GLuint texture;
01671     glGenTextures(1, &texture);
01672     glBindTexture(GL_TEXTURE_2D, texture);
01673 
01674     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
01675     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01676     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01677 
01678     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xin, yin, w, h, 0);
01679 
01680     glBindBuffer(GL_ARRAY_BUFFER, _dimRegionVBO);
01681 
01682     float width = w;
01683     float height = h;
01684     float x = xin;
01685     float y = yin;
01686     float points[24] = {
01687         x, y, 0.0f, 0.0f,
01688         x + width, y, 1.0f, 0.0f,
01689         x + width, y + height, 1.0f, 1.0f,
01690         x + width, y + height, 1.0f, 1.0f,
01691         x, y + height, 0.0f, 1.0f,
01692         x, y, 0.0f, 0.0f,
01693     };
01694 
01695     glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * sizeof(float), points);
01696 
01697     _dimRegionProgram->use();
01698     _dimRegionProgram->setUniform("scaleWH", Math::Vector2d(1.f / _screenWidth, 1.f / _screenHeight));
01699     _dimRegionProgram->setUniform("tex", 0);
01700 
01701     glDisable(GL_DEPTH_TEST);
01702     glDepthMask(GL_FALSE);
01703 
01704     glDrawArrays(GL_TRIANGLES, 0, 6);
01705 
01706     glEnable(GL_DEPTH_TEST);
01707     glDepthMask(GL_TRUE);
01708 
01709     glDeleteTextures(1, &texture);
01710 }
01711 
01712 
01713 void GfxOpenGLS::irisAroundRegion(int x1, int y1, int x2, int y2) {
01714     _irisProgram->use();
01715     _irisProgram->setUniform("color", Math::Vector3d(0.0f, 0.0f, 0.0f));
01716     _irisProgram->setUniform("scaleWH", Math::Vector2d(1.f / _gameWidth, 1.f / _gameHeight));
01717 
01718     float fx1 = x1;
01719     float fx2 = x2;
01720     float fy1 = y1;
01721     float fy2 = y2;
01722     float width = _screenWidth;
01723     float height = _screenHeight;
01724     float points[20] = {
01725         0.0f, 0.0f,
01726         0.0f, fy1,
01727         width, 0.0f,
01728         fx2, fy1,
01729         width, height,
01730         fx2, fy2,
01731         0.0f, height,
01732         fx1, fy2,
01733         0.0f, fy1,
01734         fx1, fy1
01735     };
01736 
01737     glBindBuffer(GL_ARRAY_BUFFER, _irisVBO);
01738     glBufferSubData(GL_ARRAY_BUFFER, 0, 20 * sizeof(float), points);
01739 
01740     glDisable(GL_DEPTH_TEST);
01741     glDepthMask(GL_FALSE);
01742 
01743     glDrawArrays(GL_TRIANGLE_STRIP, 0, 10);
01744 
01745     glEnable(GL_DEPTH_TEST);
01746     glDepthMask(GL_TRUE);
01747 }
01748 
01749 
01750 void GfxOpenGLS::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
01751     if (!*text)
01752         return;
01753 
01754     glEnable(GL_BLEND);
01755     glDisable(GL_DEPTH_TEST);
01756     glBindTexture(GL_TEXTURE_2D, _emergTexture);
01757     _emergProgram->use();
01758     Math::Vector3d colors(float(fgColor.getRed()) / 255.0f,
01759                           float(fgColor.getGreen()) / 255.0f,
01760                           float(fgColor.getBlue()) / 255.0f);
01761     _emergProgram->setUniform("color", colors);
01762     _emergProgram->setUniform("sizeWH", Math::Vector2d(float(8) / _gameWidth, float(16) / _gameHeight));
01763     _emergProgram->setUniform("texScale", Math::Vector2d(float(8) / 128, float(16) / 128));
01764 
01765     for (; *text; ++text, x+=10) {
01766         int blockcol = *text & 0xf;
01767         int blockrow = *text / 16;
01768         _emergProgram->setUniform("offsetXY", Math::Vector2d(float(x) / _gameWidth, float(y) / _gameHeight));
01769         _emergProgram->setUniform("texOffsetXY", Math::Vector2d(float(blockcol * 8) / 128, float(blockrow * 16) / 128));
01770         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
01771     }
01772 }
01773 
01774 void GfxOpenGLS::loadEmergFont() {
01775     uint8 *atlas = new uint8[128 * 128];
01776     memset(atlas, 0, 128 * 128);
01777 
01778     for (int c = 32; c < 128; ++c) {
01779         int blockrow = c / 16;
01780         int blockcol = c & 0xf;
01781         for (int row = 0; row < 13; ++row) {
01782             int base = 128 * (16 * blockrow + row) + 8 * blockcol;
01783             uint8 val = Font::emerFont[c - 32][row];
01784             atlas[base + 0] = (val & 0x80) ? 255 : 0;
01785             atlas[base + 1] = (val & 0x40) ? 255 : 0;
01786             atlas[base + 2] = (val & 0x20) ? 255 : 0;
01787             atlas[base + 3] = (val & 0x10) ? 255 : 0;
01788             atlas[base + 4] = (val & 0x08) ? 255 : 0;
01789             atlas[base + 5] = (val & 0x04) ? 255 : 0;
01790             atlas[base + 6] = (val & 0x02) ? 255 : 0;
01791             atlas[base + 7] = (val & 0x01) ? 255 : 0;
01792         }
01793     }
01794 
01795     glGenTextures(1, &_emergTexture);
01796     glBindTexture(GL_TEXTURE_2D, _emergTexture);
01797     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01798     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01799     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01800     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01801     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 128, 128, 0, GL_ALPHA, GL_UNSIGNED_BYTE, atlas);
01802 
01803     delete[] atlas;
01804 }
01805 
01806 void GfxOpenGLS::drawGenericPrimitive(const float *vertices, uint32 numVertices, const PrimitiveObject *primitive) {
01807     const Color color(primitive->getColor());
01808     const Math::Vector3d colorV =
01809       Math::Vector3d(color.getRed(), color.getGreen(), color.getBlue()) / 255.f;
01810 
01811     GLuint prim = nextPrimitive();
01812     glBindBuffer(GL_ARRAY_BUFFER, prim);
01813     glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(float), vertices);
01814 
01815     glDisable(GL_DEPTH_TEST);
01816     glDepthMask(GL_FALSE);
01817 
01818     _primitiveProgram->enableVertexAttribute("position", prim, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
01819     _primitiveProgram->use(true);
01820     _primitiveProgram->setUniform("color", colorV);
01821     _primitiveProgram->setUniform("scaleWH", Math::Vector2d(1.f / _gameWidth, 1.f / _gameHeight));
01822 
01823     switch (primitive->getType()) {
01824         case PrimitiveObject::RectangleType:
01825             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
01826             break;
01827         case PrimitiveObject::LineType:
01828             glDrawArrays(GL_LINES, 0, 2);
01829             break;
01830         case PrimitiveObject::PolygonType:
01831             glDrawArrays(GL_LINES, 0, 4);
01832             break;
01833         default:
01834             // Impossible
01835             break;
01836     }
01837 
01838     glBindBuffer(GL_ARRAY_BUFFER, 0);
01839     glDepthMask(GL_TRUE);
01840     glEnable(GL_DEPTH_TEST);
01841 }
01842 
01843 void GfxOpenGLS::drawRectangle(const PrimitiveObject *primitive) {
01844     float x1 = primitive->getP1().x * _scaleW;
01845     float y1 = primitive->getP1().y * _scaleH;
01846     float x2 = primitive->getP2().x * _scaleW;
01847     float y2 = primitive->getP2().y * _scaleH;
01848 
01849     if (primitive->isFilled()) {
01850         float data[] = { x1, y1, x2 + 1, y1, x1, y2 + 1, x2 + 1, y2 + 1 };
01851         drawGenericPrimitive(data, 8, primitive);
01852     } else {
01853         float top[] =    { x1, y1, x2 + 1, y1, x1, y1 + 1, x2 + 1, y1 + 1 };
01854         float right[] =  { x2, y1, x2 + 1, y1, x2, y2 + 1, x2 + 1, y2 + 1 };
01855         float bottom[] = { x1, y2, x2 + 1, y2, x1, y2 + 1, x2 + 1, y2 + 1 };
01856         float left[] =   { x1, y1, x1 + 1, y1, x1, y2 + 1, x1 + 1, y2 + 1 };
01857         drawGenericPrimitive(top, 8, primitive);
01858         drawGenericPrimitive(right, 8, primitive);
01859         drawGenericPrimitive(bottom, 8, primitive);
01860         drawGenericPrimitive(left, 8, primitive);
01861     }
01862 
01863 }
01864 
01865 void GfxOpenGLS::drawLine(const PrimitiveObject *primitive) {
01866     float x1 = primitive->getP1().x * _scaleW;
01867     float y1 = primitive->getP1().y * _scaleH;
01868     float x2 = primitive->getP2().x * _scaleW;
01869     float y2 = primitive->getP2().y * _scaleH;
01870 
01871     float data[] = { x1, y1, x2, y2 };
01872 
01873     drawGenericPrimitive(data, 4, primitive);
01874 }
01875 
01876 void GfxOpenGLS::drawPolygon(const PrimitiveObject *primitive) {
01877     float x1 = primitive->getP1().x * _scaleW;
01878     float y1 = primitive->getP1().y * _scaleH;
01879     float x2 = primitive->getP2().x * _scaleW;
01880     float y2 = primitive->getP2().y * _scaleH;
01881     float x3 = primitive->getP3().x * _scaleW;
01882     float y3 = primitive->getP3().y * _scaleH;
01883     float x4 = primitive->getP4().x * _scaleW;
01884     float y4 = primitive->getP4().y * _scaleH;
01885 
01886     const float data[] = { x1, y1, x2 + 1, y2 + 1, x3, y3 + 1, x4 + 1, y4 };
01887 
01888     drawGenericPrimitive(data, 8, primitive);
01889 }
01890 
01891 void GfxOpenGLS::prepareMovieFrame(Graphics::Surface* frame) {
01892     int width = frame->w;
01893     int height = frame->h;
01894     const byte *bitmap = (const byte *)frame->getPixels();
01895 
01896     GLenum frameType, frameFormat;
01897 
01898     // GLES2 support is needed here, so:
01899     // - frameFormat GL_BGRA is not supported, so use GL_RGBA
01900     // - no format conversion, so same format is used for internal storage, so swizzle in shader
01901     // - GL_UNSIGNED_INT_8_8_8_8[_REV] do not exist, so use _BYTE and fix
01902     //   endianness in shader.
01903     if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0) || frame->format == Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0)) {
01904         // frame->format: GBRA
01905         // read in little endian: {A, R, G, B}, swap: {B, G, R, A}, swizzle: {R, G, B, A}
01906         // read in big endian: {B, G, R, A}, swizzle: {R, G, B, A}
01907         frameType = GL_UNSIGNED_BYTE;
01908         frameFormat = GL_RGBA;
01909         _smushSwizzle = true;
01910 #ifdef SCUMM_LITTLE_ENDIAN
01911         _smushSwap = true;
01912 #else
01913         _smushSwap = false;
01914 #endif
01915 
01916     } else if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0) || frame->format == Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)) {
01917         // frame->format: ARGB
01918         // read in little endian: {B, G, R, A}, swizzle: {R, G, B, A}
01919         // read in big endian: {A, R, G, B}, swap: {B, G, R, A}, swizzle: {R, G, B, A}
01920         frameType = GL_UNSIGNED_BYTE;
01921         frameFormat = GL_RGBA;
01922         _smushSwizzle = true;
01923 #ifdef SCUMM_LITTLE_ENDIAN
01924         _smushSwap = false;
01925 #else
01926         _smushSwap = true;
01927 #endif
01928     } else if (frame->format == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
01929         frameType = GL_UNSIGNED_SHORT_5_6_5;
01930         frameFormat = GL_RGB;
01931         _smushSwizzle = false;
01932         _smushSwap = false;
01933     } else {
01934         error("Unknown pixelformat: Bpp: %d RBits: %d GBits: %d BBits: %d ABits: %d RShift: %d GShift: %d BShift: %d AShift: %d",
01935             frame->format.bytesPerPixel,
01936             -(frame->format.rLoss - 8),
01937             -(frame->format.gLoss - 8),
01938             -(frame->format.bLoss - 8),
01939             -(frame->format.aLoss - 8),
01940             frame->format.rShift,
01941             frame->format.gShift,
01942             frame->format.bShift,
01943             frame->format.aShift);
01944     }
01945 
01946     // create texture
01947     if (_smushTexId == 0) {
01948         glGenTextures(1, &_smushTexId);
01949     }
01950     glBindTexture(GL_TEXTURE_2D, _smushTexId);
01951     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01952     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01953     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01954     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01955     glTexImage2D(GL_TEXTURE_2D, 0, frameFormat, nextHigher2(width), nextHigher2(height), 0, frameFormat, frameType, NULL);
01956 
01957     glPixelStorei(GL_UNPACK_ALIGNMENT, frame->format.bytesPerPixel);
01958     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, frameFormat, frameType, bitmap);
01959     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01960 
01961     _smushWidth = (int)(width);
01962     _smushHeight = (int)(height);
01963 }
01964 
01965 void GfxOpenGLS::drawMovieFrame(int offsetX, int offsetY) {
01966     _smushProgram->use();
01967     glDisable(GL_DEPTH_TEST);
01968 
01969     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01970     _smushProgram->setUniform("texcrop", Math::Vector2d(float(_smushWidth) / nextHigher2(_smushWidth), float(_smushHeight) / nextHigher2(_smushHeight)));
01971     _smushProgram->setUniform("scale", Math::Vector2d(float(_smushWidth)/ float(_gameWidth), float(_smushHeight) / float(_gameHeight)));
01972     _smushProgram->setUniform("offset", Math::Vector2d(float(offsetX) / float(_gameWidth), float(offsetY) / float(_gameHeight)));
01973     _smushProgram->setUniform("swap", _smushSwap);
01974     _smushProgram->setUniform("swizzle", _smushSwizzle);
01975     glBindTexture(GL_TEXTURE_2D, _smushTexId);
01976 
01977     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01978 
01979     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01980     glEnable(GL_DEPTH_TEST);
01981 }
01982 
01983 
01984 void GfxOpenGLS::releaseMovieFrame() {
01985     if (_smushTexId > 0) {
01986         glDeleteTextures(1, &_smushTexId);
01987         _smushTexId = 0;
01988     }
01989 }
01990 
01991 
01992 const char *GfxOpenGLS::getVideoDeviceName() {
01993     return "OpenGLS Renderer";
01994 }
01995 
01996 void GfxOpenGLS::renderBitmaps(bool render) {
01997 
01998 }
01999 
02000 void GfxOpenGLS::renderZBitmaps(bool render) {
02001 
02002 }
02003 
02004 
02005 void GfxOpenGLS::createEMIModel(EMIModel *model) {
02006     EMIModelUserData *mud = new EMIModelUserData;
02007     model->_userData = mud;
02008     mud->_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_vertices, GL_STREAM_DRAW);
02009 
02010     mud->_normalsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_normals, GL_STREAM_DRAW);
02011 
02012     mud->_texCoordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 2 * sizeof(float), model->_texVerts, GL_STATIC_DRAW);
02013 
02014     mud->_colorMapVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 4 * sizeof(byte), model->_colorMap, GL_STATIC_DRAW);
02015 
02016     OpenGL::Shader * actorShader = _actorProgram->clone();
02017     actorShader->enableVertexAttribute("position", mud->_verticesVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
02018     actorShader->enableVertexAttribute("normal", mud->_normalsVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
02019     actorShader->enableVertexAttribute("texcoord", mud->_texCoordsVBO, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
02020     actorShader->enableVertexAttribute("color", mud->_colorMapVBO, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(byte), 0);
02021     mud->_shader = actorShader;
02022 
02023     for (uint32 i = 0; i < model->_numFaces; ++i) {
02024         EMIMeshFace * face = &model->_faces[i];
02025         face->_indicesEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, face->_faceLength * 3 * sizeof(uint32), face->_indexes, GL_STATIC_DRAW);
02026     }
02027 
02028     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
02029 }
02030 
02031 void GfxOpenGLS::destroyEMIModel(EMIModel *model) {
02032     for (uint32 i = 0; i < model->_numFaces; ++i) {
02033         EMIMeshFace *face = &model->_faces[i];
02034         OpenGL::Shader::freeBuffer(face->_indicesEBO);
02035         face->_indicesEBO = 0;
02036     }
02037 
02038     EMIModelUserData *mud = static_cast<EMIModelUserData *>(model->_userData);
02039 
02040     if (mud) {
02041         OpenGL::Shader::freeBuffer(mud->_verticesVBO);
02042         OpenGL::Shader::freeBuffer(mud->_normalsVBO);
02043         OpenGL::Shader::freeBuffer(mud->_texCoordsVBO);
02044         OpenGL::Shader::freeBuffer(mud->_colorMapVBO);
02045 
02046         delete mud->_shader;
02047         delete mud;
02048     }
02049 
02050     model->_userData = nullptr;
02051 }
02052 
02053 void GfxOpenGLS::createMesh(Mesh *mesh) {
02054     Common::Array<GrimVertex> meshInfo;
02055     meshInfo.reserve(mesh->_numVertices * 5);
02056     for (int i = 0; i < mesh->_numFaces; ++i) {
02057         MeshFace *face = &mesh->_faces[i];
02058         face->_userData = new uint32;
02059         *(uint32 *)face->_userData = meshInfo.size();
02060 
02061         if (face->getNumVertices() < 3)
02062             continue;
02063 
02064 #define VERT(j) (&mesh->_vertices[3 * face->getVertex(j)])
02065 #define TEXVERT(j) (face->hasTexture() ? &mesh->_textureVerts[2 * face->getTextureVertex(j)] : zero_texVerts)
02066 #define NORMAL(j) (&mesh->_vertNormals[3 * face->getVertex(j)])
02067 
02068         for (int j = 2; j < face->getNumVertices(); ++j) {
02069             meshInfo.push_back(GrimVertex(VERT(0), TEXVERT(0), NORMAL(0)));
02070             meshInfo.push_back(GrimVertex(VERT(j - 1), TEXVERT(j - 1), NORMAL(j - 1)));
02071             meshInfo.push_back(GrimVertex(VERT(j), TEXVERT(j), NORMAL(j)));
02072         }
02073 
02074 #undef VERT
02075 #undef TEXVERT
02076 #undef NORMAL
02077 
02078     }
02079 
02080     if (meshInfo.empty()) {
02081         mesh->_userData = NULL;
02082         return;
02083     }
02084 
02085     ModelUserData *mud = new ModelUserData;
02086     mesh->_userData = mud;
02087 
02088     mud->_meshInfoVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, meshInfo.size() * sizeof(GrimVertex), &meshInfo[0], GL_STATIC_DRAW);
02089 
02090     OpenGL::Shader *shader = _actorProgram->clone();
02091     mud->_shader = shader;
02092     shader->enableVertexAttribute("position", mud->_meshInfoVBO, 3, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 0);
02093     shader->enableVertexAttribute("texcoord", mud->_meshInfoVBO, 2, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 3 * sizeof(float));
02094     shader->enableVertexAttribute("normal", mud->_meshInfoVBO, 3, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 5 * sizeof(float));
02095     shader->disableVertexAttribute("color", Math::Vector4d(1.f, 1.f, 1.f, 1.f));
02096 }
02097 
02098 void GfxOpenGLS::destroyMesh(const Mesh *mesh) {
02099     ModelUserData *mud = static_cast<ModelUserData *>(mesh->_userData);
02100 
02101     for (int i = 0; i < mesh->_numFaces; ++i) {
02102         MeshFace *face = &mesh->_faces[i];
02103         if (face->_userData) {
02104             uint32 *data = static_cast<uint32 *>(face->_userData);
02105             delete data;
02106         }
02107     }
02108 
02109     if (!mud)
02110         return;
02111 
02112     delete mud->_shader;
02113     delete mud;
02114 }
02115 
02116 static void readPixels(int x, int y, int width, int height, byte *buffer) {
02117     byte *p = buffer;
02118     for (int i = y; i < y + height; i++) {
02119         glReadPixels(x, 479 - i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, p);
02120         p += width * 4;
02121     }
02122 }
02123 
02124 Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) {
02125     Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
02126 #ifndef USE_GLES2
02127     if (useStored) {
02128         glBindTexture(GL_TEXTURE_2D, _storedDisplay);
02129         char *buffer = new char[_screenWidth * _screenHeight * 4];
02130 
02131         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
02132         byte *rawBuf = src.getRawBuffer();
02133         for (int i = 0; i < _screenHeight; i++) {
02134             memcpy(&(rawBuf[(_screenHeight - i - 1) * _screenWidth * 4]), &buffer[4 * _screenWidth * i], _screenWidth * 4);
02135         }
02136         delete[] buffer;
02137     } else
02138 #endif
02139     {
02140         readPixels(0, 0, _screenWidth, _screenHeight, src.getRawBuffer());
02141     }
02142     return createScreenshotBitmap(src, w, h, true);
02143 }
02144 
02145 void GfxOpenGLS::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
02146     readPixels(x, y, width, height, data);
02147     createSpecialtyTexture(id, data, width, height);
02148 }
02149 
02150 void GfxOpenGLS::setBlendMode(bool additive) {
02151     if (additive) {
02152         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
02153     } else {
02154         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02155     }
02156 }
02157 
02158 }
02159 
02160 #endif


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