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

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


Generated on Sat Mar 23 2019 05:01:40 for ResidualVM by doxygen 1.7.1
curved edge   curved edge