scummvm/engines/grim/emi/emi.cpp
Martin Gerhardy f2c9137979 COMMON: removed foreach.h
now that we are using c++11 we don't need this wrapper anymore
2023-01-07 02:40:44 +02:00

334 lines
8.4 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 "engines/grim/emi/emi.h"
#include "engines/grim/emi/emi_registry.h"
#include "engines/grim/emi/lua_v2.h"
#include "engines/grim/primitives.h"
#include "engines/grim/set.h"
#include "engines/grim/gfx_base.h"
#include "engines/grim/actor.h"
#include "graphics/surface.h"
namespace Grim {
EMIEngine *g_emi = nullptr;
EMIEngine::EMIEngine(OSystem *syst, uint32 gameFlags, GrimGameType gameType, Common::Platform platform, Common::Language language) :
GrimEngine(syst, gameFlags, gameType, platform, language), _sortOrderInvalidated(false), _textObjectsSortOrderInvalidated(true) {
g_emi = this;
g_emiregistry = new EmiRegistry();
}
EMIEngine::~EMIEngine() {
g_emi = nullptr;
delete g_emiregistry;
g_emiregistry = nullptr;
}
LuaBase *EMIEngine::createLua() {
return new Lua_V2();
}
const char *EMIEngine::getUpdateFilename() {
if (getGamePlatform() == Common::kPlatformWindows && !(getGameFlags() & ADGF_DEMO)) {
switch (getGameLanguage()) {
case Common::FR_FRA:
return "MonkeyUpdate_FRA.exe";
break;
case Common::DE_DEU:
return "MonkeyUpdate_DEU.exe";
break;
case Common::IT_ITA:
return "MonkeyUpdate_ITA.exe";
break;
case Common::PT_BRA:
return "MonkeyUpdate_BRZ.exe";
break;
case Common::ES_ESP:
return "MonkeyUpdate_ESP.exe";
break;
case Common::EN_ANY:
case Common::EN_GRB:
case Common::EN_USA:
default:
return "MonkeyUpdate.exe";
break;
}
} else
return nullptr;
}
void EMIEngine::pushText() {
for (TextObject *t : TextObject::getPool()) {
t->incStackLevel();
}
invalidateTextObjectsSortOrder();
}
void EMIEngine::popText() {
Common::List<TextObject *> toDelete;
for (TextObject *t : TextObject::getPool()) {
if (t->getStackLevel() == 0) {
warning("Text stack top not empty; deleting object");
toDelete.push_back(t);
} else {
t->decStackLevel();
}
}
while (!toDelete.empty()) {
TextObject *t = toDelete.front();
toDelete.pop_front();
delete t;
}
invalidateTextObjectsSortOrder();
}
void EMIEngine::purgeText() {
Common::List<TextObject *> toDelete;
for (TextObject *t : TextObject::getPool()) {
if (t->getStackLevel() == 0) {
toDelete.push_back(t);
}
}
while (!toDelete.empty()) {
TextObject *t = toDelete.front();
toDelete.pop_front();
delete t;
}
invalidateTextObjectsSortOrder();
}
void EMIEngine::drawNormalMode() {
_currSet->setupCamera();
g_driver->set3DMode();
if (_setupChanged) {
cameraPostChangeHandle(_currSet->getSetup());
_setupChanged = false;
}
// Draw actors
buildActiveActorsList();
sortActiveActorsList();
sortLayers();
Bitmap *background = _currSet->getCurrSetup()->_bkgndBm;
background->_data->load();
uint32 numLayers = background->_data->_numLayers;
Common::List<Layer *>::const_iterator nextLayer = _layers.begin();
Common::List<Actor *>::const_iterator nextActor = _activeActors.begin();
int32 currentLayer = numLayers - 1;
int aso = (nextActor != _activeActors.end()) ? (*nextActor)->getEffectiveSortOrder() : -1;
int lso = (nextLayer != _layers.end()) ? (*nextLayer)->getSortOrder() : -1;
int bgso = currentLayer * 10;
// interleave actors, background layers and additional stand-alone layers based
// on their sortorder
//
// priority for same sort order:
// background layers (highest priority)
// stand-alone layers
// actors
while (1) {
if (aso >= 0 && aso > bgso && aso > lso) {
if ((*nextActor)->isVisible() && ! (*nextActor)->isInOverworld())
(*nextActor)->draw();
nextActor++;
aso = (nextActor != _activeActors.end()) ? (*nextActor)->getEffectiveSortOrder() : -1;
continue;
}
if (bgso >= 0 && bgso >= lso && bgso >= aso) {
background->drawLayer(currentLayer);
currentLayer--;
bgso = currentLayer * 10;
continue;
}
if (lso >= 0 && lso > bgso && lso >= aso) {
(*nextLayer)->draw();
nextLayer++;
lso = (nextLayer != _layers.end()) ? (*nextLayer)->getSortOrder() : -1;
continue;
}
break;
}
/* Clear depth buffer before starting to draw the Overworld:
* - all actors of the Overworld should cover any non-Overworld drawings
* - Overworld actors need to use the depth Buffer so that e.g. the pause screen
* is drawn above the inventory
*/
g_driver->clearDepthBuffer();
g_driver->drawDimPlane();
for (Actor *a : _activeActors) {
if (a->isInOverworld())
a->draw();
}
// Draw Primitives
for (PrimitiveObject *p : PrimitiveObject::getPool()) {
p->draw();
}
flagRefreshShadowMask(false);
}
void EMIEngine::storeSaveGameImage(SaveGame *state) {
unsigned int width = 160, height = 120;
Bitmap *screenshot = g_driver->getScreenshot(width, height, true);
if (!screenshot) {
warning("Unable to store screenshot.");
return;
}
// screenshots are not using the whole size of the texture
// copy the actual screenshot to the correct position
unsigned int texWidth = 256, texHeight = 128;
unsigned int size = texWidth * texHeight;
Graphics::Surface tmp = screenshot->getData(0);
Graphics::Surface *buffer = tmp.scale(texWidth, texHeight, true);
buffer->convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
state->beginSection('SIMG');
uint16 *data = (uint16 *)buffer->getPixels();
for (unsigned int l = 0; l < size; l++) {
state->writeLEUint16(data[l]);
}
state->endSection();
delete screenshot;
buffer->free();
delete buffer;
}
void EMIEngine::temporaryStoreSaveGameImage() {
// store current rendered screen in g_driver
g_grim->updateDisplayScene();
g_driver->storeDisplay();
}
void EMIEngine::updateDrawMode() {
// For EMI, draw mode is just like normal mode with frozen frame time.
updateNormalMode();
}
void EMIEngine::invalidateTextObjectsSortOrder() {
_textObjectsSortOrderInvalidated = true;
}
void EMIEngine::invalidateActiveActorsList() {
GrimEngine::invalidateActiveActorsList();
invalidateSortOrder();
}
void EMIEngine::invalidateSortOrder() {
_sortOrderInvalidated = true;
}
bool EMIEngine::compareTextLayer(const TextObject *x, const TextObject *y) {
int xl = x->getLayer();
int yl = y->getLayer();
if (xl == yl) {
return x->getId() < y->getId();
} else {
return xl < yl;
}
}
bool EMIEngine::compareLayer(const Layer *x, const Layer *y) {
return x->getSortOrder() > y->getSortOrder();
}
void EMIEngine::drawTextObjects() {
sortTextObjects();
for (TextObject *t : _textObjects) {
t->draw();
}
}
void EMIEngine::sortTextObjects() {
if (!_textObjectsSortOrderInvalidated)
return;
_textObjectsSortOrderInvalidated = false;
_textObjects.clear();
for (TextObject *t : TextObject::getPool()) {
if (t->getStackLevel() == 0) {
_textObjects.push_back(t);
}
}
Common::sort(_textObjects.begin(), _textObjects.end(), compareTextLayer);
}
void EMIEngine::sortLayers() {
_layers.clear();
for (Layer *l : Layer::getPool()) {
_layers.push_back(l);
}
Common::sort(_layers.begin(), _layers.end(), compareLayer);
}
bool EMIEngine::compareActor(const Actor *x, const Actor *y) {
if (x->getEffectiveSortOrder() == y->getEffectiveSortOrder()) {
Set::Setup *setup = g_grim->getCurrSet()->getCurrSetup();
Math::Matrix4 camRot = setup->_rot;
Math::Vector3d xp(x->getWorldPos() - setup->_pos);
Math::Vector3d yp(y->getWorldPos() - setup->_pos);
xp = xp * camRot.getRotation();
yp = yp * camRot.getRotation();
if (fabs(xp.z() - yp.z()) < 0.001f) {
return x->getId() < y->getId();
} else {
return xp.z() > yp.z();
}
}
return x->getEffectiveSortOrder() > y->getEffectiveSortOrder();
}
void EMIEngine::sortActiveActorsList() {
if (!_sortOrderInvalidated) {
return;
}
_sortOrderInvalidated = false;
Common::sort(_activeActors.begin(), _activeActors.end(), compareActor);
}
} // end of namespace Grim