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


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