mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-23 19:16:21 +00:00
MYST3: Implement the water effect
The effect looks similar enough to the original but not exactly the same. This is CPU intensive. Once well tested it may be worth reimplementing it as a shader.
This commit is contained in:
parent
5577bd71b7
commit
fa12f7e35e
@ -22,6 +22,7 @@
|
||||
|
||||
#include "engines/myst3/console.h"
|
||||
#include "engines/myst3/database.h"
|
||||
#include "engines/myst3/effects.h"
|
||||
#include "engines/myst3/inventory.h"
|
||||
#include "engines/myst3/script.h"
|
||||
#include "engines/myst3/state.h"
|
||||
@ -340,15 +341,15 @@ bool Console::Cmd_DumpMasks(int argc, const char **argv) {
|
||||
DebugPrintf("Extracting masks for node %d:\n", nodeId);
|
||||
|
||||
for (uint i = 0; i < 6; i++) {
|
||||
bool water = _vm->_node->dumpFaceMask(nodeId, i, DirectorySubEntry::kWaterEffectMask);
|
||||
bool water = dumpFaceMask(nodeId, i, DirectorySubEntry::kWaterEffectMask);
|
||||
if (water)
|
||||
DebugPrintf("Face %d: water OK\n", i);
|
||||
|
||||
bool effect2 = _vm->_node->dumpFaceMask(nodeId, i, DirectorySubEntry::kEffect2Mask);
|
||||
bool effect2 = dumpFaceMask(nodeId, i, DirectorySubEntry::kEffect2Mask);
|
||||
if (effect2)
|
||||
DebugPrintf("Face %d: effect 2 OK\n", i);
|
||||
|
||||
bool magnet = _vm->_node->dumpFaceMask(nodeId, i, DirectorySubEntry::kMagneticEffectMask);
|
||||
bool magnet = dumpFaceMask(nodeId, i, DirectorySubEntry::kMagneticEffectMask);
|
||||
if (magnet)
|
||||
DebugPrintf("Face %d: magnet OK\n", i);
|
||||
|
||||
@ -359,4 +360,27 @@ bool Console::Cmd_DumpMasks(int argc, const char **argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type) {
|
||||
const DirectorySubEntry *maskDesc = _vm->getFileDescription(0, index, face, type);
|
||||
|
||||
if (!maskDesc)
|
||||
return false;
|
||||
|
||||
Common::MemoryReadStream *maskStream = maskDesc->getData();
|
||||
|
||||
Graphics::Surface *mask = Effect::loadMask(maskStream);
|
||||
|
||||
delete maskStream;
|
||||
|
||||
Common::DumpFile outFile;
|
||||
outFile.open(Common::String::format("dump/%d-%d.masku_%d", index, face, type));
|
||||
outFile.write(mask->getPixels(), mask->pitch * mask->h);
|
||||
outFile.close();
|
||||
|
||||
mask->free();
|
||||
delete mask;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace Myst3 */
|
||||
|
@ -41,6 +41,7 @@ private:
|
||||
Myst3Engine *_vm;
|
||||
|
||||
void describeScript(const Common::Array<Opcode> &script);
|
||||
bool dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type);
|
||||
|
||||
bool Cmd_Infos(int argc, const char **argv);
|
||||
bool Cmd_LookAt(int argc, const char **argv);
|
||||
|
@ -125,7 +125,7 @@ void Cursor::lockPosition(bool lock) {
|
||||
|
||||
_lockedAtCenter = lock;
|
||||
|
||||
g_system->lockMouse(lock);
|
||||
//g_system->lockMouse(lock);
|
||||
|
||||
if (_lockedAtCenter) {
|
||||
// Locking, just mouve the cursor at the center of the screen
|
||||
|
288
engines/myst3/effects.cpp
Normal file
288
engines/myst3/effects.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
/* ResidualVM - A 3D game interpreter
|
||||
*
|
||||
* ResidualVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the AUTHORS
|
||||
* 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 "engines/myst3/effects.h"
|
||||
#include "engines/myst3/myst3.h"
|
||||
#include "engines/myst3/state.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
Effect::Effect(Myst3Engine *vm) :
|
||||
_vm(vm) {
|
||||
}
|
||||
|
||||
Effect::~Effect() {
|
||||
for (FaceMaskMap::iterator it = _facesMasks.begin(); it != _facesMasks.end(); it++) {
|
||||
it->_value->free();
|
||||
delete it->_value;
|
||||
}
|
||||
}
|
||||
|
||||
bool Effect::loadMasks(uint32 id, DirectorySubEntry::ResourceType type) {
|
||||
// Just in case
|
||||
_facesMasks.clear();
|
||||
|
||||
bool isFrame = _vm->_state->getViewType() == kFrame;
|
||||
|
||||
// Load the mask of each face
|
||||
for (uint i = 0; i < 6; i++) {
|
||||
const DirectorySubEntry *desc = _vm->getFileDescription(0, id, i + 1, type);
|
||||
|
||||
if (desc) {
|
||||
Common::SeekableReadStream *data = desc->getData();
|
||||
|
||||
_facesMasks[i] = loadMask(data);
|
||||
|
||||
// Frame masks are vertically flipped for some reason
|
||||
if (isFrame) {
|
||||
flipVertical(_facesMasks[i]);
|
||||
}
|
||||
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
if (_facesMasks.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Graphics::Surface *Effect::loadMask(Common::SeekableReadStream *maskStream) {
|
||||
Graphics::Surface *s = new Graphics::Surface();
|
||||
s->create(640, 640, Graphics::PixelFormat::createFormatCLUT8());
|
||||
|
||||
uint32 headerOffset = 0;
|
||||
uint32 dataOffset = 0;
|
||||
|
||||
while (headerOffset < 400) {
|
||||
int blockX = (headerOffset / sizeof(dataOffset)) % 10;
|
||||
int blockY = (headerOffset / sizeof(dataOffset)) / 10;
|
||||
|
||||
maskStream->seek(headerOffset, SEEK_SET);
|
||||
dataOffset = maskStream->readUint32LE();
|
||||
headerOffset = maskStream->pos();
|
||||
|
||||
if (dataOffset != 0) {
|
||||
maskStream->seek(dataOffset, SEEK_SET);
|
||||
|
||||
for(int i = 63; i >= 0; i--) {
|
||||
int x = 0;
|
||||
byte numValues = maskStream->readByte();
|
||||
for (int j = 0; j < numValues; j++) {
|
||||
byte repeat = maskStream->readByte();
|
||||
byte value = maskStream->readByte();
|
||||
for (int k = 0; k < repeat; k++) {
|
||||
((uint8*)s->getPixels())[((blockY * 64) + i) * 640 + blockX * 64 + x] = value;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void Effect::flipVertical(Graphics::Surface *s) {
|
||||
for (int y = 0; y < s->h / 2; ++y) {
|
||||
// Flip the lines
|
||||
byte *line1P = (byte *)s->getBasePtr(0, y);
|
||||
byte *line2P = (byte *)s->getBasePtr(0, s->h - y - 1);
|
||||
|
||||
for (int x = 0; x < s->w; ++x)
|
||||
SWAP(line1P[x], line2P[x]);
|
||||
}
|
||||
}
|
||||
|
||||
WaterEffect::WaterEffect(Myst3Engine *vm) :
|
||||
Effect(vm),
|
||||
_lastUpdate(0),
|
||||
_step(0) {
|
||||
}
|
||||
|
||||
WaterEffect::~WaterEffect() {
|
||||
|
||||
}
|
||||
|
||||
WaterEffect *WaterEffect::create(Myst3Engine *vm, uint32 id) {
|
||||
WaterEffect *s = new WaterEffect(vm);
|
||||
|
||||
if (!s->loadMasks(id, DirectorySubEntry::kWaterEffectMask)) {
|
||||
delete s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool WaterEffect::isRunning() {
|
||||
return _vm->_state->getWaterEffectActive()
|
||||
&& _vm->_state->getWaterEffectRunning();
|
||||
}
|
||||
|
||||
bool WaterEffect::update() {
|
||||
if (!isRunning()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_system->getMillis() - _lastUpdate >= 1000 / (uint32)_vm->_state->getWaterEffectSpeed()) {
|
||||
_lastUpdate = g_system->getMillis();
|
||||
|
||||
_step++;
|
||||
if (_step > _vm->_state->getWaterEffectMaxStep())
|
||||
_step = 0;
|
||||
|
||||
float position = _step / (float)_vm->_state->getWaterEffectMaxStep();
|
||||
|
||||
doStep(position, _vm->_state->getViewType() == kFrame);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WaterEffect::doStep(float position, bool isFrame) {
|
||||
double timeOffset;
|
||||
double frequency;
|
||||
double ampl;
|
||||
|
||||
timeOffset = position * 2 * M_PI;
|
||||
frequency = _vm->_state->getWaterEffectFrequency() * 0.1;
|
||||
|
||||
ampl = _vm->_state->getWaterEffectAmpl() / 10.0 / 2.0;
|
||||
for (uint i = 0; i < 640; i++) {
|
||||
double ampl1;
|
||||
if (i < 320)
|
||||
ampl1 = i / 320 + 1.0;
|
||||
else
|
||||
ampl1 = (640 - i) / 320 + 1.0;
|
||||
|
||||
_bottomDisplacement[i] = sin(i / 640.0 * frequency * 2 * M_PI + timeOffset) / 2 * ampl1 * ampl;
|
||||
}
|
||||
|
||||
// FIXME: The original sets this to WaterEffectAttenuation, which causes
|
||||
// glitches here
|
||||
uint32 attenuation = 640;
|
||||
for (uint i = 0; i < attenuation; i++) {
|
||||
double ampl2 = attenuation / (attenuation - i + 1.0);
|
||||
|
||||
int8 value = sin(i / 640.0 * frequency * 2 * M_PI * ampl2 + timeOffset) / 2 * 1.0 / ampl2 * ampl;
|
||||
|
||||
if (!isFrame) {
|
||||
_verticalDisplacement[i] = value;
|
||||
} else {
|
||||
_verticalDisplacement[attenuation - 1 - i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < 640; i++) {
|
||||
double ampl3 = sin(i / 640.0 * frequency * 2 * M_PI + timeOffset) / 2.0;
|
||||
|
||||
_horizontalDisplacements[0][i] = ampl3 * 1.25 * ampl + 0.5;
|
||||
_horizontalDisplacements[1][i] = ampl3 * 1.00 * ampl + 0.5;
|
||||
_horizontalDisplacements[2][i] = ampl3 * 0.75 * ampl + 0.5;
|
||||
_horizontalDisplacements[3][i] = ampl3 * 0.50 * ampl + 0.5;
|
||||
_horizontalDisplacements[4][i] = ampl3 * 0.25 * ampl + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
void WaterEffect::applyForFace(uint face, Graphics::Surface *src, Graphics::Surface *dst) {
|
||||
if (!isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics::Surface *mask = _facesMasks.getVal(face);
|
||||
|
||||
if (!mask)
|
||||
error("No mask for face %d", face);
|
||||
|
||||
apply(src, dst, mask, face == 1, _vm->_state->getWaterEffectAmpl());
|
||||
}
|
||||
|
||||
void WaterEffect::apply(Graphics::Surface *src, Graphics::Surface *dst, Graphics::Surface *mask, bool bottomFace, int32 waterEffectAmpl) {
|
||||
|
||||
int8 *hDisplacement;
|
||||
int8 *vDisplacement;
|
||||
|
||||
if (bottomFace) {
|
||||
hDisplacement = _bottomDisplacement;
|
||||
vDisplacement = _bottomDisplacement;
|
||||
} else {
|
||||
vDisplacement = _verticalDisplacement;
|
||||
}
|
||||
|
||||
|
||||
uint32 *dstPtr = (uint32 *)dst->getPixels();
|
||||
byte *maskPtr = (byte *)mask->getPixels();
|
||||
|
||||
for (uint y = 0; y < dst->h; y++) {
|
||||
if (!bottomFace) {
|
||||
uint32 strength = (320 * (9 - y / 64)) / _vm->_state->getWaterEffectAttenuation();
|
||||
if (strength > 4)
|
||||
strength = 4;
|
||||
hDisplacement = _horizontalDisplacements[strength];
|
||||
}
|
||||
|
||||
for (uint x = 0; x < dst->w; x++) {
|
||||
int8 maskValue = *maskPtr;
|
||||
|
||||
if (maskValue != 0) {
|
||||
int8 xOffset = hDisplacement[x];
|
||||
int8 yOffset = vDisplacement[y];
|
||||
|
||||
if (maskValue < 8) {
|
||||
maskValue -= _vm->_state->getWaterEffectAmplOffset();
|
||||
if (maskValue < 0) {
|
||||
maskValue = 0;
|
||||
}
|
||||
|
||||
if (xOffset >= 0) {
|
||||
if (xOffset > maskValue)
|
||||
xOffset = maskValue;
|
||||
} else {
|
||||
if (-xOffset > maskValue)
|
||||
xOffset = -maskValue;
|
||||
}
|
||||
if (yOffset >= 0) {
|
||||
if (yOffset > maskValue)
|
||||
yOffset = maskValue;
|
||||
} else {
|
||||
if (-yOffset > maskValue)
|
||||
yOffset = -maskValue;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 srcValue1 = *(uint32 *) src->getBasePtr(x + xOffset, y + yOffset);
|
||||
uint32 srcValue2 = *(uint32 *) src->getBasePtr(x, y);
|
||||
|
||||
*dstPtr = 0xFF000000 | ((0x007F7F7F & (srcValue1 >> 1)) + (0x007F7F7F & (srcValue2 >> 1)));
|
||||
}
|
||||
|
||||
maskPtr++;
|
||||
dstPtr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Myst3 */
|
90
engines/myst3/effects.h
Normal file
90
engines/myst3/effects.h
Normal file
@ -0,0 +1,90 @@
|
||||
/* ResidualVM - A 3D game interpreter
|
||||
*
|
||||
* ResidualVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the AUTHORS
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EFFECTS_H_
|
||||
#define EFFECTS_H_
|
||||
|
||||
#include "common/hashmap.h"
|
||||
|
||||
#include "engines/myst3/directorysubentry.h"
|
||||
|
||||
namespace Graphics {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
class Myst3Engine;
|
||||
|
||||
class Effect {
|
||||
public:
|
||||
virtual ~Effect();
|
||||
|
||||
virtual bool update() = 0;
|
||||
virtual void applyForFace(uint face, Graphics::Surface *src, Graphics::Surface *dst) = 0;
|
||||
|
||||
bool hasFace(uint face) { return _facesMasks.contains(face); }
|
||||
|
||||
// Public and static for use by the debug console
|
||||
static Graphics::Surface *loadMask(Common::SeekableReadStream *maskStream);
|
||||
|
||||
protected:
|
||||
Effect(Myst3Engine *vm);
|
||||
|
||||
bool loadMasks(uint32 id, DirectorySubEntry::ResourceType type);
|
||||
void flipVertical(Graphics::Surface *s);
|
||||
|
||||
Myst3Engine *_vm;
|
||||
|
||||
typedef Common::HashMap<uint, Graphics::Surface *> FaceMaskMap;
|
||||
FaceMaskMap _facesMasks;
|
||||
|
||||
};
|
||||
|
||||
class WaterEffect : public Effect {
|
||||
public:
|
||||
static WaterEffect *create(Myst3Engine *vm, uint32 id);
|
||||
virtual ~WaterEffect();
|
||||
|
||||
bool update();
|
||||
void applyForFace(uint face, Graphics::Surface *src, Graphics::Surface *dst);
|
||||
|
||||
protected:
|
||||
WaterEffect(Myst3Engine *vm);
|
||||
|
||||
void doStep(float position, bool isFrame);
|
||||
void apply(Graphics::Surface *src, Graphics::Surface *dst, Graphics::Surface *mask,
|
||||
bool bottomFace, int32 waterEffectAmpl);
|
||||
|
||||
uint32 _lastUpdate;
|
||||
int32 _step;
|
||||
|
||||
int8 _bottomDisplacement[640];
|
||||
int8 _verticalDisplacement[640];
|
||||
int8 _horizontalDisplacements[5][640];
|
||||
|
||||
private:
|
||||
bool isRunning();
|
||||
};
|
||||
|
||||
} /* namespace Myst3 */
|
||||
#endif /* EFFECTS_H_ */
|
@ -9,6 +9,7 @@ MODULE_OBJS := \
|
||||
detection.o \
|
||||
directoryentry.o \
|
||||
directorysubentry.o \
|
||||
effects.o \
|
||||
gfx.o \
|
||||
gfx_opengl.o \
|
||||
gfx_opengl_shaders.o \
|
||||
|
@ -20,6 +20,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/myst3/effects.h"
|
||||
#include "engines/myst3/node.h"
|
||||
#include "engines/myst3/myst3.h"
|
||||
#include "engines/myst3/state.h"
|
||||
@ -38,12 +39,18 @@ void Face::setTextureFromJPEG(const DirectorySubEntry *jpegDesc) {
|
||||
Face::Face(Myst3Engine *vm) :
|
||||
_vm(vm),
|
||||
_textureDirty(true),
|
||||
_texture(0) {
|
||||
_texture(0),
|
||||
_bitmap(0),
|
||||
_finalBitmap(0) {
|
||||
}
|
||||
|
||||
void Face::uploadTexture() {
|
||||
if (_textureDirty) {
|
||||
_texture->update(_bitmap);
|
||||
if (_finalBitmap)
|
||||
_texture->update(_finalBitmap);
|
||||
else
|
||||
_texture->update(_bitmap);
|
||||
|
||||
_textureDirty = false;
|
||||
}
|
||||
}
|
||||
@ -53,6 +60,11 @@ Face::~Face() {
|
||||
delete _bitmap;
|
||||
_bitmap = 0;
|
||||
|
||||
if (_finalBitmap) {
|
||||
_finalBitmap->free();
|
||||
delete _finalBitmap;
|
||||
}
|
||||
|
||||
if (_texture) {
|
||||
_vm->_gfx->freeTexture(_texture);
|
||||
}
|
||||
@ -63,60 +75,14 @@ Node::Node(Myst3Engine *vm, uint16 id) :
|
||||
_subtitles(0) {
|
||||
for (uint i = 0; i < 6; i++)
|
||||
_faces[i] = 0;
|
||||
}
|
||||
|
||||
bool Node::dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type) {
|
||||
static const int32 kMaskSize = 640 * 640;
|
||||
|
||||
byte *mask = new byte[kMaskSize];
|
||||
memset(mask, 0, kMaskSize);
|
||||
uint32 headerOffset = 0;
|
||||
uint32 dataOffset = 0;
|
||||
|
||||
const DirectorySubEntry *maskDesc = _vm->getFileDescription(0, index, face, type);
|
||||
|
||||
if (!maskDesc) {
|
||||
delete[] mask;
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::MemoryReadStream *maskStream = maskDesc->getData();
|
||||
|
||||
while (headerOffset < 400) {
|
||||
int blockX = (headerOffset / sizeof(dataOffset)) % 10;
|
||||
int blockY = (headerOffset / sizeof(dataOffset)) / 10;
|
||||
|
||||
maskStream->seek(headerOffset, SEEK_SET);
|
||||
dataOffset = maskStream->readUint32LE();
|
||||
headerOffset = maskStream->pos();
|
||||
|
||||
if (dataOffset != 0) {
|
||||
maskStream->seek(dataOffset, SEEK_SET);
|
||||
|
||||
for(int i = 63; i >= 0; i--) {
|
||||
int x = 0;
|
||||
byte numValues = maskStream->readByte();
|
||||
for (int j = 0; j < numValues; j++) {
|
||||
byte repeat = maskStream->readByte();
|
||||
byte value = maskStream->readByte();
|
||||
for (int k = 0; k < repeat; k++) {
|
||||
mask[((blockY * 64) + i) * 640 + blockX * 64 + x] = value;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_vm->_state->getWaterEffects()) {
|
||||
Effect *effect = WaterEffect::create(vm, id);
|
||||
if (effect) {
|
||||
_effects.push_back(effect);
|
||||
_vm->_state->setWaterEffectActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
delete maskStream;
|
||||
|
||||
Common::DumpFile outFile;
|
||||
outFile.open(Common::String::format("dump/%d-%d.masku_%d", index, face, type));
|
||||
outFile.write(mask, kMaskSize);
|
||||
outFile.close();
|
||||
delete[] mask;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Node::~Node() {
|
||||
@ -125,6 +91,12 @@ Node::~Node() {
|
||||
}
|
||||
_spotItems.clear();
|
||||
|
||||
for (uint i = 0; i < _effects.size(); i++) {
|
||||
delete _effects[i];
|
||||
}
|
||||
_effects.clear();
|
||||
_vm->_state->setWaterEffectActive(false);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
delete _faces[i];
|
||||
}
|
||||
@ -206,6 +178,53 @@ void Node::update() {
|
||||
for (uint i = 0; i < _spotItems.size(); i++) {
|
||||
_spotItems[i]->updateDraw();
|
||||
}
|
||||
|
||||
bool needsUpdate = false;
|
||||
for (uint i = 0; i < _effects.size(); i++) {
|
||||
needsUpdate |= _effects[i]->update();
|
||||
}
|
||||
|
||||
// Apply the effects for all the faces
|
||||
for (uint faceId = 0; faceId < 6; faceId++) {
|
||||
Face *face = _faces[faceId];
|
||||
|
||||
if (face == 0) continue;
|
||||
|
||||
uint effectsForFace = 0;
|
||||
for (uint i = 0; i < _effects.size(); i++) {
|
||||
if (_effects[i]->hasFace(faceId))
|
||||
effectsForFace++;
|
||||
}
|
||||
|
||||
if (effectsForFace == 0) continue;
|
||||
if (!needsUpdate && !face->isTextureDirty()) continue;
|
||||
|
||||
// Alloc the target surface if necessary
|
||||
if (!face->_finalBitmap) {
|
||||
face->_finalBitmap = new Graphics::Surface();
|
||||
face->_finalBitmap->copyFrom(*face->_bitmap);
|
||||
}
|
||||
|
||||
if (effectsForFace == 1) {
|
||||
_effects[0]->applyForFace(faceId, face->_bitmap, face->_finalBitmap);
|
||||
|
||||
face->markTextureDirty();
|
||||
} else if (effectsForFace == 2) {
|
||||
// TODO: Keep the same temp surface to avoid heap fragmentation ?
|
||||
Graphics::Surface *tmp = new Graphics::Surface();
|
||||
tmp->copyFrom(*face->_bitmap);
|
||||
|
||||
_effects[0]->applyForFace(faceId, face->_bitmap, tmp);
|
||||
_effects[1]->applyForFace(faceId, tmp, face->_finalBitmap);
|
||||
|
||||
tmp->free();
|
||||
delete tmp;
|
||||
|
||||
face->markTextureDirty();
|
||||
} else {
|
||||
error("Unable to render more than 2 effects per faceId (%d)", effectsForFace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpotItem::SpotItem(Myst3Engine *vm) :
|
||||
|
@ -36,10 +36,12 @@ namespace Myst3 {
|
||||
class Texture;
|
||||
class Myst3Engine;
|
||||
class Subtitles;
|
||||
class Effect;
|
||||
|
||||
class Face {
|
||||
public:
|
||||
Graphics::Surface *_bitmap;
|
||||
Graphics::Surface *_finalBitmap;
|
||||
Texture *_texture;
|
||||
|
||||
Face(Myst3Engine *vm);
|
||||
@ -48,6 +50,8 @@ class Face {
|
||||
void setTextureFromJPEG(const DirectorySubEntry *jpegDesc);
|
||||
|
||||
void markTextureDirty() { _textureDirty = true; }
|
||||
bool isTextureDirty() { return _textureDirty; }
|
||||
|
||||
void uploadTexture();
|
||||
|
||||
private:
|
||||
@ -126,6 +130,7 @@ class Node : Drawable {
|
||||
Face *_faces[6];
|
||||
Common::Array<SpotItem *> _spotItems;
|
||||
Subtitles *_subtitles;
|
||||
Common::Array<Effect *> _effects;
|
||||
|
||||
public:
|
||||
Node(Myst3Engine *vm, uint16 id);
|
||||
@ -140,8 +145,6 @@ class Node : Drawable {
|
||||
|
||||
void loadSubtitles(uint32 id);
|
||||
bool hasSubtitlesToDraw();
|
||||
|
||||
bool dumpFaceMask(uint16 index, int face, DirectorySubEntry::ResourceType type);
|
||||
};
|
||||
|
||||
} // end of namespace Myst3
|
||||
|
@ -634,7 +634,7 @@ void Puzzles::pinball(int16 var) {
|
||||
if (var >= 0)
|
||||
return;
|
||||
|
||||
_vm->_state->setWaterEffectPaused(false);
|
||||
_vm->_state->setWaterEffectRunning(false);
|
||||
|
||||
// Remove the default panel movies
|
||||
_vm->removeMovie(10116);
|
||||
@ -840,7 +840,7 @@ void Puzzles::pinball(int16 var) {
|
||||
_vm->_sound->playEffect(1028, 50);
|
||||
} else if (jumpType == 1 || jumpType == 4) {
|
||||
_vm->_state->setVar(26, jumpType);
|
||||
_vm->_state->setWaterEffectPaused(true);
|
||||
_vm->_state->setWaterEffectRunning(true);
|
||||
// sound fade stop 1025, 7
|
||||
return;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ GameState::GameState(Myst3Engine *vm):
|
||||
|
||||
VAR(92, HotspotActiveRect, false)
|
||||
|
||||
VAR(93, WaterEffectPaused, true)
|
||||
VAR(93, WaterEffectRunning, true)
|
||||
VAR(94, WaterEffectActive, true)
|
||||
VAR(95, WaterEffectSpeed, true)
|
||||
VAR(96, WaterEffectAttenuation, true)
|
||||
|
@ -92,7 +92,7 @@ public:
|
||||
|
||||
DECLARE_VAR(92, HotspotActiveRect)
|
||||
|
||||
DECLARE_VAR(93, WaterEffectPaused)
|
||||
DECLARE_VAR(93, WaterEffectRunning)
|
||||
DECLARE_VAR(94, WaterEffectActive)
|
||||
DECLARE_VAR(95, WaterEffectSpeed)
|
||||
DECLARE_VAR(96, WaterEffectAttenuation)
|
||||
|
Loading…
x
Reference in New Issue
Block a user