2021-12-26 21:19:38 +01:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
2009-05-05 11:34:43 +00:00
|
|
|
*
|
2021-12-26 21:19:38 +01:00
|
|
|
* ScummVM 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.
|
|
|
|
*
|
2021-12-26 18:47:58 +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 3 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
|
2021-12-26 18:47:58 +01:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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
|
|
|
|
2021-11-17 23:56:21 +00:00
|
|
|
#if defined(USE_OPENGL_GAME)
|
2013-07-14 15:09:41 +02:00
|
|
|
|
2011-10-01 22:40:31 +02:00
|
|
|
#include "graphics/surface.h"
|
|
|
|
|
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"
|
2015-01-28 20:44:27 -08:00
|
|
|
#include "engines/grim/remastered/overlay.h"
|
2013-01-21 17:04:26 +01:00
|
|
|
#include "engines/grim/registry.h"
|
2009-05-05 11:34:43 +00:00
|
|
|
|
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),
|
2021-05-04 11:45:03 +03: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
|
|
|
}
|
|
|
|
|
2020-10-14 06:49:28 +01:00
|
|
|
void GfxOpenGL::setupScreen(int screenW, int screenH) {
|
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;
|
|
|
|
|
2015-02-01 15:36:56 -08:00
|
|
|
_globalScaleW = _screenWidth / (float)_globalWidth;
|
|
|
|
_globalScaleH = _screenHeight / (float)_globalHeight;
|
|
|
|
|
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
|
|
|
|
2020-10-14 06:49:28 +01:00
|
|
|
g_system->showMouse(false);
|
2011-06-02 12:16:04 +02:00
|
|
|
|
2014-07-14 08:03:10 +02:00
|
|
|
int screenSize = _screenWidth * _screenHeight * 4;
|
2021-11-02 08:47:48 +02:00
|
|
|
_storedDisplay = new byte[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
|
|
|
|
2021-12-15 20:31:04 +01:00
|
|
|
glClearStencil(~0);
|
|
|
|
|
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);
|
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;
|
|
|
|
}
|
|
|
|
|
2021-06-21 16:11:06 +01:00
|
|
|
#ifdef GL_ARB_fragment_program
|
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
|
|
|
}
|
2022-03-21 20:08:46 +01:00
|
|
|
}
|
2012-03-07 16:12:14 +01:00
|
|
|
|
2022-03-21 20:08:46 +01:00
|
|
|
if (_useDimShader) {
|
2012-03-07 16:12:14 +01:00
|
|
|
glGenProgramsARB(1, &_dimFragProgram);
|
|
|
|
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, _dimFragProgram);
|
|
|
|
|
2022-03-21 20:08:46 +01:00
|
|
|
GLint errorPos;
|
2012-03-07 16:12:14 +01:00
|
|
|
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();
|
|
|
|
|
2020-09-23 23:20:23 +02:00
|
|
|
float right = nclip * tan(fov / 2 * ((float)M_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) {
|
2021-12-15 20:31:04 +01:00
|
|
|
glScaled(1.0f, 1.0f, -1.0f);
|
2014-08-05 15:43:39 -04:00
|
|
|
_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;
|
|
|
|
}
|
|
|
|
|
2021-12-10 18:37:24 +01:00
|
|
|
static void shadowProjection(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++) {
|
2020-10-31 21:07:12 +01:00
|
|
|
uint16 *indices = (uint16 *)model->_faces[i]._indexes;
|
2013-12-10 15:52:33 +01:00
|
|
|
|
|
|
|
for (uint j = 0; j < model->_faces[i]._faceLength * 3; j++) {
|
2020-10-31 21:07:12 +01:00
|
|
|
uint16 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;
|
2021-05-04 11:45:03 +03:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
if (left < 0)
|
|
|
|
left = 0;
|
|
|
|
if (right >= _gameWidth)
|
|
|
|
right = _gameWidth - 1;
|
|
|
|
if (top < 0)
|
|
|
|
top = 0;
|
|
|
|
if (bottom >= _gameHeight)
|
|
|
|
bottom = _gameHeight - 1;
|
2021-05-04 11:45:03 +03:00
|
|
|
|
2013-12-10 15:52:33 +01:00
|
|
|
if (top >= _gameHeight || left >= _gameWidth || bottom < 0 || right < 0) {
|
|
|
|
*x1 = -1;
|
|
|
|
*y1 = -1;
|
|
|
|
*x2 = -1;
|
|
|
|
*y2 = -1;
|
|
|
|
return;
|
|
|
|
}
|
2021-05-04 11:45:03 +03:00
|
|
|
|
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();
|
2021-12-15 20:31:04 +01:00
|
|
|
|
|
|
|
// Apply the view transform.
|
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) {
|
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);
|
2021-12-10 18:37:24 +01: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());
|
|
|
|
}
|
2021-12-10 18:37:24 +01:00
|
|
|
shadowProjection(_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
|
|
|
|
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::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
|
|
|
|
2021-12-15 20:31:04 +01:00
|
|
|
glClear(GL_STENCIL_BUFFER_BIT);
|
2009-05-05 11:34:43 +00:00
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
glStencilFunc(GL_ALWAYS, 1, (GLuint)~0);
|
|
|
|
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
2021-12-15 20:31:04 +01:00
|
|
|
|
2009-05-05 11:34:43 +00:00
|
|
|
glDisable(GL_LIGHTING);
|
2011-07-19 09:08:46 +02:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
2021-12-15 20:31:04 +01:00
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
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
|
|
|
}
|
|
|
|
|
2021-12-15 20:31:04 +01:00
|
|
|
void GfxOpenGL::setShadow(Shadow *shadow) {
|
|
|
|
_currentShadowArray = shadow;
|
|
|
|
}
|
|
|
|
|
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) {
|
2020-10-31 21:07:12 +01:00
|
|
|
uint16 *indices = (uint16 *)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++) {
|
2020-10-31 21:07:12 +01:00
|
|
|
uint16 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);
|
2021-12-15 20:31:04 +01:00
|
|
|
} 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-01-02 00:50:26 +02:00
|
|
|
glEnd();
|
2021-12-15 20:31:04 +01:00
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
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();
|
|
|
|
}
|
|
|
|
|
2015-01-28 20:44:27 -08:00
|
|
|
void GfxOpenGL::drawOverlay(const Overlay *overlay) {
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2021-05-04 11:45:03 +03:00
|
|
|
|
2015-01-28 20:44:27 -08:00
|
|
|
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
|
|
|
|
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
glAlphaFunc(GL_GEQUAL, 0.5f);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
2021-05-04 11:45:03 +03:00
|
|
|
|
2015-01-28 20:44:27 -08:00
|
|
|
|
2015-02-03 19:11:18 -08:00
|
|
|
float height = overlay->getHeight() * _globalScaleH;
|
|
|
|
float width = overlay->getWidth() * _globalScaleW;
|
|
|
|
float x = overlay->_x * _globalScaleW;
|
|
|
|
float y = overlay->_y * _globalScaleH;
|
2015-01-28 20:44:27 -08:00
|
|
|
|
2015-01-31 13:36:01 -08:00
|
|
|
glBegin(GL_QUADS);
|
2015-01-28 20:44:27 -08:00
|
|
|
glTexCoord2f(0.0f, 0.0f);
|
2015-01-31 13:36:01 -08:00
|
|
|
glVertex2f(x, y);
|
2015-01-28 20:44:27 -08:00
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
2015-01-31 13:36:01 -08:00
|
|
|
glVertex2f((x + width), y);
|
2015-01-28 20:44:27 -08:00
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
2015-01-31 13:36:01 -08:00
|
|
|
glVertex2f((x + width), (y + height));
|
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
|
|
glVertex2f(x, (y + height));
|
2015-01-28 20:44:27 -08:00
|
|
|
glEnd();
|
2015-01-31 13:36:01 -08:00
|
|
|
|
|
|
|
|
2015-01-28 20:44:27 -08:00
|
|
|
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
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++) {
|
2021-11-27 20:14:44 +01:00
|
|
|
uint16 *zbufPtr = reinterpret_cast<uint16 *>(const_cast<void *>(bitmap->getImageData(pic).getPixels()));
|
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) *
|
2022-06-08 01:12:00 +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;
|
2021-11-29 20:43:09 +01:00
|
|
|
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;
|
2021-11-29 20:43:09 +01:00
|
|
|
uint16 *bitmapData = (uint16 *)const_cast<void *>(bitmap->getImageData(pic).getPixels());
|
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));
|
2021-11-29 20:43:09 +01:00
|
|
|
texOut = (byte *)const_cast<void *>(bitmap->getImageData(pic).getPixels());
|
2011-05-01 03:50:18 +08:00
|
|
|
} else {
|
2021-11-29 20:43:09 +01:00
|
|
|
texOut = (byte *)const_cast<void *>(bitmap->getImageData(pic).getPixels());
|
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,
|
2022-06-08 01:12:00 +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);
|
|
|
|
|
2021-12-15 20:31:04 +01: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()) {
|
2021-11-27 20:14:44 +01:00
|
|
|
drawDepthBitmap(dx, dy, bitmap->getWidth(), bitmap->getHeight(), (const char *)bitmap->getData(bitmap->getActiveImage() - 1).getPixels());
|
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;
|
2021-11-02 08:47:48 +02:00
|
|
|
byte *temp = new byte[arraySize]();
|
2011-05-23 14:26:44 -07:00
|
|
|
if (!temp)
|
|
|
|
error("Could not allocate %d bytes", arraySize);
|
2011-05-23 12:47:43 -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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
struct TextObjectUserData {
|
|
|
|
GLuint *_texids;
|
|
|
|
};
|
|
|
|
|
2011-05-23 22:00:53 -07:00
|
|
|
void GfxOpenGL::createTextObject(TextObject *text) {
|
2021-11-02 11:06:12 +02:00
|
|
|
if (g_grim->getGameType() != GType_GRIM || !g_grim->isRemastered())
|
2020-10-07 19:50:27 +02:00
|
|
|
return;
|
|
|
|
|
2020-10-07 21:11:04 +02:00
|
|
|
#ifdef USE_FREETYPE2
|
2015-02-03 18:46:02 -08:00
|
|
|
//error("Could not get font userdata");
|
|
|
|
const Font *font = text->getFont();
|
|
|
|
const FontTTF *f = static_cast<const FontTTF *>(font);
|
|
|
|
Graphics::Font *gf = f->_font;
|
|
|
|
int numLines = text->getNumLines();
|
|
|
|
GLuint *texids = new GLuint[numLines];
|
|
|
|
glGenTextures(numLines, texids);
|
|
|
|
// Not at all correct for line-wrapping, but atleast we get all the lines now.
|
|
|
|
for (int i = 0; i < numLines; i++) {
|
|
|
|
Graphics::Surface surface;
|
|
|
|
|
|
|
|
int width = gf->getStringWidth(text->getLines()[i]);
|
|
|
|
int height = width;
|
|
|
|
surface.create(height, width, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
|
|
|
|
gf->drawString(&surface, text->getLines()[i], 0, 0, width, 0xFFFFFFFF);
|
|
|
|
|
|
|
|
byte *bitmap = (byte *)surface.getPixels();
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texids[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);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
|
|
|
|
|
|
|
|
surface.free();
|
|
|
|
}
|
|
|
|
TextObjectUserData *ud = new TextObjectUserData;
|
|
|
|
|
|
|
|
ud->_texids = texids;
|
|
|
|
text->setUserData(ud);
|
2020-10-07 21:11:04 +02:00
|
|
|
#endif
|
2011-05-23 22:00:53 -07:00
|
|
|
}
|
|
|
|
|
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();
|
2015-02-01 15:36:56 -08:00
|
|
|
if (!userData) {
|
2021-11-02 11:06:12 +02:00
|
|
|
if (g_grim->getGameType() != GType_GRIM || !g_grim->isRemastered())
|
2020-10-07 20:18:35 +02:00
|
|
|
error("Could not get font userdata");
|
2020-10-07 21:11:04 +02:00
|
|
|
#ifdef USE_FREETYPE2
|
2015-02-01 15:36:56 -08:00
|
|
|
const FontTTF *f = static_cast<const FontTTF *>(font);
|
|
|
|
Graphics::Font *gf = f->_font;
|
|
|
|
|
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
const TextObjectUserData *ud = (const TextObjectUserData *)text->getUserData();
|
2015-02-01 15:36:56 -08:00
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
int numLines = text->getNumLines();
|
|
|
|
for (int i = 0; i < numLines; ++i) {
|
|
|
|
float width = gf->getStringWidth(text->getLines()[i]);
|
|
|
|
float height = width;
|
|
|
|
float x = text->getLineX(i);
|
2015-02-01 15:36:56 -08:00
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
float y = text->getLineY(i);
|
2015-02-01 15:36:56 -08:00
|
|
|
|
2015-02-03 19:49:47 -08:00
|
|
|
if (text->getCoords() == 2 || text->getCoords() == 1) {
|
2015-02-03 18:46:02 -08:00
|
|
|
x *= _globalScaleW;
|
|
|
|
y *= _globalScaleH;
|
2015-02-01 15:36:56 -08:00
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
width *= _globalScaleW;
|
|
|
|
height *= _globalScaleH;
|
2015-02-03 19:49:47 -08:00
|
|
|
} else if (text->getCoords() == 0) {
|
2015-02-03 18:46:02 -08:00
|
|
|
x *= _scaleW;
|
|
|
|
y *= _scaleH;
|
2015-02-01 15:36:56 -08:00
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
width *= _scaleW;
|
|
|
|
height *= _scaleH;
|
|
|
|
}
|
2015-02-01 15:36:56 -08:00
|
|
|
|
2015-02-03 18:46:02 -08:00
|
|
|
glBindTexture(GL_TEXTURE_2D, ud->_texids[i]);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f(0.0f, 0.0f);
|
|
|
|
glVertex2f(x, y);
|
|
|
|
glTexCoord2f(1.0f, 0.0f);
|
|
|
|
glVertex2f((x + width), y);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex2f((x + width), (y + height));
|
|
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
|
|
glVertex2f(x, (y + height));
|
|
|
|
glEnd();
|
|
|
|
}
|
2015-02-01 15:36:56 -08:00
|
|
|
|
|
|
|
glColor3f(1, 1, 1);
|
|
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glDepthMask(GL_TRUE);
|
2020-10-07 21:11:04 +02:00
|
|
|
#endif
|
2015-02-01 15:36:56 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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) {
|
2021-11-02 11:06:12 +02:00
|
|
|
if (g_grim->getGameType() != GType_GRIM || !g_grim->isRemastered())
|
2020-10-07 20:18:35 +02:00
|
|
|
return;
|
|
|
|
|
2020-10-07 19:50:27 +02:00
|
|
|
TextObjectUserData *ud = (TextObjectUserData *)const_cast<void *>(text->getUserData());
|
2015-02-03 18:46:02 -08:00
|
|
|
glDeleteTextures(text->getNumLines(), ud->_texids);
|
|
|
|
delete ud;
|
2011-05-23 22:00:53 -07:00
|
|
|
}
|
|
|
|
|
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-06-30 22:13:40 +02:00
|
|
|
memcpy(texdata, data, texture->_width * texture->_height * texture->_bpp);
|
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
|
|
|
|
2022-06-08 01:12:00 +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);
|
2021-12-04 22:21:12 +01:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->_width, texture->_height, 0, GL_RGBA, 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
|
|
|
}
|
|
|
|
|
2021-11-27 20:14:44 +01:00
|
|
|
void GfxOpenGL::drawDepthBitmap(int x, int y, int w, int h, const 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
|
|
|
|
2015-02-01 16:06:15 +01:00
|
|
|
double scaleW = _scaleW;
|
|
|
|
double scaleH = _scaleH;
|
|
|
|
// Remastered hack, don't scale full-screen videos for now.
|
|
|
|
if (height == 1080) {
|
|
|
|
_scaleW = 1.0f;
|
|
|
|
_scaleH = 1.0f;
|
|
|
|
}
|
|
|
|
|
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
|
2020-11-26 15:10:01 +01:00
|
|
|
// MiniGL on AmigaOS4 doesn't understand GL_UNSIGNED_INT_8_8_8_8 yet.
|
2019-09-26 17:02:54 +02:00
|
|
|
format = GL_BGRA;
|
|
|
|
dataType = GL_UNSIGNED_BYTE;
|
2020-11-22 22:28:02 +01:00
|
|
|
#endif
|
|
|
|
// Used by Grim Fandango Remastered
|
|
|
|
} else if (frame->format == Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0)) {
|
|
|
|
#if !defined(__amigaos4__)
|
|
|
|
format = GL_BGRA;
|
|
|
|
dataType = GL_UNSIGNED_INT_8_8_8_8;
|
|
|
|
#else
|
2020-11-26 15:10:01 +01:00
|
|
|
// MiniGL on AmigaOS4 doesn't understand GL_UNSIGNED_INT_8_8_8_8 yet.
|
2020-11-22 22:28:02 +01:00
|
|
|
format = GL_BGRA;
|
|
|
|
dataType = GL_UNSIGNED_BYTE;
|
2019-09-26 17:02:54 +02:00
|
|
|
#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);
|
2015-02-01 16:06:15 +01:00
|
|
|
_scaleW = scaleW;
|
|
|
|
_scaleH = scaleH;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
2011-08-14 18:35:49 +02:00
|
|
|
void GfxOpenGL::drawMovieFrame(int offsetX, int offsetY) {
|
2015-02-01 16:06:15 +01:00
|
|
|
double scaleW = _scaleW;
|
|
|
|
double scaleH = _scaleH;
|
|
|
|
// Remastered hack, don't scale full-screen videos for now.
|
|
|
|
if (_smushHeight == 1080) {
|
|
|
|
_scaleW = 1.0f;
|
|
|
|
_scaleH = 1.0f;
|
|
|
|
}
|
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);
|
2015-02-01 16:06:15 +01:00
|
|
|
|
|
|
|
_scaleW = scaleW;
|
|
|
|
_scaleH = scaleH;
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2020-02-07 23:23:22 +01:00
|
|
|
for (int i = 32; i < 128; i++) {
|
2009-05-05 11:34:43 +00:00
|
|
|
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);
|
2021-05-04 11:45:03 +03:00
|
|
|
|
2020-10-11 18:24:36 +02:00
|
|
|
char *list = const_cast<char *>(text);
|
2020-10-14 08:31:25 +02:00
|
|
|
glCallLists(strlen(text), GL_UNSIGNED_BYTE, (void *)list);
|
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) {
|
2021-11-27 20:14:44 +01:00
|
|
|
Graphics::Surface src;
|
|
|
|
src.create(_screenWidth, _screenHeight, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
|
2014-06-30 22:46:50 +02:00
|
|
|
if (useStored) {
|
2021-11-27 20:14:44 +01:00
|
|
|
memcpy(src.getPixels(), _storedDisplay, _screenWidth * _screenHeight * 4);
|
2014-06-30 22:46:50 +02:00
|
|
|
} else {
|
2021-11-27 20:14:44 +01:00
|
|
|
glReadPixels(0, 0, _screenWidth, _screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, src.getPixels());
|
2009-05-05 11:34:43 +00:00
|
|
|
}
|
2021-11-27 20:14:44 +01:00
|
|
|
Bitmap *bmp = createScreenshotBitmap(&src, w, h, false);
|
|
|
|
src.free();
|
|
|
|
return bmp;
|
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);
|
|
|
|
|
2022-06-08 01:12:00 +02:00
|
|
|
// Explicitly cast to avoid problems with C++11
|
2013-04-02 13:08:38 -07:00
|
|
|
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() {
|
2022-06-08 01:12:00 +02:00
|
|
|
if (_dimLevel == 0.0f)
|
|
|
|
return;
|
2014-07-06 12:22:34 +02:00
|
|
|
|
|
|
|
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
|