911 lines
27 KiB
C++
911 lines
27 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "graphics/surface.h"
|
|
#include "graphics/transparent_surface.h"
|
|
|
|
#include "sludge/allfiles.h"
|
|
#include "sludge/fileset.h"
|
|
#include "sludge/people.h"
|
|
#include "sludge/sprites.h"
|
|
#include "sludge/moreio.h"
|
|
#include "sludge/newfatal.h"
|
|
#include "sludge/backdrop.h"
|
|
#include "sludge/sludger.h"
|
|
#include "sludge/zbuffer.h"
|
|
#include "sludge/imgloader.h"
|
|
#include "sludge/sludge.h"
|
|
|
|
namespace Sludge {
|
|
|
|
// Sprite display informations
|
|
struct SpriteDisplay {
|
|
int x, y;
|
|
int width, height;
|
|
Graphics::FLIP_FLAGS flip;
|
|
Graphics::Surface *surface;
|
|
|
|
SpriteDisplay(int xpos, int ypos, Graphics::FLIP_FLAGS f, Graphics::Surface *ptr, int w = -1, int h = 1) :
|
|
x(xpos), y(ypos), flip(f), surface(ptr), width(w), height(h) {
|
|
}
|
|
};
|
|
|
|
// All sprites are sorted into different "layers" (up to 16) according to their relative y position to z-buffer zones
|
|
struct SpriteLayers {
|
|
int numLayers;
|
|
Common::List<SpriteDisplay> layer[16];
|
|
};
|
|
|
|
SpriteLayers spriteLayers;
|
|
|
|
extern zBufferData zBuffer;
|
|
|
|
#if 0
|
|
extern GLuint backdropTextureName;
|
|
#endif
|
|
|
|
extern inputType input;
|
|
extern int cameraX, cameraY;
|
|
extern float cameraZoom;
|
|
extern Graphics::Surface renderSurface;
|
|
extern Graphics::Surface backdropSurface;
|
|
|
|
byte currentBurnR = 0, currentBurnG = 0, currentBurnB = 0;
|
|
|
|
void forgetSpriteBank(spriteBank &forgetme) {
|
|
if (forgetme.myPalette.pal) {
|
|
delete[] forgetme.myPalette.pal;
|
|
forgetme.myPalette.pal = NULL;
|
|
delete[] forgetme.myPalette.r;
|
|
forgetme.myPalette.r = NULL;
|
|
delete[] forgetme.myPalette.g;
|
|
forgetme.myPalette.g = NULL;
|
|
delete[] forgetme.myPalette.b;
|
|
forgetme.myPalette.b = NULL;
|
|
}
|
|
|
|
for (int i = 0; i < forgetme.total; ++i) {
|
|
forgetme.sprites[i].surface.free();
|
|
forgetme.sprites[i].burnSurface.free();
|
|
}
|
|
|
|
delete []forgetme.sprites;
|
|
forgetme.sprites = NULL;
|
|
|
|
// TODO: also remove sprite bank from allLoadedBanks
|
|
// And add a function call for this function to the scripting language
|
|
}
|
|
|
|
bool reserveSpritePal(spritePalette &sP, int n) {
|
|
if (sP.pal) {
|
|
delete[] sP.pal;
|
|
delete[] sP.r;
|
|
delete[] sP.g;
|
|
delete[] sP.b;
|
|
}
|
|
|
|
sP.pal = new uint16[n];
|
|
if (!checkNew(sP.pal))
|
|
return false;
|
|
|
|
sP.r = new byte[n];
|
|
if (!checkNew(sP.r))
|
|
return false;
|
|
sP.g = new byte[n];
|
|
if (!checkNew(sP.g))
|
|
return false;
|
|
sP.b = new byte[n];
|
|
if (!checkNew(sP.b))
|
|
return false;
|
|
sP.total = n;
|
|
return (bool)(sP.pal != NULL) && (sP.r != NULL) && (sP.g != NULL) && (sP.b != NULL);
|
|
}
|
|
|
|
bool loadSpriteBank(int fileNum, spriteBank &loadhere, bool isFont) {
|
|
|
|
int total, spriteBankVersion = 0, howmany = 0, startIndex = 0;
|
|
byte *data;
|
|
|
|
setResourceForFatal(fileNum);
|
|
if (!openFileFromNum(fileNum))
|
|
return fatal("Can't open sprite bank / font");
|
|
|
|
loadhere.isFont = isFont;
|
|
|
|
total = bigDataFile->readUint16BE();
|
|
if (!total) {
|
|
spriteBankVersion = bigDataFile->readByte();
|
|
if (spriteBankVersion == 1) {
|
|
total = 0;
|
|
} else {
|
|
total = bigDataFile->readUint16BE();
|
|
}
|
|
}
|
|
|
|
if (total <= 0)
|
|
return fatal("No sprites in bank or invalid sprite bank file");
|
|
if (spriteBankVersion > 3)
|
|
return fatal("Unsupported sprite bank file format");
|
|
|
|
loadhere.total = total;
|
|
loadhere.sprites = new sprite[total];
|
|
if (!checkNew(loadhere.sprites))
|
|
return false;
|
|
byte **spriteData = new byte *[total];
|
|
if (!checkNew(spriteData))
|
|
return false;
|
|
|
|
// version 1, 2, read how many now
|
|
if (spriteBankVersion && spriteBankVersion < 3) {
|
|
howmany = bigDataFile->readByte();
|
|
startIndex = 1;
|
|
}
|
|
|
|
// version 3, sprite is png
|
|
if (spriteBankVersion == 3) {
|
|
debug(kSludgeDebugGraphics, "png sprite");
|
|
for (int i = 0; i < total; i++) {
|
|
loadhere.sprites[i].xhot = bigDataFile->readSint16LE();
|
|
loadhere.sprites[i].yhot = bigDataFile->readSint16LE();
|
|
if (!ImgLoader::loadPNGImage(bigDataFile, &loadhere.sprites[i].surface, false)) {
|
|
return fatal("fail to read png sprite");
|
|
}
|
|
}
|
|
finishAccess();
|
|
setResourceForFatal(-1);
|
|
return true;
|
|
}
|
|
|
|
// version 0, 1, 2
|
|
for (int i = 0; i < total; i++) {
|
|
uint picwidth, picheight;
|
|
// load sprite width, height, relative position
|
|
if (spriteBankVersion == 2) {
|
|
picwidth = bigDataFile->readUint16BE();
|
|
picheight = bigDataFile->readUint16BE();
|
|
loadhere.sprites[i].xhot = bigDataFile->readSint16LE();
|
|
loadhere.sprites[i].yhot = bigDataFile->readSint16LE();
|
|
} else {
|
|
picwidth = (byte)bigDataFile->readByte();
|
|
picheight = (byte)bigDataFile->readByte();
|
|
loadhere.sprites[i].xhot = bigDataFile->readByte();
|
|
loadhere.sprites[i].yhot = bigDataFile->readByte();
|
|
}
|
|
|
|
// init data
|
|
loadhere.sprites[i].surface.create(picwidth, picheight, *g_sludge->getScreenPixelFormat());
|
|
if (isFont) {
|
|
loadhere.sprites[i].burnSurface.create(picwidth, picheight, *g_sludge->getScreenPixelFormat());
|
|
}
|
|
data = (byte *)new byte[picwidth * (picheight + 1)];
|
|
if (!checkNew(data))
|
|
return false;
|
|
memset(data + picwidth * picheight, 0, picwidth);
|
|
spriteData[i] = data;
|
|
|
|
// read color
|
|
if (spriteBankVersion == 2) { // RUN LENGTH COMPRESSED DATA
|
|
uint size = picwidth * picheight;
|
|
uint pip = 0;
|
|
|
|
while (pip < size) {
|
|
byte col = bigDataFile->readByte();
|
|
int looper;
|
|
if (col > howmany) {
|
|
col -= howmany + 1;
|
|
looper = bigDataFile->readByte() + 1;
|
|
} else
|
|
looper = 1;
|
|
|
|
while (looper--) {
|
|
data[pip++] = col;
|
|
}
|
|
}
|
|
} else { // RAW DATA
|
|
uint bytes_read = bigDataFile->read(data, picwidth * picheight);
|
|
if (bytes_read != picwidth * picheight && bigDataFile->err()) {
|
|
warning("Reading error in loadSpriteBank.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// read howmany for version 0
|
|
if (!spriteBankVersion) {
|
|
howmany = bigDataFile->readByte();
|
|
startIndex = bigDataFile->readByte();
|
|
}
|
|
|
|
// Make palette for version 0, 1, 2
|
|
if (!reserveSpritePal(loadhere.myPalette, howmany + startIndex))
|
|
return false;
|
|
for (int i = 0; i < howmany; i++) {
|
|
loadhere.myPalette.r[i + startIndex] = (byte)bigDataFile->readByte();
|
|
loadhere.myPalette.g[i + startIndex] = (byte)bigDataFile->readByte();
|
|
loadhere.myPalette.b[i + startIndex] = (byte)bigDataFile->readByte();
|
|
loadhere.myPalette.pal[i + startIndex] =
|
|
(uint16)g_sludge->getOrigPixelFormat()->RGBToColor(
|
|
loadhere.myPalette.r[i + startIndex],
|
|
loadhere.myPalette.g[i + startIndex],
|
|
loadhere.myPalette.b[i + startIndex]);
|
|
}
|
|
loadhere.myPalette.originalRed = loadhere.myPalette.originalGreen = loadhere.myPalette.originalBlue = 255;
|
|
|
|
// convert
|
|
for (int i = 0; i < total; i++) {
|
|
int fromhere = 0;
|
|
int transColour = -1;
|
|
int size = loadhere.sprites[i].surface.w * loadhere.sprites[i].surface.h;
|
|
while (fromhere < size) {
|
|
byte s = spriteData[i][fromhere++];
|
|
if (s) {
|
|
transColour = s;
|
|
break;
|
|
}
|
|
}
|
|
fromhere = 0;
|
|
for (int y = 0; y < loadhere.sprites[i].surface.h; y++) {
|
|
for (int x = 0; x < loadhere.sprites[i].surface.w; x++) {
|
|
byte *target = (byte *)loadhere.sprites[i].surface.getBasePtr(x, y);
|
|
byte s = spriteData[i][fromhere++];
|
|
if (s) {
|
|
target[0] = (byte)255;
|
|
target[1] = (byte)loadhere.myPalette.b[s];
|
|
target[2] = (byte)loadhere.myPalette.g[s];
|
|
target[3] = (byte)loadhere.myPalette.r[s];
|
|
transColour = s;
|
|
} else if (transColour >= 0) {
|
|
target[0] = (byte)0;
|
|
target[1] = (byte)loadhere.myPalette.b[transColour];
|
|
target[2] = (byte)loadhere.myPalette.g[transColour];
|
|
target[3] = (byte)loadhere.myPalette.r[transColour];
|
|
}
|
|
if (isFont) {
|
|
target = (byte *)loadhere.sprites[i].burnSurface.getBasePtr(x, y);
|
|
if (s)
|
|
target[0] = loadhere.myPalette.r[s];
|
|
target[1] = (byte)255;
|
|
target[2] = (byte)255;
|
|
target[3] = (byte)255;
|
|
}
|
|
}
|
|
}
|
|
delete[] spriteData[i];
|
|
}
|
|
delete[] spriteData;
|
|
spriteData = NULL;
|
|
|
|
finishAccess();
|
|
|
|
setResourceForFatal(-1);
|
|
|
|
return true;
|
|
}
|
|
|
|
void pasteSpriteToBackDrop(int x1, int y1, sprite &single, const spritePalette &fontPal) {
|
|
x1 -= single.xhot;
|
|
y1 -= single.yhot;
|
|
Graphics::TransparentSurface tmp(single.surface, false);
|
|
tmp.blit(backdropSurface, x1, y1, Graphics::FLIP_NONE, nullptr, TS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
|
|
#if 0
|
|
float tx1 = (float)(single.tex_x) / fontPal.tex_w[single.texNum];
|
|
float ty1 = 0.0;
|
|
float tx2 = (float)(single.tex_x + single.width) / fontPal.tex_w[single.texNum];
|
|
float ty2 = (float)(single.height) / fontPal.tex_h[single.texNum];
|
|
|
|
float btx1;
|
|
float btx2;
|
|
float bty1;
|
|
float bty2;
|
|
|
|
int diffX = single.width;
|
|
int diffY = single.height;
|
|
|
|
x1 -= single.xhot;
|
|
y1 -= single.yhot;
|
|
|
|
if (! NPOT_textures) {
|
|
btx1 = backdropTexW * x1 / sceneWidth;
|
|
btx2 = backdropTexW * (x1 + single.width) / sceneWidth;
|
|
bty1 = backdropTexH * y1 / sceneHeight;
|
|
bty2 = backdropTexH * (y1 + single.height) / sceneHeight;
|
|
} else {
|
|
btx1 = (float) x1 / sceneWidth;
|
|
btx2 = (float)(x1 + single.width) / sceneWidth;
|
|
bty1 = (float) y1 / sceneHeight;
|
|
bty2 = (float)(y1 + single.height) / sceneHeight;
|
|
}
|
|
|
|
const GLfloat btexCoords[] = {
|
|
btx1, bty1,
|
|
btx2, bty1,
|
|
btx1, bty2,
|
|
btx2, bty2
|
|
};
|
|
|
|
if (x1 < 0) diffX += x1;
|
|
if (y1 < 0) diffY += y1;
|
|
if (x1 + diffX > sceneWidth) diffX = sceneWidth - x1;
|
|
if (y1 + diffY > sceneHeight) diffY = sceneHeight - y1;
|
|
if (diffX < 0) return;
|
|
if (diffY < 0) return;
|
|
|
|
setPixelCoords(true);
|
|
|
|
int xoffset = 0;
|
|
while (xoffset < diffX) {
|
|
int w = (diffX - xoffset < viewportWidth) ? diffX - xoffset : viewportWidth;
|
|
|
|
int yoffset = 0;
|
|
while (yoffset < diffY) {
|
|
int h = (diffY - yoffset < viewportHeight) ? diffY - yoffset : viewportHeight;
|
|
|
|
// Render the sprite to the backdrop
|
|
// (using mulitexturing, so the backdrop is seen where alpha < 1.0)
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glBindTexture(GL_TEXTURE_2D, backdropTextureName);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glUseProgram(shader.paste);
|
|
GLint uniform = glGetUniformLocation(shader.paste, "useLightTexture");
|
|
if (uniform >= 0) glUniform1i(uniform, 0);// No lighting
|
|
|
|
setPMVMatrix(shader.paste);
|
|
|
|
setPrimaryColor(fontPal.originalRed / 255.f, fontPal.originalGreen / 255.f, fontPal.originalBlue / 255.f, 1.0f);
|
|
glBindTexture(GL_TEXTURE_2D, fontPal.tex_names[single.texNum]);
|
|
//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
const GLfloat vertices[] = {
|
|
(GLfloat) - xoffset, (GLfloat) - yoffset, 0.,
|
|
(GLfloat)single.width - xoffset, (GLfloat) - yoffset, 0.,
|
|
(GLfloat) - xoffset, (GLfloat)single.height - yoffset, 0.,
|
|
(GLfloat)single.width - xoffset, (GLfloat)single.height - yoffset, 0.
|
|
};
|
|
|
|
const GLfloat texCoords[] = {
|
|
tx1, ty1,
|
|
tx2, ty1,
|
|
tx1, ty2,
|
|
tx2, ty2
|
|
};
|
|
|
|
drawQuad(shader.paste, vertices, 3, texCoords, NULL, btexCoords);
|
|
|
|
// Copy Our ViewPort To The Texture
|
|
glUseProgram(0);
|
|
|
|
copyTexSubImage2D(GL_TEXTURE_2D, 0, (int)((x1 < 0) ? xoffset : x1 + xoffset), (int)((y1 < 0) ? yoffset : y1 + yoffset), (int)((x1 < 0) ? viewportOffsetX - x1 : viewportOffsetX), (int)((y1 < 0) ? viewportOffsetY - y1 : viewportOffsetY), w, h, backdropTextureName);
|
|
|
|
yoffset += viewportHeight;
|
|
}
|
|
xoffset += viewportWidth;
|
|
}
|
|
setPixelCoords(false);
|
|
#endif
|
|
}
|
|
|
|
void burnSpriteToBackDrop(int x1, int y1, sprite &single, const spritePalette &fontPal) {
|
|
#if 0
|
|
float tx1 = (float)(single.tex_x - 0.5) / fontPal.tex_w[single.texNum];
|
|
float ty1 = 0.0;
|
|
float tx2 = (float)(single.tex_x + single.width + 0.5) / fontPal.tex_w[single.texNum];
|
|
float ty2 = (float)(single.height + 2) / fontPal.tex_h[single.texNum];
|
|
|
|
const GLfloat spriteTexCoords[] = {
|
|
tx1, ty1,
|
|
tx2, ty1,
|
|
tx1, ty2,
|
|
tx2, ty2
|
|
};
|
|
|
|
x1 -= single.xhot;
|
|
y1 -= single.yhot - 1;
|
|
|
|
float bx1 = (float)x1 * backdropTexW / sceneWidth;
|
|
float by1 = (float)y1 * backdropTexH / sceneHeight;
|
|
float bx2 = (float)(x1 + single.width - 1) * backdropTexW / sceneWidth;
|
|
float by2 = (float)(y1 + single.height - 1) * backdropTexH / sceneHeight;
|
|
|
|
const GLfloat backdropTexCoords[] = {
|
|
bx1, by1,
|
|
bx2, by1,
|
|
bx1, by2,
|
|
bx2, by2
|
|
};
|
|
|
|
const GLfloat backdropTexCoords2[] = {
|
|
0.0f, 0.0f,
|
|
backdropTexW, 0.0f,
|
|
0.0f, backdropTexH,
|
|
backdropTexW, backdropTexH
|
|
};
|
|
|
|
int diffX = single.width + 1;
|
|
int diffY = single.height + 2;
|
|
|
|
if (x1 < 0) diffX += x1;
|
|
if (y1 < 0) diffY += y1;
|
|
if (x1 + diffX > sceneWidth) diffX = sceneWidth - x1;
|
|
if (y1 + diffY > sceneHeight) diffY = sceneHeight - y1;
|
|
if (diffX < 0) return;
|
|
if (diffY < 0) return;
|
|
|
|
setPixelCoords(true);
|
|
setPrimaryColor(currentBurnR / 255.f, currentBurnG / 255.f, currentBurnB / 255.f, 1.0f);
|
|
|
|
GLfloat xoffset = 0.0f;
|
|
while (xoffset < diffX) {
|
|
int w = (diffX - xoffset < viewportWidth) ? diffX - xoffset : viewportWidth;
|
|
|
|
GLfloat yoffset = 0.0f;
|
|
while (yoffset < diffY) {
|
|
int h = (diffY - yoffset < viewportHeight) ? diffY - yoffset : viewportHeight;
|
|
|
|
const GLfloat backdropVertices[] = {
|
|
-x1 - xoffset, -y1 + yoffset, 0.0f,
|
|
sceneWidth - 1.0f - x1 - xoffset, -y1 + yoffset, 0.0f,
|
|
-x1 - xoffset, sceneHeight - 1.0f - y1 + yoffset, 0.0f,
|
|
sceneWidth - 1.0f - x1 - xoffset, sceneHeight - 1.0f - y1 + yoffset, 0.0f
|
|
};
|
|
|
|
const GLfloat spriteVertices[] = {
|
|
-xoffset, -yoffset, 0.0f,
|
|
single.width - 1 - xoffset, -yoffset, 0.0f,
|
|
-xoffset, single.height - 1 - yoffset, 0.0f,
|
|
single.width - 1 - xoffset, single.height - 1 - yoffset, 0.0f
|
|
};
|
|
|
|
glBindTexture(GL_TEXTURE_2D, backdropTextureName);
|
|
glUseProgram(shader.texture);
|
|
setPMVMatrix(shader.texture);
|
|
|
|
drawQuad(shader.texture, backdropVertices, 1, backdropTexCoords2);
|
|
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glBindTexture(GL_TEXTURE_2D, backdropTextureName);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glUseProgram(shader.paste);
|
|
GLint uniform = glGetUniformLocation(shader.paste, "useLightTexture");
|
|
if (uniform >= 0) glUniform1i(uniform, 0); // No lighting
|
|
|
|
setPMVMatrix(shader.paste);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, fontPal.burnTex_names[single.texNum]);
|
|
|
|
//FIXME: Test this some more. Also pasting the backdrop again is not strictly necessary but allows using the paste shader.
|
|
drawQuad(shader.paste, spriteVertices, 3, spriteTexCoords, NULL, backdropTexCoords);
|
|
glUseProgram(0);
|
|
|
|
// Copy Our ViewPort To The Texture
|
|
copyTexSubImage2D(GL_TEXTURE_2D, 0, (x1 < 0) ? xoffset : x1 + xoffset, (y1 < 0) ? yoffset : y1 + yoffset, viewportOffsetX, viewportOffsetY, w, h, backdropTextureName);
|
|
|
|
yoffset += viewportHeight;
|
|
}
|
|
xoffset += viewportWidth;
|
|
}
|
|
setPixelCoords(false);
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
extern GLuint backdropTextureName;
|
|
#endif
|
|
|
|
void fontSprite(bool flip, int x, int y, sprite &single, const spritePalette &fontPal) {
|
|
float x1 = (float)x - (float)single.xhot / cameraZoom;
|
|
float y1 = (float)y - (float)single.yhot / cameraZoom;
|
|
|
|
// Use Transparent surface to scale and blit
|
|
Graphics::TransparentSurface tmp(single.surface, false);
|
|
tmp.blit(renderSurface, x1, y1, (flip ? Graphics::FLIP_H : Graphics::FLIP_NONE), 0, TS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
|
|
|
|
if (single.burnSurface.getPixels() != nullptr) {
|
|
Graphics::TransparentSurface tmp2(single.burnSurface, false);
|
|
tmp2.blit(renderSurface, x1, y1, (flip ? Graphics::FLIP_H : Graphics::FLIP_NONE), 0, TS_RGB(fontPal.originalRed, fontPal.originalGreen, fontPal.originalBlue));
|
|
|
|
}
|
|
|
|
#if 0
|
|
float x2 = x1 + (float) single.surface.w / cameraZoom;
|
|
float y2 = y1 + (float) single.surface.h / cameraZoom;
|
|
float tx1 = (float) (single.tex_x - 0.5) / fontPal.tex_w[single.texNum];
|
|
float ty1 = 0.0;
|
|
float tx2 = (float) (single.tex_x + single.width + (flip ? 1.0 : 0.5))
|
|
/ fontPal.tex_w[single.texNum];
|
|
float ty2 = (float) (single.height + 2) / fontPal.tex_h[single.texNum];
|
|
|
|
GLfloat vertices[] = {
|
|
x1, y1, 0.0f,
|
|
x2, y1, 0.0f,
|
|
x1, y2, 0.0f,
|
|
x2, y2, 0.0f
|
|
};
|
|
if (flip) {
|
|
vertices[0] = x2;
|
|
vertices[3] = x1;
|
|
vertices[6] = x2;
|
|
vertices[9] = x1;
|
|
}
|
|
|
|
const GLfloat texCoords[] = {
|
|
tx1, ty1,
|
|
tx2, ty1,
|
|
tx1, ty2,
|
|
tx2, ty2
|
|
};
|
|
|
|
//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // GL_MODULATE instead of decal mixes the colours!
|
|
setPrimaryColor(fontPal.originalRed / 255.f, fontPal.originalGreen / 255.f, fontPal.originalBlue / 255.f, 1.0f);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, fontPal.tex_names[single.texNum]);
|
|
|
|
glUseProgram(shader.smartScaler);
|
|
GLuint uniform = glGetUniformLocation(shader.smartScaler, "useLightTexture");
|
|
if (uniform >= 0) glUniform1i(uniform, 0);
|
|
|
|
setPMVMatrix(shader.smartScaler);
|
|
|
|
if (gameSettings.antiAlias == 1) {
|
|
glUniform1i(glGetUniformLocation(shader.smartScaler, "antialias"), 1);
|
|
} else {
|
|
glUniform1i(glGetUniformLocation(shader.smartScaler, "antialias"), 0);
|
|
}
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
drawQuad(shader.smartScaler, vertices, 1, texCoords);
|
|
|
|
glDisable(GL_BLEND);
|
|
glUseProgram(0);
|
|
#endif
|
|
}
|
|
|
|
void fontSprite(int x, int y, sprite &single, const spritePalette &fontPal) {
|
|
fontSprite(false, x, y, single, fontPal);
|
|
}
|
|
|
|
void flipFontSprite(int x, int y, sprite &single, const spritePalette &fontPal) {
|
|
fontSprite(true, x, y, single, fontPal);
|
|
}
|
|
|
|
byte curLight[3];
|
|
|
|
void setDrawMode(onScreenPerson *thisPerson) {
|
|
#if 0
|
|
if (thisPerson->colourmix) {
|
|
//glEnable(GL_COLOR_SUM); FIXME: replace line?
|
|
setSecondaryColor(curLight[0]*thisPerson->r * thisPerson->colourmix / 65025 / 255.f, curLight[1]*thisPerson->g * thisPerson->colourmix / 65025 / 255.f, curLight[2]*thisPerson->b * thisPerson->colourmix / 65025 / 255.f, 1.0f);
|
|
}
|
|
|
|
//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
setPrimaryColor(curLight[0] * (255 - thisPerson->colourmix) / 65025.f, curLight[1] * (255 - thisPerson->colourmix) / 65025.f, curLight[2] * (255 - thisPerson->colourmix) / 65025.f, 1.0f - thisPerson->transparency / 255.f);
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
extern GLuint backdropTextureName;
|
|
#endif
|
|
|
|
bool scaleSprite(sprite &single, const spritePalette &fontPal, onScreenPerson *thisPerson, bool mirror) {
|
|
float x = thisPerson->x;
|
|
float y = thisPerson->y;
|
|
|
|
float scale = thisPerson->scale;
|
|
|
|
if (scale <= 0.05)
|
|
return false;
|
|
|
|
int diffX = (int)(((float)single.surface.w) * scale);
|
|
int diffY = (int)(((float)single.surface.h) * scale);
|
|
|
|
float x1, y1, x2, y2;
|
|
|
|
if (thisPerson->extra & EXTRA_FIXTOSCREEN) {
|
|
x = x / cameraZoom;
|
|
y = y / cameraZoom;
|
|
if (single.xhot < 0)
|
|
x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale / cameraZoom);
|
|
else
|
|
x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale / cameraZoom);
|
|
y1 = y - (int)((single.yhot - thisPerson->floaty) * scale / cameraZoom);
|
|
x2 = x1 + (int)(diffX / cameraZoom);
|
|
y2 = y1 + (int)(diffY / cameraZoom);
|
|
} else {
|
|
x -= cameraX;
|
|
y -= cameraY;
|
|
if (single.xhot < 0)
|
|
x1 = x - (int)((mirror ? (float)(single.surface.w - single.xhot) : (float)(single.xhot + 1)) * scale);
|
|
else
|
|
x1 = x - (int)((mirror ? (float)(single.surface.w - (single.xhot + 1)) : (float)single.xhot) * scale);
|
|
y1 = y - (int)((single.yhot - thisPerson->floaty) * scale);
|
|
x2 = x1 + diffX;
|
|
y2 = y1 + diffY;
|
|
}
|
|
|
|
// Use Transparent surface to scale and blit
|
|
if (!zBuffer.numPanels) {
|
|
Graphics::TransparentSurface tmp(single.surface, false);
|
|
tmp.blit(renderSurface, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), nullptr, TS_ARGB(255, 255, 255, 255), diffX, diffY);
|
|
} else {
|
|
int d = ((!(thisPerson->extra & EXTRA_NOZB)) && zBuffer.numPanels) ? y + cameraY : sceneHeight + 1;
|
|
addSpriteDepth(&single.surface, d, x1, y1, (mirror ? Graphics::FLIP_H : Graphics::FLIP_NONE), diffX, diffY);
|
|
}
|
|
|
|
// Are we pointing at the sprite?
|
|
if (input.mouseX >= x1 && input.mouseX <= x2 && input.mouseY >= y1 && input.mouseY <= y2) {
|
|
if (thisPerson->extra & EXTRA_RECTANGULAR)
|
|
return true;
|
|
|
|
// check if point to non transparent part
|
|
int pixelx = (int)(single.surface.w * (input.mouseX - x1) / (x2 - x1));
|
|
int pixely = (int)(single.surface.h * (input.mouseY - y1) / (y2 - y1));
|
|
uint32 *colorPtr = (uint32 *)single.surface.getBasePtr(pixelx, pixely);
|
|
|
|
uint8 a, r, g, b;
|
|
g_sludge->getScreenPixelFormat()->colorToARGB(*colorPtr, a, r, g, b);
|
|
return a != 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void resetSpriteLayers(zBufferData *pz, int x, int y, bool upsidedown) {
|
|
if (spriteLayers.numLayers > 0)
|
|
killSpriteLayers();
|
|
spriteLayers.numLayers = pz->numPanels;
|
|
for (int i = 0; i < spriteLayers.numLayers; ++i) {
|
|
SpriteDisplay node(x, y, (upsidedown ? Graphics::FLIP_V : Graphics::FLIP_NONE), &pz->sprites[i], pz->sprites[i].w, pz->sprites[i].h);
|
|
spriteLayers.layer[i].push_back(node);
|
|
}
|
|
}
|
|
|
|
void addSpriteDepth(Graphics::Surface *ptr, int depth, int x, int y, Graphics::FLIP_FLAGS flip, int width, int height) {
|
|
int i;
|
|
for (i = 1; i < zBuffer.numPanels; ++i) {
|
|
if (zBuffer.panel[i] >= depth) {
|
|
break;
|
|
}
|
|
}
|
|
--i;
|
|
SpriteDisplay node(x, y, flip, ptr, width, height);
|
|
spriteLayers.layer[i].push_back(node);
|
|
}
|
|
|
|
void displaySpriteLayers() {
|
|
for (int i = 0; i < spriteLayers.numLayers; ++i) {
|
|
Common::List<SpriteDisplay>::iterator it;
|
|
for (it = spriteLayers.layer[i].begin(); it != spriteLayers.layer[i].end(); ++it) {
|
|
Graphics::TransparentSurface tmp(*it->surface, false);
|
|
tmp.blit(renderSurface, it->x, it->y, it->flip, nullptr, TS_ARGB(255, 255, 255, 255), it->width, it->height);
|
|
}
|
|
}
|
|
killSpriteLayers();
|
|
}
|
|
|
|
void killSpriteLayers() {
|
|
for (int i = 0; i < spriteLayers.numLayers; ++i) {
|
|
spriteLayers.layer[i].clear();
|
|
}
|
|
spriteLayers.numLayers = 0;
|
|
}
|
|
|
|
// Paste a scaled sprite onto the backdrop
|
|
void fixScaleSprite(int x, int y, sprite &single, const spritePalette &fontPal, onScreenPerson *thisPerson, int camX, int camY, bool mirror) {
|
|
#if 0
|
|
float scale = thisPerson-> scale;
|
|
bool useZB = !(thisPerson->extra & EXTRA_NOZB);
|
|
bool light = !(thisPerson->extra & EXTRA_NOLITE);
|
|
|
|
if (scale <= 0.05) return;
|
|
|
|
float tx1 = (float)(single.tex_x) / fontPal.tex_w[single.texNum];
|
|
float ty1 = (float) 1.0 / fontPal.tex_h[single.texNum]; //0.0;
|
|
float tx2 = (float)(single.tex_x + single.width) / fontPal.tex_w[single.texNum];
|
|
float ty2 = (float)(single.height + 1) / fontPal.tex_h[single.texNum];
|
|
|
|
int diffX = (int)(((float)single.width) * scale);
|
|
int diffY = (int)(((float)single.height) * scale);
|
|
int x1;
|
|
if (single.xhot < 0)
|
|
x1 = x - (int)((mirror ? (float)(single.width - single.xhot) : (float)(single.xhot + 1)) * scale);
|
|
else
|
|
x1 = x - (int)((mirror ? (float)(single.width - (single.xhot + 1)) : (float)single.xhot) * scale);
|
|
int y1 = y - (int)((single.yhot - thisPerson->floaty) * scale);
|
|
|
|
float spriteWidth = diffX;
|
|
float spriteHeight = diffY;
|
|
if (x1 < 0) diffX += x1;
|
|
if (y1 < 0) diffY += y1;
|
|
if (x1 + diffX > sceneWidth) diffX = sceneWidth - x1;
|
|
if (y1 + diffY > sceneHeight) diffY = sceneHeight - y1;
|
|
if (diffX < 0) return;
|
|
if (diffY < 0) return;
|
|
|
|
GLfloat z;
|
|
|
|
if (useZB && zBuffer.numPanels) {
|
|
int i;
|
|
for (i = 1; i < zBuffer.numPanels; i++) {
|
|
if (zBuffer.panel[i] >= y + cameraY) {
|
|
i--;
|
|
break;
|
|
}
|
|
}
|
|
z = 0.999 - (double) i * (1.0 / 128.0);
|
|
} else {
|
|
z = -0.5;
|
|
}
|
|
|
|
float ltx1, btx1;
|
|
float ltx2, btx2;
|
|
float lty1, bty1;
|
|
float lty2, bty2;
|
|
if (! NPOT_textures) {
|
|
ltx1 = lightMap.texW * x1 / sceneWidth;
|
|
ltx2 = lightMap.texW * (x1 + spriteWidth) / sceneWidth;
|
|
lty1 = lightMap.texH * y1 / sceneHeight;
|
|
lty2 = lightMap.texH * (y1 + spriteHeight) / sceneHeight;
|
|
btx1 = backdropTexW * x1 / sceneWidth;
|
|
btx2 = backdropTexW * (x1 + spriteWidth) / sceneWidth;
|
|
bty1 = backdropTexH * y1 / sceneHeight;
|
|
bty2 = backdropTexH * (y1 + spriteHeight) / sceneHeight;
|
|
} else {
|
|
btx1 = ltx1 = (float) x1 / sceneWidth;
|
|
btx2 = ltx2 = (float)(x1 + spriteWidth) / sceneWidth;
|
|
bty1 = lty1 = (float) y1 / sceneHeight;
|
|
bty2 = lty2 = (float)(y1 + spriteHeight) / sceneHeight;
|
|
}
|
|
|
|
const GLfloat ltexCoords[] = {
|
|
ltx1, lty1,
|
|
ltx2, lty1,
|
|
ltx1, lty2,
|
|
ltx2, lty2
|
|
};
|
|
|
|
const GLfloat btexCoords[] = {
|
|
btx1, bty1,
|
|
btx2, bty1,
|
|
btx1, bty2,
|
|
btx2, bty2
|
|
};
|
|
|
|
if (light && lightMap.data) {
|
|
if (lightMapMode == LIGHTMAPMODE_HOTSPOT) {
|
|
int lx = x + cameraX;
|
|
int ly = y + cameraY;
|
|
if (lx < 0 || ly < 0 || lx >= sceneWidth || ly >= sceneHeight) {
|
|
curLight[0] = curLight[1] = curLight[2] = 255;
|
|
} else {
|
|
GLubyte *target = lightMap.data + (ly * sceneWidth + lx) * 4;
|
|
curLight[0] = target[0];
|
|
curLight[1] = target[1];
|
|
curLight[2] = target[2];
|
|
}
|
|
} else if (lightMapMode == LIGHTMAPMODE_PIXEL) {
|
|
curLight[0] = curLight[1] = curLight[2] = 255;
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, lightMap.name);
|
|
|
|
}
|
|
} else {
|
|
curLight[0] = curLight[1] = curLight[2] = 255;
|
|
}
|
|
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glBindTexture(GL_TEXTURE_2D, backdropTextureName);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
setPixelCoords(true);
|
|
GLfloat xoffset = 0.0f;
|
|
while (xoffset < diffX) {
|
|
int w = (diffX - xoffset < viewportWidth) ? (int)(diffX - xoffset) : viewportWidth;
|
|
|
|
GLfloat yoffset = 0.0f;
|
|
while (yoffset < diffY) {
|
|
|
|
int h = (diffY - yoffset < viewportHeight) ? (int)(diffY - yoffset) : viewportHeight;
|
|
|
|
// Render the scene - first the old backdrop (so that it'll show through when the z-buffer is active
|
|
//glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glBindTexture(GL_TEXTURE_2D, backdropTextureName);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
const GLfloat vertices[] = {
|
|
-x1 - xoffset, -y1 - yoffset, 0.0f,
|
|
sceneWidth - x1 - xoffset, -y1 - yoffset, 0.0f,
|
|
-x1 - xoffset, sceneHeight - y1 - yoffset, 0.0f,
|
|
sceneWidth - x1 - xoffset, sceneHeight - y1 - yoffset, 0.0f
|
|
};
|
|
|
|
const GLfloat texCoords[] = {
|
|
0.0f, 0.0f,
|
|
backdropTexW, 0.0f,
|
|
0.0f, backdropTexH,
|
|
backdropTexW, backdropTexH
|
|
};
|
|
|
|
glUseProgram(shader.texture);
|
|
setPMVMatrix(shader.texture);
|
|
|
|
drawQuad(shader.texture, vertices, 1, texCoords);
|
|
|
|
// The z-buffer
|
|
if (useZB) {
|
|
glDepthMask(GL_TRUE);
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
drawZBuffer((int)(x1 + xoffset + camX), (int)(y1 + yoffset + camY), false);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
// Then the sprite
|
|
glUseProgram(shader.paste);
|
|
GLint uniform = glGetUniformLocation(shader.paste, "useLightTexture");
|
|
if (uniform >= 0) glUniform1i(uniform, light && lightMapMode == LIGHTMAPMODE_PIXEL && lightMap.data);
|
|
setPMVMatrix(shader.paste);
|
|
|
|
setDrawMode(thisPerson);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, fontPal.tex_names[single.texNum]);
|
|
|
|
const GLfloat vertices2[] = {
|
|
-xoffset, -yoffset, z,
|
|
spriteWidth - xoffset, -yoffset, z,
|
|
-xoffset, spriteHeight - yoffset, z,
|
|
spriteWidth - xoffset, spriteHeight - yoffset, z
|
|
};
|
|
|
|
if (! mirror) {
|
|
GLfloat tx3 = tx1;
|
|
tx1 = tx2;
|
|
tx2 = tx3;
|
|
}
|
|
const GLfloat texCoords2[] = {
|
|
tx2, ty1,
|
|
tx1, ty1,
|
|
tx2, ty2,
|
|
tx1, ty2
|
|
};
|
|
|
|
drawQuad(shader.paste, vertices2, 3, texCoords2, ltexCoords, btexCoords);
|
|
|
|
setSecondaryColor(0., 0., 0., 1.);
|
|
//glDisable(GL_COLOR_SUM); FIXME: replace line?
|
|
// Copy Our ViewPort To The Texture
|
|
glUseProgram(0);
|
|
copyTexSubImage2D(GL_TEXTURE_2D, 0, (int)((x1 < 0) ? xoffset : x1 + xoffset), (int)((y1 < 0) ? yoffset : y1 + yoffset), (int)((x1 < 0) ? viewportOffsetX - x1 : viewportOffsetX), (int)((y1 < 0) ? viewportOffsetY - y1 : viewportOffsetY), w, h, backdropTextureName);
|
|
|
|
yoffset += viewportHeight;
|
|
}
|
|
xoffset += viewportWidth;
|
|
}
|
|
|
|
setPixelCoords(false);
|
|
glUseProgram(0);
|
|
#endif
|
|
}
|
|
|
|
} // End of namespace Sludge
|