/* 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 . * */ #include "engines/metaengine.h" #include "engines/wintermute/wintermute.h" #include "engines/wintermute/base/base_game.h" #include "engines/wintermute/base/base_engine.h" #include "engines/wintermute/base/scriptables/script_stack.h" #include "engines/wintermute/base/scriptables/script_value.h" #include "engines/wintermute/base/gfx/3dlight.h" #include "engines/wintermute/ad/ad_game.h" #include "engines/wintermute/ad/ad_scene.h" #include "engines/wintermute/ad/ad_scene_geometry.h" #include "engines/wintermute/ad/ad_actor_3dx.h" #include "engines/wintermute/ext/wme_shadowmanager.h" #include "engines/wintermute/ext/plugin_event.h" namespace Wintermute { IMPLEMENT_PERSISTENT(SXShadowManager, false) BaseScriptable *makeSXShadowManager(BaseGame *inGame, ScStack *stack) { return new SXShadowManager(inGame, stack); } ////////////////////////////////////////////////////////////////////////// SXShadowManager::SXShadowManager(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { stack->correctParams(0); PluginEventEntry event; event._type = WME_EVENT_UPDATE; event._callback = callback; event._plugin = this; _game->pluginEvents().subscribeEvent(event); _defaultLightPos = DXVector3(1.0f, 200.0f, 1.0f); _minShadow = 0.1f; _maxShadow = 1.0f; _useSmartShadows = false; _shadowColor = 0x80000000; } ////////////////////////////////////////////////////////////////////////// SXShadowManager::~SXShadowManager() { PluginEventEntry event; event._type = WME_EVENT_UPDATE; event._callback = callback; event._plugin = this; _game->pluginEvents().unsubscribeEvent(event); } ////////////////////////////////////////////////////////////////////////// const char *SXShadowManager::scToString() { return "[shadowmanager object]"; } ////////////////////////////////////////////////////////////////////////// bool SXShadowManager::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // Run() ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "Run") == 0) { stack->correctParams(0); run(); stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Stop() ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "Stop") == 0) { stack->correctParams(0); stop(); stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AddActor(string) ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "AddActor") == 0) { stack->correctParams(1); AdObject *obj = (AdObject *)stack->pop()->getNative(); if (obj) { if (strcmp(obj->scGetProperty("Type")->getString(), "actor3dx") == 0) { AdActor3DX *actor = (AdActor3DX *)obj; stack->pushBool(addActor(actor)); } } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemoveActor(string) ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "RemoveActor") == 0) { stack->correctParams(1); // nothing todo stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemoveAllActors() ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "RemoveAllActors") == 0) { stack->correctParams(0); stack->pushBool(removeAllActors()); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetNumLights() ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "GetNumLights") == 0) { stack->correctParams(0); // nothing todo stack->pushInt(0); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetLightInfo() ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "GetLightInfo") == 0) { stack->correctParams(1); // nothing todo stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetDefaultLightPos(float, float, float) ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "SetDefaultLightPos") == 0) { stack->correctParams(3); _defaultLightPos._x = stack->pop()->getFloat(); _defaultLightPos._y = stack->pop()->getFloat(); _defaultLightPos._z = stack->pop()->getFloat(); stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // EnableLight(string) ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "EnableLight") == 0) { stack->correctParams(1); const char *lightName = stack->pop()->getString(); stack->pushBool(enableLight(lightName)); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DisableLight(string) ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "DisableLight") == 0) { stack->correctParams(1); const char *lightName = stack->pop()->getString(); stack->pushBool(disableLight(lightName)); return STATUS_OK; } stack->pushNULL(); return STATUS_FAILED; } ////////////////////////////////////////////////////////////////////////// ScValue *SXShadowManager::scGetProperty(const char *name) { _scValue->setNULL(); ////////////////////////////////////////////////////////////////////////// // DefaultLightPos ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "DefaultLightPos") == 0) { _scValue->setProperty("x", _defaultLightPos._x); _scValue->setProperty("y", _defaultLightPos._y); _scValue->setProperty("z", _defaultLightPos._z); return _scValue; } ////////////////////////////////////////////////////////////////////////// // DefaultLightPosX ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DefaultLightPosX") == 0) { _scValue->setFloat(_defaultLightPos._x); return _scValue; } ////////////////////////////////////////////////////////////////////////// // DefaultLightPosY ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DefaultLightPosY") == 0) { _scValue->setFloat(_defaultLightPos._y); return _scValue; } ////////////////////////////////////////////////////////////////////////// // DefaultLightPosZ ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DefaultLightPosZ") == 0) { _scValue->setFloat(_defaultLightPos._z); return _scValue; } ////////////////////////////////////////////////////////////////////////// // MinShadow ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MinShadow") == 0) { _scValue->setFloat(_minShadow); return _scValue; } ////////////////////////////////////////////////////////////////////////// // MaxShadow ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MaxShadow") == 0) { _scValue->setFloat(_maxShadow); return _scValue; } ////////////////////////////////////////////////////////////////////////// // UseSmartShadows ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "UseSmartShadows") == 0) { _scValue->setBool(_useSmartShadows); return _scValue; } return _scValue; } ////////////////////////////////////////////////////////////////////////// bool SXShadowManager::scSetProperty(const char *name, ScValue *value) { ////////////////////////////////////////////////////////////////////////// // DefaultLightPos ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "DefaultLightPos") == 0) { _defaultLightPos._x = value->getProp("x")->getFloat(); _defaultLightPos._y = value->getProp("y")->getFloat(); _defaultLightPos._z = value->getProp("z")->getFloat(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DefaultLightPosX ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DefaultLightPosX") == 0) { _defaultLightPos._x = value->getFloat(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DefaultLightPosY ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DefaultLightPosY") == 0) { _defaultLightPos._y = value->getFloat(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DefaultLightPosZ ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DefaultLightPosZ") == 0) { _defaultLightPos._z = value->getFloat(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // MinShadow ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MinShadow") == 0) { _minShadow = value->getFloat(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // MaxShadow ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MaxShadow") == 0) { _maxShadow = value->getFloat(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // UseSmartShadows ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "UseSmartShadows") == 0) { _useSmartShadows = value->getBool(); return STATUS_OK; } return STATUS_FAILED; } ////////////////////////////////////////////////////////////////////////// bool SXShadowManager::persist(BasePersistenceManager *persistMgr) { BaseScriptable::persist(persistMgr); if (!persistMgr->getIsSaving()) { PluginEventEntry event; event._type = WME_EVENT_UPDATE; event._callback = callback; event._plugin = this; _game->pluginEvents().subscribeEvent(event); // Actor and light lists is not get restored, plugin is not designed to work this way. // Lists get refreshed by game script on scene change. _actors.clear(); _lights.clear(); } persistMgr->transferUint32(TMEMBER(_lastTime)); persistMgr->transferVector3d(TMEMBER(_defaultLightPos)); persistMgr->transferFloat(TMEMBER(_minShadow)); persistMgr->transferFloat(TMEMBER(_maxShadow)); persistMgr->transferBool(TMEMBER(_useSmartShadows)); return STATUS_OK; } void SXShadowManager::callback(void *eventData1, void *eventData2) { SXShadowManager *shadowManager = (SXShadowManager *)eventData2; uint32 time = shadowManager->_game->scGetProperty("CurrentTime")->getInt(); if (time - shadowManager->_lastTime > 20) { shadowManager->_lastTime = time; shadowManager->update(); } } void SXShadowManager::update() { if (_useSmartShadows) { AdGame *adGame = (AdGame *)_game; if (!adGame->_scene || !adGame->_scene->_geom) return; for (auto actorIt = _actors.begin(); actorIt != _actors.end(); ++actorIt) { _shadowColor = 0x00000000; float shadowWeight = 0.0f; uint32 numLights = 0; for (auto lightIt = _lights.begin(); lightIt != _lights.end(); ++lightIt) { if (!lightIt->second) continue; auto light = lightIt->first; if (light->_isSpotlight) continue; float weight1 = 0.0 * 0.11f; // TODO float r = RGBCOLGetR(light->_diffuseColor) / 255.0f; float g = RGBCOLGetG(light->_diffuseColor) / 255.0f; float b = RGBCOLGetB(light->_diffuseColor) / 255.0f; float brightness = (r + g + b) / 3.0f; float weight2 = brightness * 0.59f; float weight3 = 0.0 * 0.3; // TODO shadowWeight += (weight1 + weight2 + weight3); numLights++; } if (numLights != 0) shadowWeight /= numLights; _shadowColor = (byte)(shadowWeight * 255) << 24; actorIt->first->_shadowLightPos = _defaultLightPos; actorIt->first->_shadowColor = _shadowColor; } } } void SXShadowManager::run() { _lastTime = _game->scGetProperty("CurrentTime")->getInt(); _lights.clear(); AdGame *adGame = (AdGame *)_game; if (!adGame->_scene || !adGame->_scene->_geom) return; for (int32 l = 0; l < adGame->_scene->_geom->_lights.getSize(); l++) { auto light = adGame->_scene->_geom->_lights[l]; _lights.push_back(Common::Pair(light, true)); } } void SXShadowManager::stop() { _lights.clear(); } bool SXShadowManager::addActor(AdActor3DX *actorObj) { if (_useSmartShadows) { _actors.push_back(Common::Pair(actorObj, actorObj->_shadowColor)); } return true; } bool SXShadowManager::removeAllActors() { for (auto it = _actors.begin(); it != _actors.end(); ++it) { it->first->_shadowColor = it->second; } _actors.clear(); return true; } bool SXShadowManager::enableLight(const char *lightName) { for (auto it = _lights.begin(); it != _lights.end(); ++it) { if (scumm_stricmp(it->first->_name, lightName) == 0) it->second = true; } return true; } bool SXShadowManager::disableLight(const char *lightName) { for (auto it = _lights.begin(); it != _lights.end(); ++it) { if (scumm_stricmp(it->first->_name, lightName) == 0) it->second = false; } return true; } } // End of namespace Wintermute