diff --git a/build/config_editor.cfg b/build/config_editor.cfg index 8a02e596e8f10929760a7b9cef98d2a6a78508ea..50e8daa52e110c27c8ded7a918282ad709103d2b 100644 --- a/build/config_editor.cfg +++ b/build/config_editor.cfg @@ -15,3 +15,31 @@ hud_rangefinder 0 cl_mousesense 4.5 dev_show_triggers 1 + +dev_reset_world_on_run 1 + +alias run_level "Start level from editor" + echo "Switching to game" + terrax_detach_3d 1 + gmode ingame + dev_show_triggers 0 + hud_draw 1 +// hud_crosshair 1 +// hud_rangefinder 1 + exec ../config_game.cfg + exec ../config_game_user.cfg + bind escape end_level + spawn +endalias + +alias end_level + echo "Switching to editor" + cl_grab_cursor 0 + terrax_detach_3d 0 +// hud_draw 0 +// hud_crosshair 0 +// hud_rangefinder 0 + gmode editor +// dev_show_triggers 1 + exec ../config_editor.cfg +endalias diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index a867ed7d5d6d21a2bac09eec943028b698ef42e8..edc4d885a4c8ac5ab95a75035f4edd73fc81f15f 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -248,6 +248,7 @@ <ClInclude Include="..\..\..\source\common\string_utils.h" /> <ClInclude Include="..\..\..\source\game\BaseHandle.h" /> <ClInclude Include="..\..\..\source\game\BaseLight.h" /> + <ClInclude Include="..\..\..\source\game\Baseline.h" /> <ClInclude Include="..\..\..\source\game\BaseMag.h" /> <ClInclude Include="..\..\..\source\game\BaseScope.h" /> <ClInclude Include="..\..\..\source\game\BaseSilencer.h" /> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index 71f76362f986dc8aadad08bdd70e8444ce6fbbf2..605c80cc668bde7b56b89a5248edb8271ef63d9e 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -470,5 +470,8 @@ <ClInclude Include="..\..\..\source\game\SoundPlayer.h"> <Filter>Header Files\ents</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\Baseline.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/source/game/Baseline.h b/source/game/Baseline.h new file mode 100644 index 0000000000000000000000000000000000000000..103516a477f98ce5778bff7d5231ee92bf5ed4df --- /dev/null +++ b/source/game/Baseline.h @@ -0,0 +1,43 @@ + +/*********************************************************** +Copyright © Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018 +See the license in LICENSE +***********************************************************/ + +#include "EntityManager.h" +#include <common/assotiativearray.h> + +#ifndef __BASELINE_H +#define __BASELINE_H + +class CBaseline +{ + friend class CEntityManager; + + struct ent_record_s + { + UINT m_id; + String m_sClassname; + AssotiativeArray<String, String> m_mProps; + }; + +public: + + ID getId() + { + return(m_id); + } + +protected: + ID m_id; + Array<ent_record_s> m_aRecords; + + CBaseline(ID id):m_id(id) + { + } + ~CBaseline() + { + } +}; + +#endif diff --git a/source/game/EntityManager.cpp b/source/game/EntityManager.cpp index 656172eead6c27bb4b2951b73aac2bef40057747..f2d82f7da09e995798bf2211b3fad82719c3d5b8 100644 --- a/source/game/EntityManager.cpp +++ b/source/game/EntityManager.cpp @@ -8,28 +8,52 @@ See the license in LICENSE #include "BaseEntity.h" +#include "Baseline.h" + #include <core/sxcore.h> +void CEntityManager::CCVarEventListener::onEvent(const XEventCvarChanged *pEvent) +{ + static const bool *game_time_running = m_pCore->getConsole()->getPCVarBool("game_time_running"); + + if(game_time_running == pEvent->pCvar) + { + m_pMgr->setTimeRunning(*game_time_running); + } +} + +//########################################################################## + CEntityManager::CEntityManager(): - m_iThreadNum(1), - m_pDefaultsConf(NULL), - m_pDynClassConf(NULL) + m_cvarListener(this, Core_GetIXCore()) { loadDefaults(); loadDynClasses(); Core_0RegisterConcmdClsArg("ent_dump", this, (SXCONCMDCLSARG)&CEntityManager::dumpList); Core_0RegisterConcmdClsArg("ent_kv", this, (SXCONCMDCLSARG)&CEntityManager::entKV); + + Core_GetIXCore()->getConsole()->registerCVar("game_time_running", false, "Is game time running", FCVAR_NOTIFY); + + Core_GetIXCore()->getEventChannel<XEventCvarChanged>(EVENT_CVAR_CHANGED_GUID)->addListener(&m_cvarListener); } CEntityManager::~CEntityManager() { + Core_GetIXCore()->getEventChannel<XEventCvarChanged>(EVENT_CVAR_CHANGED_GUID)->removeListener(&m_cvarListener); + mem_release(m_pDynClassConf); mem_release(m_pDefaultsConf); } void CEntityManager::update(int thread) { + static const bool *game_time_running = Core_GetIXCore()->getConsole()->getPCVarBool("game_time_running"); + if(!*game_time_running) + { + return; + } + time_point tNow = std::chrono::high_resolution_clock::now(); timeout_t * t; timeout_output_t * to; @@ -97,10 +121,9 @@ void CEntityManager::setThreadNum(int num) } } -void CEntityManager::sync() +void CEntityManager::finalRemove() { CBaseEntity * pEnt; - // do not store m_vEntRemoveList.size()! It can change during iteration for(int i = 0; i < (int)m_vEntRemoveList.size(); ++i) { @@ -112,6 +135,13 @@ void CEntityManager::sync() } } m_vEntRemoveList.clearFast(); +} + +void CEntityManager::sync() +{ + CBaseEntity * pEnt; + + finalRemove(); for(int i = 0, l = m_vTimeout.size(); i < l; ++i) { @@ -272,12 +302,12 @@ ID CEntityManager::setTimeout(void(CBaseEntity::*func)(float dt), CBaseEntity *p t.func = func; t.pEnt = pEnt; - t.fStartTime = t.fNextTime = std::chrono::high_resolution_clock::now(); + t.fStartTime = t.fNextTime = m_isTimeRunning ? std::chrono::high_resolution_clock::now() : m_tStopPoint; t.fNextTime += std::chrono::microseconds((long long)(delay * 1000000.0f)); ID id; { - ScopedLock lock(m_mxTimeout); + ScopedSpinLock lock(m_mxTimeout); if(m_vFreeTimeout.size()) { @@ -301,12 +331,12 @@ ID CEntityManager::setInterval(void(CBaseEntity::*func)(float dt), CBaseEntity * t.func = func; t.pEnt = pEnt; - t.fStartTime = t.fNextTime = std::chrono::high_resolution_clock::now(); + t.fStartTime = t.fNextTime = m_isTimeRunning ? std::chrono::high_resolution_clock::now() : m_tStopPoint; t.fNextTime += std::chrono::microseconds((long long)(delay * 1000000.0f)); ID id; { - ScopedLock lock(m_mxInterval); + ScopedSpinLock lock(m_mxInterval); if(m_vFreeInterval.size()) { id = m_vFreeInterval[0]; @@ -724,7 +754,7 @@ void CEntityManager::dumpList(int argc, const char **argv) } if(!filter[0] || strstr(pEnt->getClassName(), filter)) { - printf(" " COLOR_LGREEN "%4d" COLOR_GREEN " | " COLOR_LGREEN "%24s" COLOR_GREEN " | " COLOR_LGREEN "%16s" COLOR_GREEN " |\n", i, pEnt->getClassName(), pEnt->getName()); + printf(" " COLOR_LGREEN "%-4d" COLOR_GREEN " | " COLOR_LGREEN "%-24s" COLOR_GREEN " | " COLOR_LGREEN "%-16s" COLOR_GREEN " |\n", i, pEnt->getClassName(), pEnt->getName()); } } @@ -846,7 +876,7 @@ void CEntityManager::setOutputTimeout(named_output_t *pOutput, inputdata_t *pDat t.pOutput = pOutput; t.data = *pData; - t.fStartTime = t.fNextTime = std::chrono::high_resolution_clock::now(); + t.fStartTime = t.fNextTime = m_isTimeRunning ? std::chrono::high_resolution_clock::now() : m_tStopPoint; t.fNextTime += std::chrono::microseconds((long long)((pOutput->useRandomDelay ? randf(pOutput->fDelay, pOutput->fDelayTo) : pOutput->fDelay) * 1000000.0f)); m_vOutputTimeout.push_back(t); @@ -897,3 +927,299 @@ bool CEntityManager::isEditorMode() { return(m_isEditorMode); } + +void CEntityManager::setTimeRunning(bool set) +{ + time_point tNow = std::chrono::high_resolution_clock::now(); + m_isTimeRunning = set; + if(set) + { + auto tDelta = tNow - m_tStopPoint; + + timeout_t *t; + timeout_output_t *to; + + for(UINT i = 0, l = m_vOutputTimeout.size(); i < l; ++i) + { + to = &m_vOutputTimeout[i]; + if(to->status == TS_WAIT) + { + to->fNextTime += tDelta; + to->fStartTime += tDelta; + } + } + + for(UINT i = 0, l = m_vTimeout.size(); i < l; ++i) + { + t = &m_vTimeout[i]; + if(t->status == TS_WAIT) + { + t->fNextTime += tDelta; + t->fStartTime += tDelta; + } + } + + for(UINT i = 0, l = m_vInterval.size(); i < l; ++i) + { + t = &m_vInterval[i]; + if(t->status == TS_WAIT) + { + t->fNextTime += tDelta; + t->fStartTime += tDelta; + } + } + } + else + { + m_tStopPoint = tNow; + } +} + +CBaseline* CEntityManager::createBaseline(ID id) +{ + if(!ID_VALID(id)) + { + id = m_aBaselines.size(); + } + else + { + if((UINT)id < m_aBaselines.size()) + { + mem_delete(m_aBaselines[id]); + } + else + { + m_aBaselines.reserve(id + 1); + for(int i = m_aBaselines.size(); i < id + 1; ++i) + { + m_aBaselines[i] = 0; + } + } + + } + CBaseline *pBaseline = m_aBaselines[id] = new CBaseline(id); + + CBaseEntity *pEnt; + proptable_t * pTbl; + char buf[4096]; + EntDefaultsMap *pDefaults; + const EntDefaultsMap::Node *pNode; + + for(int i = 0, l = m_vEntList.size(); i < l; ++i) + { + pEnt = m_vEntList[i]; + if(pEnt && (pEnt->getFlags() & EF_LEVEL) && !(pEnt->getFlags() & EF_REMOVED)) + { + CBaseline::ent_record_s record; + record.m_id = pEnt->getId(); + record.m_sClassname = pEnt->getClassName(); + + pDefaults = CEntityFactoryMap::GetInstance()->getDefaults(pEnt->getClassName()); + pTbl = CEntityFactoryMap::GetInstance()->getPropTable(pEnt->getClassName()); + do + { + for(int j = 0; j < pTbl->numFields; ++j) + { + if(pTbl->pData[j].szKey && !(pTbl->pData[j].flags & PDFF_INPUT) && !record.m_mProps.KeyExists(pTbl->pData[j].szKey)) + { + pEnt->getKV(pTbl->pData[j].szKey, buf, sizeof(buf)); + //test defaults + if(!pDefaults->KeyExists(pTbl->pData[j].szKey, &pNode) || strcmp(*(pNode->Val), buf)) + { + record.m_mProps[pTbl->pData[j].szKey] = buf; + } + } + } + } + while((pTbl = pTbl->pBaseProptable)); + + pBaseline->m_aRecords.push_back(record); + } + } + return(pBaseline); +} + +CBaseline* CEntityManager::getBaseline(ID id) +{ + if(!ID_VALID(id) || (UINT)id >= m_aBaselines.size()) + { + return(NULL); + } + + return(m_aBaselines[id]); +} + +void CEntityManager::dispatchBaseline(CBaseline *pBaseline) +{ + CBaseEntity *pEnt; + unloadObjLevel(); + finalRemove(); + //m_vFreeIDs.clearFast(); + //m_vEntList.resize(RESERVED_SLOTS); + + if(!pBaseline->m_aRecords.size()) + { + return; + } + + UINT idMax = pBaseline->m_aRecords[pBaseline->m_aRecords.size() - 1].m_id; + if(m_vEntList.size() <= idMax) + { + m_vEntList.reserve(idMax + 1); + } + + const AssotiativeArray<String, String>::Node *pNode; + for(int i = 0, l = pBaseline->m_aRecords.size(); i < l; ++i) + { + CBaseline::ent_record_s *pRecord = &pBaseline->m_aRecords[i]; + + if(!(pEnt = CREATE_ENTITY_NOPOST(pRecord->m_sClassname.c_str(), this))) + { + printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, pRecord->m_sClassname.c_str()); + continue; + } + + if(pEnt->getId() != pRecord->m_id) + { + m_vEntList[pEnt->getId()] = NULL; + m_vFreeIDs.push_back(pEnt->getId()); + + for(UINT j = m_vEntList.size(); j < pRecord->m_id; ++j) + { + m_vEntList[j] = NULL; + m_vFreeIDs.push_back(j); + } + if(pRecord->m_id < m_vEntList.size() && m_vEntList[pRecord->m_id]) + { + ID newId = m_vEntList.size(); + if(m_vFreeIDs.size()) + { + newId = m_vFreeIDs[m_vFreeIDs.size() - 1]; + m_vFreeIDs.erase(m_vFreeIDs.size() - 1); + } + m_vEntList[newId] = m_vEntList[pRecord->m_id]; + m_vEntList[newId]->m_iId = newId; + } + else + { + int idx = m_vFreeIDs.indexOf(pRecord->m_id); + if(idx >= 0) + { + m_vFreeIDs.erase(idx); + } + } + m_vEntList[pRecord->m_id] = pEnt; + pEnt->m_iId = pRecord->m_id; + } + + if(pRecord->m_mProps.KeyExists("name", &pNode)) + { + pEnt->setKV("name", pNode->Val->c_str()); + } + if(pRecord->m_mProps.KeyExists("origin", &pNode)) + { + pEnt->setKV("origin", pNode->Val->c_str()); + } + if(pRecord->m_mProps.KeyExists("rotation", &pNode)) + { + pEnt->setKV("rotation", pNode->Val->c_str()); + } + + pEnt->setFlags(pEnt->getFlags() | EF_LEVEL); + } + + const char *key; + for(int i = 0, l = pBaseline->m_aRecords.size(); i < l; ++i) + { + CBaseline::ent_record_s *pRecord = &pBaseline->m_aRecords[i]; + + pEnt = m_vEntList[pRecord->m_id]; + for(AssotiativeArray<String, String>::Iterator it = pRecord->m_mProps.begin(); it; it++) + { + key = it.first->c_str(); + + if(strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation")) + { + pEnt->setKV(key, it.second->c_str()); + } + } + } + + for(int i = 1, l = m_vEntList.size(); i < l; ++i) + { + pEnt = m_vEntList[i]; + if(pEnt) + { + pEnt->onPostLoad(); + } + } +} + +#if 0 +void CEntityManager::serializeBaseline(CBaseline *pBaseline, INETbuff *pBuf) +{ + CBaseline::ent_record_s *pRecord; + const char *key; + + pBuf->writeChar(pBaseline->m_aRecords.size()); + for(int i = 0, l = pBaseline->m_aRecords.size(); i < l; ++i) + { + pRecord = &pBaseline->m_aRecords[i]; + pBuf->writeChar(pRecord->m_id); + pBuf->writeString(pRecord->m_sClassname.c_str()); + + pBuf->writeChar(pRecord->m_mProps.Size()); + for(AssotiativeArray<String, String>::Iterator it = pRecord->m_mProps.begin(); it; it++) + { + pBuf->writeString(it.first->c_str()); + pBuf->writeString(it.second->c_str()); + } + } +} + +CBaseline *CEntityManager::deserializeBaseline(ID id, INETbuff *pBuf) +{ + assert(ID_VALID(id)); + + if(id < m_aBaselines.size()) + { + mem_delete(m_aBaselines[id]); + } + else + { + m_aBaselines.reserve(id + 1); + for(int i = m_aBaselines.size(); i < id + 1; ++i) + { + m_aBaselines[i] = 0; + } + } + CBaseline *pBaseline = m_aBaselines[id] = new CBaseline(id); + + UINT uCount = pBuf->readChar(); + char buf[4096], buf2[32]; + + for(UINT i = 0; i < uCount; ++i) + { + CBaseline::ent_record_s record; + record.m_id = pBuf->readChar(); + pBuf->readString(buf, sizeof(buf)); + record.m_sClassname = buf; + + //printf("Ent: %s\n", buf); + + UINT uPropCount = pBuf->readChar(); + for(UINT j = 0; j < uPropCount; ++j) + { + pBuf->readString(buf2, sizeof(buf2)); + pBuf->readString(buf, sizeof(buf)); + //printf(" %s: \"%s\"\n", buf2, buf); + record.m_mProps[buf2] = buf; + } + //printf("\n"); + + pBaseline->m_aRecords.push_back(record); + } + + return(pBaseline); +} +#endif diff --git a/source/game/EntityManager.h b/source/game/EntityManager.h index 9ae3a173834b4f00cd5f6ffcccefaf3f1e1b3b23..03cd994d3df1453b7708ab743569c6cf8f2e90bd 100644 --- a/source/game/EntityManager.h +++ b/source/game/EntityManager.h @@ -12,7 +12,8 @@ See the license in LICENSE #include <gdefines.h> #include <common/array.h> #include <chrono> -#include <mutex> +#include <xcommon/XEvents.h> +#include <xcommon/IXCore.h> #include "proptable.h" @@ -67,8 +68,25 @@ struct timeout_output_t inputdata_t data; }; +class CBaseline; + class CEntityManager { + class CCVarEventListener: public IEventListener<XEventCvarChanged> + { + public: + CCVarEventListener(CEntityManager *pMgr, IXCore *pCore): + m_pMgr(pMgr), + m_pCore(pCore) + {} + + void onEvent(const XEventCvarChanged *pEvent) override; + + private: + CEntityManager *m_pMgr; + IXCore *m_pCore; + }; + friend class CBaseEntity; friend class CEntityFactoryMap; public: @@ -113,6 +131,17 @@ public: void setEditorMode(bool isEditor = true); bool isEditorMode(); + void setTimeRunning(bool set); + + CBaseline* createBaseline(ID forceId = -1); + CBaseline* getBaseline(ID id); + void dispatchBaseline(CBaseline *pBaseline); + +#if 0 + void serializeBaseline(CBaseline *pBaseline, INETbuff *pBuf); + CBaseline *deserializeBaseline(ID id, INETbuff *pBuf); +#endif + protected: ID reg(CBaseEntity *pEnt); void unreg(ID ent); @@ -131,16 +160,25 @@ protected: Array<ID> m_vFreeInterval; Array<ID> m_vFreeTimeout; - int m_iThreadNum; + int m_iThreadNum = 1; //! @warning это нужно хранить в течение работы проги, т.к. таблицы дефолтов ссылаются напрямую на этот объект - ISXConfig *m_pDefaultsConf; - ISXConfig *m_pDynClassConf; + ISXConfig *m_pDefaultsConf = NULL; + ISXConfig *m_pDynClassConf = NULL; bool m_isEditorMode = false; - std::mutex m_mxTimeout; - std::mutex m_mxInterval; + SpinLock m_mxTimeout; + SpinLock m_mxInterval; + + bool m_isTimeRunning = false; + time_point m_tStopPoint = std::chrono::high_resolution_clock::now(); + CCVarEventListener m_cvarListener; + + Array<CBaseline*> m_aBaselines; + +private: + void finalRemove(); }; #endif diff --git a/source/game/GameData.cpp b/source/game/GameData.cpp index 7efb990990460a026b4050e7816afd278ca2dce7..75df4dc378ee72850ebfc26a183badac4c428e3d 100644 --- a/source/game/GameData.cpp +++ b/source/game/GameData.cpp @@ -639,6 +639,9 @@ GameData::GameData(HWND hWnd, bool isGame): Core_0RegisterCVarFloat("cl_mousesense", 2.0f, "Mouse sense value"); Core_0RegisterCVarBool("cl_invert_y", false, "Invert Y axis"); + Core_0RegisterCVarBool("dev_reset_world_on_run", false, "Reset world on level run"); + + Core_0RegisterCVarBool("cl_bob", true, "View bobbing"); Core_0RegisterCVarFloat("cl_bob_walk_y", 0.1f, "View bobbing walk y amplitude"); Core_0RegisterCVarFloat("cl_bob_walk_x", 0.1f, "View bobbing walk strafe amplitude"); diff --git a/source/game/GameStates.cpp b/source/game/GameStates.cpp index 4241ef43b875ce9794ce95b8eefaef06a0aae40a..a91c98c4289737c694d099ad36d10459f31d9d5b 100644 --- a/source/game/GameStates.cpp +++ b/source/game/GameStates.cpp @@ -1,6 +1,7 @@ #include "GameStates.h" #include "GameData.h" +#include "Baseline.h" #include <score/sxscore.h> #include <input/sxinput.h> @@ -25,6 +26,7 @@ CMainMenuGameState::~CMainMenuGameState() void CMainMenuGameState::activate() { + printf("CMainMenuGameState::activate()\n"); GameData::m_pGUIStack->setActiveDesktop(m_pDesktop); if(GameData::m_pGuiLayer) @@ -40,6 +42,7 @@ void CMainMenuGameState::activate() void CMainMenuGameState::deactivate() { + printf("CMainMenuGameState::deactivate()\n"); if(GameData::m_pGuiLayer) { GameData::m_pGuiLayer->play(false); @@ -72,6 +75,7 @@ CIngameMenuGameState::~CIngameMenuGameState() void CIngameMenuGameState::activate() { + printf("CIngameMenuGameState::activate()\n"); GameData::m_pGUIStack->setActiveDesktop(m_pDesktop); if(GameData::m_pGuiLayer) @@ -87,6 +91,7 @@ void CIngameMenuGameState::activate() void CIngameMenuGameState::deactivate() { + printf("CIngameMenuGameState::deactivate()\n"); GameData::m_pGUIStack->setActiveDesktop(m_pDesktop); if(GameData::m_pGuiLayer) @@ -104,6 +109,14 @@ void CIngameMenuGameState::deactivate() void CIngameGameState::activate() { + printf("CIngameGameState::activate()\n"); + static const bool *dev_reset_world_on_run = GET_PCVAR_BOOL("dev_reset_world_on_run"); + + if(*dev_reset_world_on_run) + { + m_pBaseLine = GameData::m_pMgr->createBaseline(m_pBaseLine ? m_pBaseLine->getId() : -1); + } + Core_0ConsoleExecCmd("cl_grab_cursor 1"); GameData::m_pHUDcontroller->activate(); @@ -113,6 +126,8 @@ void CIngameGameState::activate() SSInput_SetEnable(true); SPhysics_EnableSimulation(); + Core_0ConsoleExecCmd("game_time_running 1"); + if(GameData::m_pGameLayer) { GameData::m_pGameLayer->play(true); @@ -121,6 +136,11 @@ void CIngameGameState::activate() void CIngameGameState::deactivate() { + printf("CIngameGameState::deactivate()\n"); + static const bool *dev_reset_world_on_run = GET_PCVAR_BOOL("dev_reset_world_on_run"); + + Core_0ConsoleExecCmd("game_time_running 0"); + ID idTimerRender = Core_RIntGet(G_RI_INT_TIMER_GAME); Core_TimeWorkingSet(idTimerRender, false); SSCore_ChannelStop(SX_SOUND_CHANNEL_GAME); @@ -131,14 +151,20 @@ void CIngameGameState::deactivate() { GameData::m_pGameLayer->play(false); } + + if(*dev_reset_world_on_run) + { + GameData::m_pMgr->dispatchBaseline(m_pBaseLine); + } } //########################################################################## void CEditorState::activate() { - ID idTimerRender = Core_RIntGet(G_RI_INT_TIMER_GAME); - Core_TimeWorkingSet(idTimerRender, true); + printf("CEditorState::activate()\n"); +// ID idTimerRender = Core_RIntGet(G_RI_INT_TIMER_GAME); +// Core_TimeWorkingSet(idTimerRender, true); //SSCore_ChannelPlay(SX_SOUND_CHANNEL_GAME); // SSInput_SetEnable(true); @@ -147,10 +173,11 @@ void CEditorState::activate() void CEditorState::deactivate() { + printf("CEditorState::deactivate()\n"); GameData::m_pMgr->setEditorMode(false); - ID idTimerRender = Core_RIntGet(G_RI_INT_TIMER_GAME); - Core_TimeWorkingSet(idTimerRender, false); +// ID idTimerRender = Core_RIntGet(G_RI_INT_TIMER_GAME); +// Core_TimeWorkingSet(idTimerRender, false); //SSCore_ChannelStop(SX_SOUND_CHANNEL_GAME); // SSInput_SetEnable(false); } diff --git a/source/game/GameStates.h b/source/game/GameStates.h index 4e23299023c89d96b6d5fe73ccdd6329911d91cc..027048b79de7a96b254fcb2ce43681d9a212bc79 100644 --- a/source/game/GameStates.h +++ b/source/game/GameStates.h @@ -4,6 +4,8 @@ #include "IGameState.h" #include <gui/guimain.h> +class CBaseline; + class CMainMenuGameState final: public IGameState { public: @@ -28,18 +30,21 @@ protected: gui::IDesktop *m_pDesktop; }; -class CIngameGameState: public IGameState +class CIngameGameState final: public IGameState { public: - void activate(); - void deactivate(); + void activate() override; + void deactivate() override; + +private: + CBaseline *m_pBaseLine = NULL; }; -class CEditorState: public IGameState +class CEditorState final: public IGameState { public: - void activate(); - void deactivate(); + void activate() override; + void deactivate() override; }; #endif diff --git a/source/light/LightSystem.cpp b/source/light/LightSystem.cpp index c31c81bdc2bb674dace547c6413192d097e2f6fd..85c8137b5423a50325a4507472f228af5cda0038 100644 --- a/source/light/LightSystem.cpp +++ b/source/light/LightSystem.cpp @@ -13,11 +13,17 @@ public: { switch(pEvent->type) { + case XEventLevel::TYPE_LOAD_BEGIN: + m_pLightSystem->setEnabled(false); + break; + case XEventLevel::TYPE_LOAD_END: XEventLevelSize levelSize; m_pLevelSizeChannel->broadcastEvent(&levelSize); m_pLightSystem->setLevelSize(levelSize.vMin, levelSize.vMax); + + m_pLightSystem->setEnabled(true); break; } } @@ -413,6 +419,11 @@ void XMETHODCALLTYPE CLightSystem::updateVisibility() { assert(m_pMainCamera); + if(!m_isEnabled) + { + return; + } + float3 vCamPos; m_pMainCamera->getPosition(&vCamPos); float3 vCamDir; @@ -492,6 +503,11 @@ void XMETHODCALLTYPE CLightSystem::setRenderPipeline(IXRenderPipeline *pRenderPi void XMETHODCALLTYPE CLightSystem::renderGI(IGXTexture2D *pLightTotal, IGXTexture2D *pTempBuffer) { + if(!m_isEnabled) + { + return; + } + IGXContext *pCtx = m_pDevice->getThreadContext(); IGXDepthStencilSurface *pOldDSSurface = pCtx->getDepthStencilSurface(); diff --git a/source/light/LightSystem.h b/source/light/LightSystem.h index 1be91aa3eccd91e8864e3badfac99c18f175a1fd..bfd88491d1a748060722ee414cca173f8a35218c 100644 --- a/source/light/LightSystem.h +++ b/source/light/LightSystem.h @@ -47,6 +47,11 @@ public: void XMETHODCALLTYPE renderToneMapping(IGXTexture2D *pSourceLight) override; void XMETHODCALLTYPE renderDebug() override; + void setEnabled(bool set) + { + m_isEnabled = set; + } + protected: void showGICubes(); @@ -175,6 +180,8 @@ protected: IGXTexture2D *m_pLightLuminance1 = NULL; IGXTexture2D *m_pAdaptedLuminance[2]; UINT m_uCurrAdaptedLuminanceTarget = 0; + + bool m_isEnabled = true; }; #endif diff --git a/source/terrax/mainWindow.cpp b/source/terrax/mainWindow.cpp index 4107d9ed22535d9ab76ea382c3dc4e031cb23717..1a70c5e5e2d11ca1c3a3bf6f93c529c086141801 100644 --- a/source/terrax/mainWindow.cpp +++ b/source/terrax/mainWindow.cpp @@ -1307,6 +1307,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case ID_FILE_EXIT: PostMessage(hWnd, WM_CLOSE, 0, 0); break; + + case ID_LEVEL_RUN: + g_pEngine->getCore()->getConsole()->execCommand("run_level"); + break; } break; diff --git a/source/terrax/resource.h b/source/terrax/resource.h index 517c8900907cc0402bb88d5709184c79f2854b50..0598f6e2c8ac8743f096b5b4d4d612c1a66af56f 100644 Binary files a/source/terrax/resource.h and b/source/terrax/resource.h differ diff --git a/source/terrax/terrax.cpp b/source/terrax/terrax.cpp index 26b466eb8d510e7807954cfc08971483a8cb2cc0..7254332892f6cbe2c14fde2ff3531ccc7bcf48d5 100644 --- a/source/terrax/terrax.cpp +++ b/source/terrax/terrax.cpp @@ -83,8 +83,70 @@ class CEngineCallback: public IXEngineCallback public: void XMETHODCALLTYPE onGraphicsResize(UINT uWidth, UINT uHeight, bool isFullscreen, bool isBorderless, IXEngine *pEngine) override { - XReleaseViewports(); - XInitViewports(); + static const bool *terrax_detach_3d = NULL; + if(!terrax_detach_3d && m_pCore) + { + terrax_detach_3d = m_pCore->getConsole()->getPCVarBool("terrax_detach_3d"); + } + + if(terrax_detach_3d && *terrax_detach_3d) + { + RECT rc = {0, 0, (int)uWidth, (int)uHeight}; + + HMONITOR monitor = MonitorFromWindow(g_hTopLeftWnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(monitor, &info); + bool bForceNoBorder = (rc.right - rc.left == info.rcMonitor.right - info.rcMonitor.left + && rc.bottom - rc.top == info.rcMonitor.bottom - info.rcMonitor.top); + + + SetClassLong(g_hTopLeftWnd, GCL_STYLE, GetClassLong(g_hTopLeftWnd, GCL_STYLE) | CS_NOCLOSE); + + DWORD wndStyle = GetWindowLong(g_hTopLeftWnd, GWL_STYLE) | WS_MINIMIZEBOX | WS_SYSMENU; + + if(isFullscreen || isBorderless || bForceNoBorder) + { + wndStyle &= ~(WS_SYSMENU | WS_CAPTION | WS_MAXIMIZE | WS_MINIMIZE | WS_THICKFRAME); + } + else + { + wndStyle |= WS_CAPTION | WS_THICKFRAME; + wndStyle &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX); + } + + SetWindowLong(g_hTopLeftWnd, GWL_STYLE, wndStyle); + + + AdjustWindowRect(&rc, wndStyle, false); + + UINT uSWPflags = SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER; + + + int iPosX = 0; + int iPosY = 0; + if(!(isFullscreen || isBorderless)) + { + iPosX = (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2; + iPosY = (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2; + } + RECT rcOld; + GetWindowRect(g_hTopLeftWnd, &rcOld); + + + if(rcOld.right - rcOld.left != rc.right - rc.left || rcOld.bottom - rcOld.top != rc.bottom - rc.top) + { + uSWPflags &= ~SWP_NOSIZE; + //SetWindowPos(m_hWnd, HWND_TOP, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); + } + + SetWindowPos(g_hTopLeftWnd, HWND_TOP, iPosX, iPosY, rc.right - rc.left, rc.bottom - rc.top, uSWPflags); + } + else + { + XReleaseViewports(); + XInitViewports(); + } } bool XMETHODCALLTYPE processWindowMessages() override @@ -236,10 +298,22 @@ public: ICamera* XMETHODCALLTYPE getCameraForFrame() override { + static const bool *terrax_detach_3d = m_pCore->getConsole()->getPCVarBool("terrax_detach_3d"); + if(*terrax_detach_3d) + { + return(SGame_GetActiveCamera()); + } + return(g_xConfig.m_pViewportCamera[XWP_TOP_LEFT]); } + void setCore(IXCore *pCore) + { + m_pCore = pCore; + } + protected: + IXCore *m_pCore = NULL; }; class CRenderPipeline: public IXUnknownImplementation<IXRenderPipeline> @@ -284,6 +358,13 @@ public: void renderFrame(float fDeltaTime) override { m_pOldPipeline->renderFrame(fDeltaTime); + + static const bool *terrax_detach_3d = m_pCore->getConsole()->getPCVarBool("terrax_detach_3d"); + + if(*terrax_detach_3d) + { + return; + } IGXContext *pDXDevice = getDevice()->getThreadContext(); pDXDevice->setDepthStencilState(g_pDSDefault); @@ -384,8 +465,22 @@ public: { m_pOldPipeline->updateVisibility(); + static const bool *terrax_detach_3d = m_pCore->getConsole()->getPCVarBool("terrax_detach_3d"); + + if(*terrax_detach_3d) + { + return; + } + + HWND hWnds[] = {g_hTopRightWnd, g_hBottomLeftWnd, g_hBottomRightWnd}; + for(UINT i = 0; i < 3; ++i) { + if(!IsWindowVisible(hWnds[i])) + { + continue; + } + m_pCameraVisibility[i + 1]->updateForCamera(g_xConfig.m_pViewportCamera[i + 1]); } } @@ -449,6 +544,55 @@ public: IXRenderableVisibility *m_pCameraVisibility[4]; }; +class CCVarEventListener: public IEventListener<XEventCvarChanged> +{ +public: + CCVarEventListener(IXCore *pCore): + m_pCore(pCore) + {} + void onEvent(const XEventCvarChanged *pEvent) override + { + static const bool *terrax_detach_3d = m_pCore->getConsole()->getPCVarBool("terrax_detach_3d"); + + if(terrax_detach_3d == pEvent->pCvar) + { + if(*terrax_detach_3d) + { + ShowWindow(g_hTopLeftWnd, SW_HIDE); + m_lOldStyle = GetWindowLongA(g_hTopLeftWnd, GWL_STYLE); + SetParent(g_hTopLeftWnd, NULL); + SetWindowLongA(g_hTopLeftWnd, GWL_STYLE, WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + SetWindowTextA(g_hTopLeftWnd, "SkyXEngine"); + + m_lOldExStyle = GetWindowLongA(g_hTopLeftWnd, GWL_EXSTYLE); + SetWindowLongA(g_hTopLeftWnd, GWL_EXSTYLE, 0); + + SetWindowPos(g_hTopLeftWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); + + EnableWindow(g_hWndMain, FALSE); + } + else + { + EnableWindow(g_hWndMain, TRUE); + + ShowWindow(g_hTopLeftWnd, SW_HIDE); + SetParent(g_hTopLeftWnd, g_hWndMain); + SetWindowLongA(g_hTopLeftWnd, GWL_STYLE, m_lOldStyle); + SetWindowLongA(g_hTopLeftWnd, GWL_EXSTYLE, m_lOldExStyle); + SetWindowPos(g_hTopLeftWnd, HWND_TOP, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); + PostMessage(g_hWndMain, WM_SIZE, 0, 0); + + ShowCursor(TRUE); + } + } + } + +private: + IXCore *m_pCore; + LONG m_lOldStyle; + LONG m_lOldExStyle; +}; + #if defined(_WINDOWS) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { @@ -481,11 +625,17 @@ int main(int argc, char **argv) g_pEngine = pEngine; CEngineCallback engineCb; pEngine->initGraphics((XWINDOW_OS_HANDLE)g_hTopLeftWnd, &engineCb); + engineCb.setCore(pEngine->getCore()); + pEngine->getCore()->getConsole()->registerCVar("terrax_detach_3d", false, "", FCVAR_NOTIFY); pEngine->getCore()->getConsole()->execCommand("gmode editor"); pEngine->getCore()->getConsole()->execCommand("exec ../config_editor.cfg"); CRenderPipeline *pPipeline = new CRenderPipeline(Core_GetIXCore()); XInitGuiWindow(false); + CCVarEventListener cvarListener(pEngine->getCore()); + auto *pChannel = pEngine->getCore()->getEventChannel<XEventCvarChanged>(EVENT_CVAR_CHANGED_GUID); + pChannel->addListener(&cvarListener); + RECT rcTopLeft; GetClientRect(g_hTopLeftWnd, &rcTopLeft); @@ -890,6 +1040,8 @@ int main(int argc, char **argv) } XReleaseViewports(); + pChannel->removeListener(&cvarListener); + mem_release(g_pDashedMaterial); mem_release(g_pDSNoZ); mem_release(g_pDSDefault); diff --git a/source/terrax/terrax.rc b/source/terrax/terrax.rc index 5d28e5830d0cfdb2425ede311dd3c18348908b04..01c8a740f5570fc68ad10939428f6ea57e0a2acb 100644 Binary files a/source/terrax/terrax.rc and b/source/terrax/terrax.rc differ