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("isBillboard", GL_TRUE);
01070     _spriteProgram->setUniform("lightsEnabled", false);
01071     if (g_grim->getGameType() == GType_GRIM) {
01072         _spriteProgram->setUniform1f("alphaRef", 0.5f);
01073     } else if (sprite->_flags2 & Sprite::AlphaTest) {
01074         _spriteProgram->setUniform1f("alphaRef", 0.1f);
01075     } else {
01076         _spriteProgram->setUniform1f("alphaRef", 0.0f);
01077     }
01078 
01079     // FIXME: Currently vertex-specific colors are not supported for sprites.
01080     // It is unknown at this time if this is really needed anywhere.
01081     Math::Vector4d color(sprite->_red[0] / 255.0f, sprite->_green[0] / 255.0f, sprite->_blue[0] / 255.0f, sprite->_alpha[0] / 255.0f);
01082     _spriteProgram->setUniform("uniformColor", color);
01083 
01084     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01085     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01086     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01087     glEnable(GL_DEPTH_TEST);
01088     glDepthMask(GL_TRUE);
01089     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01090 }
01091 
01092 void GfxOpenGLS::enableLights() {
01093     _lightsEnabled = true;
01094 }
01095 
01096 void GfxOpenGLS::disableLights() {
01097     _lightsEnabled = false;
01098 }
01099 
01100 void GfxOpenGLS::setupLight(Grim::Light *light, int lightId) {
01101     _lightsEnabled = true;
01102 
01103     if (lightId >= _maxLights) {
01104         return;
01105     }
01106 
01107     // Disable previous lights.
01108     if (lightId == 0) {
01109         _hasAmbientLight = false;
01110         for (int id = 0; id < _maxLights; ++id)
01111             _lights[id]._color.w() = 0.0;
01112     }
01113 
01114     Math::Vector4d &lightColor  = _lights[lightId]._color;
01115     Math::Vector4d &lightPos    = _lights[lightId]._position;
01116     Math::Vector4d &lightDir    = _lights[lightId]._direction;
01117     Math::Vector4d &lightParams = _lights[lightId]._params;
01118 
01119     lightColor.x() = (float)light->_color.getRed();
01120     lightColor.y() = (float)light->_color.getGreen();
01121     lightColor.z() = (float)light->_color.getBlue();
01122     lightColor.w() = light->_scaledintensity;
01123 
01124     if (light->_type == Grim::Light::Omni) {
01125         lightPos = Math::Vector4d(light->_pos.x(), light->_pos.y(), light->_pos.z(), 1.0f);
01126         lightDir = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01127         lightParams = Math::Vector4d(light->_falloffNear, light->_falloffFar, 0.0f, 0.0f);
01128     } else if (light->_type == Grim::Light::Direct) {
01129         lightPos = Math::Vector4d(-light->_dir.x(), -light->_dir.y(), -light->_dir.z(), 0.0f);
01130         lightDir = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01131     } else if (light->_type == Grim::Light::Spot) {
01132         lightPos = Math::Vector4d(light->_pos.x(), light->_pos.y(), light->_pos.z(), 1.0f);
01133         lightDir = Math::Vector4d(light->_dir.x(), light->_dir.y(), light->_dir.z(), 1.0f);
01134         lightParams = Math::Vector4d(light->_falloffNear, light->_falloffFar, light->_cospenumbraangle, light->_cosumbraangle);
01135     } else if (light->_type == Grim::Light::Ambient) {
01136         lightPos = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01137         lightDir = Math::Vector4d(0.0f, 0.0f, 0.0f, -1.0f);
01138         _hasAmbientLight = true;
01139     }
01140 }
01141 
01142 void GfxOpenGLS::turnOffLight(int lightId) {
01143     if (lightId >= _maxLights) {
01144         return;
01145     }
01146 
01147     _lights[lightId]._color = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
01148     _lights[lightId]._position = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
01149     _lights[lightId]._direction = Math::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
01150 }
01151 
01152 
01153 void GfxOpenGLS::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
01154     texture->_texture = new GLuint[1];
01155     glGenTextures(1, (GLuint *)texture->_texture);
01156     char *texdata = new char[texture->_width * texture->_height * 4];
01157     char *texdatapos = texdata;
01158 
01159     if (cmap != NULL) { // EMI doesn't have colour-maps
01160         int bytes = 4;
01161         for (int y = 0; y < texture->_height; y++) {
01162             for (int x = 0; x < texture->_width; x++) {
01163                 uint8 col = *(const uint8 *)(data);
01164                 if (col == 0) {
01165                     memset(texdatapos, 0, bytes); // transparent
01166                     if (!texture->_hasAlpha) {
01167                         texdatapos[3] = '\xff'; // fully opaque
01168                     }
01169                 } else {
01170                     memcpy(texdatapos, cmap->_colors + 3 * (col), 3);
01171                     texdatapos[3] = '\xff'; // fully opaque
01172                 }
01173                 texdatapos += bytes;
01174                 data++;
01175             }
01176         }
01177     } else {
01178         memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
01179     }
01180 
01181     GLuint format = 0;
01182     GLuint internalFormat = 0;
01183     if (texture->_colorFormat == BM_RGBA) {
01184         format = GL_RGBA;
01185         internalFormat = GL_RGBA;
01186     } else if (texture->_colorFormat == BM_BGRA) {
01187 #ifdef USE_GLES2
01188         format = GL_RGBA;
01189         internalFormat = GL_RGBA;
01190 #else
01191         format = GL_BGRA;
01192         internalFormat = GL_RGBA;
01193 #endif
01194     } else { // The only other colorFormat we load right now is BGR
01195 #ifdef USE_GLES2
01196         format = GL_RGB;
01197         internalFormat = GL_RGB;
01198 #else
01199         format = GL_BGR;
01200         internalFormat = GL_RGBA;
01201 #endif
01202     }
01203 
01204     GLuint *textures = (GLuint *)texture->_texture;
01205     glBindTexture(GL_TEXTURE_2D, textures[0]);
01206 
01207     // Remove darkened lines in EMI intro
01208     if (g_grim->getGameType() == GType_MONKEY4 && clamp) {
01209         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01210         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01211     } else {
01212         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
01213         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
01214     }
01215 
01216     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01217     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01218     glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, texture->_width, texture->_height, 0, format, GL_UNSIGNED_BYTE, texdata);
01219     delete[] texdata;
01220 }
01221 
01222 void GfxOpenGLS::selectTexture(const Texture *texture) {
01223     GLuint *textures = (GLuint *)texture->_texture;
01224     glBindTexture(GL_TEXTURE_2D, textures[0]);
01225 
01226     if (texture->_hasAlpha && g_grim->getGameType() == GType_MONKEY4) {
01227         glEnable(GL_BLEND);
01228     }
01229 
01230     _selectedTexture = const_cast<Texture *>(texture);
01231 }
01232 
01233 void GfxOpenGLS::destroyTexture(Texture *texture) {
01234     GLuint *textures = static_cast<GLuint *>(texture->_texture);
01235     if (textures) {
01236         glDeleteTextures(1, textures);
01237         delete[] textures;
01238     }
01239 }
01240 
01241 void GfxOpenGLS::createBitmap(BitmapData *bitmap) {
01242     if (bitmap->_format != 1) {
01243         for (int pic = 0; pic < bitmap->_numImages; pic++) {
01244             uint16 *zbufPtr = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
01245             for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
01246                 uint16 val = READ_LE_UINT16(zbufPtr + i);
01247                 // fix the value if it is incorrectly set to the bitmap transparency color
01248                 if (val == 0xf81f) {
01249                     val = 0;
01250                 }
01251                 zbufPtr[i] = 0xffff - ((uint32)val) * 0x10000 / 100 / (0x10000 - val);
01252             }
01253         }
01254     }
01255 
01256     bitmap->_hasTransparency = false;
01257     if (bitmap->_format == 1) {
01258         bitmap->_numTex = 1;
01259         GLuint *textures = new GLuint[bitmap->_numTex * bitmap->_numImages];
01260         bitmap->_texIds = textures;
01261         glGenTextures(bitmap->_numTex * bitmap->_numImages, textures);
01262 
01263         byte *texData = 0;
01264         byte *texOut = 0;
01265 
01266         GLint format = GL_RGBA;
01267         GLint type = GL_UNSIGNED_BYTE;
01268         int bytes = 4;
01269 
01270         glPixelStorei(GL_UNPACK_ALIGNMENT, bytes);
01271 
01272         for (int pic = 0; pic < bitmap->_numImages; pic++) {
01273             if (bitmap->_format == 1 && bitmap->_bpp == 16 && bitmap->_colorFormat != BM_RGB1555) {
01274                 if (texData == 0)
01275                     texData = new byte[bytes * bitmap->_width * bitmap->_height];
01276                 // Convert data to 32-bit RGBA format
01277                 byte *texDataPtr = texData;
01278                 uint16 *bitmapData = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
01279                 for (int i = 0; i < bitmap->_width * bitmap->_height; i++, texDataPtr += bytes, bitmapData++) {
01280                     uint16 pixel = *bitmapData;
01281                     int r = pixel >> 11;
01282                     texDataPtr[0] = (r << 3) | (r >> 2);
01283                     int g = (pixel >> 5) & 0x3f;
01284                     texDataPtr[1] = (g << 2) | (g >> 4);
01285                     int b = pixel & 0x1f;
01286                     texDataPtr[2] = (b << 3) | (b >> 2);
01287                     if (pixel == 0xf81f) { // transparent
01288                         texDataPtr[3] = 0;
01289                         bitmap->_hasTransparency = true;
01290                     } else {
01291                         texDataPtr[3] = 255;
01292                     }
01293                 }
01294                 texOut = texData;
01295             } else if (bitmap->_format == 1 && bitmap->_colorFormat == BM_RGB1555) {
01296                 bitmap->convertToColorFormat(pic, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
01297                 texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
01298             } else {
01299                 texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
01300             }
01301 
01302             int actualWidth = nextHigher2(bitmap->_width);
01303             int actualHeight = nextHigher2(bitmap->_height);
01304 
01305             glBindTexture(GL_TEXTURE_2D, textures[bitmap->_numTex * pic]);
01306             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01307             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01308             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01309             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01310             glTexImage2D(GL_TEXTURE_2D, 0, format, actualWidth, actualHeight, 0, format, type, NULL);
01311 
01312             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->_width, bitmap->_height, format, type, texOut);
01313         }
01314 
01315         if (texData)
01316             delete[] texData;
01317         bitmap->freeData();
01318 
01319         OpenGL::Shader *shader = _backgroundProgram->clone();
01320         bitmap->_userData = shader;
01321 
01322         if (g_grim->getGameType() == GType_MONKEY4) {
01323             GLuint vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, bitmap->_numCoords * 4 * sizeof(float), bitmap->_texc, GL_STATIC_DRAW);
01324             shader->enableVertexAttribute("position", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
01325             shader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2*sizeof(float));
01326         }
01327     } else {
01328         bitmap->_numTex = 0;
01329         bitmap->_texIds = NULL;
01330         bitmap->_userData = NULL;
01331     }
01332 }
01333 
01334 void GfxOpenGLS::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer) {
01335     if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
01336         BitmapData *data = bitmap->_data;
01337         OpenGL::Shader *shader = (OpenGL::Shader *)data->_userData;
01338         GLuint *textures = (GLuint *)bitmap->getTexIds();
01339 
01340         glDisable(GL_DEPTH_TEST);
01341 
01342         glEnable(GL_BLEND);
01343         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01344 
01345         shader->use();
01346         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01347         assert(layer < data->_numLayers);
01348         uint32 offset = data->_layers[layer]._offset;
01349         for (uint32 i = offset; i < offset + data->_layers[layer]._numImages; ++i) {
01350             glBindTexture(GL_TEXTURE_2D, textures[data->_verts[i]._texid]);
01351 
01352             unsigned short startVertex = data->_verts[i]._pos / 4 * 6;
01353             unsigned short numVertices = data->_verts[i]._verts / 4 * 6;
01354             glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_SHORT, (void *)(startVertex * sizeof(unsigned short)));
01355         }
01356         return;
01357     }
01358 
01359     int format = bitmap->getFormat();
01360     if ((format == 1 && !_renderBitmaps) || (format == 5 && !_renderZBitmaps)) {
01361         return;
01362     }
01363 
01364     if (format == 1) {
01365         GLuint *textures = (GLuint *)bitmap->getTexIds();
01366         if (bitmap->getFormat() == 1 && bitmap->getHasTransparency()) {
01367             glEnable(GL_BLEND);
01368             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01369         } else {
01370             glDisable(GL_BLEND);
01371         }
01372 
01373         OpenGL::Shader *shader = (OpenGL::Shader *)bitmap->_data->_userData;
01374         shader->use();
01375         glDisable(GL_DEPTH_TEST);
01376         glDepthMask(GL_FALSE);
01377 
01378         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01379         int cur_tex_idx = bitmap->getNumTex() * (bitmap->getActiveImage() - 1);
01380         glBindTexture(GL_TEXTURE_2D, textures[cur_tex_idx]);
01381         float width = bitmap->getWidth();
01382         float height = bitmap->getHeight();
01383         shader->setUniform("offsetXY", Math::Vector2d(float(dx) / _gameWidth, float(dy) / _gameHeight));
01384         shader->setUniform("sizeWH", Math::Vector2d(width / _gameWidth, height / _gameHeight));
01385         shader->setUniform("texcrop", Math::Vector2d(width / nextHigher2((int)width), height / nextHigher2((int)height)));
01386         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01387 
01388         glDisable(GL_BLEND);
01389         glDepthMask(GL_TRUE);
01390         glEnable(GL_DEPTH_TEST);
01391     } else {
01392         // Only draw the manual zbuffer when enabled
01393         if (bitmap->getActiveImage() - 1 < bitmap->getNumImages()) {
01394             drawDepthBitmap(dx, dy, bitmap->getWidth(), bitmap->getHeight(), (char *)bitmap->getData(bitmap->getActiveImage() - 1).getRawBuffer());
01395         } else {
01396             warning("zbuffer image has index out of bounds! %d/%d", bitmap->getActiveImage(), bitmap->getNumImages());
01397         }
01398         return;
01399     }
01400 }
01401 
01402 void GfxOpenGLS::drawDepthBitmap(int x, int y, int w, int h, char *data) {
01403     static int prevX = -1, prevY = -1;
01404     static char *prevData = NULL;
01405 
01406     if (prevX == x && prevY == y && data == prevData)
01407         return;
01408 
01409     prevX = x;
01410     prevY = y;
01411     prevData = data;
01412 
01413     glActiveTexture(GL_TEXTURE1);
01414     glBindTexture(GL_TEXTURE_2D, _zBufTex);
01415     glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // 16 bit Z depth bitmap
01416     glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
01417     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01418     glActiveTexture(GL_TEXTURE0);
01419 }
01420 
01421 void GfxOpenGLS::destroyBitmap(BitmapData *bitmap) {
01422     GLuint *textures = (GLuint *)bitmap->_texIds;
01423     if (textures) {
01424         glDeleteTextures(bitmap->_numTex * bitmap->_numImages, textures);
01425         delete[] textures;
01426         bitmap->_texIds = 0;
01427     }
01428     OpenGL::Shader *shader = (OpenGL::Shader *)bitmap->_userData;
01429     if (g_grim->getGameType() == GType_MONKEY4) {
01430         glDeleteBuffers(1, &shader->getAttributeAt(0)._vbo);
01431     }
01432     delete shader;
01433 
01434     if (bitmap->_format != 1) {
01435         bitmap->freeData();
01436     }
01437 }
01438 
01439 void GfxOpenGLS::createFont(Font *font) {
01440     const byte *bitmapData = font->getFontData();
01441     uint dataSize = font->getDataSize();
01442 
01443     uint8 bpp = 4;
01444     uint8 charsWide = 16;
01445     uint8 charsHigh = 16;
01446 
01447     byte *texDataPtr = new byte[dataSize * bpp];
01448     byte *data = texDataPtr;
01449 
01450     for (uint i = 0; i < dataSize; i++, texDataPtr += bpp, bitmapData++) {
01451         byte pixel = *bitmapData;
01452         if (pixel == 0x00) {
01453             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 0;
01454         } else if (pixel == 0x80) {
01455             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = 0;
01456             texDataPtr[3] = 255;
01457         } else if (pixel == 0xFF) {
01458             texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 255;
01459         }
01460     }
01461     int size = 0;
01462     for (int i = 0; i < 256; ++i) {
01463         int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
01464         int m = MAX(width, height);
01465         if (m > size)
01466             size = m;
01467     }
01468     assert(size < 64);
01469     if (size < 8)
01470         size = 8;
01471     if (size < 16)
01472         size = 16;
01473     else if (size < 32)
01474         size = 32;
01475     else if (size < 64)
01476         size = 64;
01477 
01478     uint arraySize = size * size * bpp * charsWide * charsHigh;
01479     byte *temp = new byte[arraySize];
01480 
01481     memset(temp, 0, arraySize);
01482 
01483     FontUserData *userData = new FontUserData;
01484     font->setUserData(userData);
01485     userData->texture = 0;
01486     userData->size = size;
01487 
01488     GLuint *texture = &(userData->texture);
01489     glGenTextures(1, texture);
01490 
01491     for (int i = 0, row = 0; i < 256; ++i) {
01492         int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
01493         int32 d = font->getCharOffset(i);
01494         for (int x = 0; x < height; ++x) {
01495             // a is the offset to get to the correct row.
01496             // b is the offset to get to the correct line in the character.
01497             // c is the offset of the character from the start of the row.
01498             uint a = row * size * size * bpp * charsHigh;
01499             uint b = x * size * charsWide * bpp;
01500             uint c = 0;
01501             if (i != 0)
01502                 c = ((i - 1) % 16) * size * bpp;
01503 
01504             uint pos = a + b + c;
01505             uint pos2 = d * bpp + x * width * bpp;
01506             assert(pos + width * bpp <= arraySize);
01507             assert(pos2 + width * bpp <= dataSize * bpp);
01508             memcpy(temp + pos, data + pos2, width * bpp);
01509         }
01510         if (i != 0 && i % charsWide == 0)
01511             ++row;
01512     }
01513 
01514     glBindTexture(GL_TEXTURE_2D, texture[0]);
01515     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01516     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01517     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01518     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01519     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size * charsWide, size * charsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
01520 
01521     delete[] data;
01522     delete[] temp;
01523 }
01524 
01525 void GfxOpenGLS::destroyFont(Font *font) {
01526     const FontUserData *data = (const FontUserData *)font->getUserData();
01527     if (data) {
01528         glDeleteTextures(1, &(data->texture));
01529         delete data;
01530     }
01531 }
01532 
01533 void GfxOpenGLS::createTextObject(TextObject *text) {
01534     const Color &color = text->getFGColor();
01535     const Font *font = text->getFont();
01536 
01537     const FontUserData *userData = (const FontUserData *)font->getUserData();
01538     if (!userData)
01539         error("Could not get font userdata");
01540 
01541     float sizeW = float(userData->size) / _gameWidth;
01542     float sizeH = float(userData->size) / _gameHeight;
01543     const Common::String *lines = text->getLines();
01544     int numLines = text->getNumLines();
01545 
01546     int numCharacters = 0;
01547     for (int j = 0; j < numLines; ++j) {
01548         numCharacters += lines[j].size();
01549     }
01550 
01551     float *bufData = new float[numCharacters * 16];
01552     float *cur = bufData;
01553 
01554     for (int j = 0; j < numLines; ++j) {
01555         const Common::String &line = lines[j];
01556         int x = text->getLineX(j);
01557         int y = text->getLineY(j);
01558         for (uint i = 0; i < line.size(); ++i) {
01559             uint8 character = line[i];
01560             float w = y + font->getCharStartingLine(character);
01561             if (g_grim->getGameType() == GType_GRIM)
01562                 w += font->getBaseOffsetY();
01563             float z = x + font->getCharStartingCol(character);
01564             z /= _gameWidth;
01565             w /= _gameHeight;
01566             float width = 1 / 16.f;
01567             float cx = ((character - 1) % 16) / 16.0f;
01568             float cy = ((character - 1) / 16) / 16.0f;
01569 
01570             float charData[] = {
01571                     z, w, cx, cy,
01572                     z + sizeW, w, cx + width, cy,
01573                     z + sizeW, w + sizeH, cx + width, cy + width,
01574                     z, w + sizeH, cx, cy + width
01575             };
01576             memcpy(cur, charData, 16 * sizeof(float));
01577             cur += 16;
01578 
01579             x += font->getCharKernedWidth(character);
01580         }
01581     }
01582     GLuint vbo;
01583     if (text->isBlastDraw()) {
01584         vbo = _blastVBO;
01585         glBindBuffer(GL_ARRAY_BUFFER, vbo);
01586         glBufferSubData(GL_ARRAY_BUFFER, 0, numCharacters * 16 * sizeof(float), bufData);
01587     } else {
01588         vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, numCharacters * 16 * sizeof(float), bufData, GL_STATIC_DRAW);
01589     }
01590 
01591     OpenGL::Shader * textShader = _textProgram->clone();
01592     glBindBuffer(GL_ARRAY_BUFFER, vbo);
01593 
01594     textShader->enableVertexAttribute("position", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
01595     textShader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
01596 
01597     TextUserData * td = new TextUserData;
01598     td->characters = numCharacters;
01599     td->shader = textShader;
01600     td->color = color;
01601     td->texture = userData->texture;
01602     text->setUserData(td);
01603     delete[] bufData;
01604 }
01605 
01606 void GfxOpenGLS::drawTextObject(const TextObject *text) {
01607     glEnable(GL_BLEND);
01608     glDisable(GL_DEPTH_TEST);
01609     const TextUserData * td = (const TextUserData *) text->getUserData();
01610     assert(td);
01611     td->shader->use();
01612 
01613     Math::Vector3d colors(float(td->color.getRed()) / 255.0f,
01614                           float(td->color.getGreen()) / 255.0f,
01615                           float(td->color.getBlue()) / 255.0f);
01616     _textProgram->setUniform("color", colors);
01617     glBindTexture(GL_TEXTURE_2D, td->texture);
01618     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01619     glDrawElements(GL_TRIANGLES, td->characters * 6, GL_UNSIGNED_SHORT, 0);
01620     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01621     glEnable(GL_DEPTH_TEST);
01622 }
01623 
01624 void GfxOpenGLS::destroyTextObject(TextObject *text) {
01625     const TextUserData * td = (const TextUserData *) text->getUserData();
01626     if (!text->isBlastDraw()) {
01627         glDeleteBuffers(1, &td->shader->getAttributeAt(0)._vbo);
01628     }
01629     text->setUserData(NULL);
01630 
01631     delete td->shader;
01632     delete td;
01633 }
01634 
01635 void GfxOpenGLS::storeDisplay() {
01636     glBindTexture(GL_TEXTURE_2D, _storedDisplay);
01637     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _screenWidth, _screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
01638     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01639     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01640     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, _screenWidth, _screenHeight, 0);
01641 }
01642 
01643 void GfxOpenGLS::copyStoredToDisplay() {
01644     if (!_dimProgram)
01645         return;
01646 
01647     _dimProgram->use();
01648     _dimProgram->setUniform("scaleWH", Math::Vector2d(1.f, 1.f));
01649     _dimProgram->setUniform("tex", 0);
01650 
01651     glBindTexture(GL_TEXTURE_2D, _storedDisplay);
01652 
01653     glDisable(GL_DEPTH_TEST);
01654     glDepthMask(GL_FALSE);
01655 
01656     glDrawArrays(GL_TRIANGLES, 0, 6);
01657 
01658     glEnable(GL_DEPTH_TEST);
01659     glDepthMask(GL_TRUE);
01660 }
01661 
01662 void GfxOpenGLS::dimScreen() {
01663 
01664 }
01665 
01666 void GfxOpenGLS::dimRegion(int xin, int yReal, int w, int h, float level) {
01667     xin = (int)(xin * _scaleW);
01668     yReal = (int)(yReal * _scaleH);
01669     w = (int)(w * _scaleW);
01670     h = (int)(h * _scaleH);
01671     int yin = _screenHeight - yReal - h;
01672 
01673     GLuint texture;
01674     glGenTextures(1, &texture);
01675     glBindTexture(GL_TEXTURE_2D, texture);
01676 
01677     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
01678     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01679     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01680 
01681     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xin, yin, w, h, 0);
01682 
01683     glBindBuffer(GL_ARRAY_BUFFER, _dimRegionVBO);
01684 
01685     float width = w;
01686     float height = h;
01687     float x = xin;
01688     float y = yin;
01689     float points[24] = {
01690         x, y, 0.0f, 0.0f,
01691         x + width, y, 1.0f, 0.0f,
01692         x + width, y + height, 1.0f, 1.0f,
01693         x + width, y + height, 1.0f, 1.0f,
01694         x, y + height, 0.0f, 1.0f,
01695         x, y, 0.0f, 0.0f,
01696     };
01697 
01698     glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * sizeof(float), points);
01699 
01700     _dimRegionProgram->use();
01701     _dimRegionProgram->setUniform("scaleWH", Math::Vector2d(1.f / _screenWidth, 1.f / _screenHeight));
01702     _dimRegionProgram->setUniform("tex", 0);
01703 
01704     glDisable(GL_DEPTH_TEST);
01705     glDepthMask(GL_FALSE);
01706 
01707     glDrawArrays(GL_TRIANGLES, 0, 6);
01708 
01709     glEnable(GL_DEPTH_TEST);
01710     glDepthMask(GL_TRUE);
01711 
01712     glDeleteTextures(1, &texture);
01713 }
01714 
01715 
01716 void GfxOpenGLS::irisAroundRegion(int x1, int y1, int x2, int y2) {
01717     _irisProgram->use();
01718     _irisProgram->setUniform("color", Math::Vector3d(0.0f, 0.0f, 0.0f));
01719     _irisProgram->setUniform("scaleWH", Math::Vector2d(1.f / _gameWidth, 1.f / _gameHeight));
01720 
01721     float fx1 = x1;
01722     float fx2 = x2;
01723     float fy1 = y1;
01724     float fy2 = y2;
01725     float width = _screenWidth;
01726     float height = _screenHeight;
01727     float points[20] = {
01728         0.0f, 0.0f,
01729         0.0f, fy1,
01730         width, 0.0f,
01731         fx2, fy1,
01732         width, height,
01733         fx2, fy2,
01734         0.0f, height,
01735         fx1, fy2,
01736         0.0f, fy1,
01737         fx1, fy1
01738     };
01739 
01740     glBindBuffer(GL_ARRAY_BUFFER, _irisVBO);
01741     glBufferSubData(GL_ARRAY_BUFFER, 0, 20 * sizeof(float), points);
01742 
01743     glDisable(GL_DEPTH_TEST);
01744     glDepthMask(GL_FALSE);
01745 
01746     glDrawArrays(GL_TRIANGLE_STRIP, 0, 10);
01747 
01748     glEnable(GL_DEPTH_TEST);
01749     glDepthMask(GL_TRUE);
01750 }
01751 
01752 
01753 void GfxOpenGLS::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
01754     if (!*text)
01755         return;
01756 
01757     glEnable(GL_BLEND);
01758     glDisable(GL_DEPTH_TEST);
01759     glBindTexture(GL_TEXTURE_2D, _emergTexture);
01760     _emergProgram->use();
01761     Math::Vector3d colors(float(fgColor.getRed()) / 255.0f,
01762                           float(fgColor.getGreen()) / 255.0f,
01763                           float(fgColor.getBlue()) / 255.0f);
01764     _emergProgram->setUniform("color", colors);
01765     _emergProgram->setUniform("sizeWH", Math::Vector2d(float(8) / _gameWidth, float(16) / _gameHeight));
01766     _emergProgram->setUniform("texScale", Math::Vector2d(float(8) / 128, float(16) / 128));
01767 
01768     for (; *text; ++text, x+=10) {
01769         int blockcol = *text & 0xf;
01770         int blockrow = *text / 16;
01771         _emergProgram->setUniform("offsetXY", Math::Vector2d(float(x) / _gameWidth, float(y) / _gameHeight));
01772         _emergProgram->setUniform("texOffsetXY", Math::Vector2d(float(blockcol * 8) / 128, float(blockrow * 16) / 128));
01773         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
01774     }
01775 }
01776 
01777 void GfxOpenGLS::loadEmergFont() {
01778     uint8 *atlas = new uint8[128 * 128];
01779     memset(atlas, 0, 128 * 128);
01780 
01781     for (int c = 32; c < 128; ++c) {
01782         int blockrow = c / 16;
01783         int blockcol = c & 0xf;
01784         for (int row = 0; row < 13; ++row) {
01785             int base = 128 * (16 * blockrow + row) + 8 * blockcol;
01786             uint8 val = Font::emerFont[c - 32][row];
01787             atlas[base + 0] = (val & 0x80) ? 255 : 0;
01788             atlas[base + 1] = (val & 0x40) ? 255 : 0;
01789             atlas[base + 2] = (val & 0x20) ? 255 : 0;
01790             atlas[base + 3] = (val & 0x10) ? 255 : 0;
01791             atlas[base + 4] = (val & 0x08) ? 255 : 0;
01792             atlas[base + 5] = (val & 0x04) ? 255 : 0;
01793             atlas[base + 6] = (val & 0x02) ? 255 : 0;
01794             atlas[base + 7] = (val & 0x01) ? 255 : 0;
01795         }
01796     }
01797 
01798     glGenTextures(1, &_emergTexture);
01799     glBindTexture(GL_TEXTURE_2D, _emergTexture);
01800     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01801     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01802     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01803     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01804     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 128, 128, 0, GL_ALPHA, GL_UNSIGNED_BYTE, atlas);
01805 
01806     delete[] atlas;
01807 }
01808 
01809 void GfxOpenGLS::drawGenericPrimitive(const float *vertices, uint32 numVertices, const PrimitiveObject *primitive) {
01810     const Color color(primitive->getColor());
01811     const Math::Vector3d colorV =
01812       Math::Vector3d(color.getRed(), color.getGreen(), color.getBlue()) / 255.f;
01813 
01814     GLuint prim = nextPrimitive();
01815     glBindBuffer(GL_ARRAY_BUFFER, prim);
01816     glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(float), vertices);
01817 
01818     glDisable(GL_DEPTH_TEST);
01819     glDepthMask(GL_FALSE);
01820 
01821     _primitiveProgram->enableVertexAttribute("position", prim, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
01822     _primitiveProgram->use(true);
01823     _primitiveProgram->setUniform("color", colorV);
01824     _primitiveProgram->setUniform("scaleWH", Math::Vector2d(1.f / _gameWidth, 1.f / _gameHeight));
01825 
01826     switch (primitive->getType()) {
01827         case PrimitiveObject::RectangleType:
01828             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
01829             break;
01830         case PrimitiveObject::LineType:
01831             glDrawArrays(GL_LINES, 0, 2);
01832             break;
01833         case PrimitiveObject::PolygonType:
01834             glDrawArrays(GL_LINES, 0, 4);
01835             break;
01836         default:
01837             // Impossible
01838             break;
01839     }
01840 
01841     glBindBuffer(GL_ARRAY_BUFFER, 0);
01842     glDepthMask(GL_TRUE);
01843     glEnable(GL_DEPTH_TEST);
01844 }
01845 
01846 void GfxOpenGLS::drawRectangle(const PrimitiveObject *primitive) {
01847     float x1 = primitive->getP1().x * _scaleW;
01848     float y1 = primitive->getP1().y * _scaleH;
01849     float x2 = primitive->getP2().x * _scaleW;
01850     float y2 = primitive->getP2().y * _scaleH;
01851 
01852     if (primitive->isFilled()) {
01853         float data[] = { x1, y1, x2 + 1, y1, x1, y2 + 1, x2 + 1, y2 + 1 };
01854         drawGenericPrimitive(data, 8, primitive);
01855     } else {
01856         float top[] =    { x1, y1, x2 + 1, y1, x1, y1 + 1, x2 + 1, y1 + 1 };
01857         float right[] =  { x2, y1, x2 + 1, y1, x2, y2 + 1, x2 + 1, y2 + 1 };
01858         float bottom[] = { x1, y2, x2 + 1, y2, x1, y2 + 1, x2 + 1, y2 + 1 };
01859         float left[] =   { x1, y1, x1 + 1, y1, x1, y2 + 1, x1 + 1, y2 + 1 };
01860         drawGenericPrimitive(top, 8, primitive);
01861         drawGenericPrimitive(right, 8, primitive);
01862         drawGenericPrimitive(bottom, 8, primitive);
01863         drawGenericPrimitive(left, 8, primitive);
01864     }
01865 
01866 }
01867 
01868 void GfxOpenGLS::drawLine(const PrimitiveObject *primitive) {
01869     float x1 = primitive->getP1().x * _scaleW;
01870     float y1 = primitive->getP1().y * _scaleH;
01871     float x2 = primitive->getP2().x * _scaleW;
01872     float y2 = primitive->getP2().y * _scaleH;
01873 
01874     float data[] = { x1, y1, x2, y2 };
01875 
01876     drawGenericPrimitive(data, 4, primitive);
01877 }
01878 
01879 void GfxOpenGLS::drawPolygon(const PrimitiveObject *primitive) {
01880     float x1 = primitive->getP1().x * _scaleW;
01881     float y1 = primitive->getP1().y * _scaleH;
01882     float x2 = primitive->getP2().x * _scaleW;
01883     float y2 = primitive->getP2().y * _scaleH;
01884     float x3 = primitive->getP3().x * _scaleW;
01885     float y3 = primitive->getP3().y * _scaleH;
01886     float x4 = primitive->getP4().x * _scaleW;
01887     float y4 = primitive->getP4().y * _scaleH;
01888 
01889     const float data[] = { x1, y1, x2 + 1, y2 + 1, x3, y3 + 1, x4 + 1, y4 };
01890 
01891     drawGenericPrimitive(data, 8, primitive);
01892 }
01893 
01894 void GfxOpenGLS::prepareMovieFrame(Graphics::Surface* frame) {
01895     int width = frame->w;
01896     int height = frame->h;
01897     const byte *bitmap = (const byte *)frame->getPixels();
01898 
01899     GLenum frameType, frameFormat;
01900 
01901     // GLES2 support is needed here, so:
01902     // - frameFormat GL_BGRA is not supported, so use GL_RGBA
01903     // - no format conversion, so same format is used for internal storage, so swizzle in shader
01904     // - GL_UNSIGNED_INT_8_8_8_8[_REV] do not exist, so use _BYTE and fix
01905     //   endianness in shader.
01906     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)) {
01907         // frame->format: GBRA
01908         // read in little endian: {A, R, G, B}, swap: {B, G, R, A}, swizzle: {R, G, B, A}
01909         // read in big endian: {B, G, R, A}, swizzle: {R, G, B, A}
01910         frameType = GL_UNSIGNED_BYTE;
01911         frameFormat = GL_RGBA;
01912         _smushSwizzle = true;
01913 #ifdef SCUMM_LITTLE_ENDIAN
01914         _smushSwap = true;
01915 #else
01916         _smushSwap = false;
01917 #endif
01918 
01919     } 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)) {
01920         // frame->format: ARGB
01921         // read in little endian: {B, G, R, A}, swizzle: {R, G, B, A}
01922         // read in big endian: {A, R, G, B}, swap: {B, G, R, A}, swizzle: {R, G, B, A}
01923         frameType = GL_UNSIGNED_BYTE;
01924         frameFormat = GL_RGBA;
01925         _smushSwizzle = true;
01926 #ifdef SCUMM_LITTLE_ENDIAN
01927         _smushSwap = false;
01928 #else
01929         _smushSwap = true;
01930 #endif
01931     } else if (frame->format == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
01932         frameType = GL_UNSIGNED_SHORT_5_6_5;
01933         frameFormat = GL_RGB;
01934         _smushSwizzle = false;
01935         _smushSwap = false;
01936     } else {
01937         error("Unknown pixelformat: Bpp: %d RBits: %d GBits: %d BBits: %d ABits: %d RShift: %d GShift: %d BShift: %d AShift: %d",
01938             frame->format.bytesPerPixel,
01939             -(frame->format.rLoss - 8),
01940             -(frame->format.gLoss - 8),
01941             -(frame->format.bLoss - 8),
01942             -(frame->format.aLoss - 8),
01943             frame->format.rShift,
01944             frame->format.gShift,
01945             frame->format.bShift,
01946             frame->format.aShift);
01947     }
01948 
01949     // create texture
01950     if (_smushTexId == 0) {
01951         glGenTextures(1, &_smushTexId);
01952     }
01953     glBindTexture(GL_TEXTURE_2D, _smushTexId);
01954     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01955     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01956     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
01957     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
01958     glTexImage2D(GL_TEXTURE_2D, 0, frameFormat, nextHigher2(width), nextHigher2(height), 0, frameFormat, frameType, NULL);
01959 
01960     glPixelStorei(GL_UNPACK_ALIGNMENT, frame->format.bytesPerPixel);
01961     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, frameFormat, frameType, bitmap);
01962     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
01963 
01964     _smushWidth = (int)(width);
01965     _smushHeight = (int)(height);
01966 }
01967 
01968 void GfxOpenGLS::drawMovieFrame(int offsetX, int offsetY) {
01969     _smushProgram->use();
01970     glDisable(GL_DEPTH_TEST);
01971 
01972     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
01973     _smushProgram->setUniform("texcrop", Math::Vector2d(float(_smushWidth) / nextHigher2(_smushWidth), float(_smushHeight) / nextHigher2(_smushHeight)));
01974     _smushProgram->setUniform("scale", Math::Vector2d(float(_smushWidth)/ float(_gameWidth), float(_smushHeight) / float(_gameHeight)));
01975     _smushProgram->setUniform("offset", Math::Vector2d(float(offsetX) / float(_gameWidth), float(offsetY) / float(_gameHeight)));
01976     _smushProgram->setUniform("swap", _smushSwap);
01977     _smushProgram->setUniform("swizzle", _smushSwizzle);
01978     glBindTexture(GL_TEXTURE_2D, _smushTexId);
01979 
01980     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
01981 
01982     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
01983     glEnable(GL_DEPTH_TEST);
01984 }
01985 
01986 
01987 void GfxOpenGLS::releaseMovieFrame() {
01988     if (_smushTexId > 0) {
01989         glDeleteTextures(1, &_smushTexId);
01990         _smushTexId = 0;
01991     }
01992 }
01993 
01994 
01995 const char *GfxOpenGLS::getVideoDeviceName() {
01996     return "OpenGLS Renderer";
01997 }
01998 
01999 void GfxOpenGLS::renderBitmaps(bool render) {
02000 
02001 }
02002 
02003 void GfxOpenGLS::renderZBitmaps(bool render) {
02004 
02005 }
02006 
02007 
02008 void GfxOpenGLS::createEMIModel(EMIModel *model) {
02009     EMIModelUserData *mud = new EMIModelUserData;
02010     model->_userData = mud;
02011     mud->_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_vertices, GL_STREAM_DRAW);
02012 
02013     mud->_normalsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_normals, GL_STREAM_DRAW);
02014 
02015     mud->_texCoordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 2 * sizeof(float), model->_texVerts, GL_STATIC_DRAW);
02016 
02017     mud->_colorMapVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 4 * sizeof(byte), model->_colorMap, GL_STATIC_DRAW);
02018 
02019     OpenGL::Shader * actorShader = _actorProgram->clone();
02020     actorShader->enableVertexAttribute("position", mud->_verticesVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
02021     actorShader->enableVertexAttribute("normal", mud->_normalsVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
02022     actorShader->enableVertexAttribute("texcoord", mud->_texCoordsVBO, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
02023     actorShader->enableVertexAttribute("color", mud->_colorMapVBO, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4 * sizeof(byte), 0);
02024     mud->_shader = actorShader;
02025 
02026     for (uint32 i = 0; i < model->_numFaces; ++i) {
02027         EMIMeshFace * face = &model->_faces[i];
02028         face->_indicesEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, face->_faceLength * 3 * sizeof(uint32), face->_indexes, GL_STATIC_DRAW);
02029     }
02030 
02031     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
02032 }
02033 
02034 void GfxOpenGLS::destroyEMIModel(EMIModel *model) {
02035     for (uint32 i = 0; i < model->_numFaces; ++i) {
02036         EMIMeshFace *face = &model->_faces[i];
02037         OpenGL::Shader::freeBuffer(face->_indicesEBO);
02038         face->_indicesEBO = 0;
02039     }
02040 
02041     EMIModelUserData *mud = static_cast<EMIModelUserData *>(model->_userData);
02042 
02043     if (mud) {
02044         OpenGL::Shader::freeBuffer(mud->_verticesVBO);
02045         OpenGL::Shader::freeBuffer(mud->_normalsVBO);
02046         OpenGL::Shader::freeBuffer(mud->_texCoordsVBO);
02047         OpenGL::Shader::freeBuffer(mud->_colorMapVBO);
02048 
02049         delete mud->_shader;
02050         delete mud;
02051     }
02052 
02053     model->_userData = nullptr;
02054 }
02055 
02056 void GfxOpenGLS::createMesh(Mesh *mesh) {
02057     Common::Array<GrimVertex> meshInfo;
02058     meshInfo.reserve(mesh->_numVertices * 5);
02059     for (int i = 0; i < mesh->_numFaces; ++i) {
02060         MeshFace *face = &mesh->_faces[i];
02061         face->_userData = new uint32;
02062         *(uint32 *)face->_userData = meshInfo.size();
02063 
02064         if (face->getNumVertices() < 3)
02065             continue;
02066 
02067 #define VERT(j) (&mesh->_vertices[3 * face->getVertex(j)])
02068 #define TEXVERT(j) (face->hasTexture() ? &mesh->_textureVerts[2 * face->getTextureVertex(j)] : zero_texVerts)
02069 #define NORMAL(j) (&mesh->_vertNormals[3 * face->getVertex(j)])
02070 
02071         for (int j = 2; j < face->getNumVertices(); ++j) {
02072             meshInfo.push_back(GrimVertex(VERT(0), TEXVERT(0), NORMAL(0)));
02073             meshInfo.push_back(GrimVertex(VERT(j - 1), TEXVERT(j - 1), NORMAL(j - 1)));
02074             meshInfo.push_back(GrimVertex(VERT(j), TEXVERT(j), NORMAL(j)));
02075         }
02076 
02077 #undef VERT
02078 #undef TEXVERT
02079 #undef NORMAL
02080 
02081     }
02082 
02083     if (meshInfo.empty()) {
02084         mesh->_userData = NULL;
02085         return;
02086     }
02087 
02088     ModelUserData *mud = new ModelUserData;
02089     mesh->_userData = mud;
02090 
02091     mud->_meshInfoVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, meshInfo.size() * sizeof(GrimVertex), &meshInfo[0], GL_STATIC_DRAW);
02092 
02093     OpenGL::Shader *shader = _actorProgram->clone();
02094     mud->_shader = shader;
02095     shader->enableVertexAttribute("position", mud->_meshInfoVBO, 3, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 0);
02096     shader->enableVertexAttribute("texcoord", mud->_meshInfoVBO, 2, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 3 * sizeof(float));
02097     shader->enableVertexAttribute("normal", mud->_meshInfoVBO, 3, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 5 * sizeof(float));
02098     shader->disableVertexAttribute("color", Math::Vector4d(1.f, 1.f, 1.f, 1.f));
02099 }
02100 
02101 void GfxOpenGLS::destroyMesh(const Mesh *mesh) {
02102     ModelUserData *mud = static_cast<ModelUserData *>(mesh->_userData);
02103 
02104     for (int i = 0; i < mesh->_numFaces; ++i) {
02105         MeshFace *face = &mesh->_faces[i];
02106         if (face->_userData) {
02107             uint32 *data = static_cast<uint32 *>(face->_userData);
02108             delete data;
02109         }
02110     }
02111 
02112     if (!mud)
02113         return;
02114 
02115     delete mud->_shader;
02116     delete mud;
02117 }
02118 
02119 static void readPixels(int x, int y, int width, int height, byte *buffer) {
02120     byte *p = buffer;
02121     for (int i = y; i < y + height; i++) {
02122         glReadPixels(x, 479 - i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, p);
02123         p += width * 4;
02124     }
02125 }
02126 
02127 Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) {
02128     Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
02129 #ifndef USE_GLES2
02130     if (useStored) {
02131         glBindTexture(GL_TEXTURE_2D, _storedDisplay);
02132         char *buffer = new char[_screenWidth * _screenHeight * 4];
02133 
02134         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
02135         byte *rawBuf = src.getRawBuffer();
02136         for (int i = 0; i < _screenHeight; i++) {
02137             memcpy(&(rawBuf[(_screenHeight - i - 1) * _screenWidth * 4]), &buffer[4 * _screenWidth * i], _screenWidth * 4);
02138         }
02139         delete[] buffer;
02140     } else
02141 #endif
02142     {
02143         readPixels(0, 0, _screenWidth, _screenHeight, src.getRawBuffer());
02144     }
02145     return createScreenshotBitmap(src, w, h, true);
02146 }
02147 
02148 void GfxOpenGLS::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
02149     readPixels(x, y, width, height, data);
02150     createSpecialtyTexture(id, data, width, height);
02151 }
02152 
02153 void GfxOpenGLS::setBlendMode(bool additive) {
02154     if (additive) {
02155         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
02156     } else {
02157         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02158     }
02159 }
02160 
02161 }
02162 
02163 #endif


Generated on Sat Feb 16 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge