From 1ca15f3b97aeaa80aa160e7317018834d70a7ffc Mon Sep 17 00:00:00 2001 From: D-AIRY <admin@ds-servers.com> Date: Mon, 29 Jun 2020 19:34:11 +0300 Subject: [PATCH] TerraX Copypaste --- build/config_editor.cfg | 2 +- proj/terrax/vs2013/terrax.vcxproj | 2 + proj/terrax/vs2013/terrax.vcxproj.filters | 6 + source/core/Config.cpp | 17 +- source/core/Config.h | 2 + source/game/EditorObject.cpp | 1 + source/geom/plugin_main.cpp | 138 ++++++++++- source/terrax/CommandDelete.cpp | 2 +- source/terrax/CommandPaste.cpp | 96 ++++++++ source/terrax/CommandPaste.h | 44 ++++ source/terrax/CommandProperties.cpp | 4 +- source/terrax/mainWindow.cpp | 288 +++++++++++++++++++++- source/xcommon/IXConfig.h | 2 + source/xcommon/editor/IXEditorObject.h | 1 + 14 files changed, 589 insertions(+), 16 deletions(-) create mode 100644 source/terrax/CommandPaste.cpp create mode 100644 source/terrax/CommandPaste.h diff --git a/build/config_editor.cfg b/build/config_editor.cfg index 4fb54a4de..1f0c7fee8 100644 --- a/build/config_editor.cfg +++ b/build/config_editor.cfg @@ -2,7 +2,7 @@ echo "Executing editor config file" cl_mode_editor 1 -dbg_config_save 1 +// dbg_config_save 1 r_stats 2 diff --git a/proj/terrax/vs2013/terrax.vcxproj b/proj/terrax/vs2013/terrax.vcxproj index 9afc56dd3..667772490 100644 --- a/proj/terrax/vs2013/terrax.vcxproj +++ b/proj/terrax/vs2013/terrax.vcxproj @@ -206,6 +206,7 @@ <ClCompile Include="..\..\..\source\terrax\CommandCreate.cpp" /> <ClCompile Include="..\..\..\source\terrax\CommandDelete.cpp" /> <ClCompile Include="..\..\..\source\terrax\CommandMove.cpp" /> + <ClCompile Include="..\..\..\source\terrax\CommandPaste.cpp" /> <ClCompile Include="..\..\..\source\terrax\CommandProperties.cpp" /> <ClCompile Include="..\..\..\source\terrax\CommandRotate.cpp" /> <ClCompile Include="..\..\..\source\terrax\CommandScale.cpp" /> @@ -232,6 +233,7 @@ <ClInclude Include="..\..\..\source\terrax\CommandCreate.h" /> <ClInclude Include="..\..\..\source\terrax\CommandDelete.h" /> <ClInclude Include="..\..\..\source\terrax\CommandMove.h" /> + <ClInclude Include="..\..\..\source\terrax\CommandPaste.h" /> <ClInclude Include="..\..\..\source\terrax\CommandProperties.h" /> <ClInclude Include="..\..\..\source\terrax\CommandRotate.h" /> <ClInclude Include="..\..\..\source\terrax\CommandScale.h" /> diff --git a/proj/terrax/vs2013/terrax.vcxproj.filters b/proj/terrax/vs2013/terrax.vcxproj.filters index 5a19fdacb..eaee64362 100644 --- a/proj/terrax/vs2013/terrax.vcxproj.filters +++ b/proj/terrax/vs2013/terrax.vcxproj.filters @@ -90,6 +90,9 @@ <ClCompile Include="..\..\..\source\terrax\Tools.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\terrax\CommandPaste.cpp"> + <Filter>Source Files\cmd</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\terrax\terrax.rc"> @@ -166,6 +169,9 @@ <ClInclude Include="..\..\..\source\terrax\Tools.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\terrax\CommandPaste.h"> + <Filter>Header Files\cmd</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Image Include="..\..\..\source\terrax\resource\new.bmp"> diff --git a/source/core/Config.cpp b/source/core/Config.cpp index 711eea85f..a89165180 100644 --- a/source/core/Config.cpp +++ b/source/core/Config.cpp @@ -816,7 +816,18 @@ void CConfig::clear() m_vIncludes.clear(); m_mFinalValues.clear(); m_mSections.clear(); - BaseFile = "\0"; + BaseFile = ""; +} +void CConfig::clear2() +{ + auto tmp = BaseFile; + clear(); + BaseFile = tmp; + FILE *pF = fopen(BaseFile.c_str(), "wb"); + if(pF) + { + fclose(pF); + } } AssotiativeArray<CConfigString, CConfig::CSection> * CConfig::getSections() @@ -852,6 +863,10 @@ bool XMETHODCALLTYPE CXConfig::save() { return(m_pConfig->save() == 0); } +void XMETHODCALLTYPE CXConfig::clear() +{ + m_pConfig->clear2(); +} const char* XMETHODCALLTYPE CXConfig::getKey(const char *szSection, const char *szKey) { diff --git a/source/core/Config.h b/source/core/Config.h index 340005725..637230bf8 100644 --- a/source/core/Config.h +++ b/source/core/Config.h @@ -110,6 +110,7 @@ public: void Release(); void clear(); + void clear2(); AssotiativeArray<CConfigString, CSection> * getSections(); @@ -160,6 +161,7 @@ public: bool XMETHODCALLTYPE open(const char *szPath) override; bool XMETHODCALLTYPE save() override; + void XMETHODCALLTYPE clear() override; const char* XMETHODCALLTYPE getKey(const char *szSection, const char *szKey) override; const char* XMETHODCALLTYPE getKeyName(const char *szSection, UINT uIndex) override; diff --git a/source/game/EditorObject.cpp b/source/game/EditorObject.cpp index cd636ff5b..11199d637 100644 --- a/source/game/EditorObject.cpp +++ b/source/game/EditorObject.cpp @@ -94,6 +94,7 @@ void CEditorObject::_iniFieldList() xField.szHelp = ""; xField.szKey = pField->szKey; xField.szName = pField->szEdName; + xField.isGeneric = !fstrcmp(pField->szKey, "origin") || !fstrcmp(pField->szKey, "rotation") || !fstrcmp(pField->szKey, "scale"); m_aFields.push_back(xField); } diff --git a/source/geom/plugin_main.cpp b/source/geom/plugin_main.cpp index 1245f35a9..cb9fc1bf6 100644 --- a/source/geom/plugin_main.cpp +++ b/source/geom/plugin_main.cpp @@ -14,6 +14,14 @@ //! версия формата файла статики #define SX_GEOM_FILE_FORMAT_VERSION 1 +struct vertex_static +{ + float3_t Pos; /*!< Позиция */ + float2_t Tex; /*!< Текстурные координаты */ + float3_t Norm; /*!< Нормаль */ +}; + + class CLevelLoadListener: public IEventListener<XEventLevel> { public: @@ -61,6 +69,130 @@ public: } } + // https://dev.ds-servers.com/sip/engine/-/blob/8306303dda397cb047048559a29ea8051822fa04/source/geom/static_geom.cpp + bool loadOld(FILE *pFile) + { + int32_t countgroup = -1; + fread(&countgroup, sizeof(int32_t), 1, pFile); + + for(int i = 0; i < countgroup; ++i) + { + int32_t tmpstrlen; + fread(&tmpstrlen, sizeof(int32_t), 1, pFile); + fseek(pFile, sizeof(char) * tmpstrlen, SEEK_CUR); + + //записываем количество буферов в подгруппе + int32_t countbuffingroup = -1; + fread(&countbuffingroup, sizeof(int32_t), 1, pFile); + + for(int k = 0; k < countbuffingroup; ++k) + { + //записываем количество моделей, которые используют данную подгруппу + int32_t countusingmodels; + fread(&countusingmodels, sizeof(int32_t), 1, pFile); + for(int j = 0; j < countusingmodels; ++j) + { + fseek(pFile, sizeof(int32_t), SEEK_CUR); + } + + int32_t iCountVertex, iCountIndex; + + fread(&iCountVertex, sizeof(int32_t), 1, pFile); + fread(&iCountIndex, sizeof(int32_t), 1, pFile); + + fseek(pFile, sizeof(vertex_static)* iCountVertex, SEEK_CUR); + } + } + + int32_t countmodels; + fread(&countmodels, sizeof(int32_t), 1, pFile); + + for(int i = 0; i < countmodels; ++i) + { + int32_t countsubset; + fread(&countsubset, sizeof(int32_t), 1, pFile); + + CBaseEntity *pEntity = SGame_CreateEntity("prop_static"); + + int32_t iStrLen = 0; + char szStr[1024]; + + fread(&iStrLen, sizeof(int32_t), 1, pFile); + fread(szStr, sizeof(char), iStrLen, pFile); + szStr[iStrLen] = 0; + pEntity->setKV("name", szStr); + + fread(&iStrLen, sizeof(int32_t), 1, pFile); + strcpy(szStr, "meshes/"); + fread(szStr + 7, sizeof(char), iStrLen, pFile); + szStr[iStrLen + 7] = 0; + pEntity->setKV("model", szStr); + + int32_t iCountPoly; + fread(&iCountPoly, sizeof(int32_t), 1, pFile); + + //считываем трансформации + //{ + float3 vPosition, vRotation, vScale; + fread(&(vPosition.x), sizeof(float), 1, pFile); + fread(&(vPosition.y), sizeof(float), 1, pFile); + fread(&(vPosition.z), sizeof(float), 1, pFile); + pEntity->setPos(vPosition); + + fread(&(vRotation.x), sizeof(float), 1, pFile); + fread(&(vRotation.y), sizeof(float), 1, pFile); + fread(&(vRotation.z), sizeof(float), 1, pFile); + pEntity->setOrient(SMQuaternion(-vRotation.x, 'x') * SMQuaternion(-vRotation.y, 'y') * SMQuaternion(-vRotation.z, 'z')); + + fread(&(vScale.x), sizeof(float), 1, pFile); + fread(&(vScale.y), sizeof(float), 1, pFile); + fread(&(vScale.z), sizeof(float), 1, pFile); + sprintf_s(szStr, "%f", vScale.y); + pEntity->setKV("scale", szStr); + //} + + pEntity->setKV("use_trimesh", "1"); + + fread(&iStrLen, sizeof(int32_t), 1, pFile); + if(iStrLen > 0) + { + fseek(pFile, sizeof(char) * iStrLen, SEEK_SET); + } + + + pEntity->setFlags(pEntity->getFlags() | EF_LEVEL | EF_EXPORT); +#if 0 + for(int k = 0; k < countsubset; ++k) + { + CModel::CSubSet gdb; + fread(&gdb, sizeof(CModel::CSubSet), 1, file); + m_aAllModels[i]->m_aSubSets.push_back(gdb); + + char tmptex[1024]; + sprintf(tmptex, "%s.dds", m_aAllGroups[gdb.m_idGroup]->m_sName.c_str()); + m_aAllModels[i]->m_aIDsTexures[k] = SGCore_MtlLoad(tmptex, MTL_TYPE_GEOM); + } + + Array<CSegment**> queue; + int tmpcount = 0; + queue.push_back(&(m_aAllModels[i]->m_pArrSplits)); + + while(queue.size()) + { + loadSplit(queue[0], file, &queue); + + queue.erase(0); + ++tmpcount; + } +#endif + + break; + } + + + return(false); + } + void loadLevel(const char *szPath) { FILE *pFile = fopen(szPath, "rb"); @@ -79,7 +211,11 @@ public: if(ui64Magic != SX_GEOM_MAGIC_NUM) { - LibReport(REPORT_MSG_LEVEL_ERROR, "file static geometry [%s] is not static geometry\n", szPath); + fseek(pFile, 0, SEEK_SET); + if(!loadOld(pFile)) + { + LibReport(REPORT_MSG_LEVEL_ERROR, "file static geometry [%s] is not static geometry\n", szPath); + } fclose(pFile); return; } diff --git a/source/terrax/CommandDelete.cpp b/source/terrax/CommandDelete.cpp index f557a0e01..3da0d717c 100644 --- a/source/terrax/CommandDelete.cpp +++ b/source/terrax/CommandDelete.cpp @@ -28,7 +28,7 @@ bool CCommandDelete::undo() pObj->pObject->setOrient(pObj->qRotate); pObj->pObject->preSetup(); - for(auto i = pObj->mKeyValues.begin(); i; i++) + for(auto i = pObj->mKeyValues.begin(); i; ++i) { pObj->pObject->setKV(i.first->c_str(), i.second->c_str()); } diff --git a/source/terrax/CommandPaste.cpp b/source/terrax/CommandPaste.cpp new file mode 100644 index 000000000..badb08bc2 --- /dev/null +++ b/source/terrax/CommandPaste.cpp @@ -0,0 +1,96 @@ +#include "CommandPaste.h" +#include <common/aastring.h> + +extern AssotiativeArray<AAString, IXEditable*> g_mEditableSystems; + +bool CCommandPaste::exec() +{ + if(!m_pCommandSelect) + { + m_pCommandSelect = new CCommandSelect(); + + for(UINT i = 0, l = g_pLevelObjects.size(); i < l; ++i) + { + if(g_pLevelObjects[i]->isSelected()) + { + m_pCommandSelect->addDeselected(i); + } + } + } + + m_pCommandSelect->exec(); + + _paste_obj *pObj; + for(UINT i = 0, l = m_aObjects.size(); i < l; ++i) + { + pObj = &m_aObjects[i]; + + pObj->pObject->setSelected(true); + pObj->pObject->create(); + + pObj->pObject->setPos(pObj->vPos); + pObj->pObject->setScale(pObj->vScale); + pObj->pObject->setOrient(pObj->qRotate); + pObj->pObject->preSetup(); + for(auto i = pObj->mKeyValues.begin(); i; ++i) + { + pObj->pObject->setKV(i.first->c_str(), i.second->c_str()); + } + pObj->pObject->postSetup(); + + g_pLevelObjects.push_back(pObj->pObject); + } + XUpdatePropWindow(); + return(m_aObjects.size()); +} +bool CCommandPaste::undo() +{ + _paste_obj *pObj; + for(int i = m_aObjects.size() - 1; i >= 0; --i) + { + pObj = &m_aObjects[i]; + + pObj->pObject->remove(); + g_pLevelObjects.erase(g_pLevelObjects.size() - 1); + } + + m_pCommandSelect->undo(); + + XUpdatePropWindow(); + return(true); +} + +CCommandPaste::~CCommandPaste() +{ + for(UINT i = 0, l = m_aObjects.size(); i < l; ++i) + { + mem_release(m_aObjects[i].pObject); + } + mem_delete(m_pCommandSelect); +} + +UINT CCommandPaste::addObject(const char *szTypeName, const char *szClassName, const float3 &vPos, const float3 &vScale, const SMQuaternion &qRotate) +{ + const AssotiativeArray<AAString, IXEditable*>::Node *pNode; + if(!g_mEditableSystems.KeyExists(AAString(szTypeName), &pNode)) + { + LibReport(REPORT_MSG_LEVEL_ERROR, "Unknown object type %s, skipping!", szTypeName); + return(~0u); + } + + _paste_obj obj; + obj.pObject = (*(pNode->Val))->newObject(szClassName); + obj.vPos = vPos; + obj.vScale = vScale; + obj.qRotate = qRotate; + + m_aObjects.push_back(obj); + + return(m_aObjects.size() - 1); +} +void CCommandPaste::setKV(UINT uId, const char *szKey, const char *szValue) +{ + assert(uId < m_aObjects.size()); + + m_aObjects[uId].mKeyValues[szKey] = szValue; +} diff --git a/source/terrax/CommandPaste.h b/source/terrax/CommandPaste.h new file mode 100644 index 000000000..0f898fb20 --- /dev/null +++ b/source/terrax/CommandPaste.h @@ -0,0 +1,44 @@ +#ifndef _COMMAND_PASTE_H_ +#define _COMMAND_PASTE_H_ + +#include "Command.h" +#include "terrax.h" + +#include <common/assotiativearray.h> +#include <common/string.h> +#include <xcommon/editor/IXEditable.h> +#include "CommandSelect.h" + +class CCommandPaste: public CCommand +{ +public: + ~CCommandPaste(); + + bool exec(); + bool undo(); + + const char *getText() + { + return("paste"); + } + + UINT addObject(const char *szTypeName, const char *szClassName, const float3 &vPos, const float3 &vScale, const SMQuaternion &qRotate); + void setKV(UINT uId, const char *szKey, const char *szValue); + +protected: + struct _paste_obj + { + // ID idObject; + IXEditorObject *pObject; + AssotiativeArray<String, String> mKeyValues; + + float3_t vPos; + float3_t vScale; + SMQuaternion qRotate; + }; + Array<_paste_obj> m_aObjects; + + CCommandSelect *m_pCommandSelect = NULL; +}; + +#endif diff --git a/source/terrax/CommandProperties.cpp b/source/terrax/CommandProperties.cpp index 2949037de..12cd978aa 100644 --- a/source/terrax/CommandProperties.cpp +++ b/source/terrax/CommandProperties.cpp @@ -8,7 +8,7 @@ bool CCommandProperties::exec() pObj = &m_aObjects[j]; pObj->pObject->preSetup(); - for(auto i = pObj->mKeyValues.begin(); i; i++) + for(auto i = pObj->mKeyValues.begin(); i; ++i) { if(i.second->isChanged) { @@ -28,7 +28,7 @@ bool CCommandProperties::undo() pObj = &m_aObjects[j]; pObj->pObject->preSetup(); - for(auto i = pObj->mKeyValues.begin(); i; i++) + for(auto i = pObj->mKeyValues.begin(); i; ++i) { if(i.second->isChanged) { diff --git a/source/terrax/mainWindow.cpp b/source/terrax/mainWindow.cpp index 2c15065db..4107d9ed2 100644 --- a/source/terrax/mainWindow.cpp +++ b/source/terrax/mainWindow.cpp @@ -36,9 +36,13 @@ #include "CommandDelete.h" #include "CommandCreate.h" #include "CommandProperties.h" +#include "CommandPaste.h" #include "PropertyWindow.h" +#define CLIPBOARD_FILE "TerraX.clipboard" +char g_szClipboardFile[MAX_PATH + sizeof(CLIPBOARD_FILE)]; + #include <gui/guimain.h> extern Array<IXEditorObject*> g_pLevelObjects; @@ -297,7 +301,10 @@ BOOL XInitInstance(HINSTANCE hInstance, int nCmdShow) XCheckMenuItem(g_hMenu, ID_VIEW_GRID, g_xConfig.m_bShowGrid); - return TRUE; + GetTempPathA(sizeof(g_szClipboardFile), g_szClipboardFile); + strcat(g_szClipboardFile, CLIPBOARD_FILE); + + return(TRUE); } bool IsEditMessage() @@ -387,6 +394,256 @@ LRESULT CALLBACK StatusBarWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM return(CallWindowProc(g_pfnStatusBarOldWndproc, hWnd, message, wParam, lParam)); } +static void DeleteSelection() +{ + CCommandDelete *pDelCmd = new CCommandDelete(); + for(UINT i = 0, l = g_pLevelObjects.size(); i < l; ++i) + { + if(g_pLevelObjects[i]->isSelected()) + { + pDelCmd->addObject(i); + } + } + XExecCommand(pDelCmd); +} + +static void ToClipboard(bool isCut = false) +{ + IXConfig *pConfig = g_pEngine->getCore()->newConfig(); + pConfig->open(g_szClipboardFile); + pConfig->clear(); + + UINT uCount = 0; + char szSection[64], szTmp[64]; + + for(UINT i = 0, l = g_pLevelObjects.size(); i < l; ++i) + { + IXEditorObject *pObj = g_pLevelObjects[i]; + if(pObj->isSelected()) + { + sprintf(szSection, "obj_%u_type", uCount); + pConfig->set("meta", szSection, pObj->getTypeName()); + + sprintf(szSection, "obj_%u_class", uCount); + pConfig->set("meta", szSection, pObj->getClassName()); + + float3_t vTmp = pObj->getPos(); + sprintf(szSection, "obj_%u_pos", uCount); + sprintf(szTmp, "%f %f %f", vTmp.x, vTmp.y, vTmp.z); + pConfig->set("meta", szSection, szTmp); + + vTmp = pObj->getScale(); + sprintf(szSection, "obj_%u_scale", uCount); + sprintf(szTmp, "%f %f %f", vTmp.x, vTmp.y, vTmp.z); + pConfig->set("meta", szSection, szTmp); + + SMQuaternion qTmp = pObj->getOrient(); + sprintf(szSection, "obj_%u_orient", uCount); + sprintf(szTmp, "%f %f %f %f", qTmp.x, qTmp.y, qTmp.z, qTmp.w); + pConfig->set("meta", szSection, szTmp); + + sprintf(szSection, "obj_%u", uCount); + + + for(UINT i = 0, l = pObj->getProperyCount(); i < l; ++i) + { + const X_PROP_FIELD *pField = pObj->getPropertyMeta(i); + + if(!pField->isGeneric) + { + pConfig->set(szSection, pField->szKey, pObj->getKV(pField->szKey)); + } + } + + ++uCount; + } + } + + sprintf(szSection, "%u", uCount); + pConfig->set("meta", "count", szSection); + + sprintf(szSection, "%f %f %f", g_xState.vSelectionBoundMin.x, g_xState.vSelectionBoundMin.y, g_xState.vSelectionBoundMin.z); + pConfig->set("meta", "aabb_min", szSection); + sprintf(szSection, "%f %f %f", g_xState.vSelectionBoundMax.x, g_xState.vSelectionBoundMax.y, g_xState.vSelectionBoundMax.z); + pConfig->set("meta", "aabb_max", szSection); + + pConfig->save(); + mem_release(pConfig); + + if(isCut) + { + DeleteSelection(); + } +} + +static float GetPasteCenter(char axis, X_WINDOW_POS skipPos) +{ + for(UINT i = 0; i < 4; ++i) + { + if(i != skipPos) + { + X_2D_VIEW x2dView = g_xConfig.m_x2DView[i]; + float3 vCamPos; + g_xConfig.m_pViewportCamera[i]->getPosition(&vCamPos); + switch(axis) + { + case 'x': + if(x2dView == X2D_TOP || x2dView == X2D_FRONT) + { + return(vCamPos.x); + } + break; + + case 'y': + if(x2dView == X2D_FRONT || x2dView == X2D_SIDE) + { + return(vCamPos.y); + } + break; + + case 'z': + if(x2dView == X2D_TOP || x2dView == X2D_SIDE) + { + return(vCamPos.z); + } + break; + + default: + assert(!"Invalid axis"); + } + } + } + + return(0.0f); +} + +static float3 GetPasteCenter() +{ + X_2D_VIEW x2dView = g_xConfig.m_x2DView[g_xState.activeWindow]; + + float3 vPos; + + switch(x2dView) + { + case X2D_TOP: + vPos.x = g_xState.vWorldMousePos.x; + vPos.y = GetPasteCenter('y', g_xState.activeWindow); + vPos.z = g_xState.vWorldMousePos.y; + break; + + case X2D_FRONT: + vPos.x = g_xState.vWorldMousePos.x; + vPos.y = g_xState.vWorldMousePos.y; + vPos.z = GetPasteCenter('z', g_xState.activeWindow); + break; + + case X2D_SIDE: + vPos.x = GetPasteCenter('x', g_xState.activeWindow); + vPos.y = g_xState.vWorldMousePos.y; + vPos.z = g_xState.vWorldMousePos.x; + break; + + default: + vPos.x = GetPasteCenter('x', XWP_TOP_LEFT); + vPos.y = GetPasteCenter('y', XWP_TOP_LEFT); + vPos.z = GetPasteCenter('z', XWP_TOP_LEFT); + break; + } + + return(vPos); +} + +static void FromClipboard() +{ + IXConfig *pConfig = g_pEngine->getCore()->newConfig(); + if(pConfig->open(g_szClipboardFile)) + { + const char *szVal = pConfig->getKey("meta", "count"); + if(szVal) + { + UINT uCount = 0; + sscanf(szVal, "%u", &uCount); + + SMAABB aabb; + + szVal = pConfig->getKey("meta", "aabb_min"); + if(szVal) + { + sscanf(szVal, "%f %f %f", &aabb.vMin.x, &aabb.vMin.y, &aabb.vMin.z); + } + szVal = pConfig->getKey("meta", "aabb_max"); + if(szVal) + { + sscanf(szVal, "%f %f %f", &aabb.vMax.x, &aabb.vMax.y, &aabb.vMax.z); + } + + aabb.vMax = SMVectorMax(aabb.vMin, aabb.vMax); + float3 vClipboardCenter = (aabb.vMin + aabb.vMax) * 0.5f; + float3 vPasteCenter = GetPasteCenter(); + float3 vDelta = vPasteCenter - vClipboardCenter; + + float3 vPos, vScale; + SMQuaternion qRot; + + CCommandPaste *pCmd = new CCommandPaste(); + + char szSection[64]; + for(UINT i = 0; i < uCount; ++i) + { + sprintf(szSection, "obj_%u_type", i); + const char *szTypeName = pConfig->getKey("meta", szSection); + sprintf(szSection, "obj_%u_class", i); + const char *szClassName = pConfig->getKey("meta", szSection); + + if(!szTypeName || !szClassName) + { + continue; + } + + sprintf(szSection, "obj_%u_pos", i); + const char *szTmp = pConfig->getKey("meta", szSection); + if(szTmp) + { + sscanf(szTmp, "%f %f %f", &vPos.x, &vPos.y, &vPos.z); + } + + sprintf(szSection, "obj_%u_scale", i); + szTmp = pConfig->getKey("meta", szSection); + if(szTmp) + { + sscanf(szTmp, "%f %f %f", &vScale.x, &vScale.y, &vScale.z); + } + + sprintf(szSection, "obj_%u_orient", i); + szTmp = pConfig->getKey("meta", szSection); + if(szTmp) + { + sscanf(szTmp, "%f %f %f %f", &qRot.x, &qRot.y, &qRot.z, &qRot.w); + } + + sprintf(szSection, "obj_%u", i); + + + UINT uObj = pCmd->addObject(szTypeName, szClassName, vPos + vDelta, vScale, qRot); + + for(UINT j = 0, jl = pConfig->getKeyCount(szSection); j < jl; ++j) + { + const char *szKey = pConfig->getKeyName(szSection, j); + const char *szValue = pConfig->getKey(szSection, szKey); + + pCmd->setKV(uObj, szKey, szValue); + } + } + + XExecCommand(pCmd); + } + } + + // create objects + + mem_release(pConfig); +} + LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rect; @@ -654,6 +911,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) EnableMenuItem(hMenu, ID_EDIT_UNDO, MF_ENABLED); EnableMenuItem(hMenu, ID_EDIT_REDO, MF_ENABLED); } + else + { + bool hasSelection = g_xState.bHasSelection; + + HMENU hMenu = (HMENU)wParam; + EnableMenuItem(hMenu, ID_EDIT_CUT, hasSelection ? MF_ENABLED : MF_DISABLED); + EnableMenuItem(hMenu, ID_EDIT_COPY, hasSelection ? MF_ENABLED : MF_DISABLED); + EnableMenuItem(hMenu, ID_EDIT_DELETE, hasSelection ? MF_ENABLED : MF_DISABLED); + EnableMenuItem(hMenu, ID_EDIT_PASTE, GetFileAttributesA(g_szClipboardFile) != ~0 ? MF_ENABLED : MF_DISABLED); + } XUpdateUndoRedo(); break; @@ -886,6 +1153,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(GetFocus(), WM_COPY, 0, 0); break; } + + ToClipboard(); break; case ID_EDIT_CUT: @@ -894,6 +1163,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(GetFocus(), WM_CUT, 0, 0); break; } + + ToClipboard(true); break; case ID_EDIT_PASTE: @@ -902,6 +1173,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(GetFocus(), WM_PASTE, 0, 0); break; } + else + { + FromClipboard(); + } break; case ID_EDIT_DELETE: @@ -914,15 +1189,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; } - CCommandDelete *pDelCmd = new CCommandDelete(); - for(UINT i = 0, l = g_pLevelObjects.size(); i < l; ++i) - { - if(g_pLevelObjects[i]->isSelected()) - { - pDelCmd->addObject(i); - } - } - XExecCommand(pDelCmd); + DeleteSelection(); + break; } diff --git a/source/xcommon/IXConfig.h b/source/xcommon/IXConfig.h index 589b89f89..fe3dc7c9e 100644 --- a/source/xcommon/IXConfig.h +++ b/source/xcommon/IXConfig.h @@ -22,6 +22,8 @@ public: virtual UINT XMETHODCALLTYPE getKeyCount(const char *szSection) = 0; //!< общее количество ключей в секции virtual bool XMETHODCALLTYPE sectionExists(const char *szSection) = 0; //!< существует ли секция section virtual bool XMETHODCALLTYPE keyExists(const char *szSection, const char *szKey) = 0; //!< существует ли ключ key в секции section + + virtual void XMETHODCALLTYPE clear() = 0; //!< очистить }; #endif diff --git a/source/xcommon/editor/IXEditorObject.h b/source/xcommon/editor/IXEditorObject.h index ca22814e9..3f237d8f3 100644 --- a/source/xcommon/editor/IXEditorObject.h +++ b/source/xcommon/editor/IXEditorObject.h @@ -22,6 +22,7 @@ struct X_PROP_FIELD X_PROP_EDITOR_TYPE editorType; const void *pEditorData; const char *szHelp; + bool isGeneric; }; class IXEditorObject: public IXUnknown -- GitLab