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,125 @@
/* 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/>.
*
* Prototypes of actor functions
*/
#include "common/textconsole.h"
#include "tinsel/noir/lzss.h"
namespace Tinsel {
static byte HIGH_BITS(byte byteValue, int numBits) {
unsigned int mask = ((1 << numBits) - 1) << (8 - numBits);
return (byteValue & mask) >> (8 - numBits);
}
static byte LOW_BITS(byte byteValue, int numBits) {
unsigned int mask = ((1 << numBits) - 1);
return byteValue & mask;
}
int decompressLZSS(Common::SeekableReadStream &input, byte *output) {
static const int kDictionarySize = 4096;
byte dictionary[kDictionarySize] = {};
int dictionaryOffset = 1;
int outputOffset = 0;
byte *data = new byte[input.size()];
input.read(data, input.size());
unsigned int offset = 0;
int bitShift = 0;
int bytesWritten = 0;
while (true) {
byte value = data[offset];
byte bitMask = 0x80 >> bitShift++;
// First bit:
// 0 -> Copy data from dictionary
// 1 -> Copy raw byte from input
bool useRawByte = value & bitMask;
if (bitShift == 8) {
bitShift = 0;
offset++;
}
if (!useRawByte) {
unsigned int bitsFromFirst = 8 - bitShift;
unsigned int bitsFromLast = 16 - 8 - bitsFromFirst;
// The dictionary lookup is 16 bit:
// 12 bits for the offset
// 4 bits for the run-length
// Combined with the first bit this makes for 17 bits,
// So we will be reading from three bytes, except when
// the first bit was read from the end of a byte, then
// bitShift will be 0, and bitsFromLast will be 8.
// We make the assumption that we can dereference the third byte
// even if we aren't using it. We will check "offset" after decompression
// to verify this assumption.
unsigned int byte1 = LOW_BITS(data[offset], bitsFromFirst);
unsigned int byte2 = data[offset + 1];
unsigned int byte3 = HIGH_BITS(data[offset + 2], bitsFromLast);
unsigned int lookup = (byte1 << (8 + bitsFromLast)) | (byte2 << bitsFromLast) | byte3;
int lookupOffset = (lookup >> 4) & 0xFFF;
if (lookupOffset == 0) {
break;
}
int lookupRunLength = (lookup & 0xF) + 2;
for (int j = 0; j < lookupRunLength; j++) {
output[outputOffset++] = dictionary[(lookupOffset + j) % kDictionarySize];
dictionary[dictionaryOffset++] = dictionary[(lookupOffset + j) % kDictionarySize];
dictionaryOffset %= kDictionarySize;
}
offset += 2;
bytesWritten += lookupRunLength;
} else {
// Raw byte, but since we spent a bit first,
// we must reassemble it from potentially two bytes.
unsigned int bitsFromFirst = 8 - bitShift;
unsigned int bitsFromLast = 8 - bitsFromFirst;
byte byteValue = LOW_BITS(data[offset], bitsFromFirst) << bitsFromLast;
byteValue |= HIGH_BITS(data[offset + 1], bitsFromLast);
offset++;
output[outputOffset++] = byteValue;
dictionary[dictionaryOffset++] = byteValue;
dictionaryOffset %= kDictionarySize;
bytesWritten++;
}
}
delete[] data;
if ((int32)offset > input.size()) {
error("Read too far during decompression");
}
return bytesWritten;
}
}

View File

@@ -0,0 +1,34 @@
/* 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/>.
*
* Prototypes of actor functions
*/
#ifndef TINSEL_NOIR_LZSS_H
#define TINSEL_NOIR_LZSS_H
#include "common/stream.h"
namespace Tinsel {
int decompressLZSS(Common::SeekableReadStream &input, byte *output);
}
#endif

View File

@@ -0,0 +1,322 @@
/* 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 "tinsel/noir/notebook.h"
#include "tinsel/background.h"
#include "tinsel/dialogs.h"
#include "tinsel/film.h"
#include "tinsel/handle.h"
#include "tinsel/multiobj.h"
#include "tinsel/noir/sysreel.h"
#include "tinsel/pdisplay.h"
#include "tinsel/polygons.h"
#include "tinsel/timers.h"
namespace Tinsel {
Notebook::Notebook() {
_polygons = instantiateNoteBookPolygons();
}
Notebook::~Notebook() {
delete _polygons;
}
void Notebook::addHyperlink(int32 id1, int32 id2) {
auto *invObject = _vm->_dialogs->getInvObjectT3(id1);
if (invObject->getTitle() != 0) {
error("A clue can only be hyperlinked if it only has one title!");
return;
}
invObject = _vm->_dialogs->getInvObjectT3(id2);
if (invObject->getTitle() != 0) {
error("A clue can only be hyperlinked if it only has one title!");
return;
}
uint32 i;
for (i = 0; i < MAX_HYPERS; ++i) {
int32 curr_id1 = _hyperlinks[i].id1;
if (curr_id1 == 0) {
_hyperlinks[i].id1 = id1;
_hyperlinks[i].id2 = id2;
return;
}
if ((curr_id1 == id1) || (id1 == _hyperlinks[i].id2)) {
if ((curr_id1 != id2) && (id2 != _hyperlinks[i].id2)) {
error("A clue/title can only be hyperlinked to one other clue/title!");
}
return;
}
}
// No free hyperlink entry was found
error("Too many hyperlinks");
}
void Notebook::clearNotebookPage() {
if (_prevPage != -1) {
_pages[_prevPage].clear();
}
_prevPage = -1;
_pages[_currentPage].clear();
}
void Notebook::refresh() {
auto reel = (_currentPage == 0 ? SysReel::NOTEPAD_CLOSED : SysReel::NOTEPAD_OPEN);
auto film = GetSystemReelFilm(reel);
InitStepAnimScript(&_anim, _object, film->reels->script, ONE_SECOND / film->frate);
clearNotebookPage();
if (_currentPage != 0) {
_pages[_currentPage].fillIn();
}
}
int Notebook::addTitle(const InventoryObjectT3 &invObject) {
int id = invObject.getId();
assert(invObject.isNotebookTitle());
for (uint32 i = 0; i < _numPages; i++) {
if (_pages[i].getTitle() == id) {
return i;
}
}
int linkedFromPage = invObject.getUnknown();
// 0 page is the closed notebook, has no entries.
if (linkedFromPage != 0) {
// Allocate a line on the linked from page.
assert(_pages[linkedFromPage].getTitle() != 0);
_pages[linkedFromPage].addLine(id);
}
int pageIndex = _numPages++;
_pages[pageIndex].setTitle(id);
return pageIndex;
}
void Notebook::addClue(const InventoryObjectT3 &invObject) {
if (invObject.getUnknown() == 0) {
// This affects two clues, that should get special treatment.
warning("TODO: Handle clues with no parent page");
return;
}
// Add title if missing, otherwise just get the page it's on.
auto titleObject = _vm->_dialogs->getInvObjectT3(invObject.getUnknown());
int pageIndex = addTitle(*titleObject);
_pages[pageIndex].addLine(invObject.getId());
if (invObject.getTitle() != 0) {
auto secondTitleObject = _vm->_dialogs->getInvObjectT3(invObject.getTitle());
pageIndex = addTitle(*secondTitleObject);
_pages[pageIndex].addLine(invObject.getId());
}
}
void Notebook::addClue(int id) {
auto invObject = _vm->_dialogs->getInvObjectT3(id);
if (invObject->isNotebookTitle()) {
addTitle(*invObject);
} else {
addClue(*invObject);
}
}
int Notebook::getPageWithTitle(int id) {
for (uint32 i = 0; i < _numPages; i++) {
if (_pages[i].getTitle() == id) {
return i;
}
}
return -1;
}
void Notebook::crossClue(int id) {
auto invObject = _vm->_dialogs->getInvObjectT3(id);
if (invObject->isNotebookTitle()) {
return;
}
int titles[2] = {
invObject->getUnknown(),
invObject->getTitle()
};
for (int i = 0; i < 2; i++) {
if (titles[i] == 0) {
continue;
}
int page = getPageWithTitle(titles[i]);
if (page != -1) {
_pages[page].crossClue(id);
}
}
}
void InitNotebookAnim(OBJECT **obj, ANIM &anim, SysReel reel, int zPosition) {
auto film = GetSystemReelFilm(reel);
MultiDeleteObjectIfExists(FIELD_STATUS, obj);
*obj = InsertReelObj(film->reels);
MultiSetZPosition(*obj, zPosition);
InitStepAnimScript(&anim, *obj, film->reels->script, ONE_SECOND / film->frate);
}
void Notebook::setNextPage(int pageIndex) {
assert(_prevPage == -1 || _prevPage == (int32)_currentPage); // Check that we've cleaned any outstanding page.
_prevPage = _currentPage;
_currentPage = pageIndex;
}
void Notebook::pageFlip(bool up) {
int nextPage = _currentPage + (up ? -1 : 1);
if (nextPage <= 0) {
setNextPage(0);
refresh();
return;
} else if (nextPage == 1) {
// TODO: Should possibly just call whatever function we use to open.
InitNotebookAnim(&_object, _anim, SysReel::NOTEPAD_OPENING, Z_INV_RFRAME);
_state = BOOKSTATE::OPEN_ANIMATING;
setNextPage(nextPage);
return;
}
setNextPage(nextPage);
SysReel reel = (up ? SysReel::NOTEPAD_FLIPUP : SysReel::NOTEPAD_FLIPDOWN);
InitNotebookAnim(&_pageObject, _pageAnim, reel, 19);
_state = BOOKSTATE::PAGEFLIP;
}
void Notebook::show(bool isOpen) {
auto reel = (isOpen ? SysReel::NOTEPAD_OPEN : SysReel::NOTEPAD_OPENING);
InitNotebookAnim(&_object, _anim, reel, Z_INV_MFRAME);
_state = (isOpen ? BOOKSTATE::OPENED : BOOKSTATE::OPEN_ANIMATING);
setNextPage(1);
refresh();
DisableTags(); // Tags disabled in Notebook
DisablePointing(); // Pointing disabled in Notebook
}
bool Notebook::isOpen() const {
return _state != BOOKSTATE::CLOSED;
}
void Notebook::close() {
clearNotebookPage();
MultiDeleteObjectIfExists(FIELD_STATUS, &_object);
MultiDeleteObjectIfExists(FIELD_STATUS, &_pageObject);
_state = BOOKSTATE::CLOSED;
if (_vm->_dialogs->inventoryOrNotebookActive()) {
EnablePointing();
EnableTags();
}
}
void Notebook::stepAnimScripts() {
if (_state == BOOKSTATE::OPEN_ANIMATING) {
auto state = StepAnimScript(&_anim);
if (state == ScriptFinished) {
_state = BOOKSTATE::OPENED;
refresh();
}
}
if (_state == BOOKSTATE::PAGEFLIP) {
auto state = StepAnimScript(&_pageAnim);
if (state == ScriptFinished) {
MultiDeleteObjectIfExists(FIELD_STATUS, &_pageObject);
_state = BOOKSTATE::OPENED;
refresh();
}
}
}
int32 Notebook::GetPointedClue(const Common::Point &point) const {
if (_currentPage == 0 || _currentPage > _numPages) {
return 0;
}
return _pages[_currentPage].getClueForLine(_polygons->lineHit(point));
}
bool Notebook::handlePointer(const Common::Point &point) {
if (!isOpen()) {
return 0;
}
auto inside = _polygons->isInsideNotebook(point);
if (inside) {
auto hit = _polygons->lineHit(point);
_pages[_currentPage].handlePointAtLine(hit);
return true; // We handled the pointer
}
return false;
}
bool Notebook::handleEvent(PLR_EVENT pEvent, const Common::Point &coOrds) {
if (!isOpen()) { // TODO: Clicking outside should close the notebook
return false;
}
auto inside = _polygons->isInsideNotebook(coOrds);
switch(pEvent) {
case PLR_ACTION:
if (inside) {
return true;
}
return false;
case PLR_LOOK:
if (inside) {
return true;
}
return false;
case PLR_WALKTO: {
// Handle clue-clicks
auto poly = _polygons->mostSpecificHit(coOrds);
switch (poly) {
case NoteBookPoly::NEXT:
handleEvent(PLR_PGUP, coOrds);
return true;
case NoteBookPoly::PREV:
handleEvent(PLR_PGDN, coOrds);
return true;
case NoteBookPoly::NONE:
handleEvent(PLR_ESCAPE, coOrds);
return true;
default:
return true;
}
}
case PLR_ESCAPE:
close();
return true;
case PLR_PGUP:
pageFlip(true);
return true;
case PLR_PGDN:
pageFlip(false);
return true;
case PLR_HOME:
case PLR_END:
default:
return false;
}
return false;
}
} // End of namespace Tinsel

View File

@@ -0,0 +1,118 @@
/* 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 TINSEL_NOTEBOOK_H // prevent multiple includes
#define TINSEL_NOTEBOOK_H
#include "common/scummsys.h"
#include "notebook_page.h"
#include "tinsel/anim.h"
#include "tinsel/events.h"
#include "tinsel/object.h"
namespace Tinsel {
// links two clue/title objects together
struct HYPERLINK {
int32 id1 = 0;
int32 id2 = 0;
};
// 6 bytes large
struct ENTRY {
int32 id;
bool active;
int32 page1;
int32 indexOnPage1;
int32 page2;
int32 indexOnPage2;
};
enum class BOOKSTATE {
CLOSED = 0,
OPEN_UNKNOWN = 1,
OPEN_ANIMATING = 2,
OPENED = 3,
PAGEFLIP = 4
};
class NoteBookPolygons;
class InventoryObjectT3;
class Notebook {
public:
Notebook();
~Notebook();
// Adds a connection between a clue/title
void addHyperlink(int32 id1, int32 id2);
void addClue(int id);
void crossClue(int id);
// Called within InventoryProcess loop
void redraw();
// Called from OPENNOTEBOOK
void show(bool isOpen);
bool isOpen() const;
void close();
bool handlePointer(const Common::Point &point);
bool handleEvent(PLR_EVENT pEvent, const Common::Point &coOrds);
void stepAnimScripts();
void refresh();
NoteBookPolygons *_polygons = nullptr;
private:
int addTitle(const InventoryObjectT3 &invObject);
void addClue(const InventoryObjectT3 &invObject);
int getPageWithTitle(int id);
void pageFlip(bool up);
int32 GetPointedClue(const Common::Point &point) const;
void clearNotebookPage();
void setNextPage(int pageIndex);
const static uint32 MAX_PAGES = 0x15;
const static uint32 MAX_HYPERS = 0xf;
HYPERLINK _hyperlinks[MAX_HYPERS];
uint32 _numPages = 1;
int32 _prevPage = -1;
uint32 _currentPage = 1;
NotebookPage _pages[MAX_PAGES] = {};
ANIM _anim = {};
OBJECT *_object = nullptr;
ANIM _pageAnim = {};
OBJECT *_pageObject = nullptr;
BOOKSTATE _state = BOOKSTATE::CLOSED;
};
} // End of namespace Tinsel
#endif

View File

@@ -0,0 +1,162 @@
/* 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 "tinsel/noir/notebook_page.h"
#include "tinsel/dialogs.h"
#include "tinsel/dw.h"
#include "tinsel/film.h"
#include "tinsel/handle.h"
#include "tinsel/multiobj.h"
#include "tinsel/polygons.h"
#include "tinsel/timers.h"
#include "tinsel/tinsel.h"
#include "tinsel/noir/sysreel.h"
namespace Tinsel {
void NotebookLine::clear() {
MultiDeleteObjectIfExists(FIELD_STATUS, &_obj);
}
bool HasReelFrame(SCNHANDLE pReel) {
if (pReel) {
const FREEL* reel = (const FREEL*)_vm->_handle->LockMem(pReel);
if (reel && reel->mobj) {
const MULTI_INIT* pmi = reel->GetMultiInit();
if (pmi) {
return pmi->GetFrame() != nullptr;
}
}
}
return false;
}
int FindReelIndexForEntry(const FILM *pFilm, int pageLine) {
if (HasReelFrame(pFilm->reels[pageLine].mobj)) {
return pageLine;
}
for (int i = pageLine; i < pFilm->numreels; i++) {
if (HasReelFrame(pFilm->reels[i].mobj)) {
return i;
}
}
for (int i = pageLine; i >= 0; i--) {
if (HasReelFrame(pFilm->reels[i].mobj)) {
return i;
}
}
return -1;
}
void NotebookLine::fillIn(int pageLine) {
const FILM *pFilm = _vm->_dialogs->getObjectFilm(_id);
if (!pFilm)
return;
int reelIndex = FindReelIndexForEntry(pFilm, pageLine);
assert(reelIndex >= 0);
const FREEL *reel = &pFilm->reels[reelIndex];
MultiDeleteObjectIfExists(FIELD_STATUS, &_obj);
_obj = InsertReelObj(reel);
MultiSetZPosition(_obj, 17);
InitStepAnimScript(&_anim, _obj, pFilm->reels[reelIndex].script, ONE_SECOND / pFilm->frate);
if (_crossedOut) {
auto scribbleFilm = GetSystemReelFilm(SysReel::SCRIBBLES);
_scribbles = InsertReelObj(&scribbleFilm->reels[reelIndex]);
MultiSetZPosition(_scribbles, 18);
InitStepAnimScript(&_scribbleAnim, _scribbles, scribbleFilm->reels[reelIndex].script, ONE_SECOND / pFilm->frate);
}
}
void NotebookLine::crossOut() {
_crossedOut = true;
}
void NotebookPage::handlePointAtLine(int line) {
auto objId = getClueForLine(line);
if (objId != 0 && objId != _pointedClue) {
auto obj = _vm->_dialogs->getInvObject(objId);
_vm->_dialogs->invPointEvent(obj, -1);
_pointedClue = objId;
}
}
int NotebookPage::indexOfClue(int id) const {
for (uint32 i = 0; i < _numLines; i++) {
if (_lines[i]._id == id) {
return i;
}
}
return -1;
}
bool NotebookPage::containsClue(int id) {
return indexOfClue(id) != -1;
}
void NotebookPage::crossClue(int id) {
int index = indexOfClue(id);
assert(index != -1);
_lines[index].crossOut();
}
void NotebookPage::addLine(int id) {
if (containsClue(id)) {
return;
}
assert(_numLines < MAX_ENTRIES_PER_PAGE);
_lines[_numLines++]._id = id;
}
void NotebookPage::setTitle(int id) {
_lines[0]._id = id;
if (_numLines == 0) {
_numLines++;
}
}
int32 NotebookPage::getTitle() const {
return _lines[0]._id;
}
void NotebookPage::fillIn() {
for (uint32 i = 0; i < _numLines; i++) {
_lines[i].fillIn(i);
}
}
void NotebookPage::clear() {
for (uint32 i = 0; i < _numLines; i++) {
_lines[i].clear();
}
_pointedClue = -1;
}
int NotebookPage::getClueForLine(int line) const {
if (line >= (int)_numLines) {
return 0;
}
return _lines[line]._id;
}
} // End of namespace Tinsel

View File

@@ -0,0 +1,69 @@
/* 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 TINSEL_NOTEBOOK_PAGE_H // prevent multiple includes
#define TINSEL_NOTEBOOK_PAGE_H
#include "common/scummsys.h"
#include "tinsel/anim.h"
#include "tinsel/tinsel.h"
#include "tinsel/object.h"
namespace Tinsel {
class NotebookLine {
public:
int _id = 0;
void crossOut();
void clear();
void fillIn(int pageLine);
private:
bool _crossedOut = false;
ANIM _anim = {};
OBJECT *_obj = nullptr;
OBJECT *_scribbles = nullptr;
ANIM _scribbleAnim = {};
};
class NotebookPage {
public:
bool containsClue(int id);
void crossClue(int id);
void addLine(int id);
void setTitle(int id);
int32 getTitle() const;
void fillIn();
void clear();
int getPointedClue(const Common::Point &point) const;
int getClueForLine(int line) const;
void handlePointAtLine(int line);
private:
int indexOfClue(int id) const;
int _pointedClue = -1;
const static uint32 MAX_ENTRIES_PER_PAGE = 8;
NotebookLine _lines[MAX_ENTRIES_PER_PAGE] = {};
uint32 _numLines = 0;
};
} // End of namespace Tinsel
#endif // SCUMMVM_NOTEBOOK_PAGE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
/* 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.
*
* Spriter - 3D Renderer
*/
#ifndef TINSEL_SPRITER_H
#define TINSEL_SPRITER_H
#include "tinsel/dw.h"
#include "common/rect.h"
#include "common/stack.h"
#include "common/str.h"
#include "math/vector3d.h"
#include "math/vector2d.h"
#include "math/matrix4.h"
#if defined(USE_TINYGL)
#include "graphics/tinygl/tinygl.h"
#endif
namespace Tinsel {
typedef Common::FixedStack<Math::Matrix4, 30> MatrixStack;
enum RenderProgramOp : uint16 {
MATRIX_DUPLICATE = 1,
MATRIX_REMOVE = 2,
UNUSED = 3,
TRANSFORM = 4,
TRANSLATE_X = 5,
TRANSLATE_Y = 6,
TRANSLATE_Z = 7,
TRANSLATE_XYZ = 8,
ROTATE_X = 9,
ROTATE_Y = 10,
ROTATE_Z = 11,
ROTATE_XYZ = 17,
STOP = 16,
};
struct AnimationInfo {
Common::String name;
uint meshNum;
uint translateTablesHunk;
uint translateTables;
uint translateNum;
uint rotateTablesHunk;
uint rotateTables;
uint rotateNum;
uint scaleTablesHunk;
uint scaleTables;
uint scaleNum;
uint maxFrame;
};
struct MeshInfo {
uint meshTablesHunk;
uint meshTables;
uint programHunk;
uint program;
};
struct Hunk {
Common::Array<uint8> data;
Common::Array<uint> mappingIdx;
uint size;
uint flags;
};
typedef Common::Array<Hunk> Hunks;
typedef Common::Array<Math::Vector3d> Vectors;
struct Primitive {
uint indices[8];
uint color;
Math::Vector2d uv[4];
uint texture;
};
enum MeshPartType {
MESH_PART_TYPE_COLOR,
MESH_PART_TYPE_SOLID,
MESH_PART_TYPE_TEXTURE,
};
struct MeshPart {
MeshPartType type;
uint cull;
uint numVertices;
Common::Array<Primitive> primitives;
};
struct Mesh {
Common::Array<Math::Vector3d> vertices;
Common::Array<Math::Vector3d> normals;
Common::Array<MeshPart> parts;
Common::Array<MeshPart> parts2;
};
struct Meshes {
uint vertexCount;
uint normalCount;
Common::Array<Mesh> meshes;
};
typedef Common::Array<Vectors> AnimationData;
struct ModelTables {
Vectors translations;
Vectors rotations;
Vectors scales;
Meshes meshes;
};
enum ModelFlags {
MODEL_HAS_TRANSLATION_TABLE = 1,
MODEL_HAS_SCALE_TABLE = 2,
MODEL_HAS_ROTATION_TABLE = 4
};
struct Model {
Hunks hunks;
Hunks hunksOverlay; // The game script can load additional data to supplement the main model. E.g. a special animation.
uint animationCount;
uint field_0xe;
uint field_0xf;
uint8* program;
// animation tables
AnimationData startTranslateTables;
AnimationData startRotateTables;
AnimationData startScaleTables;
AnimationData endTranslateTables;
AnimationData endRotateTables;
AnimationData endScaleTables;
int startFrame;
int endFrame;
uint flags;
uint field_0x32;
uint field_0x33;
ModelTables tables;
Math::Vector3d position;
Math::Vector3d rotation;
Math::Vector3d scale;
uint time; // interpolant
};
struct Viewport {
int ap;
float width;
float height;
Common::Rect rect;
};
struct View {
int centerX;
int centerY;
Common::Rect viewRect;
Common::Rect screenRect;
Viewport viewport;
Math::Vector3d position;
Math::Vector3d rotation;
};
class Spriter {
private:
MatrixStack _modelMatrix;
MatrixStack* _currentMatrix;
Common::Array<AnimationInfo> _animMain;
AnimationInfo _animShadow;
MeshInfo _meshMain;
Common::Array<MeshInfo> _meshShadow;
View _view;
Common::Array<uint8> _palette;
Common::Array<uint8> _textureData;
bool _textureGenerated;
#if defined(USE_TINYGL)
uint _texture[4];
#endif
bool _modelIdle;
uint _animId;
uint _animSpeed;
uint _animDelay;
uint _animDelayMax;
uint _sequencesCount;
uint _direction;
public:
Model _modelMain;
Model _modelShadow;
public:
Spriter();
virtual ~Spriter();
void Init(int width, int height);
void SetCamera(int rotX, int rotY, int rotZ, int posX, int posY, int posZ, int cameraAp);
void TransformSceneXYZ(int x, int y, int z, int& xOut, int& yOut);
void Load(const Common::String& modelName, const Common::String& textureName);
void SetPalette(SCNHANDLE hPalette);
void SetSequence(uint animId, uint delay);
Common::Rect Draw(int direction, int x, int y, int z, int tDelta);
private:
const Math::Matrix4& MatrixCurrent() const;
void MatrixReset();
void MatrixPop();
void MatrixPush();
void MatrixTranslate(float x, float y, float z);
void MatrixScale(float x, float y, float z);
void MatrixRotateX(float angle);
void MatrixRotateY(float angle);
void MatrixRotateZ(float angle);
void SetViewport(int ap);
// Loading of the model
void LoadH(const Common::String& modelName);
void LoadGBL(const Common::String& modelName);
void LoadRBH(const Common::String& modelName, Hunks& hunks);
void LoadVMC(const Common::String& textureName);
void UpdateTextures();
Meshes LoadMeshes(const Hunks &hunks, uint hunk, uint offset, int frame);
template<bool convert>
AnimationData LoadAnimationData(const Hunks &hunks, uint hunk, uint offset);
void InitModel(Model& model, MeshInfo& meshInfo, Common::Array<AnimationInfo>& animInfo, uint flags);
// Processing of the model
void RunRenderProgram(Model &model, bool preprocess);
void FindSimilarVertices(Mesh& mesh, Vectors& vertices, Common::Array<uint16>& sameVertices) const;
void MergeVertices(Mesh& mesh, Common::Array<uint16>& sameVertices);
void TransformMesh(Mesh& mesh, Vectors& vertices);
void CalculateNormals(Mesh& mesh, Vectors& vertices, Vectors &normals);
// Rendering
void RenderModel(Model& model);
void RenderMesh(Mesh& mesh, Vectors& vertices, Vectors &normals);
void RenderMeshPartColor(MeshPart& part, Vectors& vertices, Vectors &normals);
void RenderMeshPartTexture(MeshPart& part, Vectors& vertices, Vectors &normals);
// Animation
bool SetStartFrame(Model &model, const AnimationInfo &anim, int frame);
bool SetEndFrame(Model &model, const AnimationInfo &anim, int frame);
};
} // End of namespace Tinsel
#endif // TINSEL_SPRITER_H

View File

@@ -0,0 +1,67 @@
/* 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 "tinsel/noir/sysreel.h"
#include "common/scummsys.h"
#include "tinsel/cursor.h"
#include "tinsel/pid.h"
#include "tinsel/tinsel.h"
namespace Tinsel {
/**
* Returns the handle to the sysreel at the given index.
*
* @param index reel to get the handle to
*/
SCNHANDLE SystemReel::get(SysReel index) {
assert((int)index >= 0 && (int)index < MAX_SYSREELS);
return _reels[(int)index];
}
/**
* Stores a reel at an index and if the index is a cursor
*
* @param index where to store the reel
* @param reel handle to the reel
*/
void SystemReel::set(int32 index, SCNHANDLE reel) {
assert(index >= 0 && index < MAX_SYSREELS);
if (index == (int)SysReel::LOADSCREEN) {
if (CoroScheduler.getCurrentPID() != PID_SCENE) {
return;
}
}
_reels[index] = reel;
// Noir actually calls a function specifically for doing DwInitCursor on
// system reel 11.
if (index == (int)SysReel::CURSOR && reel != 0) {
_vm->_cursor->DwInitCursor(reel);
}
}
} // End of namespace Tinsel

View File

@@ -0,0 +1,66 @@
/* 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 TINSEL_SYSREEL_H // prevent multiple includes
#define TINSEL_SYSREEL_H
#include "tinsel/dw.h"
namespace Tinsel {
enum class SysReel {
NOTEPAD_OPENING = 4,
NOTEPAD_OPEN = 5,
NOTEPAD_CLOSED = 6,
NOTEPAD_FLIPDOWN = 7,
NOTEPAD_FLIPUP = 8,
SCRIBBLES = 9,
CURSOR = 11,
INVMAIN = 15,
SLIDER = 16,
CONVERSATION_FRAME = 19,
OPTIONS_MENU = 21,
LOADSAVE_MENU = 22,
QUIT_MENU = 23,
SUBTITLES_MENU = 24,
SLIDER_BG = 25,
SLIDER_HI = 26,
LEFT = 29,
RIGHT = 30,
LOADSCREEN = 31
};
class SystemReel {
public:
SystemReel() = default;
SCNHANDLE get(SysReel index);
void set(int32 index, SCNHANDLE reel);
private:
const static int32 MAX_SYSREELS = 0x28;
SCNHANDLE _reels[MAX_SYSREELS];
};
} // End of namespace Tinsel
#endif