MACVENTURE: Implemente dynamic object drawing

This commit is contained in:
Borja Lorente 2016-06-22 00:47:53 +02:00
parent 4d8f8fd36b
commit 0743e9531b
8 changed files with 199 additions and 81 deletions

View File

@ -86,6 +86,16 @@ Gui::Gui(MacVentureEngine *engine, Common::MacResManager *resman) {
Gui::~Gui() {
if (_windowData)
delete _windowData;
if (_controlData)
delete _controlData;
Common::HashMap<ObjID, ImageAsset*>::const_iterator it = _assets.begin();
for (; it != _assets.end(); it++) {
delete it->_value;
}
}
void Gui::draw() {
@ -104,6 +114,10 @@ void Gui::drawTitle() {
warning("drawTitle hasn't been tested yet");
}
void Gui::drawExit(ObjID id) {
warning("Unimplemented method: drawExit");
}
bool Gui::processEvent(Common::Event &event) {
bool processed = false;
if (event.type == Common::EVENT_LBUTTONDOWN) {
@ -164,7 +178,7 @@ void Gui::updateWindowInfo(WindowReference ref, ObjID objID, const Common::Array
originx = originx > childPos.x ? childPos.x : originx;
originy = originy > childPos.y ? childPos.y : originy;
}
data.children.push_back(child);
data.children.push_back(DrawableObject(child, kBlitDirect));
}
}
if (originx != 0x7fff) data.bounds.left = originx;
@ -172,6 +186,20 @@ void Gui::updateWindowInfo(WindowReference ref, ObjID objID, const Common::Array
if (ref != kMainGameWindow) data.updateScroll = true;
}
void Gui::addChild(WindowReference target, ObjID child) {
findWindowData(target).children.push_back(DrawableObject(child, kBlitDirect));
}
void Gui::removeChild(WindowReference target, ObjID child) {
WindowData data = findWindowData(target);
uint index = 0;
for (;index < data.children.size(); index++) {
if (data.children[index].obj == child) break;
}
data.children.remove_at(index);
}
void Gui::initGUI() {
_screen.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8());
_wm.setScreen(&_screen);
@ -230,6 +258,7 @@ void Gui::initWindows() {
_selfWindow->setCallback(selfWindowCallback, this);
loadBorder(_selfWindow, "border_self_inac.bmp", false);
loadBorder(_selfWindow, "border_self_act.bmp", true);
findWindowData(kSelfWindow).children.push_back(DrawableObject(1, kBlitDirect));
// Exits Window
_exitsWindow = _wm.addWindow(false, true, true);
@ -443,7 +472,6 @@ void Gui::drawWindows() {
drawCommandsWindow();
drawMainGameWindow();
drawSelfWindow();
}
void Gui::drawCommandsWindow() {
@ -460,8 +488,7 @@ void Gui::drawCommandsWindow() {
data.bounds.right - data.bounds.left,
kColorBlack,
Graphics::kTextAlignCenter);
}
else {
} else {
Common::List<CommandButton>::const_iterator it = _controlData->begin();
for (; it != _controlData->end(); ++it) {
CommandButton button = *it;
@ -474,32 +501,15 @@ void Gui::drawCommandsWindow() {
void Gui::drawMainGameWindow() {
Graphics::ManagedSurface *srf = _mainGameWindow->getSurface();
BorderBounds border = borderBounds(getWindowData(kMainGameWindow).type);
srf->fillRect(
Common::Rect(
border.leftOffset * 2,
border.topOffset * 2,
srf->w - (border.rightOffset * 3),
srf->h - (border.bottomOffset * 3)),
kColorBlack);
WindowData &data = findWindowData(kMainGameWindow);
for (Common::Array<ObjID>::const_iterator it = data.children.begin(); it != data.children.end(); it++) {
Common::Point pos = _engine->getObjPosition(*it);
srf->fillRect(
Common::Rect(
border.leftOffset * 2 + pos.x,
border.topOffset * 2 + pos.y,
5,
5),
kColorBlack);
}
ImageAsset bg(3, _graphics);
bg.blitInto(
_mainGameWindow->getSurface(),
border.leftOffset * 2,
border.topOffset * 2,
kBlitDirect);
// Tests
ImageAsset testBg(3, _graphics);
testBg.blitInto(srf, border.leftOffset * 2, border.topOffset * 2, kBlitDirect);
//ImageAsset testImg(428, _graphics);
//testImg.blitInto(srf, border.leftOffset * 2 + 10,border.topOffset * 2 + 10, kBlitBIC);
drawObjectsInWindow(kMainGameWindow, _mainGameWindow->getSurface());
}
@ -515,6 +525,27 @@ void Gui::drawSelfWindow() {
kColorWhite);
}
void Gui::drawObjectsInWindow(WindowReference target, Graphics::ManagedSurface * surface) {
WindowData &data = findWindowData(kMainGameWindow);
BorderBounds border = borderBounds(data.type);
Common::Point pos;
ObjID child;
BlitMode mode;
for (Common::Array<DrawableObject>::const_iterator it = data.children.begin(); it != data.children.end(); it++) {
child = (*it).obj;
mode = (BlitMode)(*it).mode;
pos = _engine->getObjPosition(child);
if (!_assets.contains(child)) {
_assets[child] = new ImageAsset(child, _graphics);
}
_assets[child]->blitInto(
surface,
border.leftOffset * 2 + pos.x,
border.topOffset * 2 + pos.y,
mode);
}
}
WindowData & Gui::findWindowData(WindowReference reference) {
assert(_windowData);
@ -631,7 +662,7 @@ void Gui::handleMenuAction(MenuAction action) {
}
void Gui::updateWindow(WindowReference winID, bool containerOpen) {
if (winID > 0x90) return;
if (winID > 0x90 || winID == kNoWindow) return;
if (winID == kSelfWindow || containerOpen) {
if (winID == kMainGameWindow) {
drawMainGameWindow();
@ -639,9 +670,21 @@ void Gui::updateWindow(WindowReference winID, bool containerOpen) {
warning("Unimplemented: fill window with background");
}
WindowData &data = findWindowData(winID);
Common::Array<ObjID> children = data.children;
for (Common::Array<ObjID>::const_iterator it = children.begin(); it != children.end(); it++) {
warning("Unimplemented: draw object %x", *it);
Common::Array<DrawableObject> &children = data.children;
for (uint i = 0; i < children.size(); i++) {
uint flag = 0;
ObjID child = children[i].obj;
BlitMode mode;
bool off = _engine->isObjVisible(child);
if (!off || _engine->isObjClickable(child)) {
mode = kBlitBIC;
if (_engine->isObjSelected(child)) {
mode = kBlitOR;
} else if (off || flag) {
mode = kBlitXOR;
}
children[i] = DrawableObject(child, mode);
}
}
if (data.type == kZoomDoc && data.updateScroll) {
warning("Unimplemented: update scroll");
@ -682,7 +725,6 @@ WindowReference Gui::createInventoryWindow() {
bool Gui::tryCloseWindow(WindowReference winID) {
WindowData data = findWindowData(winID);
Graphics::MacWindow *wind;
if (winID < 0x80) { // Inventory window
warning("Window closing not implemented");
} else {

View File

@ -39,7 +39,9 @@ using namespace Graphics::MacWindowConstants;
class MacVentureEngine;
typedef uint32 ObjID;
//namespace MacVentureMenuActions {
class CommandButton;
class ImageAsset;
enum MenuAction {
kMenuActionAbout,
kMenuActionNew,
@ -60,6 +62,7 @@ enum MenuAction {
//} using namespace MacVentureMenuActions;
enum WindowReference {
kNoWindow = 0,
kCommandsWindow = 0x80,
kMainGameWindow = 0x81,
kOutConsoleWindow = 0x82,
@ -83,6 +86,16 @@ enum MVWindowType {
kRDoc10 = 0x16
};
struct DrawableObject {
ObjID obj;
byte mode;
DrawableObject(ObjID id, byte md) {
obj = id;
mode = md;
}
};
struct WindowData {
Common::Rect bounds;
MVWindowType type;
@ -91,7 +104,7 @@ struct WindowData {
WindowReference refcon;
uint8 titleLength;
Common::String title;
Common::Array<ObjID> children;
Common::Array<DrawableObject> children;
bool updateScroll;
};
@ -139,6 +152,7 @@ public:
void draw();
void drawMenu();
void drawTitle();
void drawExit(ObjID id);
bool processEvent(Common::Event &event);
void handleMenuAction(MenuAction action);
void updateWindow(WindowReference winID, bool containerOpen);
@ -164,6 +178,9 @@ public:
void setWindowTitle(WindowReference winID, Common::String string);
void updateWindowInfo(WindowReference ref, ObjID objID, const Common::Array<ObjID> &children);
void addChild(WindowReference target, ObjID child);
void removeChild(WindowReference target, ObjID child);
// Ugly switches
BorderBounds borderBounds(MVWindowType type);
@ -188,10 +205,10 @@ private: // Attributes
Graphics::Menu *_menu;
Container *_graphics;
Common::HashMap<ObjID, ImageAsset*> _assets;
private: // Methods
// Initializers
void initGUI();
void initWindows();
@ -209,6 +226,8 @@ private: // Methods
void drawMainGameWindow();
void drawSelfWindow();
void drawObjectsInWindow(WindowReference target, Graphics::ManagedSurface *surface);
// Finders
WindowData& findWindowData(WindowReference reference);

View File

@ -318,9 +318,9 @@ byte ImageAsset::walkHuff(const PPICHuff & huff, Common::BitStream & stream) {
}
void ImageAsset::blitInto(Graphics::ManagedSurface *target, uint32 x, uint32 y, BlitMode mode) {
debug("Blitting image %x ", _id);
if (mode == kBlitDirect) {
blitDirect(target, x, y, _imgData);
return;
}
if (_container->getItemByteSize(_mask)) { // Has mask
@ -344,7 +344,7 @@ void ImageAsset::blitInto(Graphics::ManagedSurface *target, uint32 x, uint32 y,
}
}
if (_container->getItemByteSize(_id) && mode > 0) {
blitXOR(target, x, y, _maskData);
blitXOR(target, x, y, _imgData);
}
}

View File

@ -31,6 +31,14 @@ namespace MacVenture {
typedef uint32 ObjID;
class Container;
enum BlitMode {
kBlitDirect = 0,
kBlitBIC = 1,
kBlitOR = 2,
kBlitXOR = 3
};
enum GraphicsEncoding {
kPPIC0 = 0,
kPPIC1 = 1,
@ -44,13 +52,6 @@ struct PPICHuff {
uint8 symbols[17];
};
enum BlitMode {
kBlitDirect = 0,
kBlitBIC = 1,
kBlitOR = 2,
kBlitXOR = 3
};
class ImageAsset {
public:
ImageAsset(ObjID original, Container *container);

View File

@ -115,13 +115,15 @@ Common::Error MacVentureEngine::run() {
if (_prepared) {
_prepared = false;
if (!_halted)
updateState();
if (_cmdReady || _halted) {
_halted = false;
if (runScriptEngine()) {
_halted = true;
_paused = true;
}
else {
} else {
_paused = false;
if (!updateState()) {
updateControls();
@ -131,10 +133,9 @@ Common::Error MacVentureEngine::run() {
if (_gameState == kGameStateWinnig || _gameState == kGameStateLosing) {
endGame();
}
_gui->draw();
}
}
_gui->draw();
g_system->updateScreen();
g_system->delayMillis(50);
@ -210,7 +211,7 @@ void MacVentureEngine::enqueueObject(ObjectQueueID type, ObjID objID) {
obj.exitx = _world->getObjAttr(objID, kAttrExitX);
obj.exity = _world->getObjAttr(objID, kAttrExitY);
obj.hidden = _world->getObjAttr(objID, kAttrHiddenExit);
obj.offsecreen = _world->getObjAttr(objID, kAttrInvisible);
obj.offscreen = _world->getObjAttr(objID, kAttrInvisible);
obj.invisible = _world->getObjAttr(objID, kAttrUnclickable);
_objQueue.push_back(obj);
}
@ -224,7 +225,7 @@ void MacVentureEngine::enqueueText(TextQueueID type, ObjID target, ObjID source,
_textQueue.push_back(newText);
}
void MacVentureEngine::printTexts() {
bool MacVentureEngine::printTexts() {
warning("printTexts: unimplemented");
for (uint i = 0; i < _textQueue.size(); i++) {
QueuedText text = _textQueue.front();
@ -232,12 +233,15 @@ void MacVentureEngine::printTexts() {
switch (text.id) {
case kTextNumber:
debug("Print Number: %d", text.asset);
gameChanged();
break;
case kTextNewLine:
debug("Print Newline: ");
gameChanged();
break;
case kTextPlain:
debug("Print Plain Text: %s", _world->getText(text.asset).c_str());
gameChanged();
break;
}
}
@ -326,7 +330,8 @@ void MacVentureEngine::endGame() {
bool MacVentureEngine::updateState() {
runObjQueue();
return true;
bool wait = printTexts();
return wait;
}
void MacVentureEngine::revert() {
@ -359,7 +364,7 @@ void MacVentureEngine::runObjQueue() {
closeObject(obj.object);
break;
case 0x7:
checkObject(obj.object);
checkObject(obj);
break;
case 0x8:
reflectSwap(obj.object);
@ -428,40 +433,68 @@ void MacVentureEngine::closeObject(ObjID objID) {
return;
}
void MacVentureEngine::checkObject(ObjID objID) {
void MacVentureEngine::checkObject(QueuedObject old) {
//warning("checkObject: unimplemented");
bool hasChanged = false;
debug("Check Object[%d] parent[%d] x[%d] y[%d]",
objID,
_world->getObjAttr(objID, kAttrParentObject),
_world->getObjAttr(objID, kAttrPosX),
_world->getObjAttr(objID, kAttrPosY));
old.object,
_world->getObjAttr(old.object, kAttrParentObject),
_world->getObjAttr(old.object, kAttrPosX),
_world->getObjAttr(old.object, kAttrPosY));
//bool incoming = isIncomingObj(objID);
//if (incoming) removeIncoming(objID);
if (objID == 1) {
if (_world->getObjAttr(objID, kAttrParentObject) != 0) {
enqueueObject(kSetToPlayerParent, objID);
}
}
_gui->updateWindow(findParentWindow(objID), true);
ObjID id = old.object;
if (id == 1) {
if (old.parent != _world->getObjAttr(id, kAttrParentObject)) {
enqueueObject(kSetToPlayerParent, id);
}
if (old.offscreen != _world->getObjAttr(id, kAttrInvisible) ||
old.invisible != _world->getObjAttr(id, kAttrUnclickable)) {
updateWindow(findParentWindow(id));
}
} else if (old.parent != _world->getObjAttr(id, kAttrParentObject) ||
old.x != _world->getObjAttr(id, kAttrPosX) ||
old.y != _world->getObjAttr(id, kAttrPosY)) {
WindowReference oldWin = getObjWindow(old.parent);
if (oldWin) {
_gui->removeChild(oldWin, id);
hasChanged = true;
}
WindowReference win = getObjWindow(objID);
ObjID parent = objID;
ObjID root = _world->getObjAttr(1, kAttrParentObject);
while (parent != root) {
if (parent == 0 || !_world->getObjAttr(parent, kAttrContainerOpen)) break;
parent = _world->getObjAttr(parent, kAttrParentObject);
WindowReference newWin = getObjWindow(id);
if (newWin) {
_gui->addChild(newWin, id);
hasChanged = true;
}
} else if (old.offscreen != _world->getObjAttr(id, kAttrInvisible) ||
old.invisible != _world->getObjAttr(id, kAttrUnclickable)) {
updateWindow(findParentWindow(id));
}
if (parent == root) {
if (_world->getObjAttr(id, kAttrIsExit)) {
if (hasChanged ||
old.hidden != _world->getObjAttr(id, kAttrHiddenExit) ||
old.exitx != _world->getObjAttr(id, kAttrExitX) ||
old.exity != _world->getObjAttr(id, kAttrExitY))
_gui->drawExit(id);
}
WindowReference win = getObjWindow(id);
ObjID cur = id;
ObjID root = _world->getObjAttr(1, kAttrParentObject);
while (cur != root) {
if (cur == 0 || !_world->getObjAttr(cur, kAttrContainerOpen)) break;
cur = _world->getObjAttr(cur, kAttrParentObject);
}
if (cur == root) {
if (win) return;
enqueueObject(kOpenWindow, objID);
enqueueObject(kOpenWindow, id); //open
} else {
if (!win) return;
enqueueObject(kCloseWindow, objID);
enqueueObject(kCloseWindow, id); //close
}
// Update children
Common::Array<ObjID> children = _world->getChildren(objID, true);
Common::Array<ObjID> children = _world->getChildren(id, true);
for (uint i = 0; i < children.size(); i++) {
enqueueObject(kUpdateObject, children[i]);
}
@ -543,6 +576,19 @@ Common::Point MacVentureEngine::getObjPosition(ObjID objID) {
return Common::Point(_world->getObjAttr(objID, kAttrPosX), _world->getObjAttr(objID, kAttrPosY));
}
bool MacVentureEngine::isObjVisible(ObjID objID) {
return _world->getObjAttr(objID, kAttrInvisible) == 0;
}
bool MacVentureEngine::isObjClickable(ObjID objID) {
return _world->getObjAttr(objID, kAttrUnclickable) == 0;
}
bool MacVentureEngine::isObjSelected(ObjID objID) {
warning("Unimplemented: isObjSelected");
return false;
}
WindowReference MacVentureEngine::getObjWindow(ObjID objID) {
switch (objID) {
case 0xfffc: return kExitsWindow;
@ -555,7 +601,12 @@ WindowReference MacVentureEngine::getObjWindow(ObjID objID) {
}
WindowReference MacVentureEngine::findObjWindow(ObjID objID) {
return kMainGameWindow;
// This is a bit of a hack, we take advantage of the consecutive nature of references
for (uint i = kCommandsWindow; i <= kDiplomaWindow; i++) {
const WindowData &data = _gui->getWindowData((WindowReference)i);
if (data.refcon == objID) { return data.refcon; }
}
return kNoWindow;
}
WindowReference MacVentureEngine::findParentWindow(ObjID objID) {

View File

@ -133,7 +133,7 @@ struct QueuedObject {
uint exitx;
uint exity;
bool hidden;
bool offsecreen;
bool offscreen;
bool invisible;
};
@ -175,7 +175,7 @@ public:
void enqueueText(TextQueueID type, ObjID target, ObjID source, ObjID text);
void runObjQueue();
void printTexts();
bool printTexts();
void focusObjWin(ObjID objID);
void updateWindow(WindowReference winID);
@ -190,7 +190,11 @@ public:
uint32 randBetween(uint32 min, uint32 max);
uint32 getInvolvedObjects();
// Attributes consult
Common::Point getObjPosition(ObjID objID);
bool isObjVisible(ObjID objID);
bool isObjClickable(ObjID objID);
bool isObjSelected(ObjID objID);
WindowReference getObjWindow(ObjID objID);
WindowReference findObjWindow(ObjID objID);
@ -212,7 +216,7 @@ private:
void focusObjectWindow(ObjID objID);
void openObject(ObjID objID);
void closeObject(ObjID objID);
void checkObject(ObjID objID);
void checkObject(QueuedObject objID);
void reflectSwap(ObjID objID);
void toggleExits();
void zoomObject(ObjID objID);
@ -252,6 +256,7 @@ private: // Attributes
bool _gameChanged;
Common::Array<QueuedObject> _objQueue;
Common::Array<QueuedObject> _inQueue;
Common::Array<QueuedObject> _soundQueue;
Common::Array<QueuedText> _textQueue;

View File

@ -1,13 +1,13 @@
MODULE := engines/macventure
MODULE_OBJS := \
image.o \
detection.o \
gui.o \
object.o \
text.o \
world.o \
script.o \
image.o \
macventure.o
MODULE_DIRS += \

View File

@ -122,7 +122,7 @@ Common::Array<ObjID> World::getChildren(ObjID objID, bool recursive) {
res.push_back(getChildren(child, false));
child = _relations[child * 2 + 1];
}
return Common::Array<ObjID>();
return res;
}
Attribute World::getGlobal(uint32 attrID) {