Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/file.h"
#include "common/scummsys.h"
#include "common/str.h"
#include "zvision/graphics/cursors/cursor.h"
namespace ZVision {
ZorkCursor::ZorkCursor()
: _width(0),
_height(0),
_hotspotX(0),
_hotspotY(0) {
}
ZorkCursor::ZorkCursor(ZVision *engine, const Common::Path &fileName)
: _width(0),
_height(0),
_hotspotX(0),
_hotspotY(0) {
Common::File file;
if (!file.open(fileName))
error("Cursor file %s does not exist", fileName.toString().c_str());
uint32 magic = file.readUint32BE();
if (magic != MKTAG('Z', 'C', 'R', '1')) {
warning("%s is not a Zork Cursor file", fileName.toString().c_str());
return;
}
_hotspotX = file.readUint16LE();
_hotspotY = file.readUint16LE();
_width = file.readUint16LE();
_height = file.readUint16LE();
uint dataSize = _width * _height * sizeof(uint16);
_surface.create(_width, _height, engine->_resourcePixelFormat);
uint32 bytesRead = file.read(_surface.getPixels(), dataSize);
assert(bytesRead == dataSize);
#ifndef SCUMM_LITTLE_ENDIAN
int16 *buffer = (int16 *)_surface.getPixels();
for (uint32 i = 0; i < dataSize / 2; ++i)
buffer[i] = FROM_LE_16(buffer[i]);
#endif
}
ZorkCursor::ZorkCursor(const ZorkCursor &other) {
_width = other._width;
_height = other._height;
_hotspotX = other._hotspotX;
_hotspotY = other._hotspotY;
_surface.copyFrom(other._surface);
}
ZorkCursor &ZorkCursor::operator=(const ZorkCursor &other) {
_width = other._width;
_height = other._height;
_hotspotX = other._hotspotX;
_hotspotY = other._hotspotY;
_surface.free();
_surface.copyFrom(other._surface);
return *this;
}
ZorkCursor::~ZorkCursor() {
_surface.free();
}
} // End of namespace ZVision

View File

@@ -0,0 +1,77 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ZVISION_CURSOR_H
#define ZVISION_CURSOR_H
#include "graphics/surface.h"
#include "zvision/zvision.h"
namespace Common {
class String;
}
namespace ZVision {
/**
* Utility class to parse and hold cursor data
* Modeled off Graphics::Cursor
*/
class ZorkCursor {
public:
ZorkCursor();
ZorkCursor(ZVision *engine, const Common::Path &fileName);
ZorkCursor(const ZorkCursor &other);
~ZorkCursor();
private:
uint16 _width;
uint16 _height;
uint16 _hotspotX;
uint16 _hotspotY;
Graphics::Surface _surface;
public:
ZorkCursor &operator=(const ZorkCursor &other);
uint16 getWidth() const {
return _width;
}
uint16 getHeight() const {
return _height;
}
uint16 getHotspotX() const {
return _hotspotX;
}
uint16 getHotspotY() const {
return _hotspotY;
}
byte getKeyColor() const {
return 0;
}
const byte *getSurface() const {
return (const byte *)_surface.getPixels();
}
};
} // End of namespace ZVision
#endif

View File

@@ -0,0 +1,153 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
#include "common/system.h"
#include "graphics/cursorman.h"
#include "graphics/pixelformat.h"
#include "zvision/zvision.h"
#include "zvision/graphics/cursors/cursor_manager.h"
namespace ZVision {
const char *CursorManager::_cursorNames[NUM_CURSORS] = { "active", "arrow", "backward", "downarrow", "forward", "handpt", "handpu", "hdown", "hleft",
"hright", "hup", "idle", "leftarrow", "rightarrow", "suggest_surround", "suggest_tilt", "turnaround", "zuparrow"
};
const char *CursorManager::_zgiCursorFileNames[NUM_CURSORS] = { "g0gbc011.zcr", "g0gac011.zcr", "g0gac021.zcr", "g0gac031.zcr", "g0gac041.zcr", "g0gac051.zcr", "g0gac061.zcr", "g0gac071.zcr", "g0gac081.zcr",
"g0gac091.zcr", "g0gac101.zcr", "g0gac011.zcr", "g0gac111.zcr", "g0gac121.zcr", "g0gac131.zcr", "g0gac141.zcr", "g0gac151.zcr", "g0gac161.zcr"
};
const char *CursorManager::_zNemCursorFileNames[NUM_CURSORS] = { "00act", "arrow", "back", "down", "forw", "handpt", "handpu", "hdown", "hleft",
"hright", "hup", "00idle", "left", "right", "ssurr", "stilt", "turn", "up"
};
CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat &pixelFormat)
: _engine(engine),
_pixelFormat(pixelFormat),
_cursorIsPushed(false),
_item(0),
_lastitem(0),
_currentCursor(CursorIndex_Idle) {
for (int i = 0; i < NUM_CURSORS; i++) {
if (_engine->getGameId() == GID_NEMESIS) {
Common::Path name;
if (i == 1) {
// Cursors "arrowa.zcr" and "arrowb.zcr" are missing
_cursors[i][0] = _cursors[i][1] = ZorkCursor();
continue;
}
name = Common::Path(Common::String::format("%sa.zcr", _zNemCursorFileNames[i]));
_cursors[i][0] = ZorkCursor(_engine, name); // Up cursor
name = Common::Path(Common::String::format("%sb.zcr", _zNemCursorFileNames[i]));
_cursors[i][1] = ZorkCursor(_engine, name); // Down cursor
} else if (_engine->getGameId() == GID_GRANDINQUISITOR) {
_cursors[i][0] = ZorkCursor(_engine, _zgiCursorFileNames[i]); // Up cursor
char buffer[25];
memset(buffer, 0, 25);
strncpy(buffer, _zgiCursorFileNames[i], 24);
buffer[3] += 2;
_cursors[i][1] = ZorkCursor(_engine, buffer); // Down cursor
}
}
}
void CursorManager::setItemID(int id) {
if (id != _item) {
if (id) {
Common::Path file;
if (_engine->getGameId() == GID_NEMESIS) {
file = Common::Path(Common::String::format("%2.2d%s%c.zcr", id, "idle", 'a'));
_cursors[NUM_CURSORS][0] = ZorkCursor(_engine, file);
file = Common::Path(Common::String::format("%2.2d%s%c.zcr", id, "idle", 'b'));
_cursors[NUM_CURSORS][1] = ZorkCursor(_engine, file);
file = Common::Path(Common::String::format("%2.2d%s%c.zcr", id, "act", 'a'));
_cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file);
file = Common::Path(Common::String::format("%2.2d%s%c.zcr", id, "act", 'b'));
_cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file);
} else if (_engine->getGameId() == GID_GRANDINQUISITOR) {
file = Common::Path(Common::String::format("g0b%cc%2.2x1.zcr", 'a' , id));
_cursors[NUM_CURSORS][0] = ZorkCursor(_engine, file);
file = Common::Path(Common::String::format("g0b%cc%2.2x1.zcr", 'c' , id));
_cursors[NUM_CURSORS][1] = ZorkCursor(_engine, file);
file = Common::Path(Common::String::format("g0b%cc%2.2x1.zcr", 'b' , id));
_cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file);
file = Common::Path(Common::String::format("g0b%cc%2.2x1.zcr", 'd' , id));
_cursors[NUM_CURSORS + 1][1] = ZorkCursor(_engine, file);
} else
return;
}
_item = id;
changeCursor(CursorIndex_Idle);
}
}
void CursorManager::initialize() {
changeCursor(_cursors[CursorIndex_Idle][_cursorIsPushed]);
showMouse(true);
}
void CursorManager::changeCursor(const ZorkCursor &cursor) {
CursorMan.replaceCursor(cursor.getSurface(), cursor.getWidth(), cursor.getHeight(), cursor.getHotspotX(), cursor.getHotspotY(), cursor.getKeyColor(), false, &_pixelFormat);
}
void CursorManager::cursorDown(bool pushed) {
if (_cursorIsPushed == pushed)
return;
_cursorIsPushed = pushed;
changeCursor(_cursors[_currentCursor][_cursorIsPushed]);
}
void CursorManager::changeCursor(int id) {
if (_item && (id == CursorIndex_Active ||
id == CursorIndex_Idle ||
id == CursorIndex_HandPu)) {
if (id == CursorIndex_Idle) {
id = CursorIndex_ItemIdle;
} else {
id = CursorIndex_ItemAct;
}
}
if (_currentCursor != id || ((id == CursorIndex_ItemAct || id == CursorIndex_ItemIdle) && _lastitem != _item)) {
_currentCursor = id;
_lastitem = _item;
changeCursor(_cursors[_currentCursor][_cursorIsPushed]);
}
}
int CursorManager::getCursorId(const Common::String &name) {
for (int i = 0; i < NUM_CURSORS; i++) {
if (name.equals(_cursorNames[i])) {
return i;
}
}
return CursorIndex_Idle;
}
void CursorManager::showMouse(bool vis) {
CursorMan.showMouse(vis);
}
} // End of namespace ZVision

View File

@@ -0,0 +1,132 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ZVISION_CURSOR_MANAGER_H
#define ZVISION_CURSOR_MANAGER_H
#include "common/str.h"
#include "zvision/graphics/cursors/cursor.h"
namespace Graphics {
struct PixelFormat;
}
namespace ZVision {
class ZVision;
/**
* Mostly usable cursors
*/
enum CursorIndex {
CursorIndex_Active = 0,
CursorIndex_DownArr = 3,
CursorIndex_HandPu = 6,
CursorIndex_Idle = 11,
CursorIndex_Left = 12,
CursorIndex_Right = 13,
CursorIndex_UpArr = 17,
CursorIndex_ItemIdle = 18,
CursorIndex_ItemAct = 19
};
/**
* Class to manage cursor changes. The actual changes have to be done
* through CursorMan. Otherwise the cursor will disappear after GMM
* or debug console.
* TODO: Figure out a way to get rid of the extraneous data copying due to having to use CursorMan
*/
class CursorManager {
public:
CursorManager(ZVision *engine, const Graphics::PixelFormat &pixelFormat);
private:
static const int NUM_CURSORS = 18;
// 18 default cursors in up/down states, +2 for items idle/act cursors
ZorkCursor _cursors[NUM_CURSORS + 2][2];
ZVision *_engine;
const Graphics::PixelFormat _pixelFormat;
bool _cursorIsPushed;
int _item;
int _lastitem;
int _currentCursor;
static const char *_cursorNames[];
static const char *_zgiCursorFileNames[];
static const char *_zNemCursorFileNames[];
public:
/** Creates the idle cursor and shows it */
void initialize();
/**
* Change cursor to specified cursor ID. If item setted to not 0 and cursor id idle/acrive/handpu change cursor to item.
*
* @param id Wanted cursor id.
*/
void changeCursor(int id);
/**
* Return founded id for string contains cursor name
*
* @param name Cursor name
* @return Id of cursor or idle cursor id if not found
*/
int getCursorId(const Common::String &name);
/**
* Load cursor for item by id, and try to change cursor to item cursor if it's not 0
*
* @param id Item id or 0 for no item cursor
*/
void setItemID(int id);
/**
* Change the cursor to a certain push state. If the cursor is already in the specified push state, nothing will happen.
*
* @param pushed Should the cursor be pushed (true) or not pushed (false) (Another way to say it: down or up)
*/
void cursorDown(bool pushed);
/**
* Show or hide mouse cursor.
*
* @param vis Should the cursor be showed (true) or hide (false)
*/
void showMouse(bool vis);
private:
/**
* Calls CursorMan.replaceCursor() using the data in cursor
*
* @param cursor The cursor to show
*/
void changeCursor(const ZorkCursor &cursor);
};
} // End of namespace ZVision
#endif

View File

@@ -0,0 +1,170 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/effects/fog.h"
#include "zvision/scripting/script_manager.h"
namespace ZVision {
FogFx::FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::Path &clouds):
GraphicsEffect(engine, key, region, ported) {
_map = Map;
_r = 0;
_g = 0;
_b = 0;
_pos = 0;
if (SearchMan.hasFile(clouds))
_engine->getRenderManager()->readImageToSurface(clouds, _fog);
else
_engine->getRenderManager()->readImageToSurface("cloud.tga", _fog);
_mp.resize(_fog.h);
for (int16 i = 0; i < _fog.h; i++) {
_mp[i].resize(_fog.w);
for (int16 j = 0; j < _fog.w; j++)
_mp[i][j] = true;
}
for (uint8 i = 0; i < 32; i++)
_colorMap[i] = 0;
}
FogFx::~FogFx() {
if (_map)
delete _map;
for (uint16 i = 0; i < _mp.size(); i++)
_mp[i].clear();
_mp.clear();
}
const Graphics::Surface *FogFx::draw(const Graphics::Surface &srcSubRect) {
_surface.copyFrom(srcSubRect);
EffectMap::iterator it = _map->begin();
uint32 cnt = 0;
for (uint16 j = 0; j < _surface.h; j++) {
uint16 *lineBuf = (uint16 *)_surface.getBasePtr(0, j);
for (uint16 i = 0; i < _surface.w; i++) {
if (it->inEffect) {
// Not 100% equivalent, but looks nice and not buggy
uint8 sr, sg, sb;
_engine->_resourcePixelFormat.colorToRGB(lineBuf[i], sr, sg, sb);
uint16 fogColor = *(uint16 *)_fog.getBasePtr((i + _pos) % _fog.w, j);
uint8 dr, dg, db;
_engine->_resourcePixelFormat.colorToRGB(_colorMap[fogColor & 0x1F], dr, dg, db);
uint16 fr = dr + sr;
if (fr > 255)
fr = 255;
uint16 fg = dg + sg;
if (fg > 255)
fg = 255;
uint16 fb = db + sb;
if (fb > 255)
fb = 255;
lineBuf[i] = _engine->_resourcePixelFormat.RGBToColor(fr, fg, fb);
}
cnt++;
if (cnt >= it->count) {
it++;
cnt = 0;
}
if (it == _map->end())
break;
}
if (it == _map->end())
break;
}
return &_surface;
}
void FogFx::update() {
_pos += _engine->getScriptManager()->getStateValue(StateKey_EF9_Speed);
_pos %= _fog.w;
debugC(2, kDebugEffect, "Updating fog effect");
uint8 dr = _engine->getScriptManager()->getStateValue(StateKey_EF9_R);
uint8 dg = _engine->getScriptManager()->getStateValue(StateKey_EF9_G);
uint8 db = _engine->getScriptManager()->getStateValue(StateKey_EF9_B);
dr = CLIP((int)dr, 0, 31);
dg = CLIP((int)dg, 0, 31);
db = CLIP((int)db, 0, 31);
if (dr != _r || dg != _g || db != _b) {
if (_r > dr)
_r--;
else if (_r < dr)
_r++;
if (_g > dg)
_g--;
else if (_g < dg)
_g++;
if (_b > db)
_b--;
else if (_b < db)
_b++;
// Not 100% equivalent, but looks nice and not buggy
_colorMap[31] = _engine->_resourcePixelFormat.RGBToColor(_r << 3, _g << 3, _b << 3);
for (uint8 i = 0; i < 31; i++) {
float perc = (float)i / 31.0;
uint8 cr = (uint8)((float)_r * perc);
uint8 cg = (uint8)((float)_g * perc);
uint8 cb = (uint8)((float)_b * perc);
_colorMap[i] = _engine->_resourcePixelFormat.RGBToColor(cr << 3, cg << 3, cb << 3);
}
}
for (uint16 j = 0; j < _fog.h; j++) {
uint16 *pix = (uint16 *)_fog.getBasePtr(0, j);
for (uint16 i = 0; i < _fog.w; i++) {
if (_mp[j][i]) {
if ((pix[i] & 0x1F) == 0x1F) {
pix[i]--;
_mp[j][i] = false;
} else
pix[i]++;
} else {
if ((pix[i] & 0x1F) == 0) {
pix[i]++;
_mp[j][i] = true;
} else
pix[i]--;
}
}
}
}
} // End of namespace ZVision

View File

@@ -0,0 +1,52 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ZVISION_FOG_H
#define ZVISION_FOG_H
#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
// Used by Zork: Nemesis for the mixing chamber gas effect in the gas puzzle (location tt5e, when the blinds are down)
class FogFx : public GraphicsEffect {
public:
FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::Path &clouds);
~FogFx() override;
const Graphics::Surface *draw(const Graphics::Surface &srcSubRect) override;
void update() override;
private:
EffectMap *_map;
Graphics::Surface _fog;
uint8 _r, _g, _b;
int32 _pos;
Common::Array< Common::Array< bool > > _mp;
uint16 _colorMap[32];
};
} // End of namespace ZVision
#endif // ZVISION_FOG_H

View File

@@ -0,0 +1,106 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/effects/light.h"
namespace ZVision {
LightFx::LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD, int8 maxD):
GraphicsEffect(engine, key, region, ported) {
_map = Map;
_delta = delta;
_up = true;
_pos = 0;
_minD = minD;
if (_minD < -delta)
_minD = -delta;
_maxD = maxD;
if (_maxD > delta)
_maxD = delta;
}
LightFx::~LightFx() {
if (_map)
delete _map;
}
const Graphics::Surface *LightFx::draw(const Graphics::Surface &srcSubRect) {
_surface.copyFrom(srcSubRect);
EffectMap::iterator it = _map->begin();
uint32 cnt = 0;
uint32 dcolor = 0;
if (_pos < 0) {
uint8 cc = ((-_pos) & 0x1F) << 3;
dcolor = _engine->_resourcePixelFormat.RGBToColor(cc, cc, cc);
} else {
uint8 cc = (_pos & 0x1F) << 3;
dcolor = _engine->_resourcePixelFormat.RGBToColor(cc, cc, cc);
}
for (uint16 j = 0; j < _surface.h; j++) {
uint16 *lineBuf = (uint16 *)_surface.getBasePtr(0, j);
for (uint16 i = 0; i < _surface.w; i++) {
if (it->inEffect) {
if (_pos < 0) {
lineBuf[i] -= dcolor;
} else {
lineBuf[i] += dcolor;
}
}
cnt++;
if (cnt >= it->count) {
it++;
cnt = 0;
}
if (it == _map->end())
break;
}
if (it == _map->end())
break;
}
return &_surface;
}
void LightFx::update() {
if (_up)
_pos++;
else
_pos--;
if (_pos <= _minD) {
_up = !_up;
_pos = _minD;
} else if (_pos >= _maxD) {
_up = !_up;
_pos = _maxD;
}
}
} // End of namespace ZVision

View File

@@ -0,0 +1,52 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LIGHTFX_H_INCLUDED
#define LIGHTFX_H_INCLUDED
#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
class LightFx : public GraphicsEffect {
public:
LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD = -127, int8 maxD = 127);
~LightFx() override;
const Graphics::Surface *draw(const Graphics::Surface &srcSubRect) override;
void update() override;
private:
EffectMap *_map;
int32 _delta;
bool _up;
int32 _pos;
int8 _minD;
int8 _maxD;
};
} // End of namespace ZVision
#endif // LIGHTFX_H_INCLUDED

View File

@@ -0,0 +1,142 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/scummsys.h"
#include "zvision/zvision.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/effects/wave.h"
namespace ZVision {
WaveFx::WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd):
GraphicsEffect(engine, key, region, ported) {
_frame = 0;
_frameCount = frames;
_ampls.resize(_frameCount);
_halfWidth = _region.width() / 2;
_halfHeight = _region.height() / 2;
int32 frmsize = _halfWidth * _halfHeight;
float phase = 0;
int16 quarterWidth = _halfWidth / 2;
int16 quarterHeight = _halfHeight / 2;
for (int16 i = 0; i < _frameCount; i++) {
_ampls[i].resize(frmsize);
for (int16 y = 0; y < _halfHeight; y++)
for (int16 x = 0; x < _halfWidth; x++) {
int16 dx = (x - quarterWidth);
int16 dy = (y - quarterHeight);
_ampls[i][x + y * _halfWidth] = (int8)(ampl * sin(sqrt(dx * dx / (float)centerX + dy * dy / (float)centerY) / (-waveln * 3.1415926) + phase));
}
phase += spd;
}
}
WaveFx::~WaveFx() {
for (uint16 i = 0; i < _ampls.size(); i++)
_ampls[i].clear();
_ampls.clear();
}
const Graphics::Surface *WaveFx::draw(const Graphics::Surface &srcSubRect) {
for (int16 y = 0; y < _halfHeight; y++) {
uint16 *abc = (uint16 *)_surface.getBasePtr(0, y);
uint16 *abc2 = (uint16 *)_surface.getBasePtr(0, _halfHeight + y);
uint16 *abc3 = (uint16 *)_surface.getBasePtr(_halfWidth, y);
uint16 *abc4 = (uint16 *)_surface.getBasePtr(_halfWidth, _halfHeight + y);
for (int16 x = 0; x < _halfWidth; x++) {
int8 amnt = _ampls[_frame][x + _halfWidth * y];
int16 nX = x + amnt;
int16 nY = y + amnt;
if (nX < 0)
nX = 0;
if (nX >= _region.width())
nX = _region.width() - 1;
if (nY < 0)
nY = 0;
if (nY >= _region.height())
nY = _region.height() - 1;
*abc = *(const uint16 *)srcSubRect.getBasePtr(nX, nY);
nX = x + amnt + _halfWidth;
nY = y + amnt;
if (nX < 0)
nX = 0;
if (nX >= _region.width())
nX = _region.width() - 1;
if (nY < 0)
nY = 0;
if (nY >= _region.height())
nY = _region.height() - 1;
*abc3 = *(const uint16 *)srcSubRect.getBasePtr(nX, nY);
nX = x + amnt;
nY = y + amnt + _halfHeight;
if (nX < 0)
nX = 0;
if (nX >= _region.width())
nX = _region.width() - 1;
if (nY < 0)
nY = 0;
if (nY >= _region.height())
nY = _region.height() - 1;
*abc2 = *(const uint16 *)srcSubRect.getBasePtr(nX, nY);
nX = x + amnt + _halfWidth;
nY = y + amnt + _halfHeight;
if (nX < 0)
nX = 0;
if (nX >= _region.width())
nX = _region.width() - 1;
if (nY < 0)
nY = 0;
if (nY >= _region.height())
nY = _region.height() - 1;
*abc4 = *(const uint16 *)srcSubRect.getBasePtr(nX, nY);
abc++;
abc2++;
abc3++;
abc4++;
}
}
return &_surface;
}
void WaveFx::update() {
_frame = (_frame + 1) % _frameCount;
}
} // End of namespace ZVision

View File

@@ -0,0 +1,50 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef WAVEFX_H_INCLUDED
#define WAVEFX_H_INCLUDED
#include "common/array.h"
#include "zvision/graphics/graphics_effect.h"
namespace ZVision {
class ZVision;
class WaveFx : public GraphicsEffect {
public:
WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd);
~WaveFx() override;
const Graphics::Surface *draw(const Graphics::Surface &srcSubRect) override;
void update() override;
private:
int16 _frame;
int16 _frameCount;
int16 _halfWidth, _halfHeight;
Common::Array< Common::Array< int8 > > _ampls;
};
} // End of namespace ZVision
#endif // WAVEFX_H_INCLUDED

View File

@@ -0,0 +1,84 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRAPHICS_EFFECT_H_INCLUDED
#define GRAPHICS_EFFECT_H_INCLUDED
#include "common/list.h"
#include "common/rect.h"
#include "graphics/surface.h"
#include "zvision/zvision.h"
namespace ZVision {
class ZVision;
class GraphicsEffect {
public:
GraphicsEffect(ZVision *engine, uint32 key, Common::Rect region, bool ported) : _engine(engine), _key(key), _region(region), _ported(ported) {
_surface.create(_region.width(), _region.height(), _engine->_resourcePixelFormat);
}
virtual ~GraphicsEffect() {}
uint32 getKey() {
return _key;
}
Common::Rect getRegion() {
return _region;
}
// If true, effect is applied to the current background image prior to panoramic warping
// If false, effect is applied to the effects buffer, which corresponds directly to the working window
bool isPort() {
return _ported;
}
// Make a copy of supplied surface, draw effect on it, then return that altered surface
virtual const Graphics::Surface *draw(const Graphics::Surface &srcSubRect) {
return &_surface;
}
virtual void update() {}
protected:
ZVision *_engine;
uint32 _key;
Common::Rect _region;
bool _ported;
Graphics::Surface _surface;
// Static member functions
public:
};
struct EffectMapUnit {
uint32 count;
bool inEffect;
};
typedef Common::List<EffectMapUnit> EffectMap;
} // End of namespace ZVision
#endif // GRAPHICS_EFFECT_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,376 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ZVISION_RENDER_MANAGER_H
#define ZVISION_RENDER_MANAGER_H
#include "common/hashmap.h"
#include "common/rect.h"
#include "graphics/framelimiter.h"
#include "graphics/managed_surface.h"
#include "graphics/screen.h"
#include "graphics/surface.h"
#include "zvision/graphics/graphics_effect.h"
#include "zvision/graphics/render_table.h"
#include "zvision/text/truetype_font.h"
class OSystem;
namespace Common {
class String;
class SeekableReadStream;
}
namespace Video {
class VideoDecoder;
}
namespace ZVision {
class RenderManager {
public:
RenderManager(ZVision *engine, const ScreenLayout layout, const Graphics::PixelFormat pixelFormat, bool doubleFPS, bool widescreen = false);
~RenderManager();
typedef Common::List<GraphicsEffect *> EffectsList;
private:
ZVision *_engine;
OSystem *_system;
const Graphics::PixelFormat _pixelFormat;
const ScreenLayout _layout;
bool _hiRes = false;
Graphics::FrameLimiter _frameLimiter;
/**
* A Rectangle representing the screen/window resolution.
*/
Common::Rect _screenArea;
Common::Rect _HDscreenArea = Common::Rect(800, 600);
Common::Rect _HDscreenAreaWide = Common::Rect(720, 377);
Common::Point _textOffset; //Position vector of text area origin relative to working window origin
/**
* A Rectangle placed inside _screenArea All in-game coordinates
* are given in this coordinate space. Also, all images are clipped to the
* edges of this Rectangle
*/
Common::Rect _workingArea;
Common::Point _workingAreaCenter; //Center of the working area in working area coordinates
/**
Managed surface representing physical screen; dirty rectangles will be handled automatically by this from now on
*/
Graphics::Screen _screen;
/** A buffer for background image that's being used to create the background */
Graphics::Surface _currentBackgroundImage;
Common::Rect _backgroundDirtyRect;
/**
* The x1 or y1 offset of the subRectangle of the background that is currently displayed on the screen
* It will be x1 if PANORAMA, or y1 if TILT
*/
int16 _backgroundOffset;
/** The width of the current background image */
uint16 _backgroundWidth;
/** The height of the current background image */
uint16 _backgroundHeight;
// A buffer that holds the portion of the background that is used to render the final image
// If it's a normal scene, the pixels will be blitted directly to the screen
// If it's a panorma / tilt scene, the pixels will be first warped to _warpedSceneSurface
Graphics::Surface _backgroundSurface;
Graphics::ManagedSurface _workingManagedSurface;
Common::Rect _backgroundSurfaceDirtyRect;
//TODO: Migrate this functionality to SubtitleManager to improve encapsulation
//*
// Buffer for drawing subtitles & other messages
Graphics::Surface _textSurface;
Graphics::ManagedSurface _textManagedSurface;
Common::Rect _textSurfaceDirtyRect;
//*/
// Rectangle for subtitles & other messages
Common::Rect _textArea; //NB Screen coordinates
Common::Rect _textLetterbox; //Section of text area outside working window, to be filled with black when blanked
Common::Rect _textOverlay; //Section of text area to be filled with colorkey when blanked (may potentially intersect text letterbox area if screen/window is wider than working area!)
// Buffer for drawing menu
Graphics::Surface _menuSurface;
Graphics::ManagedSurface _menuManagedSurface;
Common::Rect _menuSurfaceDirtyRect; //subrectangle of menu area outside working area
// Rectangle for menu area
Common::Rect _menuArea; //Screen coordinates
Common::Rect _menuLetterbox; //Section of menu area to be filled with black when blanked
Common::Rect _menuOverlay; //Section of menu area to be filled with colorkey when blanked (may potentially intersect menu letterbox area if screen/window is wider than working area!)
//Buffer for streamed video playback
//*
Graphics::ManagedSurface _vidManagedSurface;
/*/
Graphics::Surface _vidSurface;
//*/
//Area of streamed video playback
Common::Rect _vidArea;
// A buffer used for apply graphics effects
Graphics::Surface _effectSurface;
// A buffer to store the result of the panorama / tilt warps
Graphics::Surface _warpedSceneSurface;
/** Used to warp the background image */
RenderTable _renderTable;
// Visual effects list
EffectsList _effects;
//Pointer to currently active backbuffer output surface
Graphics::Surface *_outputSurface;
bool _doubleFPS;
bool _widescreen;
public:
void initialize(bool hiRes = false);
/**
* Renders the scene to the screen
* Returns true if screen was updated
* If streamMode is set true, all background processing is skipped and the previous framebuffer is used
*/
bool renderSceneToScreen(bool immediate = false, bool overlayOnly = false, bool preStream = false);
Graphics::ManagedSurface &getVidSurface(Common::Rect dstRect); //dstRect is defined relative to working area origin
const Common::Rect &getMenuArea() const {
return _menuArea;
}
const Common::Rect &getWorkingArea() const {
return _workingArea;
}
/**
* Blits the image or a portion of the image to the background.
*
* @param fileName Name of the image file
* @param destinationX X position where the image should be put. Coords are in working window space, not screen space!
* @param destinationY Y position where the image should be put. Coords are in working window space, not screen space!
*/
void renderImageToBackground(const Common::Path &fileName, int16 destinationX, int16 destinationY);
/**
* Blits the image or a portion of the image to the background.
*
* @param fileName Name of the image file
* @param destX X position where the image should be put. Coords are in working window space, not screen space!
* @param destY Y position where the image should be put. Coords are in working window space, not screen space!
* @param colorkey Transparent color
*/
void renderImageToBackground(const Common::Path &fileName, int16 destX, int16 destY, uint32 colorkey);
/**
* Blits the image or a portion of the image to the background.
*
* @param fileName Name of the image file
* @param destX X position where the image should be put. Coords are in working window space, not screen space!
* @param destY Y position where the image should be put. Coords are in working window space, not screen space!
* @param keyX X position of transparent color
* @param keyY Y position of transparent color
*/
void renderImageToBackground(const Common::Path &fileName, int16 destX, int16 destY, int16 keyX, int16 keyY);
/**
* Sets the current background image to be used by the RenderManager and immediately
* blits it to the screen. (It won't show up until the end of the frame)
*
* @param fileName The name of the image file
*/
void setBackgroundImage(const Common::Path &fileName);
/**
* Set the background position (_backgroundOffset). If the current RenderState is PANORAMA, the offset
* will be in the horizontal direction. If the current RenderState is TILT, the offset will be in the
* vertical direction.
*
* This method will not render anything on the screen. So if nothing else is called that renders the
* background, the change won't be seen until next frame.
*
* @param offset The amount to offset the background
*/
void setBackgroundPosition(int offset);
/**
* Converts a point in screen coordinate space to image coordinate space
*
* @param point Point in screen coordinate space
* @return Point in image coordinate space
*/
const Common::Point screenSpaceToImageSpace(const Common::Point &point);
// Return pointer of RenderTable object
RenderTable *getRenderTable();
// Return current background offset
uint32 getCurrentBackgroundOffset();
/**
* Creates a copy of surface and transposes the data.
*
* Note: The user is responsible for calling free() on the returned surface
* and then deleting it
*
* @param surface The data to be transposed
* @return A copy of the surface with the data transposed
*/
static Graphics::Surface *tranposeSurface(const Graphics::Surface *surface);
// Scale buffer (nearest)
void scaleBuffer(const void *src, void *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint32 dstWidth, uint32 dstHeight);
/**
* Blit from one surface to another surface
*
* @param src Source surface
* @param srcRect Rectangle defining area of source surface to blit; if this rectangle is empty or not supplied, entire source surface is blitted
* @param dst Destination surface
* @param x Destination surface x coordinate
* @param y Destination surface y coordinate
*/
void blitSurfaceToSurface(const Graphics::Surface &src, Common::Rect srcRect, Graphics::Surface &dst, int _x, int _y);
void blitSurfaceToSurface(const Graphics::Surface &src, Common::Rect srcRect, Graphics::Surface &dst, int _x, int _y, uint32 colorkey);
void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int _x, int _y) {blitSurfaceToSurface(src, Common::Rect(src.w, src.h), dst, _x, _y);}
void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int _x, int _y, uint32 colorkey) {blitSurfaceToSurface(src, Common::Rect(src.w, src.h), dst, _x, _y, colorkey);}
// Blitting surface-to-background methods
void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, int32 colorkey = -1);
// Blitting surface-to-background methods with scale
void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &dstRect, int32 colorkey = -1);
/**
* Blit from source surface to menu area
*
* @param src Source surface
* @param x x coordinate relative to menu area origin
* @param y y coordinate relative to menu area origin
*/
void blitSurfaceToMenu(const Graphics::Surface &src, int16 x, int16 y, int32 colorkey = 0);
/**
* Blit from source surface to text area
*
* @param src Source surface
* @param x x coordinate relative to text area origin
* @param y y coordinate relative to text area origin
*/
void blitSurfaceToText(const Graphics::Surface &src, int16 x, int16 y, int32 colorkey = 0);
// Return background size
Common::Point getBkgSize();
// Return portion of background as new surface
Graphics::Surface *getBkgRect(Common::Rect &rect);
// Load image into new surface
Graphics::Surface *loadImage(const Common::Path &file);
Graphics::Surface *loadImage(const Common::Path &file, bool transposed);
// Clear whole/area of menu backbuffer
void clearMenuSurface(bool force = false, int32 colorkey = -1);
// Clear whole/area of subtitle backbuffer
void clearTextSurface(bool force = false, int32 colorkey = -1);
// Copy needed portion of background surface to workingArea surface
void prepareBackground();
/**
* Reads an image file pixel data into a Surface buffer. Also, if the image
* is transposed, it will un-transpose the pixel data. The function will
* call destination::create() if the dimensions of destination do not match
* up with the dimensions of the image.
*
* @param fileName The name of a .tga file
* @param destination A reference to the Surface to store the pixel data in
*/
void readImageToSurface(const Common::Path &fileName, Graphics::Surface &destination);
/**
* Reads an image file pixel data into a Surface buffer. Also, if the image
* is transposed, it will un-transpose the pixel data. The function will
* call destination::create() if the dimensions of destination do not match
* up with the dimensions of the image.
*
* @param fileName The name of a .tga file
* @param destination A reference to the Surface to store the pixel data in
* @param transposed Transpose flag
*/
void readImageToSurface(const Common::Path &fileName, Graphics::Surface &destination, bool transposed);
// Add visual effect to effects list
void addEffect(GraphicsEffect *_effect);
// Delete effect(s) by ID (ID equal to slot of action:region that create this effect)
void deleteEffect(uint32 ID);
// Create "mask" for effects - (color +/- depth) will be selected as not transparent. Like color selection
// xy - base color
// depth - +/- of base color
// rect - rectangle where select pixels
// minD - if not NULL will receive real bottom border of depth
// maxD - if not NULL will receive real top border of depth
EffectMap *makeEffectMap(const Common::Point &xy, int16 depth, const Common::Rect &rect, int8 *minD, int8 *maxD);
// Create "mask" for effects by simple transparent color
EffectMap *makeEffectMap(const Graphics::Surface &surf, uint16 transp);
// Return background rectangle in screen coordinates
Common::Rect transformBackgroundSpaceRectToScreenSpace(const Common::Rect &src);
// Mark whole background surface as dirty
void markDirty();
/*
// Fill background surface by color
void bkgFill(uint8 r, uint8 g, uint8 b);
*/
void checkBorders();
void rotateTo(int16 to, int16 time);
void updateRotation();
void upscaleRect(Common::Rect &rect);
};
} // End of namespace ZVision
#endif

View File

@@ -0,0 +1,345 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/rect.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "math/utils.h"
#include "zvision/graphics/render_table.h"
#include "zvision/scripting/script_manager.h"
namespace ZVision {
RenderTable::RenderTable(ZVision *engine, uint16 numColumns, uint16 numRows, const Graphics::PixelFormat &pixelFormat)
: _engine(engine),
_system(engine->_system),
_numRows(numRows),
_numColumns(numColumns),
_renderState(FLAT),
_pixelFormat(pixelFormat) {
assert(numRows != 0 && numColumns != 0);
_internalBuffer = new FilterPixel[numRows * numColumns];
memset(&_panoramaOptions, 0, sizeof(_panoramaOptions));
memset(&_tiltOptions, 0, sizeof(_tiltOptions));
_halfRows = floor((_numRows - 1) / 2);
_halfColumns = floor((_numColumns - 1) / 2);
_halfWidth = (float)_numColumns / 2.0f - 0.5f;
_halfHeight = (float)_numRows / 2.0f - 0.5f;
}
RenderTable::~RenderTable() {
delete[] _internalBuffer;
}
void RenderTable::setRenderState(RenderState newState) {
_renderState = newState;
switch (newState) {
case PANORAMA:
_panoramaOptions.verticalFOV = Math::deg2rad<float>(27.0f);
_panoramaOptions.linearScale = 0.55f;
_panoramaOptions.reverse = false;
_panoramaOptions.zeroPoint = 0;
break;
case TILT:
_tiltOptions.verticalFOV = Math::deg2rad<float>(27.0f);
_tiltOptions.linearScale = 0.65f;
_tiltOptions.reverse = false;
break;
case FLAT:
// Intentionally left empty
break;
default:
break;
}
}
const Common::Point RenderTable::convertWarpedCoordToFlatCoord(const Common::Point &point) {
// If we're outside the range of the RenderTable, no warping is happening. Return the maximum image coords
if (point.x >= (int16)_numColumns || point.y >= (int16)_numRows || point.x < 0 || point.y < 0) {
int16 x = CLIP<int16>(point.x, 0, (int16)_numColumns);
int16 y = CLIP<int16>(point.y, 0, (int16)_numRows);
return Common::Point(x, y);
}
uint32 index = point.y * _numColumns + point.x;
Common::Point newPoint(point);
newPoint.x += (_internalBuffer[index]._xDir ? _internalBuffer[index]._src.right : _internalBuffer[index]._src.left);
newPoint.y += (_internalBuffer[index]._yDir ? _internalBuffer[index]._src.bottom : _internalBuffer[index]._src.top);
return newPoint;
}
// Disused at present; potentially useful for future rendering efficient improvements.
/*/
void RenderTable::mutateImage(uint16 *sourceBuffer, uint16 *destBuffer, uint32 destWidth, const Common::Rect &subRect) {
uint32 destOffset = 0;
uint32 sourceXIndex = 0;
uint32 sourceYIndex = 0;
if(highQuality) {
// TODO - convert to high quality pixel filtering
for (int16 y = subRect.top; y < subRect.bottom; ++y) {
uint32 sourceOffset = y * _numColumns;
for (int16 x = subRect.left; x < subRect.right; ++x) {
uint32 normalizedX = x - subRect.left;
uint32 index = sourceOffset + x;
// RenderTable only stores offsets from the original coordinates
sourceYIndex = y + _internalBuffer[index]._src.top;
sourceXIndex = x + _internalBuffer[index]._src.left;
destBuffer[destOffset + normalizedX] = sourceBuffer[sourceYIndex * _numColumns + sourceXIndex];
}
destOffset += destWidth;
}
}
else {
for (int16 y = subRect.top; y < subRect.bottom; ++y) {
uint32 sourceOffset = y * _numColumns;
for (int16 x = subRect.left; x < subRect.right; ++x) {
uint32 normalizedX = x - subRect.left;
uint32 index = sourceOffset + x;
// RenderTable only stores offsets from the original coordinates
sourceYIndex = y + _internalBuffer[index]._src.top;
sourceXIndex = x + _internalBuffer[index]._src.left;
destBuffer[destOffset + normalizedX] = sourceBuffer[sourceYIndex * _numColumns + sourceXIndex];
}
destOffset += destWidth;
}
}
}
// */
void RenderTable::mutateImage(Graphics::Surface *dstBuf, Graphics::Surface *srcBuf, bool highQuality) {
uint32 destOffset = 0;
uint32 sourceOffset = 0;
uint16 *sourceBuffer = (uint16 *)srcBuf->getPixels();
uint16 *destBuffer = (uint16 *)dstBuf->getPixels();
if (highQuality != _highQuality) {
_highQuality = highQuality;
generateRenderTable();
}
uint32 mutationTime = _system->getMillis();
if (_highQuality) {
// Apply bilinear interpolation
for (int16 y = 0; y < srcBuf->h; ++y) {
sourceOffset = y * _numColumns;
for (int16 x = 0; x < srcBuf->w; ++x) {
const FilterPixel &curP = _internalBuffer[sourceOffset + x];
const uint32 srcIndexYT = y + curP._src.top;
const uint32 srcIndexYB = y + curP._src.bottom;
const uint32 srcIndexXL = x + curP._src.left;
const uint32 srcIndexXR = x + curP._src.right;
uint32 rTL, rTR, rBL, rBR;
uint32 gTL, gTR, gBL, gBR;
uint32 bTL, bTR, bBL, bBR;
splitColor(sourceBuffer[srcIndexYT * _numColumns + srcIndexXL], rTL, gTL, bTL);
splitColor(sourceBuffer[srcIndexYT * _numColumns + srcIndexXR], rTR, gTR, bTR);
splitColor(sourceBuffer[srcIndexYB * _numColumns + srcIndexXL], rBL, gBL, bBL);
splitColor(sourceBuffer[srcIndexYB * _numColumns + srcIndexXR], rBR, gBR, bBR);
const uint32 rF = curP._fTL * rTL + curP._fTR * rTR + curP._fBL * rBL + curP._fBR * rBR;
const uint32 gF = curP._fTL * gTL + curP._fTR * gTR + curP._fBL * gBL + curP._fBR * gBR;
const uint32 bF = curP._fTL * bTL + curP._fTR * bTR + curP._fBL * bBL + curP._fBR * bBR;
destBuffer[destOffset] = mergeColor(rF, gF, bF);
destOffset++;
}
}
} else {
// Apply nearest-neighbour interpolation
for (int16 y = 0; y < srcBuf->h; ++y) {
sourceOffset = y * _numColumns;
for (int16 x = 0; x < srcBuf->w; ++x) {
const uint32 index = sourceOffset + x;
// RenderTable only stores offsets from the original coordinates
const uint32 srcIndexX = x + (_internalBuffer[index]._xDir ? _internalBuffer[index]._src.right : _internalBuffer[index]._src.left);
const uint32 srcIndexY = y + (_internalBuffer[index]._yDir ? _internalBuffer[index]._src.bottom : _internalBuffer[index]._src.top);
destBuffer[destOffset] = sourceBuffer[srcIndexY * _numColumns + srcIndexX];
destOffset++;
}
}
}
mutationTime = _system->getMillis() - mutationTime;
debugC(5, kDebugGraphics, "\tPanorama mutation time %dms, %s quality", mutationTime, _highQuality ? "high" : "low");
}
void RenderTable::generateRenderTable() {
switch (_renderState) {
case RenderTable::PANORAMA: {
generateLookupTable(false);
break;
}
case RenderTable::TILT:
generateLookupTable(true);
break;
case RenderTable::FLAT:
// Intentionally left empty
break;
default:
break;
}
}
void RenderTable::generateLookupTable(bool tilt) {
debugC(1, kDebugGraphics, "Generating %s lookup table.", tilt ? "tilt" : "panorama");
debugC(5, kDebugGraphics, "_halfWidth %f, _halfHeight %f", _halfWidth, _halfHeight);
debugC(5, kDebugGraphics, "_halfRows %d, _halfColumns %d", _halfRows, _halfColumns);
uint32 generationTime = _system->getMillis();
float cosAlpha, polarCoordInCylinderCoords, cylinderRadius, xOffset, yOffset;
uint32 indexTL, indexBL, indexTR, indexBR;
auto outerLoop = [&](uint & polarCoord, float & halfPolarSize, float & scale) {
// polarCoord is the coordinate of the working window pixel parallel to the direction of camera rotation
// halfPolarSize is the distance from the central axis to the outermost working window pixel in the direction of camera rotation
// alpha represents the angle in the direction of camera rotation between the view axis and the centre of a pixel at the given polar coordinate
const float alpha = atan(((float)polarCoord - halfPolarSize) / cylinderRadius);
// To map the polar coordinate to the cylinder surface coordinates, we just need to calculate the arc length
// We also scale it by linearScale
polarCoordInCylinderCoords = (cylinderRadius * scale * alpha) + halfPolarSize;
cosAlpha = cos(alpha);
};
auto innerLoop = [&](uint & polarCoord, uint & linearCoord, float & halfLinearSize, float & polarOffset, float & linearOffset) {
// To calculate linear coordinate in cylinder coordinates, we can do similar triangles comparison,
// comparing the triangle from the center to the screen and from the center to the edge of the cylinder
const float linearCoordInCylinderCoords = halfLinearSize + ((float)linearCoord - halfLinearSize) * cosAlpha;
linearOffset = linearCoordInCylinderCoords - linearCoord;
polarOffset = polarCoordInCylinderCoords - polarCoord;
_internalBuffer[indexTL] = FilterPixel(xOffset, yOffset, _highQuality);
// Transformation is both horizontally and vertically symmetrical about the camera axis,
// We can thus save on trigonometric calculations by computing one quarter of the transformation matrix and then mirroring it in both X & Y:
_internalBuffer[indexBL] = _internalBuffer[indexTL];
_internalBuffer[indexBL].flipV();
_internalBuffer[indexTR] = _internalBuffer[indexTL];
_internalBuffer[indexTR].flipH();
_internalBuffer[indexBR] = _internalBuffer[indexBL];
_internalBuffer[indexBR].flipH();
};
if (tilt) {
cylinderRadius = (_halfWidth + 0.5f) / tan(_tiltOptions.verticalFOV);
_tiltOptions.gap = cylinderRadius * atan2((float)(_halfHeight / cylinderRadius), 1.0f) * _tiltOptions.linearScale;
for (uint y = 0; y <= _halfRows; ++y) {
outerLoop(y, _halfHeight, _tiltOptions.linearScale);
const uint32 columnIndexTL = y * _numColumns;
const uint32 columnIndexBL = (_numRows - (y + 1)) * _numColumns;
const uint32 columnIndexTR = columnIndexTL + (_numColumns - 1);
const uint32 columnIndexBR = columnIndexBL + (_numColumns - 1);
for (uint x = 0; x <= _halfColumns; ++x) {
indexTL = columnIndexTL + x;
indexBL = columnIndexBL + x;
indexTR = columnIndexTR - x;
indexBR = columnIndexBR - x;
innerLoop(y, x, _halfWidth, yOffset, xOffset);
}
}
} else {
cylinderRadius = (_halfHeight + 0.5f) / tan(_panoramaOptions.verticalFOV);
for (uint x = 0; x <= _halfColumns; ++x) {
const uint32 columnIndexL = x;
const uint32 columnIndexR = (_numColumns - 1) - x;
uint32 rowIndexT = 0;
uint32 rowIndexB = _numColumns * (_numRows - 1);
outerLoop(x, _halfWidth, _panoramaOptions.linearScale);
for (uint y = 0; y <= _halfRows; ++y) {
indexTL = rowIndexT + columnIndexL;
indexBL = rowIndexB + columnIndexL;
indexTR = rowIndexT + columnIndexR;
indexBR = rowIndexB + columnIndexR;
innerLoop(x, y, _halfHeight, xOffset, yOffset);
rowIndexT += _numColumns;
rowIndexB -= _numColumns;
}
}
}
generationTime = _system->getMillis() - generationTime;
debugC(1, kDebugGraphics, "Render table generated, %s quality", _highQuality ? "high" : "low");
debugC(1, kDebugGraphics, "\tRender table generation time %dms", generationTime);
}
void RenderTable::setPanoramaFoV(float fov) {
assert(fov > 0.0f);
_panoramaOptions.verticalFOV = Math::deg2rad<float>(fov);
}
void RenderTable::setPanoramaScale(float scale) {
assert(scale > 0.0f);
_panoramaOptions.linearScale = scale;
}
void RenderTable::setPanoramaReverse(bool reverse) {
_panoramaOptions.reverse = reverse;
}
bool RenderTable::getPanoramaReverse() {
return _panoramaOptions.reverse;
}
void RenderTable::setPanoramaZeroPoint(uint16 point) {
_panoramaOptions.zeroPoint = point;
}
uint16 RenderTable::getPanoramaZeroPoint() {
return _panoramaOptions.zeroPoint;
}
void RenderTable::setTiltFoV(float fov) {
assert(fov > 0.0f);
_tiltOptions.verticalFOV = Math::deg2rad<float>(fov);
}
void RenderTable::setTiltScale(float scale) {
assert(scale > 0.0f);
_tiltOptions.linearScale = scale;
}
void RenderTable::setTiltReverse(bool reverse) {
_tiltOptions.reverse = reverse;
}
float RenderTable::getTiltGap() {
return _tiltOptions.gap;
}
float RenderTable::getAngle() {
switch (_renderState) {
case TILT:
return Math::rad2deg<float>(_tiltOptions.verticalFOV);
case PANORAMA:
return Math::rad2deg<float>(_panoramaOptions.verticalFOV);
default:
return 1.0f;
}
}
float RenderTable::getLinscale() {
switch (_renderState) {
case TILT:
return _tiltOptions.linearScale;
case PANORAMA:
return _panoramaOptions.linearScale;
default:
return 1.0f;
}
}
} // End of namespace ZVision

View File

@@ -0,0 +1,169 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ZVISION_RENDER_TABLE_H
#define ZVISION_RENDER_TABLE_H
#include "common/rect.h"
#include "graphics/surface.h"
#include "zvision/zvision.h"
class OSystem;
namespace ZVision {
class FilterPixel {
public:
// Bitfields representing sequential direction of contraction
bool _xDir = false; // false left, true right
bool _yDir = false; // false up, true down
Common::Rect _src = Common::Rect(0, 0); // Coordinates of four panorama image pixels around actual working window pixel
float _fX, _fY, _fTL, _fTR, _fBL, _fBR;
FilterPixel() {}
FilterPixel(float x, float y, bool highQuality = false) {
_src.left = int16(floor(x));
_src.right = int16(ceil(x));
_src.top = int16(floor(y));
_src.bottom = int16(ceil(y));
if (highQuality) {
_fX = x - (float)_src.left;
_fY = y - (float)_src.top;
_fTL = (1 - _fX) * (1 - _fY);
_fTR = _fX * (1 - _fY);
_fBL = (1 - _fX) * _fY;
_fBR = _fX * _fY;
} else {
// Nearest neighbour
_xDir = (x - _src.left) > 0.5f;
_yDir = (y - _src.top) > 0.5f;
}
}
~FilterPixel() {}
inline void flipH() {
_src.left = -_src.left;
_src.right = -_src.right;
}
inline void flipV() {
_src.top = -_src.top;
_src.bottom = -_src.bottom;
}
};
class RenderTable {
public:
RenderTable(ZVision *engine, uint16 numRows, uint16 numColumns, const Graphics::PixelFormat &pixelFormat);
~RenderTable();
// Common::Point testPixel = Common::Point(255,0);
public:
enum RenderState {
PANORAMA,
TILT,
FLAT
};
private:
ZVision *_engine;
OSystem *_system;
uint16 _numRows, _numColumns, _halfRows, _halfColumns; // Working area width, height; half width, half height, in whole pixels
float _halfWidth, _halfHeight; // Centre axis to midpoint of outermost pixel
FilterPixel *_internalBuffer;
RenderState _renderState;
bool _highQuality = false;
const Graphics::PixelFormat _pixelFormat;
inline void splitColor(uint16 &color, uint32 &r, uint32 &g, uint32 &b) const {
// NB Left & right shifting unnecessary for interpolating & recombining, so not bothering in order to save cycles
r = color & 0x001f;
g = color & 0x03e0;
b = color & 0x7c00;
}
inline uint16 mergeColor(const uint32 &r, const uint32 &g, const uint32 &b) const {
// NB Red uses the lowest bits in RGB555 and so doesn't need its fractional bits masked away after averaging
return r | (g & 0x03e0) | (b & 0x7c00);
}
struct {
float verticalFOV; // Radians
float linearScale;
bool reverse;
uint16 zeroPoint;
} _panoramaOptions;
struct {
float verticalFOV; // Radians
float linearScale;
bool reverse;
float gap;
} _tiltOptions;
public:
RenderState getRenderState() {
return _renderState;
}
void setRenderState(RenderState newState);
const Common::Point convertWarpedCoordToFlatCoord(const Common::Point &point); // input point in working area coordinates
// void mutateImage(uint16 *sourceBuffer, uint16 *destBuffer, uint32 destWidth, const Common::Rect &subRect);
void mutateImage(Graphics::Surface *dstBuf, Graphics::Surface *srcBuf, bool filter = false);
template <typename I>
Common::String pixelToBinary(const I &pixel, bool splitColors = true) const {
uint8 bits = sizeof(pixel) << 3;
Common::String str("0b");
I spaceMask = 0;
for (uint8 i = 0; i < 3; i++)
spaceMask = (spaceMask << 5) + 0x10;
for (I mask = 0x01 << (bits - 1); mask; mask >>= 1) {
if (splitColors && (spaceMask & mask))
str += " ";
str += mask & pixel ? "1" : "0";
}
return str;
}
void generateRenderTable();
void setPanoramaFoV(float fov); // Degrees
void setPanoramaScale(float scale);
void setPanoramaReverse(bool reverse);
void setPanoramaZeroPoint(uint16 point);
uint16 getPanoramaZeroPoint();
bool getPanoramaReverse();
void setTiltFoV(float fov); // Degrees
void setTiltScale(float scale);
void setTiltReverse(bool reverse);
float getTiltGap();
float getAngle();
float getLinscale();
private:
void generateLookupTable(bool tilt = false);
void generatePanoramaLookupTable();
void generateTiltLookupTable();
};
} // End of namespace ZVision
#endif