2012-01-06 23:29:45 +01:00
|
|
|
/* ResidualVM - A 3D game interpreter
|
2009-05-05 11:34:43 +00:00
|
|
|
*
|
2012-01-06 23:29:45 +01:00
|
|
|
* ResidualVM is the legal property of its developers, whose names
|
2011-04-16 14:12:44 +02:00
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
2009-05-05 11:34:43 +00:00
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
2012-12-19 23:15:43 +01:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2014-04-05 18:18:42 +02:00
|
|
|
*
|
2012-12-19 23:15:43 +01:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2009-05-05 11:34:43 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2012-12-19 23:15:43 +01:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2014-04-05 18:18:42 +02:00
|
|
|
*
|
2012-12-19 23:15:43 +01:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-05-05 11:34:43 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-07-14 08:04:37 +02:00
|
|
|
#if defined(WIN32)
|
2010-01-24 08:23:20 +00:00
|
|
|
#include <windows.h>
|
|
|
|
// winnt.h defines ARRAYSIZE, but we want our own one...
|
|
|
|
#undef ARRAYSIZE
|
|
|
|
#endif
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
#include "common/endian.h"
|
2009-05-07 19:06:31 +00:00
|
|
|
#include "common/system.h"
|
2013-08-26 09:46:25 +02:00
|
|
|
#include "common/config-manager.h"
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2015-12-28 17:10:11 +01:00
|
|
|
#if defined(USE_OPENGL) && !defined(USE_GLES2)
|
2013-07-14 15:09:41 +02:00
|
|
|
|
2011-10-01 22:40:31 +02:00
|
|
|
#include "graphics/surface.h"
|
2012-01-16 17:12:14 +01:00
|
|
|
#include "graphics/pixelbuffer.h"
|
2011-10-01 22:40:31 +02:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
#include "math/glmath.h"
|
|
|
|
|
2009-05-24 19:13:58 +00:00
|
|
|
#include "engines/grim/actor.h"
|
|
|
|
#include "engines/grim/colormap.h"
|
|
|
|
#include "engines/grim/font.h"
|
|
|
|
#include "engines/grim/material.h"
|
|
|
|
#include "engines/grim/gfx_opengl.h"
|
2009-06-26 16:13:11 +00:00
|
|
|
#include "engines/grim/grim.h"
|
2011-05-13 17:55:14 -07:00
|
|
|
#include "engines/grim/bitmap.h"
|
|
|
|
#include "engines/grim/primitives.h"
|
2013-07-07 17:18:30 -07:00
|
|
|
#include "engines/grim/sprite.h"
|
2011-07-23 12:14:33 +02:00
|
|
|
#include "engines/grim/model.h"
|
2011-09-19 16:53:08 +02:00
|
|
|
#include "engines/grim/set.h"
|
2012-01-29 16:14:36 +01:00
|
|
|
#include "engines/grim/emi/modelemi.h"
|
2013-01-21 17:04:26 +01:00
|
|
|
#include "engines/grim/registry.h"
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-05-20 03:12:48 +08:00
|
|
|
|
2015-05-06 11:24:42 +08:00
|
|
|
#if defined (SDL_BACKEND) && defined(GL_ARB_fragment_program) && !defined(USE_GLEW)
|
2011-05-19 20:19:28 +08:00
|
|
|
|
2011-05-20 03:12:48 +08:00
|
|
|
// We need SDL.h for SDL_GL_GetProcAddress.
|
|
|
|
#include "backends/platform/sdl/sdl-sys.h"
|
|
|
|
|
2011-05-19 20:19:28 +08:00
|
|
|
// Extension functions needed for fragment programs.
|
|
|
|
PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
|
|
|
|
PFNGLBINDPROGRAMARBPROC glBindProgramARB;
|
|
|
|
PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
|
|
|
|
PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
|
2012-03-07 16:12:14 +01:00
|
|
|
PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB;
|
2011-05-19 20:19:28 +08:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
namespace Grim {
|
|
|
|
|
2011-05-21 18:18:27 +02:00
|
|
|
GfxBase *CreateGfxOpenGL() {
|
|
|
|
return new GfxOpenGL();
|
|
|
|
}
|
|
|
|
|
2011-05-19 20:19:28 +08:00
|
|
|
// Simple ARB fragment program that writes the value from a texture to the Z-buffer.
|
|
|
|
static char fragSrc[] =
|
|
|
|
"!!ARBfp1.0\n\
|
2011-11-01 05:18:31 +08:00
|
|
|
TEMP d;\n\
|
|
|
|
TEX d, fragment.texcoord[0], texture[0], 2D;\n\
|
|
|
|
MOV result.depth, d.r;\n\
|
2011-05-19 20:19:28 +08:00
|
|
|
END\n";
|
|
|
|
|
2012-03-07 16:12:14 +01:00
|
|
|
static char dimFragSrc[] =
|
|
|
|
"!!ARBfp1.0\n\
|
|
|
|
PARAM level = program.local[0];\n\
|
|
|
|
TEMP color;\n\
|
|
|
|
TEMP d;\n\
|
|
|
|
TEX d, fragment.texcoord[0], texture[0], 2D;\n\
|
|
|
|
TEMP sum;\n\
|
|
|
|
MOV sum, d.r;\n\
|
|
|
|
ADD sum, sum, d.g;\n\
|
|
|
|
ADD sum, sum, d.b;\n\
|
|
|
|
MUL sum, sum, 0.33;\n\
|
|
|
|
MUL sum, sum, level.x;\n\
|
|
|
|
MOV result.color.r, sum;\n\
|
|
|
|
MOV result.color.g, sum;\n\
|
|
|
|
MOV result.color.b, sum;\n\
|
|
|
|
END\n";
|
|
|
|
|
2013-04-21 15:09:39 +02:00
|
|
|
GfxOpenGL::GfxOpenGL() : _smushNumTex(0),
|
2014-05-29 15:35:46 -07:00
|
|
|
_smushTexIds(nullptr), _smushWidth(0), _smushHeight(0),
|
2013-10-26 13:57:55 -07:00
|
|
|
_useDepthShader(false), _fragmentProgram(0), _useDimShader(0),
|
2014-05-29 15:35:46 -07:00
|
|
|
_dimFragProgram(0), _maxLights(0), _storedDisplay(nullptr),
|
2013-10-26 13:57:55 -07:00
|
|
|
_emergFont(0), _alpha(1.f) {
|
2014-05-05 15:00:39 +02:00
|
|
|
// GL_LEQUAL as glDepthFunc ensures that subsequent drawing attempts for
|
2014-05-01 12:34:23 +02:00
|
|
|
// the same triangles are not ignored by the depth test.
|
|
|
|
// That's necessary for EMI where some models have multiple faces which
|
|
|
|
// refer to the same vertices. The first face is usually using the
|
|
|
|
// color map and the following are using textures.
|
|
|
|
_depthFunc = (g_grim->getGameType() == GType_MONKEY4) ? GL_LEQUAL : GL_LESS;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
GfxOpenGL::~GfxOpenGL() {
|
2020-02-12 22:57:46 +01:00
|
|
|
releaseMovieFrame();
|
2009-05-05 11:34:43 +00:00
|
|
|
delete[] _storedDisplay;
|
2012-01-27 17:44:33 +01:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_emergFont && glIsList(_emergFont))
|
|
|
|
glDeleteLists(_emergFont, 128);
|
2011-05-19 20:19:28 +08:00
|
|
|
|
|
|
|
#ifdef GL_ARB_fragment_program
|
|
|
|
if (_useDepthShader)
|
|
|
|
glDeleteProgramsARB(1, &_fragmentProgram);
|
2012-03-07 16:12:14 +01:00
|
|
|
|
|
|
|
if (_useDimShader)
|
|
|
|
glDeleteProgramsARB(1, &_dimFragProgram);
|
2011-05-19 20:19:28 +08:00
|
|
|
#endif
|
2014-12-31 01:42:44 +01:00
|
|
|
for (unsigned int i = 0; i < _numSpecialtyTextures; i++) {
|
|
|
|
destroyTexture(&_specialtyTextures[i]);
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-31 08:55:57 +00:00
|
|
|
byte *GfxOpenGL::setupScreen(int screenW, int screenH, bool fullscreen) {
|
2009-05-05 11:34:43 +00:00
|
|
|
_screenWidth = screenW;
|
|
|
|
_screenHeight = screenH;
|
2012-01-25 23:02:24 +01:00
|
|
|
_scaleW = _screenWidth / (float)_gameWidth;
|
|
|
|
_scaleH = _screenHeight / (float)_gameHeight;
|
|
|
|
|
2011-05-19 20:19:28 +08:00
|
|
|
_useDepthShader = false;
|
2012-03-07 16:12:14 +01:00
|
|
|
_useDimShader = false;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-06-02 12:16:04 +02:00
|
|
|
g_system->showMouse(!fullscreen);
|
|
|
|
|
2014-07-06 11:18:35 +02:00
|
|
|
g_system->setWindowCaption("ResidualVM: OpenGL Renderer");
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-14 08:03:10 +02:00
|
|
|
int screenSize = _screenWidth * _screenHeight * 4;
|
|
|
|
_storedDisplay = new byte[screenSize];
|
|
|
|
memset(_storedDisplay, 0, screenSize);
|
2009-05-05 11:34:43 +00:00
|
|
|
_smushNumTex = 0;
|
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
_currentShadowArray = nullptr;
|
2012-11-18 16:24:12 +01:00
|
|
|
glViewport(0, 0, _screenWidth, _screenHeight);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-05-20 00:12:43 +02:00
|
|
|
GLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
2009-05-05 11:34:43 +00:00
|
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientSource);
|
2015-03-16 22:53:52 +01:00
|
|
|
GLfloat diffuseReflectance[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseReflectance);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-20 20:58:22 +03:00
|
|
|
if (g_grim->getGameType() == GType_GRIM) {
|
|
|
|
glPolygonOffset(-6.0, -6.0);
|
|
|
|
}
|
2009-05-07 19:06:31 +00:00
|
|
|
|
2011-05-19 20:19:28 +08:00
|
|
|
initExtensions();
|
2012-02-24 17:41:52 +01:00
|
|
|
glGetIntegerv(GL_MAX_LIGHTS, &_maxLights);
|
2011-05-19 20:19:28 +08:00
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
return nullptr;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2013-07-09 21:12:55 +02:00
|
|
|
void GfxOpenGL::initExtensions() {
|
2013-08-26 09:46:25 +02:00
|
|
|
if (!ConfMan.getBool("use_arb_shaders")) {
|
2013-01-21 17:04:26 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-20 02:33:52 +08:00
|
|
|
#if defined (SDL_BACKEND) && defined(GL_ARB_fragment_program)
|
2015-05-06 11:24:42 +08:00
|
|
|
#ifndef USE_GLEW
|
2011-05-20 01:20:47 +08:00
|
|
|
union {
|
2013-07-09 21:12:55 +02:00
|
|
|
void *obj_ptr;
|
2011-05-20 01:20:47 +08:00
|
|
|
void (APIENTRY *func_ptr)();
|
|
|
|
} u;
|
2011-05-20 03:12:48 +08:00
|
|
|
// We're casting from an object pointer to a function pointer, the
|
|
|
|
// sizes need to be the same for this to work.
|
|
|
|
assert(sizeof(u.obj_ptr) == sizeof(u.func_ptr));
|
2011-05-20 01:20:47 +08:00
|
|
|
u.obj_ptr = SDL_GL_GetProcAddress("glGenProgramsARB");
|
|
|
|
glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)u.func_ptr;
|
|
|
|
u.obj_ptr = SDL_GL_GetProcAddress("glBindProgramARB");
|
|
|
|
glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)u.func_ptr;
|
|
|
|
u.obj_ptr = SDL_GL_GetProcAddress("glProgramStringARB");
|
|
|
|
glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)u.func_ptr;
|
|
|
|
u.obj_ptr = SDL_GL_GetProcAddress("glDeleteProgramsARB");
|
|
|
|
glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)u.func_ptr;
|
2012-03-07 16:12:14 +01:00
|
|
|
u.obj_ptr = SDL_GL_GetProcAddress("glProgramLocalParameter4fARB");
|
|
|
|
glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)u.func_ptr;
|
2015-05-06 11:24:42 +08:00
|
|
|
#endif
|
2011-05-19 20:19:28 +08:00
|
|
|
|
2013-07-09 21:12:55 +02:00
|
|
|
const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
|
2016-03-10 05:54:24 +01:00
|
|
|
if (extensions && strstr(extensions, "ARB_fragment_program")) {
|
2011-05-19 20:19:28 +08:00
|
|
|
_useDepthShader = true;
|
2012-03-07 16:12:14 +01:00
|
|
|
_useDimShader = true;
|
2011-05-19 20:19:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (_useDepthShader) {
|
|
|
|
glGenProgramsARB(1, &_fragmentProgram);
|
|
|
|
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _fragmentProgram);
|
|
|
|
|
|
|
|
GLint errorPos;
|
|
|
|
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragSrc), fragSrc);
|
|
|
|
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
|
|
|
|
if (errorPos != -1) {
|
2012-03-07 16:12:14 +01:00
|
|
|
warning("Error compiling depth fragment program:\n%s", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
|
2011-11-01 03:55:08 +08:00
|
|
|
_useDepthShader = false;
|
2011-05-19 20:19:28 +08:00
|
|
|
}
|
2012-03-07 16:12:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
glGenProgramsARB(1, &_dimFragProgram);
|
|
|
|
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _dimFragProgram);
|
|
|
|
|
|
|
|
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dimFragSrc), dimFragSrc);
|
|
|
|
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
|
|
|
|
if (errorPos != -1) {
|
|
|
|
warning("Error compiling dim fragment program:\n%s", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
|
|
|
|
_useDimShader = false;
|
|
|
|
}
|
2011-05-19 20:19:28 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
const char *GfxOpenGL::getVideoDeviceName() {
|
|
|
|
return "OpenGL Renderer";
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-07-19 22:42:43 -04:00
|
|
|
void GfxOpenGL::setupCameraFrustum(float fov, float nclip, float fclip) {
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
2009-05-10 14:15:07 +00:00
|
|
|
float right = nclip * tan(fov / 2 * (LOCAL_PI / 180));
|
2009-05-05 11:34:43 +00:00
|
|
|
glFrustum(-right, right, -right * 0.75, right * 0.75, nclip, fclip);
|
|
|
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
}
|
|
|
|
|
2012-06-08 00:03:05 +02:00
|
|
|
void GfxOpenGL::positionCamera(const Math::Vector3d &pos, const Math::Vector3d &interest, float roll) {
|
2014-08-05 15:43:39 -04:00
|
|
|
Math::Vector3d up_vec(0, 0, 1);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
glRotatef(roll, 0, 0, -1);
|
2012-06-08 00:03:05 +02:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
if (pos.x() == interest.x() && pos.y() == interest.y())
|
|
|
|
up_vec = Math::Vector3d(0, 1, 0);
|
2012-01-29 22:04:45 +01:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
Math::Matrix4 lookMatrix = Math::makeLookAtMatrix(pos, interest, up_vec);
|
|
|
|
glMultMatrixf(lookMatrix.getData());
|
|
|
|
glTranslated(-pos.x(), -pos.y(), -pos.z());
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
void GfxOpenGL::positionCamera(const Math::Vector3d &pos, const Math::Matrix4 &rot) {
|
|
|
|
glScaled(1, 1, -1);
|
|
|
|
_currentPos = pos;
|
|
|
|
_currentRot = rot;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-09 18:41:01 +03:00
|
|
|
Math::Matrix4 GfxOpenGL::getModelView() {
|
|
|
|
Math::Matrix4 modelView;
|
|
|
|
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
|
|
|
|
2014-08-05 15:43:39 -04:00
|
|
|
glMultMatrixf(_currentRot.getData());
|
2014-06-09 18:41:01 +03:00
|
|
|
glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, modelView.getData());
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
} else {
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, modelView.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
modelView.transpose();
|
|
|
|
return modelView;
|
|
|
|
}
|
|
|
|
|
|
|
|
Math::Matrix4 GfxOpenGL::getProjection() {
|
|
|
|
Math::Matrix4 projection;
|
|
|
|
glGetFloatv(GL_PROJECTION_MATRIX, projection.getData());
|
|
|
|
projection.transpose();
|
|
|
|
return projection;
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::clearScreen() {
|
2009-05-05 11:34:43 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
2014-06-17 21:00:17 +02:00
|
|
|
void GfxOpenGL::clearDepthBuffer() {
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::flipBuffer() {
|
|
|
|
g_system->updateScreen();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
bool GfxOpenGL::isHardwareAccelerated() {
|
2009-05-05 11:34:43 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-06-23 00:24:43 +03:00
|
|
|
bool GfxOpenGL::supportsShaders() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-04 18:07:24 -08:00
|
|
|
static void glShadowProjection(const Math::Vector3d &light, const Math::Vector3d &plane, const Math::Vector3d &normal, bool dontNegate) {
|
2009-05-05 11:34:43 +00:00
|
|
|
// Based on GPL shadow projection example by
|
|
|
|
// (c) 2002-2003 Phaetos <phaetos@gaffga.de>
|
|
|
|
float d, c;
|
|
|
|
float mat[16];
|
|
|
|
float nx, ny, nz, lx, ly, lz, px, py, pz;
|
|
|
|
|
2011-05-01 06:15:37 +08:00
|
|
|
nx = normal.x();
|
|
|
|
ny = normal.y();
|
|
|
|
nz = normal.z();
|
2009-05-05 11:34:43 +00:00
|
|
|
// for some unknown for me reason normal need negation
|
2011-05-01 06:15:37 +08:00
|
|
|
if (!dontNegate) {
|
2009-05-05 11:34:43 +00:00
|
|
|
nx = -nx;
|
|
|
|
ny = -ny;
|
|
|
|
nz = -nz;
|
|
|
|
}
|
|
|
|
lx = light.x();
|
|
|
|
ly = light.y();
|
|
|
|
lz = light.z();
|
|
|
|
px = plane.x();
|
|
|
|
py = plane.y();
|
|
|
|
pz = plane.z();
|
|
|
|
|
|
|
|
d = nx * lx + ny * ly + nz * lz;
|
|
|
|
c = px * nx + py * ny + pz * nz - d;
|
|
|
|
|
|
|
|
mat[0] = lx * nx + c;
|
|
|
|
mat[4] = ny * lx;
|
|
|
|
mat[8] = nz * lx;
|
|
|
|
mat[12] = -lx * c - lx * d;
|
|
|
|
|
|
|
|
mat[1] = nx * ly;
|
|
|
|
mat[5] = ly * ny + c;
|
|
|
|
mat[9] = nz * ly;
|
|
|
|
mat[13] = -ly * c - ly * d;
|
|
|
|
|
|
|
|
mat[2] = nx * lz;
|
|
|
|
mat[6] = ny * lz;
|
|
|
|
mat[10] = lz * nz + c;
|
|
|
|
mat[14] = -lz * c - lz * d;
|
|
|
|
|
|
|
|
mat[3] = nx;
|
|
|
|
mat[7] = ny;
|
|
|
|
mat[11] = nz;
|
|
|
|
mat[15] = -d;
|
|
|
|
|
|
|
|
glMultMatrixf((GLfloat *)mat);
|
|
|
|
}
|
|
|
|
|
2014-07-22 19:13:29 -04:00
|
|
|
void GfxOpenGL::getScreenBoundingBox(const Mesh *model, int *x1, int *y1, int *x2, int *y2) {
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_currentShadowArray) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-06 05:55:07 +08:00
|
|
|
GLdouble top = 1000;
|
|
|
|
GLdouble right = -1000;
|
|
|
|
GLdouble left = 1000;
|
|
|
|
GLdouble bottom = -1000;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < model->_numFaces; i++) {
|
2014-07-10 07:29:01 +02:00
|
|
|
Math::Vector3d obj;
|
2013-07-09 21:12:55 +02:00
|
|
|
float *pVertices;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
for (int j = 0; j < model->_faces[i].getNumVertices(); j++) {
|
2009-05-05 11:34:43 +00:00
|
|
|
GLdouble modelView[16], projection[16];
|
|
|
|
GLint viewPort[4];
|
|
|
|
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projection);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewPort);
|
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
pVertices = model->_vertices + 3 * model->_faces[i].getVertex(j);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
obj.set(*(pVertices), *(pVertices + 1), *(pVertices + 2));
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
Math::Vector3d win;
|
2014-08-15 12:25:48 +02:00
|
|
|
Math::gluMathProject<GLdouble, GLint>(obj, modelView, projection, viewPort, win);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-07-10 07:29:01 +02:00
|
|
|
if (win.x() > right)
|
|
|
|
right = win.x();
|
|
|
|
if (win.x() < left)
|
|
|
|
left = win.x();
|
|
|
|
if (win.y() < top)
|
|
|
|
top = win.y();
|
|
|
|
if (win.y() > bottom)
|
|
|
|
bottom = win.y();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-06 05:55:07 +08:00
|
|
|
double t = bottom;
|
2012-01-27 19:59:34 +01:00
|
|
|
bottom = _gameHeight - top;
|
|
|
|
top = _gameHeight - t;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
if (left < 0)
|
|
|
|
left = 0;
|
2012-01-27 19:59:34 +01:00
|
|
|
if (right >= _gameWidth)
|
|
|
|
right = _gameWidth - 1;
|
2009-05-05 11:34:43 +00:00
|
|
|
if (top < 0)
|
|
|
|
top = 0;
|
2012-01-27 19:59:34 +01:00
|
|
|
if (bottom >= _gameHeight)
|
|
|
|
bottom = _gameHeight - 1;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-27 19:59:34 +01:00
|
|
|
if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
|
2009-05-05 11:34:43 +00:00
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*x1 = (int)left;
|
|
|
|
*y1 = (int)top;
|
|
|
|
*x2 = (int)right;
|
|
|
|
*y2 = (int)bottom;
|
|
|
|
}
|
|
|
|
|
2014-07-22 19:13:29 -04:00
|
|
|
void GfxOpenGL::getScreenBoundingBox(const EMIModel *model, int *x1, int *y1, int *x2, int *y2) {
|
2013-12-10 15:52:33 +01:00
|
|
|
if (_currentShadowArray) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
GLdouble top = 1000;
|
|
|
|
GLdouble right = -1000;
|
|
|
|
GLdouble left = 1000;
|
|
|
|
GLdouble bottom = -1000;
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
GLdouble modelView[16], projection[16];
|
|
|
|
GLint viewPort[4];
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projection);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewPort);
|
2014-07-10 07:23:47 +02:00
|
|
|
|
2013-12-31 15:30:15 +01:00
|
|
|
for (uint i = 0; i < model->_numFaces; i++) {
|
2013-12-10 15:52:33 +01:00
|
|
|
int *indices = (int *)model->_faces[i]._indexes;
|
|
|
|
|
|
|
|
for (uint j = 0; j < model->_faces[i]._faceLength * 3; j++) {
|
|
|
|
int index = indices[j];
|
2014-07-10 07:29:01 +02:00
|
|
|
Math::Vector3d obj = model->_drawVertices[index];
|
|
|
|
Math::Vector3d win;
|
2014-08-15 12:25:48 +02:00
|
|
|
Math::gluMathProject<GLdouble, GLint>(obj, modelView, projection, viewPort, win);
|
2014-07-10 07:29:01 +02:00
|
|
|
|
|
|
|
if (win.x() > right)
|
|
|
|
right = win.x();
|
|
|
|
if (win.x() < left)
|
|
|
|
left = win.x();
|
|
|
|
if (win.y() < top)
|
|
|
|
top = win.y();
|
|
|
|
if (win.y() > bottom)
|
|
|
|
bottom = win.y();
|
2013-12-10 15:52:33 +01:00
|
|
|
}
|
|
|
|
}
|
2014-08-03 13:16:01 -04:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
double t = bottom;
|
|
|
|
bottom = _gameHeight - top;
|
|
|
|
top = _gameHeight - t;
|
|
|
|
|
|
|
|
if (left < 0)
|
|
|
|
left = 0;
|
|
|
|
if (right >= _gameWidth)
|
|
|
|
right = _gameWidth - 1;
|
|
|
|
if (top < 0)
|
|
|
|
top = 0;
|
|
|
|
if (bottom >= _gameHeight)
|
|
|
|
bottom = _gameHeight - 1;
|
|
|
|
|
|
|
|
if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-17 01:09:13 +01:00
|
|
|
*x1 = (int)left;
|
2014-07-31 15:54:35 -04:00
|
|
|
*y1 = (int)top;
|
2013-12-10 15:52:33 +01:00
|
|
|
*x2 = (int)right;
|
2014-07-31 15:54:35 -04:00
|
|
|
*y2 = (int)bottom;
|
2013-12-10 15:52:33 +01:00
|
|
|
}
|
|
|
|
|
2014-08-03 13:16:01 -04:00
|
|
|
void GfxOpenGL::getActorScreenBBox(const Actor *actor, Common::Point &p1, Common::Point &p2) {
|
|
|
|
// Get the actor's bounding box information (describes a 3D box)
|
|
|
|
Math::Vector3d bboxPos, bboxSize;
|
|
|
|
actor->getBBoxInfo(bboxPos, bboxSize);
|
|
|
|
|
|
|
|
// Translate the bounding box to the actor's position
|
|
|
|
Math::Matrix4 m = actor->getFinalMatrix();
|
|
|
|
bboxPos = bboxPos + actor->getWorldPos();
|
|
|
|
|
|
|
|
// Set up the camera coordinate system
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
2014-08-05 15:43:39 -04:00
|
|
|
Math::Matrix4 worldRot = _currentRot;
|
2014-08-03 13:16:01 -04:00
|
|
|
glMultMatrixf(worldRot.getData());
|
|
|
|
glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
|
|
|
|
// Get the current OpenGL state
|
|
|
|
GLdouble modelView[16], projection[16];
|
|
|
|
GLint viewPort[4];
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projection);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewPort);
|
|
|
|
|
|
|
|
// Set values outside of the screen range
|
|
|
|
p1.x = 1000;
|
|
|
|
p1.y = 1000;
|
|
|
|
p2.x = -1000;
|
|
|
|
p2.y = -1000;
|
|
|
|
|
|
|
|
// Project all of the points in the 3D bounding box
|
|
|
|
Math::Vector3d p, projected;
|
|
|
|
for (int x = 0; x < 2; x++) {
|
|
|
|
for (int y = 0; y < 2; y++) {
|
|
|
|
for (int z = 0; z < 2; z++) {
|
|
|
|
Math::Vector3d added(bboxSize.x() * 0.5f * (x * 2 - 1), bboxSize.y() * 0.5f * (y * 2 - 1), bboxSize.z() * 0.5f * (z * 2 - 1));
|
|
|
|
m.transform(&added, false);
|
|
|
|
p = bboxPos + added;
|
2014-08-15 12:25:48 +02:00
|
|
|
Math::gluMathProject<GLdouble, GLint>(p, modelView, projection, viewPort, projected);
|
2014-08-03 13:16:01 -04:00
|
|
|
|
|
|
|
// Find the points
|
|
|
|
if (projected.x() < p1.x)
|
|
|
|
p1.x = projected.x();
|
|
|
|
if (projected.y() < p1.y)
|
|
|
|
p1.y = projected.y();
|
|
|
|
if (projected.x() > p2.x)
|
|
|
|
p2.x = projected.x();
|
|
|
|
if (projected.y() > p2.y)
|
|
|
|
p2.y = projected.y();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Swap the p1/p2 y coorindates
|
|
|
|
int16 tmp = p1.y;
|
|
|
|
p1.y = 480 - p2.y;
|
|
|
|
p2.y = 480 - tmp;
|
|
|
|
|
|
|
|
// Restore the state
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2013-12-04 14:26:44 +01:00
|
|
|
void GfxOpenGL::startActorDraw(const Actor *actor) {
|
|
|
|
_currentActor = actor;
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
2014-07-20 20:58:22 +03:00
|
|
|
glEnable(GL_LIGHTING);
|
2012-04-12 21:55:33 +02:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4 && !actor->isInOverworld()) {
|
|
|
|
// Apply the view transform.
|
2014-08-05 15:43:39 -04:00
|
|
|
glMultMatrixf(_currentRot.getData());
|
2014-07-20 20:58:22 +03:00
|
|
|
glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
}
|
|
|
|
|
2009-06-18 21:07:51 +00:00
|
|
|
if (_currentShadowArray) {
|
2009-06-18 20:23:46 +00:00
|
|
|
// TODO find out why shadowMask at device in woods is null
|
2009-06-18 21:35:29 +00:00
|
|
|
if (!_currentShadowArray->shadowMask) {
|
|
|
|
_currentShadowArray->shadowMask = new byte[_screenWidth * _screenHeight];
|
2011-03-21 05:16:27 +08:00
|
|
|
_currentShadowArray->shadowMaskSize = _screenWidth * _screenHeight;
|
2009-06-18 21:07:51 +00:00
|
|
|
}
|
2011-06-07 22:58:42 +02:00
|
|
|
Sector *shadowSector = _currentShadowArray->planeList.front().sector;
|
2014-07-20 20:58:22 +03:00
|
|
|
glDepthMask(GL_FALSE);
|
2009-06-18 21:35:29 +00:00
|
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2014-07-03 21:02:01 +02:00
|
|
|
// glColor3f(0.0f, 1.0f, 0.0f); // debug draw color
|
2014-07-20 20:58:22 +03:00
|
|
|
if (g_grim->getGameType() == GType_GRIM) {
|
|
|
|
glColor3ub(_shadowColorR, _shadowColorG, _shadowColorB);
|
|
|
|
} else {
|
|
|
|
glColor3ub(_currentShadowArray->color.getRed(), _currentShadowArray->color.getGreen(), _currentShadowArray->color.getBlue());
|
|
|
|
}
|
2009-06-18 21:35:29 +00:00
|
|
|
glShadowProjection(_currentShadowArray->pos, shadowSector->getVertices()[0], shadowSector->getNormal(), _currentShadowArray->dontNegate);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2012-04-13 19:45:33 +02:00
|
|
|
|
2013-12-04 14:26:44 +01:00
|
|
|
const float alpha = actor->getEffectiveAlpha();
|
2012-04-13 19:45:33 +02:00
|
|
|
if (alpha < 1.f) {
|
|
|
|
_alpha = alpha;
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
|
2014-01-19 03:36:59 +01:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-06-10 22:45:01 +03:00
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glFrontFace(GL_CW);
|
|
|
|
|
2014-01-19 03:36:59 +01:00
|
|
|
if (actor->isInOverworld()) {
|
|
|
|
const Math::Vector3d &pos = actor->getWorldPos();
|
|
|
|
const Math::Quaternion &quat = actor->getRotationQuat();
|
|
|
|
// At distance 3.2, a 6.4x4.8 actor fills the screen.
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
float right = 1;
|
|
|
|
float top = right * 0.75;
|
2014-06-17 21:01:16 +02:00
|
|
|
float div = 6.0f;
|
2014-07-14 09:33:37 +02:00
|
|
|
glFrustum(-right / div, right / div, -top / div, top / div, 1.0f / div, 3276.8f);
|
2014-01-19 03:36:59 +01:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glScalef(1.0, 1.0, -1.0);
|
|
|
|
glTranslatef(pos.x(), pos.y(), pos.z());
|
|
|
|
glMultMatrixf(quat.toMatrix().getData());
|
|
|
|
} else {
|
2014-02-16 11:36:12 +01:00
|
|
|
Math::Matrix4 m = actor->getFinalMatrix();
|
|
|
|
m.transpose();
|
|
|
|
glMultMatrixf(m.getData());
|
2014-01-19 03:36:59 +01:00
|
|
|
}
|
2012-07-03 20:03:17 +02:00
|
|
|
} else {
|
2014-01-19 03:36:59 +01:00
|
|
|
// Grim
|
|
|
|
Math::Vector3d pos = actor->getWorldPos();
|
|
|
|
const Math::Quaternion &quat = actor->getRotationQuat();
|
|
|
|
const float &scale = actor->getScale();
|
2012-07-02 23:54:17 +02:00
|
|
|
|
2014-01-19 03:36:59 +01:00
|
|
|
glTranslatef(pos.x(), pos.y(), pos.z());
|
2012-07-02 23:54:17 +02:00
|
|
|
glScalef(scale, scale, scale);
|
2012-07-07 20:33:33 +02:00
|
|
|
glMultMatrixf(quat.toMatrix().getData());
|
2012-01-29 22:04:45 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::finishActorDraw() {
|
2012-04-12 21:55:33 +02:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
2009-05-05 11:34:43 +00:00
|
|
|
glPopMatrix();
|
2012-04-12 21:55:33 +02:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPopMatrix();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
2014-07-03 21:55:10 +02:00
|
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2012-04-13 19:45:33 +02:00
|
|
|
if (_alpha < 1.f) {
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
_alpha = 1.f;
|
|
|
|
}
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_currentShadowArray) {
|
|
|
|
glEnable(GL_LIGHTING);
|
2011-04-06 05:55:07 +08:00
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
}
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2014-06-10 22:45:01 +03:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
}
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2013-07-01 23:35:16 +02:00
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
2014-05-29 15:35:46 -07:00
|
|
|
_currentActor = nullptr;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::setShadow(Shadow *shadow) {
|
2009-05-05 11:34:43 +00:00
|
|
|
_currentShadowArray = shadow;
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::drawShadowPlanes() {
|
2009-05-05 11:34:43 +00:00
|
|
|
/* glColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
_currentShadowArray->planeList.begin();
|
|
|
|
for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); i++) {
|
2011-12-12 12:26:49 +01:00
|
|
|
Sector *shadowSector = i->sector;
|
2009-05-05 11:34:43 +00:00
|
|
|
glBegin(GL_POLYGON);
|
|
|
|
for (int k = 0; k < shadowSector->getNumVertices(); k++) {
|
|
|
|
glVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
*/
|
2011-12-12 12:26:49 +01:00
|
|
|
|
2014-07-20 20:58:22 +03:00
|
|
|
glPushMatrix();
|
|
|
|
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
|
|
|
// Apply the view transform.
|
2014-08-05 15:43:39 -04:00
|
|
|
glMultMatrixf(_currentRot.getData());
|
2014-07-20 20:58:22 +03:00
|
|
|
glTranslatef(-_currentPos.x(), -_currentPos.y(), -_currentPos.z());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
2011-07-15 05:26:53 +08:00
|
|
|
glDepthMask(GL_FALSE);
|
2009-05-05 11:34:43 +00:00
|
|
|
glClearStencil(~0);
|
|
|
|
glClear(GL_STENCIL_BUFFER_BIT);
|
|
|
|
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
glStencilFunc(GL_ALWAYS, 1, (GLuint)~0);
|
|
|
|
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
|
|
|
glDisable(GL_LIGHTING);
|
2011-07-19 09:08:46 +02:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2014-08-19 15:46:00 +03:00
|
|
|
glColor4f(1, 1, 1, 1);
|
2010-02-04 19:43:50 +00:00
|
|
|
for (SectorListType::iterator i = _currentShadowArray->planeList.begin(); i != _currentShadowArray->planeList.end(); ++i) {
|
2011-06-07 22:58:42 +02:00
|
|
|
Sector *shadowSector = i->sector;
|
2009-05-05 11:34:43 +00:00
|
|
|
glBegin(GL_POLYGON);
|
|
|
|
for (int k = 0; k < shadowSector->getNumVertices(); k++) {
|
|
|
|
glVertex3f(shadowSector->getVertices()[k].x(), shadowSector->getVertices()[k].y(), shadowSector->getVertices()[k].z());
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
|
|
|
|
glStencilFunc(GL_EQUAL, 1, (GLuint)~0);
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
glPopMatrix();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::setShadowMode() {
|
2011-12-12 18:57:17 +01:00
|
|
|
GfxBase::setShadowMode();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::clearShadowMode() {
|
2011-12-12 18:57:17 +01:00
|
|
|
GfxBase::clearShadowMode();
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_STENCIL_TEST);
|
2011-12-12 12:26:49 +01:00
|
|
|
glDepthMask(GL_TRUE);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::setShadowColor(byte r, byte g, byte b) {
|
2009-05-05 11:34:43 +00:00
|
|
|
_shadowColorR = r;
|
|
|
|
_shadowColorG = g;
|
|
|
|
_shadowColorB = b;
|
|
|
|
}
|
|
|
|
|
2011-04-24 15:41:40 +02:00
|
|
|
void GfxOpenGL::getShadowColor(byte *r, byte *g, byte *b) {
|
|
|
|
*r = _shadowColorR;
|
|
|
|
*g = _shadowColorG;
|
|
|
|
*b = _shadowColorB;
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::set3DMode() {
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
2014-05-01 12:34:23 +02:00
|
|
|
glDepthFunc(_depthFunc);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2013-07-09 21:12:55 +02:00
|
|
|
void GfxOpenGL::drawEMIModelFace(const EMIModel *model, const EMIMeshFace *face) {
|
|
|
|
int *indices = (int *)face->_indexes;
|
2012-01-27 17:44:33 +01:00
|
|
|
|
2012-01-07 03:16:55 +01:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
2011-12-30 12:53:49 +01:00
|
|
|
glDisable(GL_ALPHA_TEST);
|
2013-07-12 12:08:14 -07:00
|
|
|
glDisable(GL_LIGHTING);
|
2014-07-20 20:58:22 +03:00
|
|
|
if (!_currentShadowArray && face->_hasTexture)
|
2012-11-14 20:57:18 +01:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
else
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2014-09-17 01:30:40 +02:00
|
|
|
if (face->_flags & EMIMeshFace::kAlphaBlend || face->_flags & EMIMeshFace::kUnknownBlend || _currentActor->hasLocalAlpha() || _alpha < 1.0f)
|
2014-08-05 18:54:34 +03:00
|
|
|
glEnable(GL_BLEND);
|
2012-01-07 03:16:55 +01:00
|
|
|
|
2011-12-30 12:53:49 +01:00
|
|
|
glBegin(GL_TRIANGLES);
|
2015-02-12 22:33:07 +01:00
|
|
|
float alpha = _alpha;
|
|
|
|
if (model->_meshAlphaMode == Actor::AlphaReplace) {
|
|
|
|
alpha *= model->_meshAlpha;
|
|
|
|
}
|
2015-02-24 22:44:10 +01:00
|
|
|
Math::Vector3d noLighting(1.f, 1.f, 1.f);
|
2012-01-27 13:48:36 +01:00
|
|
|
for (uint j = 0; j < face->_faceLength * 3; j++) {
|
2011-12-30 12:53:49 +01:00
|
|
|
int index = indices[j];
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
if (!_currentShadowArray) {
|
|
|
|
if (face->_hasTexture) {
|
|
|
|
glTexCoord2f(model->_texVerts[index].getX(), model->_texVerts[index].getY());
|
|
|
|
}
|
2015-02-24 22:44:10 +01:00
|
|
|
Math::Vector3d lighting = (face->_flags & EMIMeshFace::kNoLighting) ? noLighting : model->_lighting[index];
|
2014-07-06 12:22:34 +02:00
|
|
|
byte r = (byte)(model->_colorMap[index].r * lighting.x());
|
|
|
|
byte g = (byte)(model->_colorMap[index].g * lighting.y());
|
|
|
|
byte b = (byte)(model->_colorMap[index].b * lighting.z());
|
2018-07-09 23:32:40 +02:00
|
|
|
byte a = (int)(alpha * (model->_meshAlphaMode == Actor::AlphaReplace ? model->_colorMap[index].a * _currentActor->getLocalAlpha(index) : 255.f));
|
2014-07-20 20:58:22 +03:00
|
|
|
glColor4ub(r, g, b, a);
|
2011-12-30 12:53:49 +01:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2011-12-30 12:53:49 +01:00
|
|
|
Math::Vector3d normal = model->_normals[index];
|
2012-01-31 00:14:26 +01:00
|
|
|
Math::Vector3d vertex = model->_drawVertices[index];
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2011-12-30 12:53:49 +01:00
|
|
|
glNormal3fv(normal.getData());
|
|
|
|
glVertex3fv(vertex.getData());
|
|
|
|
}
|
|
|
|
glEnd();
|
2014-07-03 21:55:10 +02:00
|
|
|
|
2014-08-19 17:10:10 -07:00
|
|
|
if (!_currentShadowArray) {
|
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
|
2012-01-02 14:00:05 +01:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
2011-12-30 12:53:49 +01:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
2013-07-12 12:08:14 -07:00
|
|
|
glEnable(GL_LIGHTING);
|
2012-08-12 15:05:32 +02:00
|
|
|
glDisable(GL_BLEND);
|
2014-07-20 20:58:22 +03:00
|
|
|
|
|
|
|
if (!_currentShadowArray)
|
|
|
|
glDepthMask(GL_TRUE);
|
2011-12-30 12:53:49 +01:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2012-12-27 19:08:46 +01:00
|
|
|
void GfxOpenGL::drawModelFace(const Mesh *mesh, const MeshFace *face) {
|
2009-05-05 11:34:43 +00:00
|
|
|
// Support transparency in actor objects, such as the message tube
|
|
|
|
// in Manny's Office
|
2012-12-27 19:08:46 +01:00
|
|
|
float *vertices = mesh->_vertices;
|
|
|
|
float *vertNormals = mesh->_vertNormals;
|
|
|
|
float *textureVerts = mesh->_textureVerts;
|
2009-05-05 11:34:43 +00:00
|
|
|
glAlphaFunc(GL_GREATER, 0.5);
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
2014-03-30 14:38:52 -07:00
|
|
|
glNormal3fv(face->getNormal().getData());
|
2009-05-05 11:34:43 +00:00
|
|
|
glBegin(GL_POLYGON);
|
2014-03-30 14:38:52 -07:00
|
|
|
for (int i = 0; i < face->getNumVertices(); i++) {
|
|
|
|
glNormal3fv(vertNormals + 3 * face->getVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
if (face->hasTexture())
|
|
|
|
glTexCoord2fv(textureVerts + 2 * face->getTextureVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-03-30 14:38:52 -07:00
|
|
|
glVertex3fv(vertices + 3 * face->getVertex(i));
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
// Done with transparency-capable objects
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
}
|
|
|
|
|
2011-05-15 16:47:09 +03:00
|
|
|
void GfxOpenGL::drawSprite(const Sprite *sprite) {
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
2013-11-24 14:12:26 +01:00
|
|
|
|
2013-11-26 21:06:34 +01:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-01-08 23:40:18 +01:00
|
|
|
GLdouble modelview[16];
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
|
2014-06-21 08:43:55 -04:00
|
|
|
Math::Matrix4 act;
|
|
|
|
act.buildAroundZ(_currentActor->getYaw());
|
2013-11-26 21:06:34 +01:00
|
|
|
act.transpose();
|
2014-07-03 21:55:10 +02:00
|
|
|
act(3, 0) = modelview[12];
|
|
|
|
act(3, 1) = modelview[13];
|
|
|
|
act(3, 2) = modelview[14];
|
2013-11-26 21:06:34 +01:00
|
|
|
glLoadMatrixf(act.getData());
|
2014-08-05 23:06:55 +03:00
|
|
|
glTranslatef(sprite->_pos.x(), sprite->_pos.y(), -sprite->_pos.z());
|
2013-11-26 21:06:34 +01:00
|
|
|
} else {
|
2014-01-08 23:40:18 +01:00
|
|
|
glTranslatef(sprite->_pos.x(), sprite->_pos.y(), sprite->_pos.z());
|
|
|
|
GLdouble modelview[16];
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
|
|
|
|
|
2013-11-26 21:06:34 +01:00
|
|
|
// We want screen-aligned sprites so reset the rotation part of the matrix.
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
if (i == j) {
|
|
|
|
modelview[i * 4 + j] = 1.0f;
|
|
|
|
} else {
|
|
|
|
modelview[i * 4 + j] = 0.0f;
|
|
|
|
}
|
2011-05-15 16:47:09 +03:00
|
|
|
}
|
|
|
|
}
|
2013-11-26 21:06:34 +01:00
|
|
|
glLoadMatrixd(modelview);
|
2011-05-15 16:47:09 +03:00
|
|
|
}
|
|
|
|
|
2014-08-05 23:19:18 +03:00
|
|
|
if (sprite->_flags1 & Sprite::BlendAdditive) {
|
2014-06-17 18:26:16 +03:00
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
|
|
} else {
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
|
2011-05-15 16:47:09 +03:00
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
|
2014-08-18 13:08:35 +03:00
|
|
|
if (g_grim->getGameType() == GType_GRIM) {
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
glAlphaFunc(GL_GEQUAL, 0.5f);
|
|
|
|
} else if (sprite->_flags2 & Sprite::AlphaTest) {
|
2014-06-20 00:01:13 +03:00
|
|
|
glEnable(GL_ALPHA_TEST);
|
2014-08-18 13:08:35 +03:00
|
|
|
glAlphaFunc(GL_GEQUAL, 0.1f);
|
2014-06-20 00:01:13 +03:00
|
|
|
} else {
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
}
|
|
|
|
|
2014-08-05 23:19:18 +03:00
|
|
|
if (sprite->_flags2 & Sprite::DepthTest) {
|
2014-06-20 00:01:13 +03:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
2013-01-02 02:15:01 +02:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2014-08-05 23:09:16 +03:00
|
|
|
glDepthMask(GL_TRUE);
|
2013-07-08 14:33:29 -07:00
|
|
|
|
2014-01-05 16:44:51 +01:00
|
|
|
float halfWidth = sprite->_width / 2;
|
|
|
|
float halfHeight = sprite->_height / 2;
|
2014-08-03 20:25:31 +03:00
|
|
|
float vertexX[] = { -1.0f, 1.0f, 1.0f, -1.0f };
|
|
|
|
float vertexY[] = { 1.0f, 1.0f, -1.0f, -1.0f };
|
2012-09-26 23:17:05 +02:00
|
|
|
|
2013-01-02 00:50:26 +02:00
|
|
|
glBegin(GL_POLYGON);
|
2014-06-21 22:49:04 +03:00
|
|
|
for (int i = 0; i < 4; ++i) {
|
2014-07-06 12:22:34 +02:00
|
|
|
float r = sprite->_red[i] / 255.0f;
|
|
|
|
float g = sprite->_green[i] / 255.0f;
|
|
|
|
float b = sprite->_blue[i] / 255.0f;
|
|
|
|
float a = sprite->_alpha[i] * _alpha / 255.0f;
|
2014-06-21 22:49:04 +03:00
|
|
|
|
|
|
|
glColor4f(r, g, b, a);
|
2014-08-03 20:25:31 +03:00
|
|
|
glTexCoord2f(sprite->_texCoordX[i], sprite->_texCoordY[i]);
|
2014-06-21 22:49:04 +03:00
|
|
|
glVertex3f(vertexX[i] * halfWidth, vertexY[i] * halfHeight, 0.0f);
|
|
|
|
}
|
2013-12-12 03:36:21 +01:00
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
2013-01-02 00:50:26 +02:00
|
|
|
glEnd();
|
2013-01-02 02:20:51 +02:00
|
|
|
} else {
|
2013-01-02 00:50:26 +02:00
|
|
|
// In Grim, the bottom edge of the sprite is at y=0 and
|
|
|
|
// the texture is flipped along the X-axis.
|
2014-01-05 16:44:51 +01:00
|
|
|
float halfWidth = sprite->_width / 2;
|
|
|
|
float height = sprite->_height;
|
2013-01-02 00:50:26 +02:00
|
|
|
|
|
|
|
glBegin(GL_POLYGON);
|
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
|
|
glVertex3f(+halfWidth, 0.0f, 0.0f);
|
|
|
|
glTexCoord2f(0.0f, 0.0f);
|
|
|
|
glVertex3f(+halfWidth, +height, 0.0f);
|
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
|
|
|
glVertex3f(-halfWidth, +height, 0.0f);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex3f(-halfWidth, 0.0f, 0.0f);
|
|
|
|
glEnd();
|
|
|
|
}
|
2011-05-15 16:47:09 +03:00
|
|
|
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
2012-11-18 15:27:19 +01:00
|
|
|
glDepthMask(GL_TRUE);
|
2014-06-17 18:26:16 +03:00
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2014-07-03 21:55:10 +02:00
|
|
|
glDisable(GL_BLEND);
|
2014-06-20 00:01:13 +03:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
2011-05-15 16:47:09 +03:00
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxOpenGL::translateViewpointStart() {
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxOpenGL::translateViewpoint(const Math::Vector3d &vec) {
|
|
|
|
glTranslatef(vec.x(), vec.y(), vec.z());
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxOpenGL::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) {
|
|
|
|
glRotatef(angle.getDegrees(), axis.x(), axis.y(), axis.z());
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2014-06-25 17:15:41 +03:00
|
|
|
void GfxOpenGL::rotateViewpoint(const Math::Matrix4 &rot) {
|
|
|
|
glMultMatrixf(rot.getData());
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:57:17 +01:00
|
|
|
void GfxOpenGL::translateViewpointFinish() {
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPopMatrix();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-07-13 14:09:32 +03:00
|
|
|
void GfxOpenGL::enableLights() {
|
2013-01-12 14:20:51 +01:00
|
|
|
if (!isShadowModeActive()) {
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
2011-07-13 14:09:32 +03:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::disableLights() {
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2011-07-23 12:14:33 +02:00
|
|
|
void GfxOpenGL::setupLight(Light *light, int lightId) {
|
2012-02-24 17:41:52 +01:00
|
|
|
if (lightId >= _maxLights) {
|
2012-02-10 14:55:04 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnable(GL_LIGHTING);
|
2015-03-15 22:02:26 +01:00
|
|
|
GLfloat lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
2014-05-31 15:29:37 +02:00
|
|
|
GLfloat lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
GLfloat lightDir[] = { 0.0f, 0.0f, -1.0f };
|
|
|
|
GLfloat cutoff = 180.0f;
|
2014-06-01 23:12:31 +02:00
|
|
|
GLfloat spot_exp = 0.0f;
|
GRIM: Disable quadratic attenuation for spotlights.
Enabling quadratic atenuation, even with values as low as 0.1, reduces spot
lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when
walking along the garage door), "hq" (see Salvador).
Disabling is not perfect either, as attenuation can be seen (at least) in
set "tu" (see fire extinguisher), but it should be overall better.
Also, it should be noted that perfect fidelity cannot be achieved with openGL
fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi),
atenuation being null below phi, full above theta, transitioning with a
configurable exponent between both (defaults to angle-linear). OpenGL would
correspond to phi=0 and theta=pi (ie, transition is always done between fixed
angles), plus a configurable hard cutoff.
2015-03-17 00:17:30 +01:00
|
|
|
GLfloat q_attenuation = 1.0f;
|
2014-05-31 15:29:37 +02:00
|
|
|
|
2015-03-22 09:00:23 +01:00
|
|
|
GLfloat intensity = light->_scaledintensity;
|
2014-06-08 09:51:28 +02:00
|
|
|
lightColor[0] = (GLfloat)light->_color.getRed() * intensity;
|
|
|
|
lightColor[1] = (GLfloat)light->_color.getGreen() * intensity;
|
|
|
|
lightColor[2] = (GLfloat)light->_color.getBlue() * intensity;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2013-07-10 16:17:28 -07:00
|
|
|
if (light->_type == Light::Omni) {
|
2009-05-05 11:34:43 +00:00
|
|
|
lightPos[0] = light->_pos.x();
|
|
|
|
lightPos[1] = light->_pos.y();
|
|
|
|
lightPos[2] = light->_pos.z();
|
2013-07-10 16:17:28 -07:00
|
|
|
} else if (light->_type == Light::Direct) {
|
2011-05-20 22:44:12 +02:00
|
|
|
lightPos[0] = -light->_dir.x();
|
|
|
|
lightPos[1] = -light->_dir.y();
|
|
|
|
lightPos[2] = -light->_dir.z();
|
2011-04-30 22:47:02 +08:00
|
|
|
lightPos[3] = 0;
|
2013-07-10 16:17:28 -07:00
|
|
|
} else if (light->_type == Light::Spot) {
|
2009-05-05 11:34:43 +00:00
|
|
|
lightPos[0] = light->_pos.x();
|
|
|
|
lightPos[1] = light->_pos.y();
|
|
|
|
lightPos[2] = light->_pos.z();
|
|
|
|
lightDir[0] = light->_dir.x();
|
|
|
|
lightDir[1] = light->_dir.y();
|
|
|
|
lightDir[2] = light->_dir.z();
|
2014-06-01 23:12:31 +02:00
|
|
|
spot_exp = 2.0f;
|
2011-05-21 04:28:48 +08:00
|
|
|
cutoff = light->_penumbraangle;
|
GRIM: Disable quadratic attenuation for spotlights.
Enabling quadratic atenuation, even with values as low as 0.1, reduces spot
lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when
walking along the garage door), "hq" (see Salvador).
Disabling is not perfect either, as attenuation can be seen (at least) in
set "tu" (see fire extinguisher), but it should be overall better.
Also, it should be noted that perfect fidelity cannot be achieved with openGL
fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi),
atenuation being null below phi, full above theta, transitioning with a
configurable exponent between both (defaults to angle-linear). OpenGL would
correspond to phi=0 and theta=pi (ie, transition is always done between fixed
angles), plus a configurable hard cutoff.
2015-03-17 00:17:30 +01:00
|
|
|
q_attenuation = 0.0f;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2013-07-10 16:17:28 -07:00
|
|
|
|
2011-05-21 04:28:48 +08:00
|
|
|
glDisable(GL_LIGHT0 + lightId);
|
2015-03-15 22:02:26 +01:00
|
|
|
glLightfv(GL_LIGHT0 + lightId, GL_DIFFUSE, lightColor);
|
2011-05-21 04:28:48 +08:00
|
|
|
glLightfv(GL_LIGHT0 + lightId, GL_POSITION, lightPos);
|
|
|
|
glLightfv(GL_LIGHT0 + lightId, GL_SPOT_DIRECTION, lightDir);
|
2014-06-01 23:12:31 +02:00
|
|
|
glLightf(GL_LIGHT0 + lightId, GL_SPOT_EXPONENT, spot_exp);
|
2011-05-21 04:28:48 +08:00
|
|
|
glLightf(GL_LIGHT0 + lightId, GL_SPOT_CUTOFF, cutoff);
|
GRIM: Disable quadratic attenuation for spotlights.
Enabling quadratic atenuation, even with values as low as 0.1, reduces spot
lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when
walking along the garage door), "hq" (see Salvador).
Disabling is not perfect either, as attenuation can be seen (at least) in
set "tu" (see fire extinguisher), but it should be overall better.
Also, it should be noted that perfect fidelity cannot be achieved with openGL
fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi),
atenuation being null below phi, full above theta, transitioning with a
configurable exponent between both (defaults to angle-linear). OpenGL would
correspond to phi=0 and theta=pi (ie, transition is always done between fixed
angles), plus a configurable hard cutoff.
2015-03-17 00:17:30 +01:00
|
|
|
glLightf(GL_LIGHT0 + lightId, GL_QUADRATIC_ATTENUATION, q_attenuation);
|
2011-05-21 04:28:48 +08:00
|
|
|
glEnable(GL_LIGHT0 + lightId);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 18:01:52 +02:00
|
|
|
void GfxOpenGL::turnOffLight(int lightId) {
|
|
|
|
glDisable(GL_LIGHT0 + lightId);
|
|
|
|
}
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
#define BITMAP_TEXTURE_SIZE 256
|
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
void GfxOpenGL::createBitmap(BitmapData *bitmap) {
|
2009-05-05 11:34:43 +00:00
|
|
|
GLuint *textures;
|
2011-05-19 20:19:28 +08:00
|
|
|
|
|
|
|
if (bitmap->_format != 1) {
|
|
|
|
for (int pic = 0; pic < bitmap->_numImages; pic++) {
|
2012-01-24 19:02:50 +01:00
|
|
|
uint16 *zbufPtr = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
|
2011-05-19 20:19:28 +08:00
|
|
|
for (int i = 0; i < (bitmap->_width * bitmap->_height); i++) {
|
2012-01-27 17:28:56 +01:00
|
|
|
uint16 val = READ_LE_UINT16(zbufPtr + i);
|
2012-01-17 16:21:30 -08:00
|
|
|
// fix the value if it is incorrectly set to the bitmap transparency color
|
|
|
|
if (val == 0xf81f) {
|
|
|
|
val = 0;
|
|
|
|
}
|
2012-01-27 19:58:17 +01:00
|
|
|
zbufPtr[i] = 0xffff - ((uint32)val) * 0x10000 / 100 / (0x10000 - val);
|
2011-05-19 20:19:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Flip the zbuffer image to match what GL expects
|
|
|
|
if (!_useDepthShader) {
|
|
|
|
for (int y = 0; y < bitmap->_height / 2; y++) {
|
|
|
|
uint16 *ptr1 = zbufPtr + y * bitmap->_width;
|
|
|
|
uint16 *ptr2 = zbufPtr + (bitmap->_height - 1 - y) * bitmap->_width;
|
|
|
|
for (int x = 0; x < bitmap->_width; x++, ptr1++, ptr2++) {
|
|
|
|
uint16 tmp = *ptr1;
|
|
|
|
*ptr1 = *ptr2;
|
|
|
|
*ptr2 = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bitmap->_format == 1 || _useDepthShader) {
|
2009-05-05 11:34:43 +00:00
|
|
|
bitmap->_hasTransparency = false;
|
|
|
|
bitmap->_numTex = ((bitmap->_width + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE) *
|
2013-07-09 21:12:55 +02:00
|
|
|
((bitmap->_height + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE);
|
2009-05-05 11:34:43 +00:00
|
|
|
bitmap->_texIds = new GLuint[bitmap->_numTex * bitmap->_numImages];
|
|
|
|
textures = (GLuint *)bitmap->_texIds;
|
|
|
|
glGenTextures(bitmap->_numTex * bitmap->_numImages, textures);
|
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
byte *texData = nullptr;
|
|
|
|
byte *texOut = nullptr;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2011-05-19 20:19:28 +08:00
|
|
|
GLint format = GL_RGBA;
|
|
|
|
GLint type = GL_UNSIGNED_BYTE;
|
|
|
|
int bytes = 4;
|
|
|
|
if (bitmap->_format != 1) {
|
|
|
|
format = GL_DEPTH_COMPONENT;
|
|
|
|
type = GL_UNSIGNED_SHORT;
|
|
|
|
bytes = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, bytes);
|
2011-05-13 14:11:04 -07:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, bitmap->_width);
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
for (int pic = 0; pic < bitmap->_numImages; pic++) {
|
2011-05-19 20:19:28 +08:00
|
|
|
if (bitmap->_format == 1 && bitmap->_bpp == 16 && bitmap->_colorFormat != BM_RGB1555) {
|
2014-05-29 15:35:46 -07:00
|
|
|
if (texData == nullptr)
|
2014-07-14 08:10:08 +02:00
|
|
|
texData = new byte[bytes * bitmap->_width * bitmap->_height];
|
2011-05-01 03:50:18 +08:00
|
|
|
// Convert data to 32-bit RGBA format
|
|
|
|
byte *texDataPtr = texData;
|
2012-01-24 19:02:50 +01:00
|
|
|
uint16 *bitmapData = reinterpret_cast<uint16 *>(bitmap->getImageData(pic).getRawBuffer());
|
2014-07-14 08:10:08 +02:00
|
|
|
for (int i = 0; i < bitmap->_width * bitmap->_height; i++, texDataPtr += bytes, bitmapData++) {
|
2011-05-01 03:50:18 +08:00
|
|
|
uint16 pixel = *bitmapData;
|
|
|
|
int r = pixel >> 11;
|
|
|
|
texDataPtr[0] = (r << 3) | (r >> 2);
|
|
|
|
int g = (pixel >> 5) & 0x3f;
|
|
|
|
texDataPtr[1] = (g << 2) | (g >> 4);
|
|
|
|
int b = pixel & 0x1f;
|
|
|
|
texDataPtr[2] = (b << 3) | (b >> 2);
|
|
|
|
if (pixel == 0xf81f) { // transparent
|
|
|
|
texDataPtr[3] = 0;
|
|
|
|
bitmap->_hasTransparency = true;
|
|
|
|
} else {
|
|
|
|
texDataPtr[3] = 255;
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2011-05-01 03:50:18 +08:00
|
|
|
texOut = texData;
|
2011-05-19 20:19:28 +08:00
|
|
|
} else if (bitmap->_format == 1 && bitmap->_colorFormat == BM_RGB1555) {
|
2012-01-24 19:02:50 +01:00
|
|
|
bitmap->convertToColorFormat(pic, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
|
|
|
|
texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
|
2011-05-01 03:50:18 +08:00
|
|
|
} else {
|
2012-01-24 19:02:50 +01:00
|
|
|
texOut = (byte *)bitmap->getImageData(pic).getRawBuffer();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < bitmap->_numTex; i++) {
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textures[bitmap->_numTex * pic + i]);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
2014-05-29 15:35:46 -07:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, format, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, format, type, nullptr);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int cur_tex_idx = bitmap->_numTex * pic;
|
|
|
|
|
|
|
|
for (int y = 0; y < bitmap->_height; y += BITMAP_TEXTURE_SIZE) {
|
|
|
|
for (int x = 0; x < bitmap->_width; x += BITMAP_TEXTURE_SIZE) {
|
2012-01-27 17:44:33 +01:00
|
|
|
int width = (x + BITMAP_TEXTURE_SIZE >= bitmap->_width) ? (bitmap->_width - x) : BITMAP_TEXTURE_SIZE;
|
2009-05-05 11:34:43 +00:00
|
|
|
int height = (y + BITMAP_TEXTURE_SIZE >= bitmap->_height) ? (bitmap->_height - y) : BITMAP_TEXTURE_SIZE;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textures[cur_tex_idx]);
|
2011-05-19 20:19:28 +08:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type,
|
2013-07-09 21:12:55 +02:00
|
|
|
texOut + (y * bytes * bitmap->_width) + (bytes * x));
|
2009-05-05 11:34:43 +00:00
|
|
|
cur_tex_idx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
2011-05-13 14:11:04 -07:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
delete[] texData;
|
2012-02-02 09:34:53 -08:00
|
|
|
bitmap->freeData();
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
void GfxOpenGL::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer) {
|
2012-11-26 17:37:56 +01:00
|
|
|
// The PS2 version of EMI uses a TGA for it's splash-screen
|
|
|
|
// avoid using the TIL-code below for that, by checking
|
2015-05-05 02:06:21 +02:00
|
|
|
// for texture coordinates set by BitmapData::loadTile
|
|
|
|
if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
|
2012-11-21 22:32:46 +01:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
2012-11-18 09:17:21 -08:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
2012-11-21 22:32:46 +01:00
|
|
|
glPushMatrix();
|
2012-11-18 09:17:21 -08:00
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(-1, 1, -1, 1, 0, 1);
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
2013-07-09 17:11:06 -07:00
|
|
|
glEnable(GL_BLEND);
|
2014-08-05 18:03:39 +03:00
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2012-11-18 09:17:21 -08:00
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
2014-07-06 12:22:34 +02:00
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
2012-11-21 18:17:24 +01:00
|
|
|
|
2012-11-18 09:17:21 -08:00
|
|
|
BitmapData *data = bitmap->_data;
|
|
|
|
GLuint *textures = (GLuint *)bitmap->getTexIds();
|
|
|
|
float *texc = data->_texc;
|
2012-11-26 01:57:07 +01:00
|
|
|
|
2015-05-16 10:32:36 +02:00
|
|
|
assert(layer < data->_numLayers);
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
uint32 offset = data->_layers[layer]._offset;
|
|
|
|
for (uint32 i = offset; i < offset + data->_layers[layer]._numImages; ++i) {
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textures[data->_verts[i]._texid]);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
uint32 ntex = data->_verts[i]._pos * 4;
|
|
|
|
for (uint32 x = 0; x < data->_verts[i]._verts; ++x) {
|
|
|
|
glTexCoord2f(texc[ntex + 2], texc[ntex + 3]);
|
|
|
|
glVertex2f(texc[ntex + 0], texc[ntex + 1]);
|
|
|
|
ntex += 4;
|
2012-11-18 09:17:21 -08:00
|
|
|
}
|
EMI: Draw background layers at intervals
Previously, we split the background layers into everything
before SO 15 and after, and drew like that. However, this caused
the pink ship in shi.setb to not be drawn.
This patch draws the layers of the background at intervals of ten.
So if a set has six layers, layer 5 is the background and 4,3,2,1,0
are rendered at sortorder 40,30,20,10,0.
2013-06-29 14:36:17 +02:00
|
|
|
glEnd();
|
2012-11-18 09:17:21 -08:00
|
|
|
}
|
|
|
|
|
2013-11-24 18:29:34 +01:00
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
2013-07-09 17:11:06 -07:00
|
|
|
glDisable(GL_BLEND);
|
2012-11-18 09:17:21 -08:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
|
2012-11-21 22:32:46 +01:00
|
|
|
glPopMatrix();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPopMatrix();
|
|
|
|
|
2012-11-18 09:17:21 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-29 23:02:52 +02:00
|
|
|
int format = bitmap->getFormat();
|
|
|
|
if ((format == 1 && !_renderBitmaps) || (format == 5 && !_renderZBitmaps)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
GLuint *textures;
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
// A lot more may need to be put there : disabling Alpha test, blending, ...
|
|
|
|
// For now, just keep this here :-)
|
2011-05-09 19:20:47 +02:00
|
|
|
if (bitmap->getFormat() == 1 && bitmap->getHasTransparency()) {
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2012-01-27 17:44:33 +01:00
|
|
|
} else {
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_BLEND);
|
2012-01-27 17:44:33 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
2011-05-19 20:19:28 +08:00
|
|
|
// If drawing a Z-buffer image, but no shaders are available, fall back to the glDrawPixels method.
|
|
|
|
if (bitmap->getFormat() == 5 && !_useDepthShader) {
|
2009-05-05 11:34:43 +00:00
|
|
|
// Only draw the manual zbuffer when enabled
|
2011-09-18 18:46:20 +02:00
|
|
|
if (bitmap->getActiveImage() - 1 < bitmap->getNumImages()) {
|
2012-02-02 09:34:53 -08:00
|
|
|
drawDepthBitmap(dx, dy, bitmap->getWidth(), bitmap->getHeight(), (char *)bitmap->getData(bitmap->getActiveImage() - 1).getRawBuffer());
|
2009-05-05 11:34:43 +00:00
|
|
|
} else {
|
2011-09-18 18:46:20 +02:00
|
|
|
warning("zbuffer image has index out of bounds! %d/%d", bitmap->getActiveImage(), bitmap->getNumImages());
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2011-05-19 20:19:28 +08:00
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap->getFormat() == 1) { // Normal image
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
} else { // ZBuffer image
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
#ifdef GL_ARB_fragment_program
|
2012-03-07 16:12:14 +01:00
|
|
|
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _fragmentProgram);
|
2011-05-19 20:19:28 +08:00
|
|
|
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
2012-02-02 09:34:53 -08:00
|
|
|
glScissor((int)(dx * _scaleW), _screenHeight - (int)(((dy + bitmap->getHeight())) * _scaleH), (int)(bitmap->getWidth() * _scaleW), (int)(bitmap->getHeight() * _scaleH));
|
2011-09-18 18:46:20 +02:00
|
|
|
int cur_tex_idx = bitmap->getNumTex() * (bitmap->getActiveImage() - 1);
|
2012-02-02 09:34:53 -08:00
|
|
|
for (int y = dy; y < (dy + bitmap->getHeight()); y += BITMAP_TEXTURE_SIZE) {
|
|
|
|
for (int x = dx; x < (dx + bitmap->getWidth()); x += BITMAP_TEXTURE_SIZE) {
|
2011-05-19 20:19:28 +08:00
|
|
|
textures = (GLuint *)bitmap->getTexIds();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textures[cur_tex_idx]);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0.0f, 0.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x * _scaleW, y * _scaleH);
|
2011-05-19 20:19:28 +08:00
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f((x + BITMAP_TEXTURE_SIZE) * _scaleW, y * _scaleH);
|
2011-05-19 20:19:28 +08:00
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f((x + BITMAP_TEXTURE_SIZE) * _scaleW, (y + BITMAP_TEXTURE_SIZE) * _scaleH);
|
2011-05-19 20:19:28 +08:00
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x * _scaleW, (y + BITMAP_TEXTURE_SIZE) * _scaleH);
|
2011-05-19 20:19:28 +08:00
|
|
|
glEnd();
|
|
|
|
cur_tex_idx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
if (bitmap->getFormat() == 1) {
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
2014-05-01 12:34:23 +02:00
|
|
|
glDepthFunc(_depthFunc);
|
2011-05-19 20:19:28 +08:00
|
|
|
#ifdef GL_ARB_fragment_program
|
|
|
|
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
#endif
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2011-05-09 19:20:47 +02:00
|
|
|
void GfxOpenGL::destroyBitmap(BitmapData *bitmap) {
|
2011-05-13 14:11:04 -07:00
|
|
|
GLuint *textures = (GLuint *)bitmap->_texIds;
|
2009-05-05 11:34:43 +00:00
|
|
|
if (textures) {
|
|
|
|
glDeleteTextures(bitmap->_numTex * bitmap->_numImages, textures);
|
|
|
|
delete[] textures;
|
2014-05-29 15:35:46 -07:00
|
|
|
bitmap->_texIds = nullptr;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-27 17:44:33 +01:00
|
|
|
struct FontUserData {
|
2011-05-23 19:06:08 -07:00
|
|
|
int size;
|
|
|
|
GLuint texture;
|
|
|
|
};
|
|
|
|
|
2011-05-22 20:43:28 -07:00
|
|
|
void GfxOpenGL::createFont(Font *font) {
|
2011-05-23 19:06:08 -07:00
|
|
|
const byte *bitmapData = font->getFontData();
|
|
|
|
uint dataSize = font->getDataSize();
|
2011-05-22 20:43:28 -07:00
|
|
|
|
2011-05-23 19:55:20 -07:00
|
|
|
uint8 bpp = 4;
|
|
|
|
uint8 charsWide = 16;
|
|
|
|
uint8 charsHigh = 16;
|
|
|
|
|
|
|
|
byte *texDataPtr = new byte[dataSize * bpp];
|
2011-05-22 20:43:28 -07:00
|
|
|
byte *data = texDataPtr;
|
|
|
|
|
2011-05-23 19:55:20 -07:00
|
|
|
for (uint i = 0; i < dataSize; i++, texDataPtr += bpp, bitmapData++) {
|
2011-05-22 20:43:28 -07:00
|
|
|
byte pixel = *bitmapData;
|
|
|
|
if (pixel == 0x00) {
|
2012-01-27 17:44:33 +01:00
|
|
|
texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 0;
|
2011-05-22 20:43:28 -07:00
|
|
|
} else if (pixel == 0x80) {
|
2012-01-27 17:44:33 +01:00
|
|
|
texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = 0;
|
2011-05-23 19:55:20 -07:00
|
|
|
texDataPtr[3] = 255;
|
2011-05-22 20:43:28 -07:00
|
|
|
} else if (pixel == 0xFF) {
|
2012-01-27 17:44:33 +01:00
|
|
|
texDataPtr[0] = texDataPtr[1] = texDataPtr[2] = texDataPtr[3] = 255;
|
2011-05-22 20:43:28 -07:00
|
|
|
}
|
|
|
|
}
|
2011-05-23 12:47:43 -07:00
|
|
|
int size = 0;
|
|
|
|
for (int i = 0; i < 256; ++i) {
|
2014-07-30 21:35:38 -04:00
|
|
|
int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
|
2011-05-23 20:03:46 -07:00
|
|
|
int m = MAX(width, height);
|
2011-05-23 14:26:44 -07:00
|
|
|
if (m > size)
|
2011-05-23 13:40:57 -07:00
|
|
|
size = m;
|
2011-05-23 12:47:43 -07:00
|
|
|
}
|
|
|
|
assert(size < 64);
|
|
|
|
if (size < 8)
|
|
|
|
size = 8;
|
|
|
|
if (size < 16)
|
|
|
|
size = 16;
|
|
|
|
else if (size < 32)
|
|
|
|
size = 32;
|
|
|
|
else if (size < 64)
|
|
|
|
size = 64;
|
|
|
|
|
2011-05-23 19:55:20 -07:00
|
|
|
uint arraySize = size * size * bpp * charsWide * charsHigh;
|
2011-05-23 14:26:44 -07:00
|
|
|
byte *temp = new byte[arraySize];
|
|
|
|
if (!temp)
|
|
|
|
error("Could not allocate %d bytes", arraySize);
|
2011-05-23 12:47:43 -07:00
|
|
|
|
2011-05-23 14:26:44 -07:00
|
|
|
memset(temp, 0, arraySize);
|
2011-05-22 20:43:28 -07:00
|
|
|
|
2011-05-23 19:06:08 -07:00
|
|
|
FontUserData *userData = new FontUserData;
|
|
|
|
font->setUserData(userData);
|
|
|
|
userData->texture = 0;
|
|
|
|
userData->size = size;
|
|
|
|
|
|
|
|
GLuint *texture = &(userData->texture);
|
|
|
|
glGenTextures(1, texture);
|
2011-05-22 20:43:28 -07:00
|
|
|
|
2011-05-23 12:47:43 -07:00
|
|
|
for (int i = 0, row = 0; i < 256; ++i) {
|
2014-07-30 21:35:38 -04:00
|
|
|
int width = font->getCharBitmapWidth(i), height = font->getCharBitmapHeight(i);
|
2011-05-26 10:37:30 -07:00
|
|
|
int32 d = font->getCharOffset(i);
|
2011-05-22 20:43:28 -07:00
|
|
|
for (int x = 0; x < height; ++x) {
|
2011-06-06 13:48:44 -07:00
|
|
|
// a is the offset to get to the correct row.
|
|
|
|
// b is the offset to get to the correct line in the character.
|
|
|
|
// c is the offset of the character from the start of the row.
|
2011-05-23 19:55:20 -07:00
|
|
|
uint a = row * size * size * bpp * charsHigh;
|
|
|
|
uint b = x * size * charsWide * bpp;
|
|
|
|
uint c = 0;
|
|
|
|
if (i != 0)
|
|
|
|
c = ((i - 1) % 16) * size * bpp;
|
|
|
|
|
2011-05-23 19:41:46 -07:00
|
|
|
uint pos = a + b + c;
|
2011-05-23 19:55:20 -07:00
|
|
|
uint pos2 = d * bpp + x * width * bpp;
|
|
|
|
assert(pos + width * bpp <= arraySize);
|
|
|
|
assert(pos2 + width * bpp <= dataSize * bpp);
|
|
|
|
memcpy(temp + pos, data + pos2, width * bpp);
|
2011-05-22 20:43:28 -07:00
|
|
|
}
|
2011-05-23 19:55:20 -07:00
|
|
|
if (i != 0 && i % charsWide == 0)
|
2011-05-23 12:47:43 -07:00
|
|
|
++row;
|
2011-05-22 20:43:28 -07:00
|
|
|
}
|
2011-05-23 19:06:08 -07:00
|
|
|
glBindTexture(GL_TEXTURE_2D, texture[0]);
|
2011-05-23 12:47:43 -07:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
2011-05-23 19:55:20 -07:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size * charsWide, size * charsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
|
2011-05-23 12:47:43 -07:00
|
|
|
|
|
|
|
delete[] data;
|
|
|
|
delete[] temp;
|
2011-05-22 20:43:28 -07:00
|
|
|
}
|
|
|
|
|
2011-05-23 14:26:44 -07:00
|
|
|
void GfxOpenGL::destroyFont(Font *font) {
|
2013-04-02 13:08:38 -07:00
|
|
|
const FontUserData *data = (const FontUserData *)font->getUserData();
|
2011-05-23 19:06:08 -07:00
|
|
|
if (data) {
|
|
|
|
glDeleteTextures(1, &(data->texture));
|
|
|
|
delete data;
|
2011-05-23 14:26:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-23 22:00:53 -07:00
|
|
|
void GfxOpenGL::createTextObject(TextObject *text) {
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:08:47 -07:00
|
|
|
void GfxOpenGL::drawTextObject(const TextObject *text) {
|
2011-05-23 16:19:47 -07:00
|
|
|
if (!text)
|
2011-05-22 20:43:28 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = text->getFGColor();
|
2012-05-05 18:08:47 -07:00
|
|
|
const Font *font = text->getFont();
|
2011-05-23 16:19:47 -07:00
|
|
|
|
2012-05-05 18:13:50 -07:00
|
|
|
glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
2012-05-05 18:08:47 -07:00
|
|
|
const FontUserData *userData = (const FontUserData *)font->getUserData();
|
2011-05-23 19:06:08 -07:00
|
|
|
if (!userData)
|
|
|
|
error("Could not get font userdata");
|
2013-11-10 09:58:54 -08:00
|
|
|
float sizeW = userData->size * _scaleW;
|
|
|
|
float sizeH = userData->size * _scaleH;
|
2011-05-23 19:06:08 -07:00
|
|
|
GLuint texture = userData->texture;
|
2011-05-23 16:19:47 -07:00
|
|
|
const Common::String *lines = text->getLines();
|
|
|
|
int numLines = text->getNumLines();
|
|
|
|
for (int j = 0; j < numLines; ++j) {
|
|
|
|
const Common::String &line = lines[j];
|
2012-01-27 18:01:44 +01:00
|
|
|
int x = text->getLineX(j);
|
|
|
|
int y = text->getLineY(j);
|
2011-05-23 16:19:47 -07:00
|
|
|
for (uint i = 0; i < line.size(); ++i) {
|
|
|
|
uint8 character = line[i];
|
2012-09-25 23:15:14 +02:00
|
|
|
float w = y + font->getCharStartingLine(character);
|
|
|
|
if (g_grim->getGameType() == GType_GRIM)
|
|
|
|
w += font->getBaseOffsetY();
|
2012-01-25 23:02:24 +01:00
|
|
|
float z = x + font->getCharStartingCol(character);
|
|
|
|
z *= _scaleW;
|
|
|
|
w *= _scaleH;
|
2011-05-23 16:19:47 -07:00
|
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
2011-06-06 13:48:44 -07:00
|
|
|
float width = 1 / 16.f;
|
2012-01-27 18:01:44 +01:00
|
|
|
float cx = ((character - 1) % 16) / 16.0f;
|
|
|
|
float cy = ((character - 1) / 16) / 16.0f;
|
2011-05-23 16:19:47 -07:00
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(cx, cy);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(z, w);
|
2011-06-06 13:48:44 -07:00
|
|
|
glTexCoord2f(cx + width, cy);
|
2013-11-10 09:58:54 -08:00
|
|
|
glVertex2f(z + sizeW, w);
|
2011-06-06 13:48:44 -07:00
|
|
|
glTexCoord2f(cx + width, cy + width);
|
2013-11-10 09:58:54 -08:00
|
|
|
glVertex2f(z + sizeW, w + sizeH);
|
2011-06-06 13:48:44 -07:00
|
|
|
glTexCoord2f(cx, cy + width);
|
2013-11-10 09:58:54 -08:00
|
|
|
glVertex2f(z, w + sizeH);
|
2011-05-23 16:19:47 -07:00
|
|
|
glEnd();
|
2014-07-30 21:35:38 -04:00
|
|
|
x += font->getCharKernedWidth(character);
|
2011-05-23 16:19:47 -07:00
|
|
|
}
|
2011-05-22 20:43:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
glColor3f(1, 1, 1);
|
|
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
2011-06-07 16:52:38 +02:00
|
|
|
glDepthMask(GL_TRUE);
|
2011-05-22 20:43:28 -07:00
|
|
|
}
|
|
|
|
|
2011-05-23 22:00:53 -07:00
|
|
|
void GfxOpenGL::destroyTextObject(TextObject *text) {
|
|
|
|
}
|
|
|
|
|
2014-07-24 15:37:11 +02:00
|
|
|
void GfxOpenGL::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
|
2014-06-30 22:13:40 +02:00
|
|
|
texture->_texture = new GLuint[1];
|
|
|
|
glGenTextures(1, (GLuint *)texture->_texture);
|
2014-07-14 09:32:45 +02:00
|
|
|
uint8 *texdata = new uint8[texture->_width * texture->_height * 4];
|
|
|
|
uint8 *texdatapos = texdata;
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
if (cmap != nullptr) { // EMI doesn't have colour-maps
|
2014-07-14 08:10:08 +02:00
|
|
|
int bytes = 4;
|
2014-06-30 22:13:40 +02:00
|
|
|
for (int y = 0; y < texture->_height; y++) {
|
|
|
|
for (int x = 0; x < texture->_width; x++) {
|
2014-07-14 09:32:45 +02:00
|
|
|
uint8 col = *data;
|
2012-01-02 14:00:05 +01:00
|
|
|
if (col == 0) {
|
2014-07-14 08:10:08 +02:00
|
|
|
memset(texdatapos, 0, bytes); // transparent
|
2014-06-30 22:13:40 +02:00
|
|
|
if (!texture->_hasAlpha) {
|
2012-01-02 14:00:05 +01:00
|
|
|
texdatapos[3] = '\xff'; // fully opaque
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(texdatapos, cmap->_colors + 3 * (col), 3);
|
2009-05-05 11:34:43 +00:00
|
|
|
texdatapos[3] = '\xff'; // fully opaque
|
|
|
|
}
|
2014-07-14 08:10:08 +02:00
|
|
|
texdatapos += bytes;
|
2012-01-02 14:00:05 +01:00
|
|
|
data++;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-02 14:00:05 +01:00
|
|
|
} else {
|
2014-07-27 19:10:02 -04:00
|
|
|
#ifdef SCUMM_BIG_ENDIAN
|
|
|
|
// Copy and swap
|
|
|
|
for (int y = 0; y < texture->_height; y++) {
|
|
|
|
for (int x = 0; x < texture->_width; x++) {
|
|
|
|
uint32 pixel = (y * texture->_width + x) * texture->_bpp;
|
|
|
|
for (int b = 0; b < texture->_bpp; b++) {
|
|
|
|
texdata[pixel + b] = data[pixel + (texture->_bpp - 1) - b];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2014-06-30 22:13:40 +02:00
|
|
|
memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
|
2014-07-27 19:10:02 -04:00
|
|
|
#endif
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2012-01-02 14:00:05 +01:00
|
|
|
GLuint format = 0;
|
2012-01-10 06:39:04 +01:00
|
|
|
GLuint internalFormat = 0;
|
2014-06-30 22:13:40 +02:00
|
|
|
if (texture->_colorFormat == BM_RGBA) {
|
2012-01-02 14:00:05 +01:00
|
|
|
format = GL_RGBA;
|
2012-01-10 06:39:04 +01:00
|
|
|
internalFormat = GL_RGBA;
|
2014-06-30 22:13:40 +02:00
|
|
|
} else if (texture->_colorFormat == BM_BGRA) {
|
2012-11-18 09:47:23 -08:00
|
|
|
format = GL_BGRA;
|
|
|
|
internalFormat = GL_RGBA;
|
2013-07-09 21:12:55 +02:00
|
|
|
} else { // The only other colorFormat we load right now is BGR
|
2012-01-10 06:39:04 +01:00
|
|
|
format = GL_BGR;
|
|
|
|
internalFormat = GL_RGB;
|
2012-01-02 14:00:05 +01:00
|
|
|
}
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
GLuint *textures = (GLuint *)texture->_texture;
|
2011-07-28 22:21:16 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, textures[0]);
|
2014-05-29 13:57:10 +02:00
|
|
|
|
|
|
|
//Remove darkened lines in EMI intro
|
2014-06-17 21:58:21 -04:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4 && clamp) {
|
2014-05-29 13:57:10 +02:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
} else {
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
}
|
|
|
|
|
2011-07-28 22:21:16 +02:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
2014-06-30 22:13:40 +02:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, texture->_width, texture->_height, 0, format, GL_UNSIGNED_BYTE, texdata);
|
2009-05-05 11:34:43 +00:00
|
|
|
delete[] texdata;
|
|
|
|
}
|
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
void GfxOpenGL::selectTexture(const Texture *texture) {
|
|
|
|
GLuint *textures = (GLuint *)texture->_texture;
|
2011-07-28 22:21:16 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, textures[0]);
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
if (texture->_hasAlpha && g_grim->getGameType() == GType_MONKEY4) {
|
2012-08-12 15:05:32 +02:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
}
|
|
|
|
|
2012-01-07 03:16:55 +01:00
|
|
|
// Grim has inverted tex-coords, EMI doesn't
|
|
|
|
if (g_grim->getGameType() != GType_MONKEY4) {
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
2014-06-30 22:13:40 +02:00
|
|
|
glScalef(1.0f / texture->_width, 1.0f / texture->_height, 1);
|
2012-01-07 03:16:55 +01:00
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 22:13:40 +02:00
|
|
|
void GfxOpenGL::destroyTexture(Texture *texture) {
|
|
|
|
GLuint *textures = (GLuint *)texture->_texture;
|
2011-05-13 14:11:04 -07:00
|
|
|
if (textures) {
|
2011-07-28 22:21:16 +02:00
|
|
|
glDeleteTextures(1, textures);
|
2011-05-13 14:11:04 -07:00
|
|
|
delete[] textures;
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::drawDepthBitmap(int x, int y, int w, int h, char *data) {
|
2012-01-27 18:01:44 +01:00
|
|
|
//if (num != 0) {
|
2013-07-09 21:12:55 +02:00
|
|
|
// warning("Animation not handled yet in GL texture path");
|
2012-01-27 18:01:44 +01:00
|
|
|
//}
|
2009-06-23 06:46:05 +00:00
|
|
|
|
2009-06-27 11:53:55 +00:00
|
|
|
if (y + h == 480) {
|
2009-05-05 11:34:43 +00:00
|
|
|
glRasterPos2i(x, _screenHeight - 1);
|
2014-05-29 15:35:46 -07:00
|
|
|
glBitmap(0, 0, 0, 0, 0, -1, nullptr);
|
2009-06-27 11:53:55 +00:00
|
|
|
} else
|
2009-05-05 11:34:43 +00:00
|
|
|
glRasterPos2i(x, y + h);
|
|
|
|
|
2009-06-27 11:53:55 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2009-06-27 12:24:13 +00:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
2009-05-05 11:34:43 +00:00
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
2009-06-27 12:24:13 +00:00
|
|
|
glDepthMask(GL_TRUE);
|
2014-07-14 07:51:37 +02:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // 16 bit Z depth bitmap
|
2009-06-23 06:46:05 +00:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glDrawPixels(w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, data);
|
|
|
|
|
2009-06-23 06:46:05 +00:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
2009-05-05 11:34:43 +00:00
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
2014-05-01 12:34:23 +02:00
|
|
|
glDepthFunc(_depthFunc);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2013-07-09 21:12:55 +02:00
|
|
|
void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
|
2011-10-01 02:51:55 +02:00
|
|
|
int height = frame->h;
|
|
|
|
int width = frame->w;
|
2013-10-13 11:30:34 +02:00
|
|
|
byte *bitmap = (byte *)frame->getPixels();
|
2011-10-01 02:51:55 +02:00
|
|
|
|
2014-12-02 17:38:31 +01:00
|
|
|
GLenum format;
|
|
|
|
GLenum dataType;
|
|
|
|
int bytesPerPixel = frame->format.bytesPerPixel;
|
|
|
|
|
|
|
|
// Aspyr Logo format
|
|
|
|
if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0)) {
|
2019-09-26 17:02:54 +02:00
|
|
|
#if !defined(__amigaos4__)
|
2014-12-02 17:38:31 +01:00
|
|
|
format = GL_BGRA;
|
|
|
|
dataType = GL_UNSIGNED_INT_8_8_8_8;
|
2019-09-26 17:02:54 +02:00
|
|
|
#else
|
|
|
|
// AmigaOS' MiniGL does not understand GL_UNSIGNED_INT_8_8_8_8 yet.
|
|
|
|
format = GL_BGRA;
|
|
|
|
dataType = GL_UNSIGNED_BYTE;
|
|
|
|
#endif
|
2016-09-17 07:04:23 +00:00
|
|
|
} else if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0)) {
|
|
|
|
format = GL_BGRA;
|
|
|
|
dataType = GL_UNSIGNED_INT_8_8_8_8_REV;
|
2014-12-02 17:38:31 +01:00
|
|
|
} else if (frame->format == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
|
|
|
|
format = GL_RGB;
|
|
|
|
dataType = GL_UNSIGNED_SHORT_5_6_5;
|
|
|
|
} else {
|
|
|
|
error("Unknown pixelformat: Bpp: %d RBits: %d GBits: %d BBits: %d ABits: %d RShift: %d GShift: %d BShift: %d AShift: %d",
|
|
|
|
frame->format.bytesPerPixel,
|
|
|
|
-(frame->format.rLoss - 8),
|
|
|
|
-(frame->format.gLoss - 8),
|
|
|
|
-(frame->format.bLoss - 8),
|
|
|
|
-(frame->format.aLoss - 8),
|
|
|
|
frame->format.rShift,
|
|
|
|
frame->format.gShift,
|
|
|
|
frame->format.bShift,
|
|
|
|
frame->format.aShift);
|
|
|
|
}
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
// remove if already exist
|
|
|
|
if (_smushNumTex > 0) {
|
|
|
|
glDeleteTextures(_smushNumTex, _smushTexIds);
|
|
|
|
delete[] _smushTexIds;
|
|
|
|
_smushNumTex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create texture
|
|
|
|
_smushNumTex = ((width + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE) *
|
2013-07-09 21:12:55 +02:00
|
|
|
((height + (BITMAP_TEXTURE_SIZE - 1)) / BITMAP_TEXTURE_SIZE);
|
2009-05-05 11:34:43 +00:00
|
|
|
_smushTexIds = new GLuint[_smushNumTex];
|
|
|
|
glGenTextures(_smushNumTex, _smushTexIds);
|
|
|
|
for (int i = 0; i < _smushNumTex; i++) {
|
|
|
|
glBindTexture(GL_TEXTURE_2D, _smushTexIds[i]);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
2014-12-02 17:38:31 +01:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, BITMAP_TEXTURE_SIZE, BITMAP_TEXTURE_SIZE, 0, format, dataType, nullptr);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2014-12-02 17:38:31 +01:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, bytesPerPixel); // 16 bit RGB 565 bitmap/32 bit BGR
|
2009-05-05 11:34:43 +00:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
|
|
|
|
|
|
int curTexIdx = 0;
|
|
|
|
for (int y = 0; y < height; y += BITMAP_TEXTURE_SIZE) {
|
|
|
|
for (int x = 0; x < width; x += BITMAP_TEXTURE_SIZE) {
|
|
|
|
int t_width = (x + BITMAP_TEXTURE_SIZE >= width) ? (width - x) : BITMAP_TEXTURE_SIZE;
|
|
|
|
int t_height = (y + BITMAP_TEXTURE_SIZE >= height) ? (height - y) : BITMAP_TEXTURE_SIZE;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
|
2014-12-02 17:38:31 +01:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t_width, t_height, format, dataType, bitmap + (y * bytesPerPixel * width) + (bytesPerPixel * x));
|
2009-05-05 11:34:43 +00:00
|
|
|
curTexIdx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
2012-01-25 23:02:24 +01:00
|
|
|
_smushWidth = (int)(width * _scaleW);
|
|
|
|
_smushHeight = (int)(height * _scaleH);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-08-14 18:35:49 +02:00
|
|
|
void GfxOpenGL::drawMovieFrame(int offsetX, int offsetY) {
|
2009-05-05 11:34:43 +00:00
|
|
|
// prepare view
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
// A lot more may need to be put there : disabling Alpha test, blending, ...
|
|
|
|
// For now, just keep this here :-)
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
// draw
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
2012-01-27 13:48:36 +01:00
|
|
|
offsetX = (int)(offsetX * _scaleW);
|
|
|
|
offsetY = (int)(offsetY * _scaleH);
|
2012-01-25 23:02:24 +01:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glScissor(offsetX, _screenHeight - (offsetY + _smushHeight), _smushWidth, _smushHeight);
|
|
|
|
|
|
|
|
int curTexIdx = 0;
|
2012-01-25 23:02:24 +01:00
|
|
|
for (int y = 0; y < _smushHeight; y += (int)(BITMAP_TEXTURE_SIZE * _scaleH)) {
|
|
|
|
for (int x = 0; x < _smushWidth; x += (int)(BITMAP_TEXTURE_SIZE * _scaleW)) {
|
2009-05-05 11:34:43 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _smushTexIds[curTexIdx]);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0, 0);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x + offsetX, y + offsetY);
|
2011-04-06 05:55:07 +08:00
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x + offsetX + BITMAP_TEXTURE_SIZE * _scaleW, y + offsetY);
|
2011-04-06 05:55:07 +08:00
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x + offsetX + BITMAP_TEXTURE_SIZE * _scaleW, y + offsetY + BITMAP_TEXTURE_SIZE * _scaleH);
|
2011-04-06 05:55:07 +08:00
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x + offsetX, y + offsetY + BITMAP_TEXTURE_SIZE * _scaleH);
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnd();
|
|
|
|
curTexIdx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2011-08-14 18:35:49 +02:00
|
|
|
void GfxOpenGL::releaseMovieFrame() {
|
2009-05-05 11:34:43 +00:00
|
|
|
if (_smushNumTex > 0) {
|
|
|
|
glDeleteTextures(_smushNumTex, _smushTexIds);
|
|
|
|
delete[] _smushTexIds;
|
|
|
|
_smushNumTex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::loadEmergFont() {
|
2014-07-14 07:51:37 +02:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 8 bit font bitmaps
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
_emergFont = glGenLists(128);
|
|
|
|
for (int i = 32; i < 127; i++) {
|
|
|
|
glNewList(_emergFont + i, GL_COMPILE);
|
|
|
|
glBitmap(8, 13, 0, 2, 10, 0, Font::emerFont[i - 32]);
|
|
|
|
glEndList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::drawEmergString(int x, int y, const char *text, const Color &fgColor) {
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
|
|
|
|
glRasterPos2i(x, y);
|
2009-10-14 06:05:14 +00:00
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glListBase(_emergFont);
|
2012-04-03 16:58:04 -07:00
|
|
|
glCallLists(strlen(text), GL_UNSIGNED_BYTE, (const GLubyte *)text);
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2014-06-30 22:46:50 +02:00
|
|
|
Bitmap *GfxOpenGL::getScreenshot(int w, int h, bool useStored) {
|
2012-01-24 18:20:33 +01:00
|
|
|
Graphics::PixelBuffer src(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), _screenWidth * _screenHeight, DisposeAfterUse::YES);
|
2014-06-30 22:46:50 +02:00
|
|
|
if (useStored) {
|
|
|
|
memcpy(src.getRawBuffer(), _storedDisplay, _screenWidth * _screenHeight * 4);
|
|
|
|
} else {
|
|
|
|
glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, src.getRawBuffer());
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2014-06-30 22:46:50 +02:00
|
|
|
return createScreenshotBitmap(src, w, h, false);
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::storeDisplay() {
|
2009-05-05 11:34:43 +00:00
|
|
|
glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, _storedDisplay);
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::copyStoredToDisplay() {
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
|
|
|
glRasterPos2i(0, _screenHeight - 1);
|
2014-05-29 15:35:46 -07:00
|
|
|
glBitmap(0, 0, 0, 0, 0, -1, nullptr);
|
2009-05-05 11:34:43 +00:00
|
|
|
glDrawPixels(_screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, _storedDisplay);
|
|
|
|
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::dimScreen() {
|
2009-05-05 11:34:43 +00:00
|
|
|
uint32 *data = (uint32 *)_storedDisplay;
|
|
|
|
for (int l = 0; l < _screenWidth * _screenHeight; l++) {
|
|
|
|
uint32 pixel = data[l];
|
|
|
|
uint8 r = (pixel & 0xFF0000) >> 16;
|
|
|
|
uint8 g = (pixel & 0x00FF00) >> 8;
|
|
|
|
uint8 b = (pixel & 0x0000FF);
|
|
|
|
uint32 color = (r + g + b) / 10;
|
|
|
|
data[l] = ((color & 0xFF) << 16) | ((color & 0xFF) << 8) | (color & 0xFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
void GfxOpenGL::dimRegion(int x, int yReal, int w, int h, float level) {
|
2012-01-27 20:01:12 +01:00
|
|
|
x = (int)(x * _scaleW);
|
2013-07-09 21:12:55 +02:00
|
|
|
yReal = (int)(yReal * _scaleH);
|
2012-01-27 20:01:12 +01:00
|
|
|
w = (int)(w * _scaleW);
|
|
|
|
h = (int)(h * _scaleH);
|
2012-03-07 16:12:14 +01:00
|
|
|
int y = _screenHeight - yReal - h;
|
|
|
|
|
|
|
|
#ifdef GL_ARB_fragment_program
|
|
|
|
if (_useDimShader) {
|
|
|
|
GLuint texture;
|
|
|
|
glGenTextures(1, &texture);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
|
|
|
2014-05-29 15:35:46 -07:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
2013-07-09 21:12:55 +02:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
2012-03-07 16:12:14 +01:00
|
|
|
|
|
|
|
glViewport(0, 0, _screenWidth, _screenHeight);
|
|
|
|
|
|
|
|
// copy the data over to the texture
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
|
|
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, w, h, 0);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, 0, _screenHeight, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _dimFragProgram);
|
|
|
|
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, level, 0, 0, 0);
|
|
|
|
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
|
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0, 0);
|
|
|
|
glVertex2f(x, y);
|
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
|
|
|
glVertex2f(x + w, y);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex2f(x + w, y + h);
|
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
|
|
glVertex2f(x, y + h);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
|
|
|
|
glDeleteTextures(1, &texture);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
uint32 *data = new uint32[w * h];
|
2012-03-07 16:12:14 +01:00
|
|
|
y = _screenHeight - yReal;
|
2009-05-09 17:47:28 +00:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
// collect the requested area and generate the dimmed version
|
|
|
|
glReadPixels(x, y - h, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
|
|
for (int ly = 0; ly < h; ly++) {
|
|
|
|
for (int lx = 0; lx < w; lx++) {
|
|
|
|
uint32 pixel = data[ly * w + lx];
|
|
|
|
uint8 r = (pixel & 0xFF0000) >> 16;
|
|
|
|
uint8 g = (pixel & 0x00FF00) >> 8;
|
|
|
|
uint8 b = (pixel & 0x0000FF);
|
|
|
|
uint32 color = (uint32)(((r + g + b) / 3) * level);
|
|
|
|
data[ly * w + lx] = ((color & 0xFF) << 16) | ((color & 0xFF) << 8) | (color & 0xFF);
|
|
|
|
}
|
|
|
|
}
|
2009-05-09 17:47:28 +00:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
|
|
|
// Set the raster position and draw the bitmap
|
|
|
|
glRasterPos2i(x, yReal + h);
|
|
|
|
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
|
|
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
|
|
|
|
delete[] data;
|
|
|
|
}
|
2011-07-28 21:36:03 +02:00
|
|
|
|
2012-01-27 17:44:33 +01:00
|
|
|
void GfxOpenGL::irisAroundRegion(int x1, int y1, int x2, int y2) {
|
2011-07-28 01:36:27 +02:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
2011-07-28 02:27:48 +02:00
|
|
|
glOrtho(0.0, _screenWidth, _screenHeight, 0.0, 0.0, 1.0);
|
2011-07-28 01:36:27 +02:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
2011-07-28 21:36:03 +02:00
|
|
|
|
2011-07-28 01:36:27 +02:00
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDepthMask(GL_FALSE);
|
2011-07-28 21:36:03 +02:00
|
|
|
|
2011-07-28 01:36:27 +02:00
|
|
|
glColor3f(0.0f, 0.0f, 0.0f);
|
|
|
|
|
2013-04-02 13:08:38 -07:00
|
|
|
//Explicitly cast to avoid problems with C++11
|
|
|
|
float fx1 = x1;
|
|
|
|
float fx2 = x2;
|
|
|
|
float fy1 = y1;
|
|
|
|
float fy2 = y2;
|
|
|
|
float width = _screenWidth;
|
|
|
|
float height = _screenHeight;
|
2011-07-28 07:30:37 +02:00
|
|
|
float points[20] = {
|
2011-07-28 02:04:56 +02:00
|
|
|
0.0f, 0.0f,
|
2013-04-02 13:08:38 -07:00
|
|
|
0.0f, fy1,
|
|
|
|
width, 0.0f,
|
|
|
|
fx2, fy1,
|
|
|
|
width, height,
|
|
|
|
fx2, fy2,
|
|
|
|
0.0f, height,
|
|
|
|
fx1, fy2,
|
|
|
|
0.0f, fy1,
|
|
|
|
fx1, fy1
|
2011-07-28 01:36:27 +02:00
|
|
|
};
|
2011-08-13 11:53:27 +02:00
|
|
|
|
2017-11-26 19:54:06 -08:00
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
|
|
for (int i = 0 ;i < 10; ++i) {
|
|
|
|
glVertex2fv(points+2*i);
|
|
|
|
}
|
|
|
|
glEnd();
|
2011-07-28 21:36:03 +02:00
|
|
|
|
2011-07-28 02:27:48 +02:00
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
2011-07-28 01:36:27 +02:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
}
|
2011-07-28 21:36:03 +02:00
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxOpenGL::drawRectangle(const PrimitiveObject *primitive) {
|
2012-04-13 17:44:13 +02:00
|
|
|
float x1 = primitive->getP1().x * _scaleW;
|
|
|
|
float y1 = primitive->getP1().y * _scaleH;
|
|
|
|
float x2 = primitive->getP2().x * _scaleW;
|
|
|
|
float y2 = primitive->getP2().y * _scaleH;
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color color(primitive->getColor());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
2012-04-13 08:54:21 -07:00
|
|
|
glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
if (primitive->isFilled()) {
|
|
|
|
glBegin(GL_QUADS);
|
2012-04-13 08:19:58 +02:00
|
|
|
glVertex2f(x1, y1);
|
2012-04-13 08:54:21 -07:00
|
|
|
glVertex2f(x2 + 1, y1);
|
|
|
|
glVertex2f(x2 + 1, y2 + 1);
|
|
|
|
glVertex2f(x1, y2 + 1);
|
2012-04-13 08:19:58 +02:00
|
|
|
glEnd();
|
2009-05-05 11:34:43 +00:00
|
|
|
} else {
|
2016-07-11 14:51:39 +00:00
|
|
|
glLineWidth(_scaleW);
|
|
|
|
glBegin(GL_LINE_LOOP);
|
2012-04-13 17:44:13 +02:00
|
|
|
glVertex2f(x1, y1);
|
2012-04-13 08:54:21 -07:00
|
|
|
glVertex2f(x2 + 1, y1);
|
|
|
|
glVertex2f(x2 + 1, y2 + 1);
|
|
|
|
glVertex2f(x1, y2 + 1);
|
2012-04-13 08:19:58 +02:00
|
|
|
glEnd();
|
|
|
|
}
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxOpenGL::drawLine(const PrimitiveObject *primitive) {
|
2012-01-25 23:02:24 +01:00
|
|
|
float x1 = primitive->getP1().x * _scaleW;
|
|
|
|
float y1 = primitive->getP1().y * _scaleH;
|
|
|
|
float x2 = primitive->getP2().x * _scaleW;
|
|
|
|
float y2 = primitive->getP2().y * _scaleH;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = primitive->getColor();
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
2012-05-05 18:13:50 -07:00
|
|
|
glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-25 23:02:24 +01:00
|
|
|
glLineWidth(_scaleW);
|
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glBegin(GL_LINES);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x1, y1);
|
|
|
|
glVertex2f(x2, y2);
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2014-07-06 12:22:34 +02:00
|
|
|
void GfxOpenGL::drawDimPlane() {
|
|
|
|
if (_dimLevel == 0.0f) return;
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, 1.0, 1.0, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
glColor4f(0.0f, 0.0f, 0.0f, _dimLevel);
|
2014-11-05 20:53:26 +01:00
|
|
|
|
2014-07-06 12:22:34 +02:00
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glVertex2f(0, 0);
|
|
|
|
glVertex2f(1.0, 0);
|
|
|
|
glVertex2f(1.0, 1.0);
|
|
|
|
glVertex2f(0, 1.0);
|
|
|
|
glEnd();
|
|
|
|
|
2014-11-05 20:53:26 +01:00
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
2014-07-06 12:22:34 +02:00
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
2012-05-05 18:03:04 -07:00
|
|
|
void GfxOpenGL::drawPolygon(const PrimitiveObject *primitive) {
|
2012-01-25 23:02:24 +01:00
|
|
|
float x1 = primitive->getP1().x * _scaleW;
|
|
|
|
float y1 = primitive->getP1().y * _scaleH;
|
|
|
|
float x2 = primitive->getP2().x * _scaleW;
|
|
|
|
float y2 = primitive->getP2().y * _scaleH;
|
|
|
|
float x3 = primitive->getP3().x * _scaleW;
|
|
|
|
float y3 = primitive->getP3().y * _scaleH;
|
|
|
|
float x4 = primitive->getP4().x * _scaleW;
|
|
|
|
float y4 = primitive->getP4().y * _scaleH;
|
2009-05-05 11:34:43 +00:00
|
|
|
|
2012-01-27 11:47:28 -08:00
|
|
|
const Color &color = primitive->getColor();
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, _screenWidth, _screenHeight, 0, 0, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
2014-12-28 08:54:36 +01:00
|
|
|
#if !defined(__amigaos4__)
|
2014-12-28 08:48:56 +01:00
|
|
|
glDisable(GL_MULTISAMPLE);
|
2014-12-28 08:54:36 +01:00
|
|
|
#endif
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
2012-05-05 18:13:50 -07:00
|
|
|
glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
|
2009-05-05 11:34:43 +00:00
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
2012-01-25 23:02:24 +01:00
|
|
|
glVertex2f(x1, y1);
|
2014-12-28 08:48:56 +01:00
|
|
|
glVertex2f(x2 + 1, y2 + 1);
|
|
|
|
glVertex2f(x3, y3 + 1);
|
|
|
|
glVertex2f(x4 + 1, y4);
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glColor3f(1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
2014-12-28 08:54:36 +01:00
|
|
|
#if !defined(__amigaos4__)
|
2014-12-28 08:48:56 +01:00
|
|
|
glEnable(GL_MULTISAMPLE);
|
2014-12-28 08:54:36 +01:00
|
|
|
#endif
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2009-05-07 19:06:31 +00:00
|
|
|
|
2014-07-24 15:37:11 +02:00
|
|
|
void GfxOpenGL::readPixels(int x, int y, int width, int height, uint8 *buffer) {
|
|
|
|
uint8 *p = buffer;
|
2013-12-18 22:41:33 +01:00
|
|
|
for (int i = y; i < y + height; i++) {
|
2014-07-24 15:49:01 +02:00
|
|
|
glReadPixels(x, _screenHeight - 1 - i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, p);
|
2013-12-18 22:41:33 +01:00
|
|
|
p += width * 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-24 15:37:11 +02:00
|
|
|
void GfxOpenGL::createSpecialtyTextureFromScreen(uint id, uint8 *data, int x, int y, int width, int height) {
|
2014-06-30 22:46:50 +02:00
|
|
|
readPixels(x, y, width, height, data);
|
|
|
|
createSpecialtyTexture(id, data, width, height);
|
2012-04-12 17:53:03 -07:00
|
|
|
}
|
|
|
|
|
2014-08-05 18:03:39 +03:00
|
|
|
void GfxOpenGL::setBlendMode(bool additive) {
|
|
|
|
if (additive) {
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
|
|
} else {
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
} // end of namespace Grim
|
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
#endif
|