scummvm/engines/sludge/sprites.cpp
2017-07-15 17:51:57 +02:00

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