From d029fe2b877cf6ac3bf30065a2f0d056e3c97e5f Mon Sep 17 00:00:00 2001 From: luciusDXL Date: Fri, 29 Sep 2023 18:38:03 -0700 Subject: [PATCH] Cleaning up TFE_Editor/ directories and contents. --- .gitignore | 1 + TheForceEngine/TFE_Audio/MidiSynth/Source.txt | 1 + .../{ => AssetBrowser}/assetBrowser.cpp | 12 +- .../{ => AssetBrowser}/assetBrowser.h | 0 .../{ => EditorAsset}/editorAsset.cpp | 2 +- .../{ => EditorAsset}/editorAsset.h | 1 - .../{ => EditorAsset}/editorColormap.cpp | 2 +- .../{ => EditorAsset}/editorColormap.h | 0 .../{ => EditorAsset}/editorFrame.cpp | 2 +- .../{ => EditorAsset}/editorFrame.h | 0 .../{ => EditorAsset}/editorLevelPreview.cpp | 2 +- .../{ => EditorAsset}/editorLevelPreview.h | 0 .../{ => EditorAsset}/editorObj3D.cpp | 2 +- .../{ => EditorAsset}/editorObj3D.h | 0 .../{ => EditorAsset}/editorSprite.cpp | 2 +- .../{ => EditorAsset}/editorSprite.h | 0 .../{ => EditorAsset}/editorTexture.cpp | 2 +- .../{ => EditorAsset}/editorTexture.h | 0 TheForceEngine/TFE_Editor/Help/helpWindow.cpp | 115 - TheForceEngine/TFE_Editor/Help/helpWindow.h | 27 - .../TFE_Editor/Rendering/editorRender.cpp | 368 -- .../TFE_Editor/Rendering/editorRender.h | 26 - .../TFE_Editor/Rendering/grid2d.cpp | 98 - TheForceEngine/TFE_Editor/Rendering/grid2d.h | 19 - .../TFE_Editor/Rendering/grid3d.cpp | 105 - TheForceEngine/TFE_Editor/Rendering/grid3d.h | 19 - .../TFE_Editor/Rendering/lineDraw2d.cpp | 207 - .../TFE_Editor/Rendering/lineDraw2d.h | 22 - .../TFE_Editor/Rendering/lineDraw3d.cpp | 161 - .../TFE_Editor/Rendering/lineDraw3d.h | 21 - .../TFE_Editor/Rendering/trianglesColor2d.cpp | 157 - .../TFE_Editor/Rendering/trianglesColor2d.h | 23 - .../TFE_Editor/Rendering/trianglesColor3d.cpp | 326 - .../TFE_Editor/Rendering/trianglesColor3d.h | 36 - .../Rendering/trianglesTextured2d.cpp | 208 - .../Rendering/trianglesTextured2d.h | 23 - TheForceEngine/TFE_Editor/archiveViewer.cpp | 687 -- TheForceEngine/TFE_Editor/archiveViewer.h | 13 - TheForceEngine/TFE_Editor/editor.cpp | 2 +- TheForceEngine/TFE_Editor/levelEditor.cpp | 5780 ----------------- TheForceEngine/TFE_Editor/levelEditor.h | 17 - TheForceEngine/TFE_Editor/levelEditorData.cpp | 1776 ----- TheForceEngine/TFE_Editor/levelEditorData.h | 304 - TheForceEngine/TFE_Editor/perfWindow.cpp | 47 - TheForceEngine/TFE_Editor/perfWindow.h | 8 - TheForceEngine/TheForceEngine.vcxproj | 32 +- TheForceEngine/TheForceEngine.vcxproj.filters | 78 +- 47 files changed, 74 insertions(+), 10660 deletions(-) create mode 100644 TheForceEngine/TFE_Audio/MidiSynth/Source.txt rename TheForceEngine/TFE_Editor/{ => AssetBrowser}/assetBrowser.cpp (99%) rename TheForceEngine/TFE_Editor/{ => AssetBrowser}/assetBrowser.h (100%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorAsset.cpp (99%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorAsset.h (93%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorColormap.cpp (94%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorColormap.h (100%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorFrame.cpp (99%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorFrame.h (100%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorLevelPreview.cpp (98%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorLevelPreview.h (100%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorObj3D.cpp (98%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorObj3D.h (100%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorSprite.cpp (99%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorSprite.h (100%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorTexture.cpp (99%) rename TheForceEngine/TFE_Editor/{ => EditorAsset}/editorTexture.h (100%) delete mode 100644 TheForceEngine/TFE_Editor/Help/helpWindow.cpp delete mode 100644 TheForceEngine/TFE_Editor/Help/helpWindow.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/editorRender.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/editorRender.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/grid2d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/grid2d.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/grid3d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/grid3d.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/lineDraw2d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/lineDraw2d.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/lineDraw3d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/lineDraw3d.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.h delete mode 100644 TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.cpp delete mode 100644 TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.h delete mode 100644 TheForceEngine/TFE_Editor/archiveViewer.cpp delete mode 100644 TheForceEngine/TFE_Editor/archiveViewer.h delete mode 100644 TheForceEngine/TFE_Editor/levelEditor.cpp delete mode 100644 TheForceEngine/TFE_Editor/levelEditor.h delete mode 100644 TheForceEngine/TFE_Editor/levelEditorData.cpp delete mode 100644 TheForceEngine/TFE_Editor/levelEditorData.h delete mode 100644 TheForceEngine/TFE_Editor/perfWindow.cpp delete mode 100644 TheForceEngine/TFE_Editor/perfWindow.h diff --git a/.gitignore b/.gitignore index 65bc4e314..5eeb49879 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ TheForceEngine/screenshots/ TheForceEngine/Reference/ TheForceEngine/LawMaker/ TheForceEngine/Backup/ +TheForceEngine/Exports/ TheForceEngine/VTune Profiler Results/ TheForceEngine/glslang/ TheForceEngine/Documentation/blog posts/ diff --git a/TheForceEngine/TFE_Audio/MidiSynth/Source.txt b/TheForceEngine/TFE_Audio/MidiSynth/Source.txt new file mode 100644 index 000000000..631f5b074 --- /dev/null +++ b/TheForceEngine/TFE_Audio/MidiSynth/Source.txt @@ -0,0 +1 @@ +https://github.com/schellingb/TinySoundFont diff --git a/TheForceEngine/TFE_Editor/assetBrowser.cpp b/TheForceEngine/TFE_Editor/AssetBrowser/assetBrowser.cpp similarity index 99% rename from TheForceEngine/TFE_Editor/assetBrowser.cpp rename to TheForceEngine/TFE_Editor/AssetBrowser/assetBrowser.cpp index 8185db3a9..a075aadd9 100644 --- a/TheForceEngine/TFE_Editor/assetBrowser.cpp +++ b/TheForceEngine/TFE_Editor/AssetBrowser/assetBrowser.cpp @@ -1,10 +1,10 @@ #include "assetBrowser.h" -#include "editorAsset.h" -#include "editorTexture.h" -#include "editorFrame.h" -#include "editorSprite.h" -#include "editorConfig.h" -#include "editor.h" +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/assetBrowser.h b/TheForceEngine/TFE_Editor/AssetBrowser/assetBrowser.h similarity index 100% rename from TheForceEngine/TFE_Editor/assetBrowser.h rename to TheForceEngine/TFE_Editor/AssetBrowser/assetBrowser.h diff --git a/TheForceEngine/TFE_Editor/editorAsset.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorAsset.cpp similarity index 99% rename from TheForceEngine/TFE_Editor/editorAsset.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorAsset.cpp index 7d87e67a2..e781572dc 100644 --- a/TheForceEngine/TFE_Editor/editorAsset.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorAsset.cpp @@ -1,5 +1,5 @@ #include "editorAsset.h" -#include "editor.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorAsset.h b/TheForceEngine/TFE_Editor/EditorAsset/editorAsset.h similarity index 93% rename from TheForceEngine/TFE_Editor/editorAsset.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorAsset.h index ea3d3b9b5..2c679cd41 100644 --- a/TheForceEngine/TFE_Editor/editorAsset.h +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorAsset.h @@ -52,7 +52,6 @@ namespace TFE_Editor typedef u64 AssetHandle; AssetHandle loadAssetData(AssetType type, Archive* archive, const AssetColorData* colorData, const char* name); - TextureGpu* loadAssetThumbnail(AssetType type, Archive* archive, const char* name, u32 thumbnailSize); void reloadAssetData(AssetHandle handle, Archive* archive, const AssetColorData* colorData); void freeAssetData(AssetHandle handle); void* getAssetData(AssetHandle handle); diff --git a/TheForceEngine/TFE_Editor/editorColormap.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorColormap.cpp similarity index 94% rename from TheForceEngine/TFE_Editor/editorColormap.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorColormap.cpp index 72b93fc58..5b390a5a7 100644 --- a/TheForceEngine/TFE_Editor/editorColormap.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorColormap.cpp @@ -1,5 +1,5 @@ #include "editorFrame.h" -#include "editor.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorColormap.h b/TheForceEngine/TFE_Editor/EditorAsset/editorColormap.h similarity index 100% rename from TheForceEngine/TFE_Editor/editorColormap.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorColormap.h diff --git a/TheForceEngine/TFE_Editor/editorFrame.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorFrame.cpp similarity index 99% rename from TheForceEngine/TFE_Editor/editorFrame.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorFrame.cpp index fae17dc0b..80e17834a 100644 --- a/TheForceEngine/TFE_Editor/editorFrame.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorFrame.cpp @@ -1,6 +1,6 @@ #include "editorFrame.h" -#include "editor.h" #include "editorColormap.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorFrame.h b/TheForceEngine/TFE_Editor/EditorAsset/editorFrame.h similarity index 100% rename from TheForceEngine/TFE_Editor/editorFrame.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorFrame.h diff --git a/TheForceEngine/TFE_Editor/editorLevelPreview.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorLevelPreview.cpp similarity index 98% rename from TheForceEngine/TFE_Editor/editorLevelPreview.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorLevelPreview.cpp index ee7b82de6..0fb7b6095 100644 --- a/TheForceEngine/TFE_Editor/editorLevelPreview.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorLevelPreview.cpp @@ -1,6 +1,6 @@ #include "editorLevelPreview.h" -#include "editor.h" #include "editorColormap.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorLevelPreview.h b/TheForceEngine/TFE_Editor/EditorAsset/editorLevelPreview.h similarity index 100% rename from TheForceEngine/TFE_Editor/editorLevelPreview.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorLevelPreview.h diff --git a/TheForceEngine/TFE_Editor/editorObj3D.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorObj3D.cpp similarity index 98% rename from TheForceEngine/TFE_Editor/editorObj3D.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorObj3D.cpp index b0e75c4d5..3c90d4353 100644 --- a/TheForceEngine/TFE_Editor/editorObj3D.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorObj3D.cpp @@ -1,6 +1,6 @@ #include "editorObj3D.h" -#include "editor.h" #include "editorColormap.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorObj3D.h b/TheForceEngine/TFE_Editor/EditorAsset/editorObj3D.h similarity index 100% rename from TheForceEngine/TFE_Editor/editorObj3D.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorObj3D.h diff --git a/TheForceEngine/TFE_Editor/editorSprite.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorSprite.cpp similarity index 99% rename from TheForceEngine/TFE_Editor/editorSprite.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorSprite.cpp index f3e91e39d..ef3325a3c 100644 --- a/TheForceEngine/TFE_Editor/editorSprite.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorSprite.cpp @@ -1,6 +1,6 @@ #include "editorSprite.h" -#include "editor.h" #include "editorColormap.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorSprite.h b/TheForceEngine/TFE_Editor/EditorAsset/editorSprite.h similarity index 100% rename from TheForceEngine/TFE_Editor/editorSprite.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorSprite.h diff --git a/TheForceEngine/TFE_Editor/editorTexture.cpp b/TheForceEngine/TFE_Editor/EditorAsset/editorTexture.cpp similarity index 99% rename from TheForceEngine/TFE_Editor/editorTexture.cpp rename to TheForceEngine/TFE_Editor/EditorAsset/editorTexture.cpp index e140d503c..eb593c5e0 100644 --- a/TheForceEngine/TFE_Editor/editorTexture.cpp +++ b/TheForceEngine/TFE_Editor/EditorAsset/editorTexture.cpp @@ -1,6 +1,6 @@ #include "editorTexture.h" -#include "editor.h" #include "editorColormap.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/editorTexture.h b/TheForceEngine/TFE_Editor/EditorAsset/editorTexture.h similarity index 100% rename from TheForceEngine/TFE_Editor/editorTexture.h rename to TheForceEngine/TFE_Editor/EditorAsset/editorTexture.h diff --git a/TheForceEngine/TFE_Editor/Help/helpWindow.cpp b/TheForceEngine/TFE_Editor/Help/helpWindow.cpp deleted file mode 100644 index ac444fb61..000000000 --- a/TheForceEngine/TFE_Editor/Help/helpWindow.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "helpWindow.h" -#include -#include -#include -#include - -#include -#include - -namespace HelpWindow -{ - static const char* s_displayStr; - static std::vector s_helpNames; - static std::vector s_helpStrings; - static Help s_curHelp; - static bool s_minimized = false; - static bool s_open = false; - static bool s_resetScroll = false; - - const char* c_helpNameEntrypoints[]= - { - "About", // HELP_ABOUT - "Manual" // HELP_MANUAL - }; - - void openLocalLink(const char* link) - { - s_resetScroll = true; - - // Search the help names until we find a match. - const size_t helpCount = s_helpNames.size(); - for (size_t i = 0; i < helpCount; i++) - { - if (strcasecmp(link, s_helpNames[i].c_str()) == 0) - { - s_displayStr = s_helpStrings[i].c_str(); - return; - } - } - - // The document has not been loaded yet. - char path[TFE_MAX_PATH]; - char fileName[TFE_MAX_PATH]; - sprintf(fileName, "Documentation/markdown/%s.md", link); - TFE_Paths::appendPath(PATH_PROGRAM, fileName, path); - - FileStream file; - if (file.open(path, FileStream::MODE_READ)) - { - std::string text; - - const size_t len = file.getSize(); - text.resize(len + 1); - file.readBuffer(&text[0], (u32)len); - text[len] = 0; - - file.close(); - - s_helpNames.push_back(link); - s_helpStrings.push_back(text); - - s_displayStr = s_helpStrings.back().c_str(); - } - } - - void init() - { - TFE_Markdown::registerLocalLinkCB(openLocalLink); - s_displayStr = nullptr; - s_curHelp = HELP_NONE; - } - - bool show(Help help, u32 width, u32 height) - { - if (help == HELP_NONE) { return false; } - if (help != s_curHelp) - { - openLocalLink(c_helpNameEntrypoints[help]); - s_curHelp = help; - } - - s_open = true; - - ImGui::SetNextWindowSize({ (f32)width, (f32)height }); - if (ImGui::Begin(c_helpNameEntrypoints[help], &s_open)) - { - if (s_resetScroll) - { - ImGui::SetScrollY(0.0f); - s_resetScroll = false; - } - - TFE_Markdown::draw(s_displayStr); - s_minimized = false; - } - else - { - s_minimized = true; - } - ImGui::End(); - - if (!s_open) { s_curHelp = HELP_NONE; s_minimized = false; } - return s_open; - } - - bool isMinimized() - { - return s_minimized; - } - - bool isOpen() - { - return s_open; - } -} diff --git a/TheForceEngine/TFE_Editor/Help/helpWindow.h b/TheForceEngine/TFE_Editor/Help/helpWindow.h deleted file mode 100644 index 8617ff26f..000000000 --- a/TheForceEngine/TFE_Editor/Help/helpWindow.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// The Force Engine Editor -// A system built to view and edit Dark Forces data files. -// The viewing aspect needs to be put in place at the beginning -// in order to properly test elements in isolation without having -// to "play" the game as intended. -////////////////////////////////////////////////////////////////////// - -#include -#include - -enum Help -{ - HELP_ABOUT = 0, - HELP_MANUAL, - HELP_COUNT, - HELP_NONE = HELP_COUNT, -}; - -namespace HelpWindow -{ - void init(); - bool show(Help help, u32 width, u32 height); - bool isMinimized(); - bool isOpen(); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/editorRender.cpp b/TheForceEngine/TFE_Editor/Rendering/editorRender.cpp deleted file mode 100644 index c7a3140a9..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/editorRender.cpp +++ /dev/null @@ -1,368 +0,0 @@ -#include "grid2d.h" -#include -#include -#include -#include -#include -#include -//Rendering 2d -#include -#include -#include -#include -//Rendering 3d -#include -#include -#include - -#include - -namespace TFE_EditorRender -{ - bool init() - { - // 2D - LineDraw2d::init(); - Grid2d::init(); - TriColoredDraw2d::init(); - TriTexturedDraw2d::init(); - // 3D - Grid3d::init(); - LineDraw3d::init(); - TrianglesColor3d::init(); - - return true; - } - - void destroy() - { - // 2D - LineDraw2d::destroy(); - Grid2d::destroy(); - TriColoredDraw2d::destroy(); - TriTexturedDraw2d::destroy(); - // 3D - Grid3d::destroy(); - LineDraw3d::destroy(); - TrianglesColor3d::destroy(); - } - - static std::vector s_vertexBuffer3d; - - void drawModel3d_Bounds(const Model* model, const Vec3f* pos, const Mat3* orientation, f32 width, u32 color) - { - Vec3f oobb[8]; - const Vec3f aabb[8]= - { - {model->localAabb[0].x, model->localAabb[0].y, model->localAabb[0].z}, - {model->localAabb[1].x, model->localAabb[0].y, model->localAabb[0].z}, - {model->localAabb[1].x, model->localAabb[0].y, model->localAabb[1].z}, - {model->localAabb[0].x, model->localAabb[0].y, model->localAabb[1].z}, - - {model->localAabb[0].x, model->localAabb[1].y, model->localAabb[0].z}, - {model->localAabb[1].x, model->localAabb[1].y, model->localAabb[0].z}, - {model->localAabb[1].x, model->localAabb[1].y, model->localAabb[1].z}, - {model->localAabb[0].x, model->localAabb[1].y, model->localAabb[1].z}, - }; - - const Vec3f* mat33 = orientation->m; - - for (u32 v = 0; v < 8; v++) - { - oobb[v].x = aabb[v].x*mat33[0].x + aabb[v].y*mat33[0].y + aabb[v].z*mat33[0].z + pos->x; - oobb[v].y = aabb[v].x*mat33[1].x + aabb[v].y*mat33[1].y + aabb[v].z*mat33[1].z + pos->y; - oobb[v].z = aabb[v].x*mat33[2].x + aabb[v].y*mat33[2].y + aabb[v].z*mat33[2].z + pos->z; - } - - for (u32 i = 0; i < 8; i++) - { - u32 i0 = (i & 3), i1 = (i + 1) & 3; - if (i >= 4) { i0 += 4; i1 += 4; } - - const Vec3f line[] = { oobb[i0], oobb[i1] }; - LineDraw3d::addLine(width, line, &color); - } - for (u32 i = 0; i < 4; i++) - { - const u32 i0 = i, i1 = i + 4; - const Vec3f line[] = { oobb[i0], oobb[i1] }; - LineDraw3d::addLine(width, line, &color); - } - } - - void drawModel3d(const EditorSector* sector, const Model* model, const Vec3f* pos, const Mat3* orientation, const u32* pal, u32 alpha) - { - const Vec3f* mat33 = orientation->m; - - const ModelObject* obj = model->objects.data(); - for (u32 i = 0; i < model->objectCount; i++, obj++) - { - // Transform vertices. - const u32 vcount = (u32)obj->vertices.size(); - const Vertex3f* vtx = obj->vertices.data(); - const Vertex2f* texVtx = obj->textureVertices.data(); - - const s32 textureIndex = obj->textureIndex; - const Texture* texture = (textureIndex >= 0) ? model->textures[textureIndex] : nullptr; - const EditorTexture* tex = LevelEditorData::createTexture(texture); - - s_vertexBuffer3d.resize(vcount); - Vec3f* dstVtx = s_vertexBuffer3d.data(); - for (u32 v = 0; v < vcount; v++, vtx++, dstVtx++) - { - dstVtx->x = vtx->x*mat33[0].x + vtx->y*mat33[0].y + vtx->z*mat33[0].z + pos->x; - dstVtx->y = vtx->x*mat33[1].x + vtx->y*mat33[1].y + vtx->z*mat33[1].z + pos->y; - dstVtx->z = vtx->x*mat33[2].x + vtx->y*mat33[2].y + vtx->z*mat33[2].z + pos->z; - } - - // Draw triangles. - const u32 triCount = (u32)obj->triangles.size(); - const ModelPolygon* tri = obj->triangles.data(); - const TexturePolygon* texTri = obj->textureTriangles.data(); - dstVtx = s_vertexBuffer3d.data(); - for (u32 t = 0; t < triCount; t++, tri++) - { - const Vec3f triVtx[3] = { dstVtx[tri->i0], dstVtx[tri->i1], dstVtx[tri->i2] }; - const u32 clr32 = (pal[tri->color] & 0x00ffffff) | alpha; - if (tri->shading == SHADING_PLANE && tex) - { - Vec2f triUv[3]; - Vec2f triUv1[3]; - - const f32 floorOffset[] = { sector->floorTexture.offsetX, sector->floorTexture.offsetY }; - triUv[0] = { triVtx[0].x, triVtx[0].z }; - triUv[1] = { triVtx[1].x, triVtx[1].z }; - triUv[2] = { triVtx[2].x, triVtx[2].z }; - - triUv1[0] = { triVtx[0].x * 0.125f + floorOffset[0], triVtx[0].z * 0.125f + floorOffset[1] }; - triUv1[1] = { triVtx[1].x * 0.125f + floorOffset[0], triVtx[1].z * 0.125f + floorOffset[1] }; - triUv1[2] = { triVtx[2].x * 0.125f + floorOffset[0], triVtx[2].z * 0.125f + floorOffset[1] }; - - TrianglesColor3d::addTexturedTriangle(triVtx, triUv, triUv1, 0x00ffffff | alpha, tex->texture, TrianglesColor3d::TRANS_BLEND); - } - else if (tri->shading >= SHADING_TEXTURE && tex) - { - const f32 dx = std::max(fabsf(triVtx[1].x - triVtx[0].x), fabsf(triVtx[2].x - triVtx[0].x)); - const f32 dy = std::max(fabsf(triVtx[1].y - triVtx[0].y), fabsf(triVtx[2].y - triVtx[0].y)); - const f32 dz = std::max(fabsf(triVtx[1].z - triVtx[0].z), fabsf(triVtx[2].z - triVtx[0].z)); - - Vec2f triUv[3]; - if (dy < dx && dy < dz) - { - for (u32 v = 0; v < 3; v++) { triUv[v] = { triVtx[v].x, triVtx[v].z }; } - } - else if (dx < dy && dx < dz) - { - for (u32 v = 0; v < 3; v++) { triUv[v] = { triVtx[v].y, triVtx[v].z }; } - } - else - { - for (u32 v = 0; v < 3; v++) { triUv[v] = { triVtx[v].x, triVtx[v].y }; } - } - - Vec2f triUv1[3] = { { texVtx[texTri->i0].x, -texVtx[texTri->i0].y }, { texVtx[texTri->i1].x, -texVtx[texTri->i1].y }, { texVtx[texTri->i2].x, -texVtx[texTri->i2].y } }; - TrianglesColor3d::addTexturedTriangle(triVtx, triUv, triUv1, 0x00ffffff | alpha, tex->texture, TrianglesColor3d::TRANS_BLEND); - } - else - { - TrianglesColor3d::addTriangle(triVtx, nullptr, clr32, true); - } - - if (texTri) { texTri++; } - } - - const u32 quadCount = (u32)obj->quads.size(); - const ModelPolygon* quad = obj->quads.data(); - const TexturePolygon* qtex = obj->textureQuads.data(); - for (u32 q = 0; q < quadCount; q++, quad++) - { - const Vec3f triVtx[6] = { dstVtx[quad->i0], dstVtx[quad->i1], dstVtx[quad->i2], dstVtx[quad->i0], dstVtx[quad->i2], dstVtx[quad->i3] }; - const u32 clr32 = (pal[quad->color] & 0x00ffffff) | alpha; - const u32 color[] = { clr32, clr32 }; - const u32 texColor[] = { 0x00ffffff | alpha, 0x00ffffff | alpha }; - if (quad->shading == SHADING_PLANE && tex) - { - Vec2f triUv[6]; - Vec2f triUv1[6]; - for (u32 v = 0; v < 6; v++) { triUv[v] = { triVtx[v].x, triVtx[v].z }; } - - const f32 floorOffset[] = { sector->floorTexture.offsetX, sector->floorTexture.offsetY }; - triUv1[0] = { triVtx[0].x * 0.125f + floorOffset[0], triVtx[0].z * 0.125f + floorOffset[1] }; - triUv1[1] = { triVtx[1].x * 0.125f + floorOffset[0], triVtx[1].z * 0.125f + floorOffset[1] }; - triUv1[2] = { triVtx[2].x * 0.125f + floorOffset[0], triVtx[2].z * 0.125f + floorOffset[1] }; - - triUv1[3] = { triVtx[3].x * 0.125f + floorOffset[0], triVtx[3].z * 0.125f + floorOffset[1] }; - triUv1[4] = { triVtx[4].x * 0.125f + floorOffset[0], triVtx[4].z * 0.125f + floorOffset[1] }; - triUv1[5] = { triVtx[5].x * 0.125f + floorOffset[0], triVtx[5].z * 0.125f + floorOffset[1] }; - - TrianglesColor3d::addTexturedTriangles(2, triVtx, triUv, triUv1, texColor, tex->texture, TrianglesColor3d::TRANS_BLEND); - } - else if (quad->shading >= SHADING_TEXTURE && tex) - { - const f32 dx = std::max(fabsf(triVtx[1].x - triVtx[0].x), fabsf(triVtx[2].x - triVtx[0].x)); - const f32 dy = std::max(fabsf(triVtx[1].y - triVtx[0].y), fabsf(triVtx[2].y - triVtx[0].y)); - const f32 dz = std::max(fabsf(triVtx[1].z - triVtx[0].z), fabsf(triVtx[2].z - triVtx[0].z)); - - // Grid - Vec2f triUv[6]; - if (dy < dx && dy < dz) - { - for (u32 v = 0; v < 6; v++) { triUv[v] = { triVtx[v].x, triVtx[v].z }; } - } - else if (dx < dy && dx < dz) - { - for (u32 v = 0; v < 6; v++) { triUv[v] = { triVtx[v].y, triVtx[v].z }; } - } - else - { - for (u32 v = 0; v < 6; v++) { triUv[v] = { triVtx[v].x, triVtx[v].y }; } - } - - // Texture - Vec2f triUv1[6] = { { texVtx[qtex->i0].x, 1.0f-texVtx[qtex->i0].y }, { texVtx[qtex->i1].x, 1.0f-texVtx[qtex->i1].y }, { texVtx[qtex->i2].x, 1.0f-texVtx[qtex->i2].y }, - { texVtx[qtex->i0].x, 1.0f-texVtx[qtex->i0].y }, { texVtx[qtex->i2].x, 1.0f-texVtx[qtex->i2].y }, { texVtx[qtex->i3].x, 1.0f-texVtx[qtex->i3].y } }; - - TrianglesColor3d::addTexturedTriangles(2, triVtx, triUv, triUv1, texColor, tex->texture, TrianglesColor3d::TRANS_BLEND); - } - else - { - TrianglesColor3d::addTriangles(2, triVtx, nullptr, color, true); - } - - if (qtex) { qtex++; } - } - } - } - - static std::vector s_vertexBuffer; - - void drawModel2d_Bounds(const Model* model, const Vec3f* pos, const Mat3* orientation, u32 color, bool highlight) - { - Vec2f oobb[4]; - const Vec3f aabb[4] = - { - {model->localAabb[0].x, model->localAabb[0].y, model->localAabb[0].z}, - {model->localAabb[1].x, model->localAabb[0].y, model->localAabb[0].z}, - {model->localAabb[1].x, model->localAabb[0].y, model->localAabb[1].z}, - {model->localAabb[0].x, model->localAabb[0].y, model->localAabb[1].z}, - }; - - f32 scale = highlight ? 1.5f : 1.0f; - const Vec3f* mat33 = orientation->m; - for (u32 v = 0; v < 4; v++) - { - oobb[v].x = (aabb[v].x*mat33[0].x + aabb[v].y*mat33[0].y + aabb[v].z*mat33[0].z)*scale + pos->x; - oobb[v].z = (aabb[v].x*mat33[2].x + aabb[v].y*mat33[2].y + aabb[v].z*mat33[2].z)*scale + pos->z; - } - - const Vec2f bounds2d[]= - { - oobb[0], oobb[1], oobb[2], - oobb[0], oobb[2], oobb[3] - }; - - u32 colorBg[] = { color , color }; - TriColoredDraw2d::addTriangles(2, bounds2d, colorBg); - } - - void drawModel2d(const EditorSector* sector, const Model* model, const Vec2f* pos, const Mat3* orientation, const u32* pal, u32 alpha) - { - const Vec3f* mat33 = orientation->m; - - const ModelObject* obj = model->objects.data(); - for (u32 i = 0; i < model->objectCount; i++, obj++) - { - // Transform vertices. - const u32 vcount = (u32)obj->vertices.size(); - const Vertex3f* vtx = obj->vertices.data(); - const Vertex2f* texVtx = obj->textureVertices.data(); - - const s32 textureIndex = obj->textureIndex; - const Texture* texture = (textureIndex >= 0) ? model->textures[textureIndex] : nullptr; - const EditorTexture* tex = LevelEditorData::createTexture(texture); - - s_vertexBuffer.resize(vcount); - Vec2f* dstVtx = s_vertexBuffer.data(); - for (u32 v = 0; v < vcount; v++, vtx++, dstVtx++) - { - dstVtx->x = vtx->x*mat33[0].x + vtx->y*mat33[0].y + vtx->z*mat33[0].z + pos->x; - dstVtx->z = vtx->x*mat33[2].x + vtx->y*mat33[2].y + vtx->z*mat33[2].z + pos->z; - } - - // Draw triangles. - const u32 triCount = (u32)obj->triangles.size(); - const ModelPolygon* tri = obj->triangles.data(); - const TexturePolygon* texTri = obj->textureTriangles.data(); - dstVtx = s_vertexBuffer.data(); - for (u32 t = 0; t < triCount; t++, tri++) - { - const Vec2f triVtx[3] = { dstVtx[tri->i0], dstVtx[tri->i1], dstVtx[tri->i2] }; - Vec2f u = { triVtx[1].x - triVtx[0].x, triVtx[1].z - triVtx[0].z }; - Vec2f v = { triVtx[2].x - triVtx[0].x, triVtx[2].z - triVtx[0].z }; - if (u.z*v.x - u.x*v.z < 0.0f) { continue; } - - const u32 clr32 = (pal[tri->color] & 0x00ffffff) | alpha; - if (tri->shading == SHADING_PLANE && tex) - { - Vec2f triUv[3]; - const f32 floorOffset[] = { sector->floorTexture.offsetX, sector->floorTexture.offsetY }; - triUv[0] = { triVtx[0].x * 0.125f + floorOffset[0], triVtx[0].z * 0.125f + floorOffset[1] }; - triUv[1] = { triVtx[1].x * 0.125f + floorOffset[0], triVtx[1].z * 0.125f + floorOffset[1] }; - triUv[2] = { triVtx[2].x * 0.125f + floorOffset[0], triVtx[2].z * 0.125f + floorOffset[1] }; - - TriTexturedDraw2d::addTriangle(triVtx, triUv, 0x00ffffff | alpha, tex->texture); - } - else if (tri->shading >= SHADING_TEXTURE && tex) - { - Vec2f triUv[3] = { { texVtx[texTri->i0].x, 1.0f-texVtx[texTri->i0].y }, { texVtx[texTri->i1].x, 1.0f-texVtx[texTri->i1].y }, { texVtx[texTri->i2].x, 1.0f-texVtx[texTri->i2].y } }; - TriTexturedDraw2d::addTriangle(triVtx, triUv, 0x00ffffff | alpha, tex->texture); - } - else - { - TriColoredDraw2d::addTriangle(triVtx, clr32); - } - if (texTri) { texTri++; } - } - - const u32 quadCount = (u32)obj->quads.size(); - const ModelPolygon* quad = obj->quads.data(); - const TexturePolygon* qtex = obj->textureQuads.data(); - for (u32 q = 0; q < quadCount; q++, quad++) - { - const Vec2f triVtx[6] = { dstVtx[quad->i0], dstVtx[quad->i1], dstVtx[quad->i2], dstVtx[quad->i0], dstVtx[quad->i2], dstVtx[quad->i3] }; - Vec2f u = { triVtx[1].x - triVtx[0].x, triVtx[1].z - triVtx[0].z }; - Vec2f v = { triVtx[2].x - triVtx[0].x, triVtx[2].z - triVtx[0].z }; - if (u.z*v.x - u.x*v.z < 0.0f) { continue; } - - const u32 clr32 = (pal[quad->color] & 0x00ffffff) | alpha; - const u32 color[] = { clr32, clr32 }; - const u32 texColor[] = { 0x00ffffff | alpha, 0x00ffffff | alpha }; - if (quad->shading == SHADING_PLANE && tex) - { - Vec2f triUv[6]; - const f32 floorOffset[] = { sector->floorTexture.offsetX, sector->floorTexture.offsetY }; - triUv[0] = { triVtx[0].x * 0.125f + floorOffset[0], triVtx[0].z * 0.125f + floorOffset[1] }; - triUv[1] = { triVtx[1].x * 0.125f + floorOffset[0], triVtx[1].z * 0.125f + floorOffset[1] }; - triUv[2] = { triVtx[2].x * 0.125f + floorOffset[0], triVtx[2].z * 0.125f + floorOffset[1] }; - - triUv[3] = { triVtx[3].x * 0.125f + floorOffset[0], triVtx[3].z * 0.125f + floorOffset[1] }; - triUv[4] = { triVtx[4].x * 0.125f + floorOffset[0], triVtx[4].z * 0.125f + floorOffset[1] }; - triUv[5] = { triVtx[5].x * 0.125f + floorOffset[0], triVtx[5].z * 0.125f + floorOffset[1] }; - - TriTexturedDraw2d::addTriangles(2, triVtx, triUv, texColor, tex->texture); - } - else if (quad->shading >= SHADING_TEXTURE && tex) - { - Vec2f triUv[6] = { { texVtx[qtex->i0].x, 1.0f-texVtx[qtex->i0].y }, { texVtx[qtex->i1].x, 1.0f-texVtx[qtex->i1].y }, { texVtx[qtex->i2].x, 1.0f-texVtx[qtex->i2].y }, - { texVtx[qtex->i0].x, 1.0f-texVtx[qtex->i0].y }, { texVtx[qtex->i2].x, 1.0f-texVtx[qtex->i2].y }, { texVtx[qtex->i3].x, 1.0f-texVtx[qtex->i3].y } }; - TriTexturedDraw2d::addTriangles(2, triVtx, triUv, texColor, tex->texture); - } - else - { - TriColoredDraw2d::addTriangles(2, triVtx, color); - } - if (qtex) { qtex++; } - } - } - } -} \ No newline at end of file diff --git a/TheForceEngine/TFE_Editor/Rendering/editorRender.h b/TheForceEngine/TFE_Editor/Rendering/editorRender.h deleted file mode 100644 index eabeab862..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/editorRender.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include -#include - -struct Model; -struct EditorSector; - -namespace TFE_EditorRender -{ - bool init(); - void destroy(); - - void drawModel2d(const EditorSector* sector, const Model* model, const Vec2f* pos, const Mat3* orientation, const u32* pal, u32 alpha); - void drawModel2d_Bounds(const Model* model, const Vec3f* pos, const Mat3* orientation, u32 color, bool highlight); - - void drawModel3d(const EditorSector* sector, const Model* model, const Vec3f* pos, const Mat3* orientation, const u32* pal, u32 alpha); - void drawModel3d_Bounds(const Model* model, const Vec3f* pos, const Mat3* orientation, f32 width, u32 color); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/grid2d.cpp b/TheForceEngine/TFE_Editor/Rendering/grid2d.cpp deleted file mode 100644 index 7da444a3a..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/grid2d.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "grid2d.h" -#include -#include -#include -#include -#include -#include - -namespace Grid2d -{ - static const AttributeMapping c_gridAttrMapping[] = - { - {ATTR_POS, ATYPE_FLOAT, 2, 0, false}, - }; - static const u32 c_gridAttrCount = TFE_ARRAYSIZE(c_gridAttrMapping); - - static Shader s_shader; - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - static s32 s_svScaleOffset = -1; - static s32 s_svGridOpacity = -1; - - bool init() - { - if (!s_shader.load("Shaders/grid2d.vert", "Shaders/grid2d.frag")) - { - return false; - } - - s_svScaleOffset = s_shader.getVariableId("ScaleOffset"); - s_svGridOpacity = s_shader.getVariableId("GridOpacitySubGrid"); - if (s_svScaleOffset < 0) - { - return false; - } - - // Upload vertex/index buffers - const Vec2f vertices[] = - { - {0.0f, 0.0f}, - {1.0f, 0.0f}, - {1.0f, 1.0f}, - {0.0f, 1.0f}, - }; - const u16 indices[] = - { - 0, 1, 2, - 0, 2, 3 - }; - - s_vertexBuffer.create(4, sizeof(Vec2f), c_gridAttrCount, c_gridAttrMapping, false, (void*)vertices); - s_indexBuffer.create(6, sizeof(u16), false, (void*)indices); - - return true; - } - - void destroy() - { - s_shader.destroy(); - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - } - - void blitToScreen(s32 width, s32 height, f32 gridScale, f32 subGridSize, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits, f32 gridOpacity) - { - DisplayInfo display; - TFE_RenderBackend::getDisplayInfo(&display); - const f32 scaleX = f32(width) * pixelsToWorldUnits / gridScale; - const f32 scaleY = f32(height) * pixelsToWorldUnits / gridScale; - const f32 offsetX = offsetX_WorldUnits / gridScale; - const f32 offsetY = offsetY_WorldUnits / gridScale; - - TFE_RenderState::setStateEnable(false, STATE_CULLING | STATE_DEPTH_TEST); - TFE_RenderState::setStateEnable(true, STATE_BLEND); - - // Enable blending. - TFE_RenderState::setBlendMode(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - - s_shader.bind(); - // Bind Uniforms & Textures. - const f32 scaleOffset[] = { scaleX, scaleY, offsetX, offsetY }; - const f32 gridOpacitySubGrid[] = { gridOpacity, subGridSize }; - s_shader.setVariable(s_svScaleOffset, SVT_VEC4, scaleOffset); - s_shader.setVariable(s_svGridOpacity, SVT_VEC2, gridOpacitySubGrid); - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - s_indexBuffer.bind(); - - // Draw. - TFE_RenderBackend::drawIndexedTriangles(2, sizeof(u16)); - - // Cleanup. - s_shader.unbind(); - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/grid2d.h b/TheForceEngine/TFE_Editor/Rendering/grid2d.h deleted file mode 100644 index 5a93619a2..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/grid2d.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include -#include - -namespace Grid2d -{ - bool init(); - void destroy(); - - void blitToScreen(s32 width, s32 height, f32 gridScale, f32 subGridSize, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits, f32 gridOpacity); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/grid3d.cpp b/TheForceEngine/TFE_Editor/Rendering/grid3d.cpp deleted file mode 100644 index a462b9fcd..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/grid3d.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "grid3d.h" -#include "editorRender.h" -#include -#include -#include -#include -#include -#include -#include - -namespace Grid3d -{ - static const AttributeMapping c_gridAttrMapping[] = - { - {ATTR_POS, ATYPE_FLOAT, 3, 0, false}, - }; - static const u32 c_gridAttrCount = TFE_ARRAYSIZE(c_gridAttrMapping); - - static Shader s_shader; - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - static s32 s_svCameraPos = -1; - static s32 s_svCameraView = -1; - static s32 s_svCameraProj = -1; - static s32 s_svGridOpacity = -1; - static s32 s_svGridHeight = -1; - - bool init() - { - if (!s_shader.load("Shaders/grid3d.vert", "Shaders/grid3d.frag")) - { - return false; - } - - s_svCameraPos = s_shader.getVariableId("CameraPos"); - s_svCameraView = s_shader.getVariableId("CameraView"); - s_svCameraProj = s_shader.getVariableId("CameraProj"); - s_svGridOpacity = s_shader.getVariableId("GridOpacitySubGrid"); - s_svGridHeight = s_shader.getVariableId("GridHeight"); - s_shader.bindTextureNameToSlot("filterMap", 0); - if (s_svCameraPos < 0 || s_svCameraView < 0 || s_svCameraProj < 0) - { - return false; - } - - // Upload vertex/index buffers - const Vec3f vertices[] = - { - {-10000.0f, 0.0f, 10000.0f}, - { 10000.0f, 0.0f, 10000.0f}, - { 10000.0f, 0.0f, -10000.0f}, - {-10000.0f, 0.0f, -10000.0f}, - }; - const u16 indices[] = - { - 0, 1, 2, - 0, 2, 3 - }; - - s_vertexBuffer.create(4, sizeof(Vec3f), c_gridAttrCount, c_gridAttrMapping, false, (void*)vertices); - s_indexBuffer.create(6, sizeof(u16), false, (void*)indices); - - return true; - } - - void destroy() - { - s_shader.destroy(); - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - } - - void draw(f32 gridScale, f32 height, f32 subGridSize, f32 gridOpacity, f32 pixelSize, const Vec3f* camPos, const Mat3* viewMtx, const Mat4* projMtx) - { - DisplayInfo display; - TFE_RenderBackend::getDisplayInfo(&display); - TFE_RenderState::setStateEnable(false, STATE_CULLING | STATE_DEPTH_WRITE); - TFE_RenderState::setStateEnable(true, STATE_BLEND | STATE_DEPTH_TEST); - TFE_RenderState::setDepthBias(); - - // Enable blending. - TFE_RenderState::setBlendMode(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - - s_shader.bind(); - // Bind Uniforms & Textures. - const f32 gridOpacitySubGrid[] = { gridOpacity*2.0f, subGridSize, pixelSize }; - s_shader.setVariable(s_svCameraPos, SVT_VEC3, camPos->m); - s_shader.setVariable(s_svCameraView, SVT_MAT3x3, (f32*)viewMtx); - s_shader.setVariable(s_svCameraProj, SVT_MAT4x4, (f32*)projMtx); - s_shader.setVariable(s_svGridOpacity, SVT_VEC3, gridOpacitySubGrid); - s_shader.setVariable(s_svGridHeight, SVT_SCALAR, &height); - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - s_indexBuffer.bind(); - - // Draw. - TFE_RenderBackend::drawIndexedTriangles(2, sizeof(u16)); - - // Cleanup. - s_shader.unbind(); - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/grid3d.h b/TheForceEngine/TFE_Editor/Rendering/grid3d.h deleted file mode 100644 index adbca16e1..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/grid3d.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include -#include - -namespace Grid3d -{ - bool init(); - void destroy(); - - void draw(f32 gridScale, f32 height, f32 subGridSize, f32 gridOpacity, f32 pixelSize, const Vec3f* camPos, const Mat3* viewMtx, const Mat4* projMtx); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/lineDraw2d.cpp b/TheForceEngine/TFE_Editor/Rendering/lineDraw2d.cpp deleted file mode 100644 index cddb75c16..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/lineDraw2d.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "lineDraw2d.h" -#include -#include -#include -#include -#include -#include - -#define LINE_MAX 65536 - -namespace LineDraw2d -{ - // Vertex Definition - struct LineVertex - { - Vec3f pos; // 2D position + width. - Vec4f uv; // Line relative position in pixels. - u32 color; // Line color + opacity. - }; - static const AttributeMapping c_lineAttrMapping[]= - { - {ATTR_POS, ATYPE_FLOAT, 3, 0, false}, - {ATTR_UV, ATYPE_FLOAT, 4, 0, false}, - {ATTR_COLOR, ATYPE_UINT8, 4, 0, true} - }; - static const u32 c_lineAttrCount = TFE_ARRAYSIZE(c_lineAttrMapping); - - static s32 s_svScaleOffset = -1; - - static Shader s_shader; - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - - static LineVertex* s_vertices = nullptr; - static u32 s_lineCount; - - bool init() - { - if (!s_shader.load("Shaders/line2d.vert", "Shaders/line2d.frag")) - { - return false; - } - - s_svScaleOffset = s_shader.getVariableId("ScaleOffset"); - if (s_svScaleOffset < 0) - { - return false; - } - - // Create buffers - // Create vertex and index buffers. - u32* indices = new u32[6 * LINE_MAX]; - u32* outIndices = indices; - for (u32 i = 0; i < LINE_MAX; i++, outIndices += 6) - { - outIndices[0] = i * 4 + 0; - outIndices[1] = i * 4 + 1; - outIndices[2] = i * 4 + 2; - - outIndices[3] = i * 4 + 0; - outIndices[4] = i * 4 + 2; - outIndices[5] = i * 4 + 3; - } - s_vertices = new LineVertex[4 * LINE_MAX]; - - s_vertexBuffer.create(4 * LINE_MAX, sizeof(LineVertex), c_lineAttrCount, c_lineAttrMapping, true); - s_indexBuffer.create(6 * LINE_MAX, sizeof(u32), false, indices); - - delete[] indices; - s_lineCount = 0; - - return true; - } - - void destroy() - { - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - delete[] s_vertices; - s_vertices = nullptr; - } - - static u32 s_width, s_height; - static f32 s_pixelsToWorldUnits; - static Vec2f s_worldUnitsToPixels; - static Vec2f s_offsetWorldUnits; - - void begin(u32 width, u32 height, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits) - { - s_width = width; - s_height = height; - s_lineCount = 0; - - s_pixelsToWorldUnits = pixelsToWorldUnits; - s_worldUnitsToPixels.x = 1.0f / pixelsToWorldUnits; - s_worldUnitsToPixels.z = -1.0f / pixelsToWorldUnits; - s_offsetWorldUnits = { -offsetX_WorldUnits* s_worldUnitsToPixels.x, offsetY_WorldUnits*s_worldUnitsToPixels.z }; - } - - void addLines(u32 count, f32 width, const Vec2f* lines, const u32* lineColors) - { - LineVertex* vert = &s_vertices[s_lineCount * 4]; - for (u32 i = 0; i < count && s_lineCount < LINE_MAX; i++, lines += 2, lineColors += 2, vert += 4) - { - s_lineCount++; - - // Convert to pixels - f32 x0 = lines[0].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - f32 x1 = lines[1].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - - f32 y0 = lines[0].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - f32 y1 = lines[1].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - - f32 dx = x1 - x0; - f32 dy = y1 - y0; - const f32 offset = width * 2.0f; - f32 scale = offset / sqrtf(dx*dx + dy * dy); - dx *= scale; - dy *= scale; - - f32 nx = dy; - f32 ny = -dx; - - // Build a quad. - f32 lx0 = x0 - dx; - f32 lx1 = x1 + dx; - f32 ly0 = y0 - dy; - f32 ly1 = y1 + dy; - - vert[0].pos.x = lx0 + nx; - vert[1].pos.x = lx1 + nx; - vert[2].pos.x = lx1 - nx; - vert[3].pos.x = lx0 - nx; - - vert[0].pos.y = ly0 + ny; - vert[1].pos.y = ly1 + ny; - vert[2].pos.y = ly1 - ny; - vert[3].pos.y = ly0 - ny; - - vert[0].pos.z = width; - vert[1].pos.z = width; - vert[2].pos.z = width; - vert[3].pos.z = width; - - // FIX with PLANE offsets (pos - (x0, y0)).DIR or (pos - (x0, y0)).NRM - // Calculate the offset from the line. - vert[0].uv.x = x0; vert[0].uv.z = x1; - vert[1].uv.x = x0; vert[1].uv.z = x1; - vert[2].uv.x = x0; vert[2].uv.z = x1; - vert[3].uv.x = x0; vert[3].uv.z = x1; - - vert[0].uv.y = y0; vert[0].uv.w = y1; - vert[1].uv.y = y0; vert[1].uv.w = y1; - vert[2].uv.y = y0; vert[2].uv.w = y1; - vert[3].uv.y = y0; vert[3].uv.w = y1; - - // Copy the colors. - vert[0].color = lineColors[0]; - vert[1].color = lineColors[1]; - vert[2].color = lineColors[1]; - vert[3].color = lineColors[0]; - } - } - - void addLine(f32 width, const Vec2f* vertices, const u32* colors) - { - addLines(1, width, vertices, colors); - } - - void drawLines() - { - if (s_lineCount < 1) { return; } - - s_vertexBuffer.update(s_vertices, s_lineCount * 4 * sizeof(LineVertex)); - - const f32 scaleX = 2.0f / f32(s_width); - const f32 scaleY = 2.0f / f32(s_height); - const f32 offsetX = -1.0f; - const f32 offsetY = -1.0f; - - TFE_RenderState::setStateEnable(false, STATE_CULLING | STATE_DEPTH_TEST); - - // Enable blending. - TFE_RenderState::setStateEnable(true, STATE_BLEND); - TFE_RenderState::setBlendMode(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - - s_shader.bind(); - // Bind Uniforms & Textures. - const f32 scaleOffset[] = { scaleX, scaleY, offsetX, offsetY }; - s_shader.setVariable(s_svScaleOffset, SVT_VEC4, scaleOffset); - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - u32 indexSizeType = s_indexBuffer.bind(); - - // Draw. - TFE_RenderBackend::drawIndexedTriangles(s_lineCount * 2, sizeof(u32)); - - // Cleanup. - s_shader.unbind(); - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - - // Clear - s_lineCount = 0; - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/lineDraw2d.h b/TheForceEngine/TFE_Editor/Rendering/lineDraw2d.h deleted file mode 100644 index 257dd9d3d..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/lineDraw2d.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include - -namespace LineDraw2d -{ - bool init(); - void destroy(); - - void begin(u32 width, u32 height, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits); - void addLines(u32 count, f32 width, const Vec2f* lines, const u32* lineColors); - void addLine(f32 width, const Vec2f* vertices, const u32* colors); - - void drawLines(); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/lineDraw3d.cpp b/TheForceEngine/TFE_Editor/Rendering/lineDraw3d.cpp deleted file mode 100644 index a688232c7..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/lineDraw3d.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "lineDraw2d.h" -#include -#include -#include -#include -#include -#include - -#define LINE_MAX 65536 - -namespace LineDraw3d -{ - // Vertex Definition - struct LineVertex - { - Vec3f pos; - Vec3f linePos0; - Vec3f linePos1; - Vec3f dirWidth; - u32 color; - }; - static const AttributeMapping c_lineAttrMapping[]= - { - {ATTR_POS, ATYPE_FLOAT, 3, 0, false}, - {ATTR_UV, ATYPE_FLOAT, 3, 0, false}, - {ATTR_UV1, ATYPE_FLOAT, 3, 0, false}, - {ATTR_UV2, ATYPE_FLOAT, 3, 0, false}, - {ATTR_COLOR, ATYPE_UINT8, 4, 0, true} - }; - static const u32 c_lineAttrCount = TFE_ARRAYSIZE(c_lineAttrMapping); - - static s32 s_svCameraPos = -1; - static s32 s_svCameraView = -1; - static s32 s_svCameraProj = -1; - - static Shader s_shader; - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - - static LineVertex* s_vertices = nullptr; - static u32 s_lineCount; - - bool init() - { - if (!s_shader.load("Shaders/line3d.vert", "Shaders/line3d.frag")) - { - return false; - } - - s_svCameraPos = s_shader.getVariableId("CameraPos"); - s_svCameraView = s_shader.getVariableId("CameraView"); - s_svCameraProj = s_shader.getVariableId("CameraProj"); - if (s_svCameraPos < 0 || s_svCameraView < 0 || s_svCameraProj < 0) - { - return false; - } - - // Create buffers - // Create vertex and index buffers. - u32* indices = new u32[6 * LINE_MAX]; - u32* outIndices = indices; - for (u32 i = 0; i < LINE_MAX; i++, outIndices += 6) - { - outIndices[0] = i * 4 + 0; - outIndices[1] = i * 4 + 1; - outIndices[2] = i * 4 + 2; - - outIndices[3] = i * 4 + 0; - outIndices[4] = i * 4 + 2; - outIndices[5] = i * 4 + 3; - } - s_vertices = new LineVertex[4 * LINE_MAX]; - - s_vertexBuffer.create(4 * LINE_MAX, sizeof(LineVertex), c_lineAttrCount, c_lineAttrMapping, true); - s_indexBuffer.create(6 * LINE_MAX, sizeof(u32), false, indices); - - delete[] indices; - s_lineCount = 0; - - return true; - } - - void destroy() - { - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - delete[] s_vertices; - s_vertices = nullptr; - } - - void addLines(u32 count, f32 width, const Vec3f* lines, const u32* lineColors) - { - LineVertex* vert = &s_vertices[s_lineCount * 4]; - for (u32 i = 0; i < count && s_lineCount < LINE_MAX; i++, lines += 2, lineColors++, vert += 4) - { - s_lineCount++; - - // Build vertices - the positions will be updated in the shader. - vert[0].pos = lines[0]; - vert[1].pos = lines[1]; - vert[2].pos = lines[1]; - vert[3].pos = lines[0]; - - vert[0].dirWidth = { -1, 1, width }; - vert[1].dirWidth = { 1, 1, width }; - vert[2].dirWidth = { 1, -1, width }; - vert[3].dirWidth = { -1, -1, width }; - - for (u32 v = 0; v < 4; v++) - { - vert[v].color = *lineColors; - vert[v].linePos0 = lines[0]; - vert[v].linePos1 = lines[1]; - } - } - } - - void addLine(f32 width, const Vec3f* vertices, const u32* colors) - { - addLines(1, width, vertices, colors); - } - - void draw(const Vec3f* camPos, const Mat3* viewMtx, const Mat4* projMtx, bool depthTest, bool useBias) - { - if (s_lineCount < 1) { return; } - - s_vertexBuffer.update(s_vertices, s_lineCount * 4 * sizeof(LineVertex)); - TFE_RenderState::setDepthBias(0.0f, useBias ? -4.0f : 0.0f); - - TFE_RenderState::setStateEnable(false, STATE_CULLING | STATE_DEPTH_WRITE); - TFE_RenderState::setStateEnable(depthTest, STATE_DEPTH_TEST); - TFE_RenderState::setDepthFunction(CMP_LEQUAL); - - // Enable blending. - TFE_RenderState::setStateEnable(true, STATE_BLEND); - TFE_RenderState::setBlendMode(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - - s_shader.bind(); - // Bind Uniforms & Textures. - s_shader.setVariable(s_svCameraPos, SVT_VEC3, camPos->m); - s_shader.setVariable(s_svCameraView, SVT_MAT3x3, (f32*)viewMtx); - s_shader.setVariable(s_svCameraProj, SVT_MAT4x4, (f32*)projMtx); - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - s_indexBuffer.bind(); - - // Draw. - TFE_RenderBackend::drawIndexedTriangles(s_lineCount * 2, sizeof(u32)); - - // Cleanup. - s_shader.unbind(); - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - - TFE_RenderState::setDepthBias(); - - // Clear - s_lineCount = 0; - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/lineDraw3d.h b/TheForceEngine/TFE_Editor/Rendering/lineDraw3d.h deleted file mode 100644 index 74d6e45d9..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/lineDraw3d.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include - -namespace LineDraw3d -{ - bool init(); - void destroy(); - - void addLines(u32 count, f32 width, const Vec3f* lines, const u32* lineColors); - void addLine(f32 width, const Vec3f* vertices, const u32* colors); - - void draw(const Vec3f* camPos, const Mat3* viewMtx, const Mat4* projMtx, bool depthTest = true, bool useBias = true); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.cpp b/TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.cpp deleted file mode 100644 index 049af826e..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "trianglesColor2d.h" -#include -#include -#include -#include -#include -#include - -#define TRIANGLE_MAX 65536 - -namespace TriColoredDraw2d -{ - struct TriangleVertex - { - Vec2f pos; // 2D position. - u32 color; // vertex color + opacity. - }; - static const AttributeMapping c_triAttrMapping[] = - { - {ATTR_POS, ATYPE_FLOAT, 2, 0, false}, - {ATTR_COLOR, ATYPE_UINT8, 4, 0, true} - }; - static const u32 c_triAttrCount = TFE_ARRAYSIZE(c_triAttrMapping); - - static s32 s_svScaleOffset = -1; - static Shader s_shader; - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - - static TriangleVertex* s_vertices = nullptr; - static u32 s_triCount; - - bool init() - { - if (!s_shader.load("Shaders/tri2dColor.vert", "Shaders/tri2dColor.frag")) - { - return false; - } - - s_svScaleOffset = s_shader.getVariableId("ScaleOffset"); - if (s_svScaleOffset < 0) - { - return false; - } - - // Create vertex and index buffers. - u32* indices = new u32[3 * TRIANGLE_MAX]; - u32* outIndices = indices; - for (u32 i = 0; i < TRIANGLE_MAX; i++, outIndices += 3) - { - outIndices[0] = i * 3 + 0; - outIndices[1] = i * 3 + 1; - outIndices[2] = i * 3 + 2; - } - s_vertices = new TriangleVertex[3 * TRIANGLE_MAX]; - - s_vertexBuffer.create(3 * TRIANGLE_MAX, sizeof(TriangleVertex), c_triAttrCount, c_triAttrMapping, true); - s_indexBuffer.create(3 * TRIANGLE_MAX, sizeof(u32), false, indices); - delete[] indices; - s_triCount = 0; - - return true; - } - - void destroy() - { - s_shader.destroy(); - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - - delete[] s_vertices; - s_vertices = nullptr; - } - - static u32 s_width, s_height; - static f32 s_pixelsToWorldUnits; - static Vec2f s_worldUnitsToPixels; - static Vec2f s_offsetWorldUnits; - - void begin(u32 width, u32 height, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits) - { - s_width = width; - s_height = height; - s_triCount = 0; - - s_pixelsToWorldUnits = pixelsToWorldUnits; - s_worldUnitsToPixels.x = 1.0f / pixelsToWorldUnits; - s_worldUnitsToPixels.z = -1.0f / pixelsToWorldUnits; - s_offsetWorldUnits = { -offsetX_WorldUnits* s_worldUnitsToPixels.x, offsetY_WorldUnits*s_worldUnitsToPixels.z }; - } - - void addTriangles(u32 count, const Vec2f* triVtx, const u32* triColors) - { - TriangleVertex* vert = &s_vertices[s_triCount * 3]; - for (u32 i = 0; i < count && s_triCount < TRIANGLE_MAX; i++, triVtx += 3, triColors++, vert += 3) - { - s_triCount++; - - // Convert to pixels - vert[0].pos.x = triVtx[0].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - vert[1].pos.x = triVtx[1].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - vert[2].pos.x = triVtx[2].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - - vert[0].pos.z = triVtx[0].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - vert[1].pos.z = triVtx[1].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - vert[2].pos.z = triVtx[2].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - - // Copy the colors. - vert[0].color = *triColors; - vert[1].color = *triColors; - vert[2].color = *triColors; - } - } - - void addTriangle(const Vec2f* triVtx, u32 triColor) - { - addTriangles(1, triVtx, &triColor); - } - - void drawTriangles() - { - if (s_triCount < 1) { return; } - - s_vertexBuffer.update(s_vertices, s_triCount * 3 * sizeof(TriangleVertex)); - - const f32 scaleX = 2.0f / f32(s_width); - const f32 scaleY = 2.0f / f32(s_height); - const f32 offsetX = -1.0f; - const f32 offsetY = -1.0f; - - TFE_RenderState::setStateEnable(false, STATE_CULLING | STATE_DEPTH_TEST | STATE_DEPTH_WRITE); - - // Enable blending. - TFE_RenderState::setStateEnable(true, STATE_BLEND); - TFE_RenderState::setBlendMode(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - - s_shader.bind(); - // Bind Uniforms & Textures. - const f32 scaleOffset[] = { scaleX, scaleY, offsetX, offsetY }; - s_shader.setVariable(s_svScaleOffset, SVT_VEC4, scaleOffset); - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - u32 indexSizeType = s_indexBuffer.bind(); - - // Draw. - TFE_RenderBackend::drawIndexedTriangles(s_triCount, sizeof(u32)); - - // Cleanup. - s_shader.unbind(); - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - - // Clear - s_triCount = 0; - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.h b/TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.h deleted file mode 100644 index 9af8c8e1c..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/trianglesColor2d.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include -#include - -namespace TriColoredDraw2d -{ - bool init(); - void destroy(); - - void begin(u32 width, u32 height, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits); - void addTriangles(u32 count, const Vec2f* triVtx, const u32* triColors); - void addTriangle(const Vec2f* triVtx, u32 triColor); - - void drawTriangles(); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.cpp b/TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.cpp deleted file mode 100644 index a65003db9..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#include "trianglesColor3d.h" -#include -#include -#include -#include -#include -#include -#include - -#define TRI_MAX 65536 -#define DRAW_CALL_MAX 2048 - -namespace TrianglesColor3d -{ - // Vertex Definition - struct TriVertex - { - Vec3f pos; - Vec2f uv; - Vec2f uv1; - u32 color; - }; - static const AttributeMapping c_triAttrMapping[]= - { - {ATTR_POS, ATYPE_FLOAT, 3, 0, false}, - {ATTR_UV, ATYPE_FLOAT, 2, 0, false}, - {ATTR_UV1, ATYPE_FLOAT, 2, 0, false}, - {ATTR_COLOR, ATYPE_UINT8, 4, 0, true} - }; - static const u32 c_triAttrCount = TFE_ARRAYSIZE(c_triAttrMapping); - - struct DrawCall - { - const TextureGpu* texture; - u32 start; - u32 count; - Tri3dTrans trans; - }; - static DrawCall s_drawCalls[DRAW_CALL_MAX]; - static DrawCall* s_curDraw; - static u32 s_drawCount; - - struct ShaderInfo - { - Shader shader; - s32 svCameraPos = -1; - s32 svCameraView = -1; - s32 svCameraProj = -1; - s32 svGridHeight = -1; - }; - static ShaderInfo s_shaderInfo[1 + TRANS_COUNT]; - - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - - static TriVertex* s_vertices = nullptr; - static u32 s_triCount; - - static const TextureGpu* s_curTexture; - static Tri3dTrans s_curTrans; - - bool loadShaderInfo(u32 index, const char* vertFile, const char* fragFile) - { - ShaderInfo* sinfo = &s_shaderInfo[index]; - if (!sinfo->shader.load(vertFile, fragFile)) - { - return false; - } - - sinfo->svCameraPos = sinfo->shader.getVariableId("CameraPos"); - sinfo->svCameraView = sinfo->shader.getVariableId("CameraView"); - sinfo->svCameraProj = sinfo->shader.getVariableId("CameraProj"); - sinfo->svGridHeight = sinfo->shader.getVariableId("GridHeight"); - sinfo->shader.bindTextureNameToSlot("filterMap", 0); - sinfo->shader.bindTextureNameToSlot("image", 1); - if (sinfo->svCameraPos < 0 || sinfo->svCameraView < 0 || sinfo->svCameraProj < 0) - { - return false; - } - - return true; - } - - bool init() - { - if (!loadShaderInfo(0, "Shaders/tri3dColor.vert", "Shaders/tri3dColor.frag")) - { - return false; - } - if (!loadShaderInfo(1, "Shaders/tri3dTexture.vert", "Shaders/tri3dTexture.frag")) - { - return false; - } - if (!loadShaderInfo(2, "Shaders/tri3dTexture.vert", "Shaders/tri3dTextureTrans.frag")) - { - return false; - } - if (!loadShaderInfo(3, "Shaders/tri3dTexture.vert", "Shaders/tri3dTextureClamp.frag")) - { - return false; - } - s_shaderInfo[4] = s_shaderInfo[1]; - s_shaderInfo[5] = s_shaderInfo[3]; - - // Create buffers - // Create vertex and index buffers. - u32* indices = new u32[3 * TRI_MAX]; - u32* outIndices = indices; - for (u32 i = 0; i < TRI_MAX; i++, outIndices += 3) - { - outIndices[0] = i * 3 + 0; - outIndices[1] = i * 3 + 1; - outIndices[2] = i * 3 + 2; - } - s_vertices = new TriVertex[3 * TRI_MAX]; - - s_vertexBuffer.create(3 * TRI_MAX, sizeof(TriVertex), c_triAttrCount, c_triAttrMapping, true); - s_indexBuffer.create(3 * TRI_MAX, sizeof(u32), false, indices); - - delete[] indices; - s_triCount = 0; - s_drawCount = 0; - s_curTexture = nullptr; - s_curTrans = TRANS_NONE; - - return true; - } - - void destroy() - { - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - delete[] s_vertices; - s_vertices = nullptr; - } - - void addTriangles(u32 count, const Vec3f* vtx, const Vec2f* uv, const u32* triColors, bool blend) - { - const Tri3dTrans trans = blend ? TRANS_BLEND : TRANS_NONE; - if (s_curTexture != nullptr || s_drawCount == 0u || s_curTrans != trans) - { - s_curDraw = &s_drawCalls[s_drawCount]; - s_curDraw->start = s_triCount * 3; - s_curDraw->count = 0; - s_curDraw->trans = trans; - s_curDraw->texture = nullptr; - s_curTexture = nullptr; - s_curTrans = trans; - - s_drawCount++; - } - s_curDraw->count += count; - - Vec2f defUv = { 0.5f, 0.5f }; - - TriVertex* vert = &s_vertices[s_triCount * 3]; - for (u32 i = 0; i < count && s_triCount < TRI_MAX; i++, vtx += 3, triColors++, vert += 3) - { - s_triCount++; - - // Build vertices - the positions will be updated in the shader. - vert[0].pos = vtx[0]; - vert[1].pos = vtx[1]; - vert[2].pos = vtx[2]; - - if (uv) - { - vert[0].uv = uv[0]; - vert[1].uv = uv[1]; - vert[2].uv = uv[2]; - - vert[0].uv1 = uv[0]; - vert[1].uv1 = uv[0]; - vert[2].uv1 = uv[0]; - } - else - { - vert[0].uv = defUv; - vert[1].uv = defUv; - vert[2].uv = defUv; - - vert[0].uv1 = defUv; - vert[1].uv1 = defUv; - vert[2].uv1 = defUv; - } - - for (u32 v = 0; v < 3; v++) - { - vert[v].color = *triColors; - } - - if (uv) { uv += 3; } - } - } - - void addTriangle(const Vec3f* vertices, const Vec2f* uv, u32 triColor, bool blend) - { - addTriangles(1, vertices, uv, &triColor, blend); - } - - void addTexturedTriangles(u32 count, const Vec3f* vtx, const Vec2f* uv, const Vec2f* uv1, const u32* triColors, const TextureGpu* texture, Tri3dTrans trans) - { - if (s_curTexture != texture || s_curTrans != trans || s_drawCount == 0u) - { - s_curDraw = &s_drawCalls[s_drawCount]; - s_curDraw->start = s_triCount * 3; - s_curDraw->count = 0; - s_curDraw->trans = trans; - s_curDraw->texture = texture; - - s_curTexture = texture; - s_curTrans = trans; - s_drawCount++; - } - s_curDraw->count += count; - - TriVertex* vert = &s_vertices[s_triCount * 3]; - for (u32 i = 0; i < count && s_triCount < TRI_MAX; i++, vtx += 3, uv += 3, triColors++, vert += 3) - { - s_triCount++; - - // Build vertices - the positions will be updated in the shader. - vert[0].pos = vtx[0]; - vert[1].pos = vtx[1]; - vert[2].pos = vtx[2]; - - vert[0].uv = uv[0]; - vert[1].uv = uv[1]; - vert[2].uv = uv[2]; - - if (uv1) - { - vert[0].uv1 = uv1[0]; - vert[1].uv1 = uv1[1]; - vert[2].uv1 = uv1[2]; - uv1 += 3; - } - else - { - vert[0].uv1 = { 0.5f, 0.5f }; - vert[1].uv1 = { 0.5f, 0.5f }; - vert[2].uv1 = { 0.5f, 0.5f }; - } - - for (u32 v = 0; v < 3; v++) - { - vert[v].color = *triColors; - } - } - } - - void addTexturedTriangle(const Vec3f* vertices, const Vec2f* uv, const Vec2f* uv1, u32 triColor, const TextureGpu* texture, Tri3dTrans trans) - { - addTexturedTriangles(1, vertices, uv, uv1, &triColor, texture, trans); - } - - void draw(const Vec3f* camPos, const Mat3* viewMtx, const Mat4* projMtx, bool depthTest, f32 gridHeight) - { - if (s_triCount < 1) { return; } - - s_vertexBuffer.update(s_vertices, s_triCount * 3 * sizeof(TriVertex)); - TFE_RenderState::setDepthBias(); - if (depthTest) - { - TFE_RenderState::setStateEnable(true, STATE_DEPTH_TEST | STATE_DEPTH_WRITE | STATE_CULLING); - } - else - { - TFE_RenderState::setStateEnable(true, STATE_CULLING); - TFE_RenderState::setStateEnable(false, STATE_DEPTH_TEST | STATE_DEPTH_WRITE); - } - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - s_indexBuffer.bind(); - - for (u32 i = 0; i < s_drawCount; i++) - { - u32 shaderIndex = 0; - if (s_drawCalls[i].texture) - { - shaderIndex = 1 + s_drawCalls[i].trans; - } - ShaderInfo* sinfo = &s_shaderInfo[shaderIndex]; - - // Enable blending. - if (s_drawCalls[i].trans == TRANS_BLEND || s_drawCalls[i].trans == TRANS_BLEND_CLAMP) - { - TFE_RenderState::setStateEnable(true, STATE_BLEND); - TFE_RenderState::setBlendMode(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); - } - else - { - TFE_RenderState::setStateEnable(false, STATE_BLEND); - } - - sinfo->shader.bind(); - // Bind Uniforms & Textures. - sinfo->shader.setVariable(sinfo->svCameraPos, SVT_VEC3, camPos->m); - sinfo->shader.setVariable(sinfo->svCameraView, SVT_MAT3x3, (f32*)viewMtx); - sinfo->shader.setVariable(sinfo->svCameraProj, SVT_MAT4x4, (f32*)projMtx); - sinfo->shader.setVariable(sinfo->svGridHeight, SVT_SCALAR, &gridHeight); - if (s_drawCalls[i].texture) - { - s_drawCalls[i].texture->bind(1); - } - - // Draw. - TFE_RenderBackend::drawIndexedTriangles(s_drawCalls[i].count, sizeof(u32), s_drawCalls[i].start); - - sinfo->shader.unbind(); - } - - // Cleanup. - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - - TextureGpu::clear(1); - - // Clear - s_triCount = 0; - s_drawCount = 0; - s_curTexture = nullptr; - s_curTrans = TRANS_NONE; - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.h b/TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.h deleted file mode 100644 index fecd69069..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/trianglesColor3d.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include - -class TextureGpu; - -namespace TrianglesColor3d -{ - enum Tri3dTrans - { - TRANS_NONE = 0, // Opaque - TRANS_CUTOUT, // Cutout transparent texels - TRANS_CLAMP, // Cutout transparent texels AND cutout any texels outside of the 0 - 1 range. - TRANS_BLEND, // Alpha blend. - TRANS_BLEND_CLAMP, // Cutout transparent texels AND cutout any texels outside of the 0 - 1 range and blend. - TRANS_COUNT, - }; - - bool init(); - void destroy(); - - void addTriangles(u32 count, const Vec3f* vtx, const Vec2f* uv, const u32* triColors, bool blend=false); - void addTriangle(const Vec3f* vertices, const Vec2f* uv, u32 triColor, bool blend = false); - - void addTexturedTriangles(u32 count, const Vec3f* vtx, const Vec2f* uv, const Vec2f* uv1, const u32* triColors, const TextureGpu* texture, Tri3dTrans trans=Tri3dTrans::TRANS_NONE); - void addTexturedTriangle(const Vec3f* vertices, const Vec2f* uv, const Vec2f* uv1, u32 triColor, const TextureGpu* texture, Tri3dTrans trans=Tri3dTrans::TRANS_NONE); - - void draw(const Vec3f* camPos, const Mat3* viewMtx, const Mat4* projMtx, bool depthTest = true, f32 gridHeight = 0.0f); -} diff --git a/TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.cpp b/TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.cpp deleted file mode 100644 index 27998679d..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "trianglesTextured2d.h" -#include -#include -#include -#include -#include -#include -#include - -#define TRIANGLE_MAX 65536 - -namespace TriTexturedDraw2d -{ - struct TriangleVertex - { - Vec2f pos; // 2D position. - Vec2f uv; // Texture coordinate. - u32 color; // vertex color + opacity. - }; - static const AttributeMapping c_triAttrMapping[] = - { - {ATTR_POS, ATYPE_FLOAT, 2, 0, false}, - {ATTR_UV, ATYPE_FLOAT, 2, 0, false}, - {ATTR_COLOR, ATYPE_UINT8, 4, 0, true} - }; - static const u32 c_triAttrCount = TFE_ARRAYSIZE(c_triAttrMapping); - - static s32 s_svScaleOffset = -1; - - static Shader s_shader; - static VertexBuffer s_vertexBuffer; - static IndexBuffer s_indexBuffer; - - static TriangleVertex* s_vertices = nullptr; - static const TextureGpu* s_curTexture = nullptr; - static u32 s_triCount; - - bool init() - { - if (!s_shader.load("Shaders/tri2dTextured.vert", "Shaders/tri2dTextured.frag")) - { - return false; - } - - s_shader.bindTextureNameToSlot("image", 0); - s_svScaleOffset = s_shader.getVariableId("ScaleOffset"); - if (s_svScaleOffset < 0) - { - return false; - } - - // Create vertex and index buffers. - u32* indices = new u32[3 * TRIANGLE_MAX]; - u32* outIndices = indices; - for (u32 i = 0; i < TRIANGLE_MAX; i++, outIndices += 3) - { - outIndices[0] = i * 3 + 0; - outIndices[1] = i * 3 + 1; - outIndices[2] = i * 3 + 2; - } - s_vertices = new TriangleVertex[3 * TRIANGLE_MAX]; - - s_vertexBuffer.create(3 * TRIANGLE_MAX, sizeof(TriangleVertex), c_triAttrCount, c_triAttrMapping, true); - s_indexBuffer.create(3 * TRIANGLE_MAX, sizeof(u32), false, indices); - - delete[] indices; - s_triCount = 0; - - return true; - } - - void destroy() - { - s_vertexBuffer.destroy(); - s_indexBuffer.destroy(); - - delete[] s_vertices; - s_vertices = nullptr; - } - - static u32 s_width, s_height; - static f32 s_pixelsToWorldUnits; - static Vec2f s_worldUnitsToPixels; - static Vec2f s_offsetWorldUnits; - - #define DRAW_CALL_MAX 2048 - struct DrawCall - { - const TextureGpu* texture; - u32 start; - u32 count; - }; - static DrawCall s_drawCalls[DRAW_CALL_MAX]; - static DrawCall* s_curDraw; - static u32 s_drawCount; - - void begin(u32 width, u32 height, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits) - { - s_width = width; - s_height = height; - s_triCount = 0; - s_curTexture = nullptr; - - s_drawCount = 0; - s_curDraw = &s_drawCalls[s_drawCount]; - s_curDraw->start = 0; - s_curDraw->count = 0; - - s_pixelsToWorldUnits = pixelsToWorldUnits; - s_worldUnitsToPixels.x = 1.0f / pixelsToWorldUnits; - s_worldUnitsToPixels.z = -1.0f / pixelsToWorldUnits; - s_offsetWorldUnits = { -offsetX_WorldUnits* s_worldUnitsToPixels.x, offsetY_WorldUnits*s_worldUnitsToPixels.z }; - } - - void addTriangles(u32 count, const Vec2f* triVtx, const Vec2f* triUv, const u32* triColors, const TextureGpu* texture) - { - if (texture != s_curTexture) - { - if (s_curDraw->count) { s_drawCount++; } - - s_curDraw = &s_drawCalls[s_drawCount]; - s_curDraw->start = s_triCount * 3; - s_curDraw->count = 0; - s_curDraw->texture = texture; - - s_curTexture = texture; - } - s_curDraw->count += count; - - TriangleVertex* vert = &s_vertices[s_triCount * 3]; - for (u32 i = 0; i < count && s_triCount < TRIANGLE_MAX; i++, triVtx += 3, triUv += 3, triColors++, vert += 3) - { - s_triCount++; - - // Convert to pixels - vert[0].pos.x = triVtx[0].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - vert[1].pos.x = triVtx[1].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - vert[2].pos.x = triVtx[2].x * s_worldUnitsToPixels.x + s_offsetWorldUnits.x; - - vert[0].pos.z = triVtx[0].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - vert[1].pos.z = triVtx[1].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - vert[2].pos.z = triVtx[2].z * s_worldUnitsToPixels.z + s_offsetWorldUnits.z; - - // Copy uvs. - vert[0].uv = triUv[0]; - vert[1].uv = triUv[1]; - vert[2].uv = triUv[2]; - - // Copy the colors. - vert[0].color = *triColors; - vert[1].color = *triColors; - vert[2].color = *triColors; - } - } - - void addTriangle(const Vec2f* triVtx, const Vec2f* triUv, u32 triColor, const TextureGpu* texture) - { - addTriangles(1, triVtx, triUv, &triColor, texture); - } - - void drawTriangles() - { - if (s_triCount < 1) { return; } - if (s_curDraw->count) - { - s_drawCount++; - } - - s_vertexBuffer.update(s_vertices, s_triCount * 3 * sizeof(TriangleVertex)); - - const f32 scaleX = 2.0f / f32(s_width); - const f32 scaleY = 2.0f / f32(s_height); - const f32 offsetX = -1.0f; - const f32 offsetY = -1.0f; - - TFE_RenderState::setStateEnable(false, STATE_CULLING | STATE_DEPTH_TEST | STATE_DEPTH_WRITE); - - // Enable blending. - TFE_RenderState::setStateEnable(true, STATE_BLEND); - TFE_RenderState::setBlendMode(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); - - s_shader.bind(); - // Bind Uniforms & Textures. - const f32 scaleOffset[] = { scaleX, scaleY, offsetX, offsetY }; - s_shader.setVariable(s_svScaleOffset, SVT_VEC4, scaleOffset); - - // Bind vertex/index buffers and setup attributes for BlitVert - s_vertexBuffer.bind(); - s_indexBuffer.bind(); - - // Draw. - for (u32 i = 0; i < s_drawCount; i++) - { - const DrawCall* draw = &s_drawCalls[i]; - if (draw->texture) { draw->texture->bind(); } - TFE_RenderBackend::drawIndexedTriangles(draw->count, sizeof(u32), draw->start); - } - - // Cleanup. - s_shader.unbind(); - s_vertexBuffer.unbind(); - s_indexBuffer.unbind(); - - // Clear - s_triCount = 0; - s_drawCount = 0; - } -} diff --git a/TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.h b/TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.h deleted file mode 100644 index 28d39acd9..000000000 --- a/TheForceEngine/TFE_Editor/Rendering/trianglesTextured2d.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -////////////////////////////////////////////////////////////////////// -// An OpenGL system to blit a texture to the screen. Uses a hardcoded -// basic shader + fullscreen triangle. -// -// Additional optional features can be added later such as filtering, -// bloom and GPU color conversion. -////////////////////////////////////////////////////////////////////// - -#include -#include - -namespace TriTexturedDraw2d -{ - bool init(); - void destroy(); - - void begin(u32 width, u32 height, f32 pixelsToWorldUnits, f32 offsetX_WorldUnits, f32 offsetY_WorldUnits); - void addTriangles(u32 count, const Vec2f* triVtx, const Vec2f* triUv, const u32* triColors, const TextureGpu* texture); - void addTriangle(const Vec2f* triVtx, const Vec2f* triUv, u32 triColor, const TextureGpu* texture); - - void drawTriangles(); -} diff --git a/TheForceEngine/TFE_Editor/archiveViewer.cpp b/TheForceEngine/TFE_Editor/archiveViewer.cpp deleted file mode 100644 index c5dd6fc45..000000000 --- a/TheForceEngine/TFE_Editor/archiveViewer.cpp +++ /dev/null @@ -1,687 +0,0 @@ -#include "archiveViewer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// Game -#include - -#include - -// TODO: Add features to the file browser: -// 1. Filter does not exclude directories. -// 2. Ability to auto-set filter. -// 3. Ability to show only directories and select them. - -namespace ArchiveViewer -{ - #define TFE_MAX_LEVELS 32 - - enum FileType - { - TYPE_TEXT = 0, - TYPE_LEV, - TYPE_PAL, - TYPE_TEX, - TYPE_FNT, - TYPE_FRAME, - TYPE_SPRITE, - TYPE_3D, - TYPE_VOC, - TYPE_GMID, - TYPE_BIN, - TYPE_COUNT - }; - - static TFE_Renderer* s_renderer = nullptr; - - static char s_curArchiveFile[TFE_MAX_PATH] = ""; - static char s_curArchiveName[TFE_MAX_PATH] = ""; - static Archive* s_curArchive = nullptr; - static std::string s_text; - static bool s_showAsText = false; - static s32 s_layer = 1; - static bool s_runLevel = false; - static bool s_showUi = true; - - static s32 s_currentFile = 0; - static std::vector s_items; - static bool s_showFile = false; - static FileType s_fileType; - static Palette256* s_curPal = nullptr; - static ColorMap* s_colorMap = nullptr; - static Texture* s_curTexture = nullptr; - static Frame* s_curFrame = nullptr; - static Sprite* s_curSprite = nullptr; - static Font* s_curFont = nullptr; - static Model* s_curModel = nullptr; - - static f32 s_mapZoom = 1.0f; - static f32 s_renderCenter[2] = { 0.0f, 0.0f }; - - static s32 s_anim = 0; - static s32 s_angle = 0; - static Vec2f s_mapPos; - - static s32 s_curLevel = 0; - static u32 s_levelCount = 0; - static char* s_levelNames[TFE_MAX_LEVELS] = { 0 }; - static char* s_levelFiles[TFE_MAX_LEVELS] = { 0 }; - - static s32 s_uiScale; - static char s_levelFile[TFE_MAX_PATH]; - //static const ViewStats* s_viewStats = nullptr; - - f32 scaleUi(s32 x) - { - return f32(x * s_uiScale / 100); - } - - void init(TFE_Renderer* renderer) - { - s_renderer = renderer; - - // Allocate space for level names. - for (u32 i = 0; i < TFE_MAX_LEVELS; i++) - { - s_levelNames[i] = new char[256]; - s_levelFiles[i] = new char[256]; - } - - s_uiScale = TFE_Ui::getUiScale(); - - bool show = false; - ImGui::Begin("ArchiveViewer", &show); - ImVec2 windowPos = ImVec2(0.0f, scaleUi(32)); - ImGui::SetWindowPos("ArchiveViewer", windowPos); - ImGui::SetWindowSize("ArchiveViewer", ImVec2(scaleUi(250), scaleUi(650))); - ImGui::End(); - - ImGui::Begin("LevelList", &show); - ImVec2 windowPosLvl = ImVec2(scaleUi(1000), scaleUi(100)); - ImGui::SetWindowPos("LevelList", windowPosLvl); - ImGui::SetWindowSize("LevelList", ImVec2(scaleUi(300), scaleUi(650))); - ImGui::End(); - - ImGui::Begin("TextViewer", &show); - ImVec2 windowPosText = ImVec2(scaleUi(300), scaleUi(10)); - ImGui::SetWindowPos("TextViewer", windowPosText); - ImGui::SetWindowSize("TextViewer", ImVec2(scaleUi(625), scaleUi(650))); - ImGui::End(); - - ImGui::Begin("ObjectViewer", &show); - windowPosText = ImVec2(scaleUi(300), scaleUi(10)); - ImGui::SetWindowPos("ObjectViewer", windowPosText); - ImGui::SetWindowSize("ObjectViewer", ImVec2(scaleUi(665), scaleUi(515))); - ImGui::End(); - - ImGui::Begin("SpriteViewer", &show); - windowPosText = ImVec2(scaleUi(300), scaleUi(10)); - ImGui::SetWindowPos("SpriteViewer", windowPosText); - ImGui::SetWindowSize("SpriteViewer", ImVec2(scaleUi(665), scaleUi(560))); - ImGui::End(); - - ImGui::Begin("LevelViewer", &show); - windowPosText = ImVec2(scaleUi(300), scaleUi(10)); - ImGui::SetWindowPos("LevelViewer", windowPosText); - ImGui::SetWindowSize("LevelViewer", ImVec2(scaleUi(665), scaleUi(600))); - ImGui::End(); - - s_curArchiveFile[0] = 0; - s_curArchiveName[0] = 0; - s_anim = 0; - s_angle = 0; - s_showAsText = false; - s_layer = 1; - - s_curPal = TFE_Palette::get256("SECBASE.PAL"); - s_renderer->enableScreenClear(true); - } - - bool render3dView() - { - const TFE_Settings_Graphics* config = TFE_Settings::getGraphicsSettings(); - - if (s_runLevel) - { - if (TFE_Input::keyPressed(KEY_F10)) - { - s_showUi = !s_showUi; - TFE_Input::enableRelativeMode(!s_showUi); - } - - GameTransition trans = TFE_GameLoop::update(false); - TFE_GameLoop::draw(); - //s_viewStats = TFE_GameLoop::getViewStats(); - - if (trans == TRANS_NEXT_LEVEL && s_curLevel >= 0 && s_curLevel + 1 < (s32)s_levelCount) - { - // Go to the next level in the list. - s_curLevel++; - - StartLocation start = {}; - start.overrideStart = false; - - strcpy(s_levelFile, s_levelFiles[s_curLevel]); - TFE_LevelAsset::load(s_levelFiles[s_curLevel]); - LevelData* level = TFE_LevelAsset::getLevelData(); - TFE_GameLoop::startLevel(level, start, s_renderer, config->gameResolution.x, config->gameResolution.z, true); - } - else if (trans == TRANS_QUIT || trans == TRANS_TO_AGENT_MENU || trans == TRANS_NEXT_LEVEL) - { - s_renderer->changeResolution(640, 480, false, TFE_Settings::getGraphicsSettings()->asyncFramebuffer, false); - s_runLevel = false; - s_showUi = true; - TFE_Input::enableRelativeMode(false); - s_renderer->enableScreenClear(true); - TFE_Audio::stopAllSounds(); - - // Reload the level - TFE_LevelAsset::load(s_levelFile); - } - else - { - const LevelData* level = TFE_LevelAsset::getLevelData(); - s_layer = 0;// level->sectors[s_viewStats->sectorId].layer; - s_mapPos = {};// { s_viewStats->pos.x, s_viewStats->pos.z }; - - s_renderer->clearMapMarkers(); - //s_renderer->addMapMarker(s_layer, s_viewStats->pos.x, s_viewStats->pos.z, 19); - } - - return true; - } - - s_renderer->setPalette(s_curPal); - TFE_RenderBackend::setPalette(s_curPal->colors); - if (s_fileType == TYPE_LEV) - { - s_renderer->drawMapLines(s_layer, s_renderCenter[0] * s_mapZoom + 320.0f, s_renderCenter[1] * s_mapZoom + 240.0f, s_mapZoom); - } - else if (s_fileType == TYPE_PAL) - { - s_renderer->drawPalette(); - } - else if (s_fileType == TYPE_TEX && s_curTexture) - { - s32 x = s_curTexture->frames[0].width < 640 ? 320 - (s_curTexture->frames[0].width >>1) : 0; - s32 y = s_curTexture->frames[0].height < 480 ? 240 - (s_curTexture->frames[0].height>>1) : 0; - if (s_curTexture->layout == TEX_LAYOUT_VERT) - { - s_renderer->drawTexture(s_curTexture, x, y); - } - else - { - s32 x = s_curTexture->frames[0].width <= 320 ? 160 : 0; - s32 y = s_curTexture->frames[0].width <= 240 ? 140 : 0; - s_renderer->drawTextureHorizontal(s_curTexture, x, y); - } - } - else if (s_fileType == TYPE_FRAME) - { - s32 x = 320 - ((s_curFrame->rect[0] + s_curFrame->rect[2]) >> 1); - s32 y = 240 - ((s_curFrame->rect[1] + s_curFrame->rect[3]) >> 1); - s_renderer->drawFrame(s_curFrame, x, y); - } - else if (s_fileType == TYPE_SPRITE) - { - s32 x = 320 - ((s_curSprite->rect[0] + s_curSprite->rect[2]) >> 1); - s32 y = 240 - ((s_curSprite->rect[1] + s_curSprite->rect[3]) >> 1); - s_renderer->drawSprite(s_curSprite, x, y, s_anim, s_angle); - } - else if (s_fileType == TYPE_FNT) - { - s_renderer->drawFont(s_curFont); - } - else if (s_fileType == TYPE_3D) - { - static Vec3f orientation = { 0, 0, 0 }; - orientation.y -= 45.0f*(f32)TFE_System::getDeltaTime(); - //TFE_GameLoop::drawModel(s_curModel, &orientation); - } - - return false; - } - - void selectPointOnMap(f32 wx, f32 wy) - { - s32 mx, my; - TFE_Input::getMousePos(&mx, &my); - - const f32 offsetX = s_renderCenter[0] * s_mapZoom + 320.0f; - const f32 offsetY = s_renderCenter[1] * s_mapZoom + 240.0f; - const f32 scale = s_mapZoom; - - const f32 rx = f32(mx - wx); - // Y up versus Y down. - const f32 ry = f32(479 - my + wy); - - const f32 mapX = (rx - offsetX) / scale; - const f32 mapY = (ry - offsetY) / scale; - s_mapPos = { mapX, mapY }; - - s_renderer->clearMapMarkers(); - s_renderer->addMapMarker(s_layer, mapX, mapY, 19); - } - - void unloadAssets() - { - TFE_Audio::stopAllSounds(); - - // Free all assets - TFE_Palette::freeAll(); - TFE_ColorMap::freeAll(); - TFE_Font::freeAll(); - TFE_Sprite::freeAll(); - TFE_Texture::freeAll(); - TFE_Model::freeAll(); - TFE_GameMessages::unload(); - TFE_LevelList::unload(); - - // Re-load and set the default palette. - s_curPal = TFE_Palette::get256("SECBASE.PAL"); - s_colorMap = TFE_ColorMap::get("SECBASE.CMP"); - s_renderer->setPalette(s_curPal); - s_renderer->setColorMap(s_colorMap); - TFE_GameMessages::load(); - TFE_LevelList::load(); - - s_levelCount = std::min((u32)TFE_MAX_LEVELS, TFE_LevelList::getLevelCount()); - for (u32 i = 0; i < s_levelCount; i++) - { - sprintf(s_levelNames[i], "%s", TFE_LevelList::getLevelName(i)); - sprintf(s_levelFiles[i], "%s.LEV", TFE_LevelList::getLevelFileName(i)); - } - } - - bool isFullscreen() - { - return s_runLevel; - } - - void draw(bool* isActive) - { - const TFE_Settings_Graphics* config = TFE_Settings::getGraphicsSettings(); - - // Do not show the editor while running the level. - if (s_runLevel) - { - //if (s_viewStats && s_showUi) - if (s_showUi) - { - LevelData* level = TFE_LevelAsset::getLevelData(); - - static bool viewStatsActive = true; - ImGui::Begin("ViewStats", &viewStatsActive); - ImGui::Text("Level Name \"%s\"", s_items[s_currentFile]); - ImGui::Text("SectorId %d", 0);// s_viewStats->sectorId); - //if (s_viewStats->sectorId >= 0 && level->sectors[s_viewStats->sectorId].name[0]) - //{ - // ImGui::Text("Sector \"%s\"", level->sectors[s_viewStats->sectorId].name); - //} - //ImGui::Text("Pos (%2.2f, %2.2f)", s_viewStats->pos.x, s_viewStats->pos.z); - //ImGui::Text("Height %2.2f", s_viewStats->pos.y); - //ImGui::Text("Angles (%2.2f, %2.2f)pi", s_viewStats->yaw/PI, s_viewStats->pitch/PI); - ImGui::Separator(); - //ImGui::Text("Iteration Count %d", s_viewStats->iterCount); - //ImGui::Text("Traversal Depth %d", s_viewStats->maxTraversalDepth); - ImGui::Text("Segs"); - //ImGui::Text(" Full %d", s_viewStats->segWallRendered); - //ImGui::Text(" Lower %d", s_viewStats->segLowerRendered); - //ImGui::Text(" Upper %d", s_viewStats->segUpperRendered); - ImGui::Text("Flats"); - //ImGui::Text(" Floor %d", s_viewStats->floorPolyRendered); - //ImGui::Text(" Ceiling %d", s_viewStats->ceilPolyRendered); - ImGui::End(); - } - return; - } - - if (s_levelCount) - { - ImGui::Begin("LevelList", isActive); - ImGui::Text("Level Count: %u", s_levelCount); - - if (ImGui::ListBox("", &s_curLevel, s_levelNames, (s32)s_levelCount, 14)) - { - s_fileType = TYPE_LEV; - strcpy(s_levelFile, s_levelFiles[s_curLevel]); - TFE_LevelAsset::load(s_levelFiles[s_curLevel]); - LevelData* level = TFE_LevelAsset::getLevelData(); - - // get the map center. - s_renderCenter[0] = 0.0f; - s_renderCenter[1] = 0.0f; - - f32 aabbMin[2] = { FLT_MAX, FLT_MAX }; - f32 aabbMax[2] = { -FLT_MAX, -FLT_MAX }; - const u32 vertexCount = (u32)level->vertices.size(); - const Vec2f* vertices = level->vertices.data(); - for (u32 v = 0; v < vertexCount; v++) - { - if (fabsf(vertices[v].x) > 4096.0f || fabsf(vertices[v].z) > 4096.0f) { continue; } - - aabbMin[0] = std::min(aabbMin[0], vertices[v].x); - aabbMin[1] = std::min(aabbMin[1], vertices[v].z); - aabbMax[0] = std::max(aabbMax[0], vertices[v].x); - aabbMax[1] = std::max(aabbMax[1], vertices[v].z); - } - - s_renderCenter[0] = -(aabbMin[0] + aabbMax[0]) * 0.5f; - s_renderCenter[1] = -(aabbMin[1] + aabbMax[1]) * 0.5f; - s_mapZoom = 1.0f; - s_renderer->clearMapMarkers(); - - StartLocation start = {}; - start.overrideStart = false; - - if (TFE_GameLoop::startLevel(level, start, s_renderer, config->gameResolution.x, config->gameResolution.z, true)) - { - s_renderer->changeResolution(config->gameResolution.x, config->gameResolution.z, config->widescreen, config->asyncFramebuffer, config->gpuColorConvert); - s_runLevel = true; - s_showUi = false; - TFE_Input::enableRelativeMode(true); - s_renderer->enableScreenClear(false); - } - } - - ImGui::End(); - } - - bool openArchiveFileDialog = false; - ImGui::Begin("ArchiveViewer", isActive); - if (ImGui::Button("Open Archive")) - { - openArchiveFileDialog = true; - } - if (s_curArchiveName[0]) - { - ImGui::Text("Current Archive: %s", s_curArchiveName); - ImGui::Text("File Count: %u", s_curArchive->getFileCount()); - - if (ImGui::ListBox("", &s_currentFile, s_items.data(), (s32)s_items.size(), 25)) - { - size_t len = (size_t)s_curArchive->getFileLength(s_currentFile); - s_text.resize(len); - - s_curArchive->openFile(s_currentFile); - s_curArchive->readFile((void*)s_text.data(), len); - s_curArchive->closeFile(); - - TFE_MidiPlayer::stop(); - - char extension[16]; - FileUtil::getFileExtension(s_items[s_currentFile], extension); - s_fileType = TYPE_BIN; - - if (strcasecmp(extension, "TXT") == 0 || strcasecmp(extension, "MSG") == 0 || strcasecmp(extension, "LST") == 0 || - strcasecmp(extension, "LVL") == 0 || strcasecmp(extension, "INF") == 0 || strcasecmp(extension, "O") == 0 || - strcasecmp(extension, "VUE") == 0 || strcasecmp(extension, "GOL") == 0) - { - s_fileType = TYPE_TEXT; - } - else if (strcasecmp(extension, "LEV") == 0) - { - s_fileType = TYPE_LEV; - strcpy(s_levelFile, s_items[s_currentFile]); - TFE_LevelAsset::load(s_items[s_currentFile]); - LevelData* level = TFE_LevelAsset::getLevelData(); - - // get the map center. - s_renderCenter[0] = 0.0f; - s_renderCenter[1] = 0.0f; - - f32 aabbMin[2] = { FLT_MAX, FLT_MAX }; - f32 aabbMax[2] = { -FLT_MAX, -FLT_MAX }; - const u32 vertexCount = (u32)level->vertices.size(); - const Vec2f* vertices = level->vertices.data(); - for (u32 v = 0; v < vertexCount; v++) - { - if (fabsf(vertices[v].x) > 4096.0f || fabsf(vertices[v].z) > 4096.0f) { continue; } - - aabbMin[0] = std::min(aabbMin[0], vertices[v].x); - aabbMin[1] = std::min(aabbMin[1], vertices[v].z); - aabbMax[0] = std::max(aabbMax[0], vertices[v].x); - aabbMax[1] = std::max(aabbMax[1], vertices[v].z); - } - - s_renderCenter[0] = -(aabbMin[0] + aabbMax[0]) * 0.5f; - s_renderCenter[1] = -(aabbMin[1] + aabbMax[1]) * 0.5f; - s_mapZoom = 1.0f; - s_renderer->clearMapMarkers(); - } - else if (strcasecmp(extension, "PAL") == 0) - { - s_fileType = TYPE_PAL; - s_curPal = TFE_Palette::get256(s_items[s_currentFile]); - } - else if (strcasecmp(extension, "BM") == 0) - { - s_fileType = TYPE_TEX; - s_curTexture = TFE_Texture::get(s_items[s_currentFile]); - } - else if (strcasecmp(extension, "PCX") == 0) - { - s_fileType = TYPE_TEX; - s_curTexture = TFE_Texture::getFromPCX(s_items[s_currentFile], s_curArchiveFile); - s_curPal = TFE_Texture::getPreviousPalette(); - } - else if (strcasecmp(extension, "FNT") == 0) - { - s_fileType = TYPE_FNT; - s_curFont = TFE_Font::get(s_items[s_currentFile]); - } - else if (strcasecmp(extension, "FME") == 0) - { - s_fileType = TYPE_FRAME; - s_curFrame = TFE_Sprite::getFrame(s_items[s_currentFile]); - } - else if (strcasecmp(extension, "WAX") == 0) - { - s_fileType = TYPE_SPRITE; - s_curSprite = TFE_Sprite::getSprite(s_items[s_currentFile]); - s_anim = 0; - s_angle = 0; - } - else if (strcasecmp(extension, "3DO") == 0) - { - s_fileType = TYPE_3D; - s_curModel = TFE_Model::get(s_items[s_currentFile]); - //TFE_GameLoop::startRenderer(s_renderer, 640, 480); - } - else if (strcasecmp(extension, "VOC") == 0 || strcasecmp(extension, "VOIC") == 0) - { - s_fileType = TYPE_VOC; - const SoundBuffer* sound = TFE_VocAsset::get(s_items[s_currentFile]); - - TFE_Audio::playOneShot(SOUND_2D, 1.0f, MONO_SEPERATION, sound, false); - } - else if (strcasecmp(extension, "GMD") == 0 || strcasecmp(extension, "GMID") == 0) - { - s_fileType = TYPE_GMID; - const GMidiAsset* song = TFE_GmidAsset::get(s_items[s_currentFile]); - TFE_MidiPlayer::playSong(song, false); - } - else if (strcasecmp(extension, "PLTT") == 0) - { - s_fileType = TYPE_PAL; - s_curPal = TFE_Palette::getPalFromPltt(s_items[s_currentFile], s_curArchiveFile); - } - else if (strcasecmp(extension, "DELT") == 0) - { - s_fileType = TYPE_TEX; - s_curTexture = TFE_Texture::getFromDelt(s_items[s_currentFile], s_curArchiveFile); - } - else if (strcasecmp(extension, "ANIM") == 0) - { - s_fileType = TYPE_TEX; - s_curTexture = TFE_Texture::getFromAnim(s_items[s_currentFile], s_curArchiveFile); - } - else if (strcasecmp(extension, "FONT") == 0) - { - s_fileType = TYPE_FNT; - s_curFont = TFE_Font::getFromFont(s_items[s_currentFile], s_curArchiveFile); - } - - for (size_t i = 0; i < len; i++) - { - if (s_text[i] < ' ' && s_text[i] != '\t' && s_text[i] != '\r' && s_text[i] != '\n') { s_text[i] = ' '; } - } - - s_showFile = true; - } - } - - if (openArchiveFileDialog) - { - FileResult res = TFE_Ui::openFileDialog("Open Archive", TFE_Paths::getPath(PATH_SOURCE_DATA), { "Gob Archive", "*.gob", "LFD Archive", "*.lfd", "LAB Archive", "*.lab" }); - if (!res.empty() && !res[0].empty()) - { - strcpy(s_curArchiveFile, res[0].c_str()); - FileUtil::getFileNameFromPath(s_curArchiveFile, s_curArchiveName, true); - - char extension[TFE_MAX_PATH]; - FileUtil::getFileExtension(s_curArchiveName, extension); - - ArchiveType type = ARCHIVE_COUNT; - if (strcasecmp(extension, "gob") == 0) { type = ARCHIVE_GOB; } - else if (strcasecmp(extension, "lfd") == 0) { type = ARCHIVE_LFD; } - else if (strcasecmp(extension, "lab") == 0) { type = ARCHIVE_LAB; } - else { assert(0); } - - s_curArchive = Archive::getArchive(type, s_curArchiveName, s_curArchiveFile); - s_currentFile = 0; - s_showFile = false; - s_fileType = TYPE_COUNT; - - TFE_AssetSystem::setCustomArchive(s_curArchive); - // All assets need to be unloaded when setting up a custom archive since they may have the same names - // as the vanilla assets. - unloadAssets(); - - const u32 fileCount = s_curArchive->getFileCount(); - s_items.resize(fileCount); - for (u32 i = 0; i < fileCount; i++) - { - s_items[i] = s_curArchive->getFileName(i); - } - } - } - - ImGui::Checkbox("Always Display As Text", &s_showAsText); - ImGui::End(); - - if (s_curArchiveName[0] && s_showFile && (s_fileType == TYPE_TEXT || s_showAsText)) - { - ImGui::Begin("TextViewer", &s_showFile); - ImGui::InputTextMultiline("", (char*)s_text.data(), s_text.size(), ImVec2(scaleUi(600), scaleUi(600)), ImGuiInputTextFlags_ReadOnly); - ImGui::End(); - } - else if (s_curArchiveName[0] && s_showFile && s_fileType == TYPE_LEV) - { - LevelData* level = TFE_LevelAsset::getLevelData(); - if (s_layer < level->layerMin) { s_layer = level->layerMin; } - else if (s_layer > level->layerMax) { s_layer = level->layerMax; } - - ImGui::Begin("LevelViewer", &s_showFile); - if (ImGui::ImageButton(TFE_RenderBackend::getVirtualDisplayGpuPtr(), ImVec2(scaleUi(640), scaleUi(480)), ImVec2(0, 1), ImVec2(1, 0), 0)) - { - ImVec2 corner = ImGui::GetWindowContentRegionMin(); - ImVec2 winPos = ImGui::GetWindowPos(); - selectPointOnMap(corner.x + winPos.x, corner.y + winPos.y); - } - ImGui::Text("Layer Range: [%d, %d]", level->layerMin, level->layerMax); - ImGui::SliderInt("Layer", &s_layer, level->layerMin, level->layerMax); - - if (ImGui::Button("Play from Marker")) - { - if (s_renderer->getMapMarkerCount() > 0) - { - StartLocation start; - start.overrideStart = true; - start.pos = s_mapPos; - start.layer = s_layer; - - if (TFE_GameLoop::startLevel(level, start, s_renderer, config->gameResolution.x, config->gameResolution.z, true)) - { - s_renderer->changeResolution(config->gameResolution.x, config->gameResolution.z, config->widescreen, config->asyncFramebuffer, config->gpuColorConvert); - s_runLevel = true; - s_showUi = false; - TFE_Input::enableRelativeMode(true); - s_renderer->enableScreenClear(false); - } - } - } - if (ImGui::Button("Play from Start")) - { - StartLocation start = {}; - start.overrideStart = false; - - if (TFE_GameLoop::startLevel(level, start, s_renderer, config->gameResolution.x, config->gameResolution.z, true)) - { - s_renderer->changeResolution(config->gameResolution.x, config->gameResolution.z, config->widescreen, config->asyncFramebuffer, config->gpuColorConvert); - s_runLevel = true; - s_showUi = false; - TFE_Input::enableRelativeMode(true); - } - } - ImGui::End(); - - // Handle right-button scrolling. - if (TFE_Input::mouseDown(MBUTTON_RIGHT)) - { - s32 x, y; - TFE_Input::getMouseMove(&x, &y); - if (x || y) - { - s_renderCenter[0] += f32(x) / s_mapZoom; - s_renderCenter[1] -= f32(y) / s_mapZoom; - } - - s32 dx, dy; - TFE_Input::getMouseWheel(&dx, &dy); - if (dy) - { - s_mapZoom += f32(dy) * f32(TFE_System::getDeltaTime() * 3.0); - } - } - } - else if (s_curArchiveName[0] && s_showFile && s_fileType == TYPE_SPRITE) - { - ImGui::Begin("SpriteViewer", &s_showFile); - ImGui::Image(TFE_RenderBackend::getVirtualDisplayGpuPtr(), ImVec2(scaleUi(640), scaleUi(480)), ImVec2(0, 1), ImVec2(1, 0)); - - ImGui::SliderInt("Animation", &s_anim, 0, s_curSprite->animationCount - 1); - ImGui::SliderInt("Angle", &s_angle, 0, s_curSprite->anim[s_anim].angleCount - 1); - - ImGui::End(); - } - else if (s_curArchiveName[0] && s_showFile) - { - ImGui::Begin("ObjectViewer", &s_showFile); - ImGui::Image(TFE_RenderBackend::getVirtualDisplayGpuPtr(), ImVec2(scaleUi(640), scaleUi(480)), ImVec2(0, 1), ImVec2(1, 0)); - ImGui::End(); - } - } -} diff --git a/TheForceEngine/TFE_Editor/archiveViewer.h b/TheForceEngine/TFE_Editor/archiveViewer.h deleted file mode 100644 index 7416b749a..000000000 --- a/TheForceEngine/TFE_Editor/archiveViewer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include -#include - -namespace ArchiveViewer -{ - void init(TFE_Renderer* renderer); - void draw(bool* isActive); - bool isFullscreen(); - - // Returns true if a fullscreen blit is required. - bool render3dView(); -} diff --git a/TheForceEngine/TFE_Editor/editor.cpp b/TheForceEngine/TFE_Editor/editor.cpp index 1b322147d..dd6a947fe 100644 --- a/TheForceEngine/TFE_Editor/editor.cpp +++ b/TheForceEngine/TFE_Editor/editor.cpp @@ -1,6 +1,6 @@ #include "editor.h" #include "editorConfig.h" -#include "assetBrowser.h" +#include #include #include #include diff --git a/TheForceEngine/TFE_Editor/levelEditor.cpp b/TheForceEngine/TFE_Editor/levelEditor.cpp deleted file mode 100644 index ae08b1e1e..000000000 --- a/TheForceEngine/TFE_Editor/levelEditor.cpp +++ /dev/null @@ -1,5780 +0,0 @@ -#include "levelEditor.h" -#include "Help/helpWindow.h" -#include "levelEditorData.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//Help -#include "help/helpWindow.h" - -#include -//Rendering 2d -#include -#include -#include -#include -//Rendering 3d -#include -#include -#include - -// Triangulation -#include - -// UI -#include - -// Game -#include - -#include -#include - -// TODO: Add features to the file browser: -// 1. Filter does not exclude directories. -// 2. Ability to auto-set filter. -// 3. Ability to show only directories and select them. - -using TrianglesColor3d::Tri3dTrans; - -#define CONV_6bitTo8bit(x) (((x)<<2) | ((x)>>4)) -#define CONV_5bitTo8bit(x) (((x)<<3) | ((x)>>2)) -#define PACK_RGB_666_888(r6, g6, b6) CONV_6bitTo8bit(r6) | (CONV_6bitTo8bit(g6)<<8) | (CONV_6bitTo8bit(b6)<<16) | (0xff << 24) - -namespace LevelEditor -{ - #define TEXTURES_GOB_START_TEX 41 - - enum EditorView - { - EDIT_VIEW_2D = 0, - EDIT_VIEW_3D, - EDIT_VIEW_3D_GAME, - EDIT_VIEW_PLAY, - }; - - enum SectorDrawMode - { - SDM_WIREFRAME = 0, - SDM_LIGHTING, - SDM_TEXTURED_FLOOR, - SDM_TEXTURED_CEIL, - SDM_COUNT - }; - - enum LevelEditMode - { - LEDIT_DRAW = 1, - LEDIT_VERTEX, - LEDIT_WALL, - LEDIT_SECTOR, - LEDIT_ENTITY - }; - - enum BooleanMode - { - BOOL_SET = 0, - BOOL_SUBTRACT, - BOOL_INV_SUBTRACT, - BOOL_ADD, - BOOL_INTERSECT, - BOOL_INV_INTERSECT, - BOOL_COUNT - }; - - struct LevelFilePath - { - char gobName[64]; - char levelFilename[64]; - char levelName[64]; - char gobPath[TFE_MAX_PATH]; - }; - - static const f32 c_worldToTexelScale = 8.0f; - static const f32 c_texelToWorldScale = 1.0f / c_worldToTexelScale; - static const f32 c_aspect = 4.0f / 3.0f; - static const f32 c_spriteTexelToWorldScale = c_texelToWorldScale / c_aspect; - - static s32 s_gridIndex = 5; - static f32 c_gridSizeMap[] = - { - 1.0f, 2.0f, 4.0f, 8.0f, 16.0f, 32.0f, 64.0f, 128.0f, 256.0f - }; - static const char* c_gridSizes[] = - { - "1", - "2", - "4", - "8", - "16", - "32", - "64", - "128", - "256", - }; - - static u32 s_recentCount = 16; // 10 (just adding the rest for testing) - static LevelFilePath s_recentLevels[16] = - { - {"DARK.GOB", "SECBASE.LEV", "Secret Base", "DARK.GOB"}, - {"DARK.GOB", "TALAY.LEV", "Talay: Tak Base", "DARK.GOB"}, - {"DARK.GOB", "SEWERS.LEV", "Anoat City", "DARK.GOB"}, - {"DARK.GOB", "TESTBASE.LEV", "Research Facility", "DARK.GOB"}, - {"DARK.GOB", "GROMAS.LEV", "Gromas Mines", "DARK.GOB"}, - {"DARK.GOB", "DTENTION.LEV", "Detention Center", "DARK.GOB"}, - {"DARK.GOB", "RAMSHED.LEV", "Ramsees Hed", "DARK.GOB"}, - {"DARK.GOB", "ROBOTICS.LEV", "Robotics Facility", "DARK.GOB"}, - {"DARK.GOB", "NARSHADA.LEV", "Nar Shaddaa", "DARK.GOB"}, - {"DARK.GOB", "JABSHIP.LEV", "Jabba's Ship", "DARK.GOB"}, - - {"DARK.GOB", "IMPCITY.LEV", "Imperial City", "DARK.GOB"}, - {"DARK.GOB", "FUELSTAT.LEV", "Fuel Station", "DARK.GOB"}, - {"DARK.GOB", "EXECUTOR.LEV", "The Executor", "DARK.GOB"}, - {"DARK.GOB", "ARC.LEV", "The Arc Hammer", "DARK.GOB"}, - - {"DEMO1.GOB", "SECBASE.LEV", "Demo 1", "DEMO1.GOB"}, - {"DEMO3.GOB", "SECBASE.LEV", "Demo 3", "DEMO3.GOB"}, - }; - - static const f32 c_gridInvisibleHeight = 10000.0f; - - static EditorView s_editView = EDIT_VIEW_2D; - static bool s_showLowerLayers = true; - static bool s_enableInfEditor = false; - - static char s_gobFile[TFE_MAX_PATH] = ""; - static char s_levelFile[TFE_MAX_PATH] = ""; - static char s_levelName[64] = ""; - static bool s_loadLevel = false; - static bool s_showSectorColors = true; - static TFE_Renderer* s_renderer; - static void* s_editCtrlToolbarData = nullptr; - static void* s_booleanToolbarData = nullptr; - static RenderTargetHandle s_view3d = nullptr; - - static EditorLevel* s_levelData = nullptr; - - static Vec2f s_editWinPos = { 0.0f, 67.0f }; - static Vec2f s_editWinSize; - static Vec2f s_editWinMapCorner; - - static f32 s_gridSize = 32.0f; - static f32 s_subGridSize = 32.0f; - // 2D Camera - static f32 s_zoom = 0.25f; - static f32 s_zoomVisual = s_zoom; - static f32 s_gridOpacity = 0.25f; - static Vec2f s_offset = { 0 }; - static Vec2f s_offsetVis = { 0 }; - // 3D Camera - struct Camera - { - Vec3f pos; - Mat3 viewMtx; - Mat4 projMtx; - Mat4 invProj; - - f32 yaw = 0.0f; - f32 pitch = 0.0f; - }; - static Camera s_camera; - - static char s_layerMem[4 * 31]; - static char* s_layerStr[31]; - static const s32 s_layerMin = -15; - static s32 s_layerIndex = 1 - s_layerMin; - static s32 s_infoHeight = 300; - - // Editing - static f32 s_gridHeight = 0.0f; - static bool s_gridAutoAdjust = false; - static bool s_showGridInSector = true; - static bool s_drawStarted = false; - static Vec3f s_drawPlaneNrm; - static Vec3f s_drawPlaneOrg; - static Vec2f s_drawBaseVtx[2]; - static bool s_moveVertex = false; - static bool s_moveWall = false; - static EditorSector s_newSector = {}; - - // Sector Rendering - static SectorDrawMode s_sectorDrawMode = SDM_WIREFRAME; - static bool s_fullbright = false; - - static u32 s_editMode = LEDIT_DRAW; - static u32 s_boolMode = BOOL_SET; - static s32 s_selectedSector = -1; - static s32 s_hoveredSector = -1; - static s32 s_selectedWall = -1; - static s32 s_hoveredWall = -1; - static s32 s_selectedEntity = -1; - static s32 s_hoveredEntity = -1; - static s32 s_selectedEntitySector = -1; - static s32 s_hoveredEntitySector = -1; - static RayHitPart s_selectWallPart; - static RayHitPart s_hoveredWallPart; - static s32 s_selectedWallSector = -1; - static s32 s_hoveredWallSector = -1; - static s32 s_selectedVertex = -1; - static s32 s_hoveredVertex = -1; - static s32 s_selectedVertexSector = -1; - static s32 s_hoveredVertexSector = -1; - static RayHitPart s_selectVertexPart; - static RayHitPart s_hoveredVertexPart; - - static Vec3f s_cursor3d = { 0 }; - static Vec3f s_cursorSnapped = { 0 }; - static Vec3f s_rayDir = { 0 }; - static s32 s_hideFrames = 0; - static const Palette256* s_palette; - static bool s_runLevel = false; - - static Archive* s_outGob = nullptr; - - // Error message - static bool s_showError = false; - static char s_errorMessage[TFE_MAX_PATH]; - - void drawSectorPolygon(const EditorSector* sector, bool hover, u32 colorOverride = 0); - void drawTexturedSectorPolygon(const EditorSector* sector, u32 color, bool floorTex); - - void loadLevel(); - void toolbarBegin(); - void toolbarEnd(); - void levelEditWinBegin(); - void levelEditWinEnd(); - void infoToolBegin(s32 height); - void infoToolEnd(); - void browserBegin(s32 offset); - void browserEnd(); - void messagePanel(ImVec2 pos); - - // Info panels - void infoPanelMap(); - void infoPanelVertex(); - void infoPanelWall(); - void infoPanelInfWall(EditorSector* sector, u32 wallId); - void infoPanelSector(); - void infoPanelEntity(); - // Browser panels - void browseTextures(); - void browseEntities(); - - void play(bool playFromDos); - - // Draw - void drawSector3d(const EditorSector* sector, const SectorTriangles* poly, bool overlay = false, bool hover = false, bool lowerLayer = false); - void drawSector3d_Lines(const EditorSector* sector, f32 width, u32 color, bool overlay = false, bool hover = false); - void drawInfWalls3d(f32 width, u32 color); - void drawWallColor(const EditorSector* sector, const Vec2f* vtx, const EditorWall* wall, const u32* color, bool blend = false, RayHitPart part = HIT_PART_UNKNOWN, bool showAllWallsOnBlend = true); - - // Error Handling - bool isValidName(const char* name); - void popupErrorMessage(const char* errorMessage); - void showErrorPopup(); - - // General viewport editing - void deleteSector(EditorSector* sector); - - // 2D viewport editing - void editSector2d(Vec2f worldPos, s32 sectorId); - void editWalls2d(Vec2f worldPos); - void editVertices2d(Vec2f worldPos); - void editEntities2d(Vec2f worldPos); - void editEntities2d(Vec2f worldPos); - void editDrawSectors2d(Vec2f worldPos); - bool editInsertVertex2d(Vec2f worldPos); - bool editInsertVertex2d(Vec2f worldPos, s32 sectorId, s32 wallId); - void clearNewSector(); - - void splitSector(EditorSector* sector, Vec2f v0, Vec2f v1, u32 insideVertexCount = 0, const Vec2f* insideVtx = nullptr); - - void* loadGpuImage(const char* localPath) - { - char imagePath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, localPath, imagePath, TFE_MAX_PATH); - SDL_Surface* image = TFE_Image::get(imagePath); - if (image) - { - TextureGpu* editCtrlHandle = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); - return TFE_RenderBackend::getGpuPtr(editCtrlHandle); - } - return nullptr; - } - - void init(TFE_Renderer* renderer) - { - TFE_EditorRender::init(); - - s_renderer = renderer; - s_renderer->enableScreenClear(true); - - // Load UI images. - s_editCtrlToolbarData = loadGpuImage("UI_Images/EditCtrl_32x6.png"); - s_booleanToolbarData = loadGpuImage("UI_Images/Boolean_32x6.png"); - - u32 idx = 0; - for (s32 i = -15; i < 16; i++, idx += 4) - { - s_layerStr[i + 15] = &s_layerMem[idx]; - sprintf(s_layerStr[i + 15], "%d", i); - } - - // Create a basic 3d camera. - s_camera.pos = { 0.0f, -2.0f, 0.0f }; - s_camera.yaw = 0.0f; - s_camera.pitch = 0.0f; - } - - void disable() - { - Archive::deleteCustomArchive(s_outGob); - TFE_EditorRender::destroy(); - - s_outGob = nullptr; - } - - bool render3dView() - { - if (s_runLevel) - { - GameTransition trans = TFE_GameLoop::update(false); - TFE_GameLoop::draw(); - - if (trans == TRANS_QUIT || trans == TRANS_TO_AGENT_MENU || trans == TRANS_NEXT_LEVEL) - { - s_runLevel = false; - TFE_Input::enableRelativeMode(false); - s_renderer->enableScreenClear(true); - } - - return true; - } - return false; - } - - bool isFullscreen() - { - return false; - } - - bool drawToolbarButton(void* ptr, u32 imageId, bool highlight) - { - const f32 imageHeightScale = 1.0f / 192.0f; - const f32 y0 = f32(imageId) * 32.0f; - const f32 y1 = y0 + 32.0f; - - ImGui::PushID(imageId); - bool res = ImGui::ImageButton(ptr, ImVec2(32, 32), ImVec2(0.0f, y0 * imageHeightScale), ImVec2(1.0f, y1 * imageHeightScale), 0, ImVec4(0, 0, 0, highlight ? 0.75f : 0.25f), ImVec4(1, 1, 1, 1)); - ImGui::PopID(); - - return res; - } - - void cameraControl2d(s32 mx, s32 my) - { - f32 moveSpd = s_zoomVisual * f32(960.0 * TFE_System::getDeltaTime()); - if (TFE_Input::keyDown(KEY_W)) - { - s_offset.z -= moveSpd; - } - else if (TFE_Input::keyDown(KEY_S)) - { - s_offset.z += moveSpd; - } - - if (TFE_Input::keyDown(KEY_A)) - { - s_offset.x -= moveSpd; - } - else if (TFE_Input::keyDown(KEY_D)) - { - s_offset.x += moveSpd; - } - - // Mouse scrolling. - if (TFE_Input::mouseDown(MBUTTON_RIGHT)) - { - s32 dx, dy; - TFE_Input::getMouseMove(&dx, &dy); - - s_offset.x -= f32(dx) * s_zoomVisual; - s_offset.z -= f32(dy) * s_zoomVisual; - } - - s32 dx, dy; - TFE_Input::getMouseWheel(&dx, &dy); - if (dy != 0) - { - // We want to zoom into the mouse position. - s32 relX = s32(mx - s_editWinMapCorner.x); - s32 relY = s32(my - s_editWinMapCorner.z); - // Old position in world units. - Vec2f worldPos; - worldPos.x = s_offset.x + f32(relX) * s_zoomVisual; - worldPos.z = s_offset.z + f32(relY) * s_zoomVisual; - - s_zoom = std::max(s_zoom - f32(dy) * s_zoom * 0.1f, 0.001f); - s_zoomVisual = floorf(s_zoom * 1000.0f) * 0.001f; - - // We want worldPos to stay put as we zoom - Vec2f newWorldPos; - newWorldPos.x = s_offset.x + f32(relX) * s_zoomVisual; - newWorldPos.z = s_offset.z + f32(relY) * s_zoomVisual; - s_offset.x += (worldPos.x - newWorldPos.x); - s_offset.z += (worldPos.z - newWorldPos.z); - } - } - - // return true to use relative mode. - bool cameraControl3d(s32 mx, s32 my) - { - // Movement - f32 moveSpd = f32(16.0 * TFE_System::getDeltaTime()); - if (TFE_Input::keyDown(KEY_LSHIFT) || TFE_Input::keyDown(KEY_RSHIFT)) - { - moveSpd *= 10.0f; - } - - if (TFE_Input::keyDown(KEY_W)) - { - s_camera.pos.x -= s_camera.viewMtx.m2.x * moveSpd; - s_camera.pos.y -= s_camera.viewMtx.m2.y * moveSpd; - s_camera.pos.z -= s_camera.viewMtx.m2.z * moveSpd; - } - else if (TFE_Input::keyDown(KEY_S)) - { - s_camera.pos.x += s_camera.viewMtx.m2.x * moveSpd; - s_camera.pos.y += s_camera.viewMtx.m2.y * moveSpd; - s_camera.pos.z += s_camera.viewMtx.m2.z * moveSpd; - } - - if (TFE_Input::keyDown(KEY_A)) - { - s_camera.pos.x -= s_camera.viewMtx.m0.x * moveSpd; - s_camera.pos.y -= s_camera.viewMtx.m0.y * moveSpd; - s_camera.pos.z -= s_camera.viewMtx.m0.z * moveSpd; - } - else if (TFE_Input::keyDown(KEY_D)) - { - s_camera.pos.x += s_camera.viewMtx.m0.x * moveSpd; - s_camera.pos.y += s_camera.viewMtx.m0.y * moveSpd; - s_camera.pos.z += s_camera.viewMtx.m0.z * moveSpd; - } - - // Turning. - if (TFE_Input::mouseDown(MBUTTON_RIGHT)) - { - s32 dx, dy; - TFE_Input::getMouseMove(&dx, &dy); - - const f32 turnSpeed = 0.01f; - s_camera.yaw += f32(dx) * turnSpeed; - s_camera.pitch -= f32(dy) * turnSpeed; - - if (s_camera.yaw < 0.0f) { s_camera.yaw += PI * 2.0f; } - else { s_camera.yaw = fmodf(s_camera.yaw, PI * 2.0f); } - - if (s_camera.pitch < -1.55f) { s_camera.pitch = -1.55f; } - else if (s_camera.pitch > 1.55f) { s_camera.pitch = 1.55f; } - - s_cursor3d = { 0 }; - return true; - } - else if (TFE_Input::relativeModeEnabled()) - { - s_hideFrames = 3; - } - return false; - } - - void editWinControls2d(s32 mx, s32 my) - { - // We want to zoom into the mouse position. - s32 relX = s32(mx - s_editWinMapCorner.x); - s32 relY = s32(my - s_editWinMapCorner.z); - - // Compute the cursor position in 3D space. - Vec2f worldPos; - worldPos.x = s_offset.x + f32(relX) * s_zoomVisual; - worldPos.z = -(s_offset.z + f32(relY) * s_zoomVisual); - s32 curSector = LevelEditorData::findSector(s_layerIndex + s_layerMin, &worldPos); - - s_cursor3d.x = worldPos.x; - s_cursor3d.y = (curSector >= 0) ? s_levelData->sectors[curSector].floorAlt : s_gridHeight; - s_cursor3d.z = worldPos.z; - - // Editing - if (s_editMode != LEDIT_SECTOR) { s_selectedSector = -1; } - if (s_editMode != LEDIT_ENTITY) { s_selectedEntity = -1; } - - if (TFE_Input::keyPressed(KEY_INSERT)) - { - editInsertVertex2d(worldPos); - } - - editSector2d(worldPos, curSector); - editWalls2d(worldPos); - editVertices2d(worldPos); - editEntities2d(worldPos); - editDrawSectors2d(worldPos); - - // Compute the visual view offset. - s_offsetVis.x = floorf(s_offset.x * 100.0f) * 0.01f; - s_offsetVis.z = floorf(s_offset.z * 100.0f) * 0.01f; - } - - Vec4f transform(const Mat4& mtx, const Vec4f& vec) - { - return { TFE_Math::dot(&mtx.m0, &vec), TFE_Math::dot(&mtx.m1, &vec), TFE_Math::dot(&mtx.m2, &vec), TFE_Math::dot(&mtx.m3, &vec) }; - } - - // Get the world direction from the current screen pixel coordinates. - Vec3f getWorldDir(s32 x, s32 y, s32 rtWidth, s32 rtHeight) - { - // Given a plane at Z = 1.0, figure out the view space position of the pixel. - const Vec4f posScreen = - { - f32(x) / f32(rtWidth) * 2.0f - 1.0f, - f32(y) / f32(rtHeight) * 2.0f - 1.0f, - -1.0f, 1.0f - }; - const Vec4f posView = transform(s_camera.invProj, posScreen); - const Mat3 viewT = TFE_Math::transpose(s_camera.viewMtx); - - const Vec3f posView3 = { posView.x, posView.y, posView.z }; - const Vec3f posRelWorld = // world relative to the camera position. - { - TFE_Math::dot(&posView3, &viewT.m0), - TFE_Math::dot(&posView3, &viewT.m1), - TFE_Math::dot(&posView3, &viewT.m2) - }; - return TFE_Math::normalize(&posRelWorld); - } - - Vec3f rayGridPlaneHit(const Vec3f& origin, const Vec3f& rayDir) - { - Vec3f hit = { 0 }; - if (fabsf(rayDir.y) < FLT_EPSILON) { return hit; } - - f32 s = (s_gridHeight - origin.y) / rayDir.y; - if (s <= 0) { return hit; } - - hit.x = origin.x + s*rayDir.x; - hit.y = origin.y + s*rayDir.y; - hit.z = origin.z + s*rayDir.z; - return hit; - } - - bool rayPlaneHit(const Vec3f& origin, const Vec3f& rayDir, Vec3f* hit) - { - const f32 den = TFE_Math::dot(&rayDir, &s_drawPlaneNrm); - if (fabsf(den) <= FLT_EPSILON) { return false; } - - Vec3f offset = { s_drawPlaneOrg.x - origin.x, s_drawPlaneOrg.y - origin.y, s_drawPlaneOrg.z - origin.z }; - f32 s = TFE_Math::dot(&offset, &s_drawPlaneNrm) / den; - if (s < 0.0f) { return false; } - - *hit = { origin.x + rayDir.x * s, origin.y + rayDir.y * s, origin.z + rayDir.z * s }; - return true; - } - - static const f32 c_vertexMerge = 0.005f; - - bool vec2Equals(const Vec2f& a, const Vec2f& b) - { - return fabsf(a.x - b.x) < c_vertexMerge && fabsf(a.z - b.z) < c_vertexMerge; - } - - // Is the position "near" a wall that it can snap to? - bool snapToGeometry(Vec3f* pos, bool view2d) - { - if (view2d) - { - Vec2f worldPos = { pos->x, pos->z }; - s32 sectorId = LevelEditorData::findSector(s_layerIndex + s_layerMin, &worldPos); - s32 wallId = LevelEditorData::findClosestWall(§orId, s_layerIndex + s_layerMin, &worldPos, s_zoomVisual * 16.0f); - if (sectorId < 0 || wallId < 0) { return false; } - - const EditorSector* sector = &s_levelData->sectors[sectorId]; - const EditorWall* wall = §or->walls[wallId]; - const Vec2f* vtx = sector->vertices.data(); - - const Vec2f& v0 = vtx[wall->i0]; - const Vec2f& v1 = vtx[wall->i1]; - - Vec2f linePos; - Geometry::closestPointOnLineSegment(v0, v1, worldPos, &linePos); - f32 maxDistSq = s_zoomVisual * 8.0f; - maxDistSq *= maxDistSq; - // First check the vertices - if (TFE_Math::distanceSq(&v0, &worldPos) < maxDistSq) - { - s_cursorSnapped.x = v0.x; - s_cursorSnapped.z = v0.z; - } - else if (TFE_Math::distanceSq(&v1, &worldPos) < maxDistSq) - { - s_cursorSnapped.x = v1.x; - s_cursorSnapped.z = v1.z; - } - else - { - f32 minDistSq = maxDistSq; - Vec2f minLinePos; - - // Holding Alt will disable grid line snapping. - if (!TFE_Input::keyDown(KEY_LALT) && !TFE_Input::keyDown(KEY_RALT)) - { - // Next check to see if we can snap to either X or Z while staying on the line. - const f32 gridScale = s_gridSize / s_subGridSize; - - // Test the nearest grid line versus line intersections and see if they are close enough - // to snap to. - Vec2f posGridSpace = { worldPos.x / gridScale, worldPos.z / gridScale }; - posGridSpace.x = floorf(posGridSpace.x + 0.5f) * gridScale; - posGridSpace.z = floorf(posGridSpace.z + 0.5f) * gridScale; - - const f32 dx = v1.x - v0.x; - const f32 dz = v1.z - v0.z; - if (fabsf(dx) > 0.005f) - { - const f32 s = (posGridSpace.x - v0.x) / dx; - const Vec2f snappedPos = { v0.x + s * dx, v0.z + s * dz }; - const f32 distSq = TFE_Math::distanceSq(&snappedPos, &worldPos); - if (distSq < minDistSq) - { - minDistSq = distSq; - minLinePos = snappedPos; - } - } - if (fabsf(dz) > 0.005f) - { - const f32 s = (posGridSpace.z - v0.z) / dz; - const Vec2f snappedPos = { v0.x + s * dx, v0.z + s * dz }; - const f32 distSq = TFE_Math::distanceSq(&snappedPos, &worldPos); - if (distSq < minDistSq) - { - minDistSq = distSq; - minLinePos = snappedPos; - } - } - } - - if (minDistSq < maxDistSq) - { - // Snap to an intersection of the grid and the line. - s_cursorSnapped.x = minLinePos.x; - s_cursorSnapped.z = minLinePos.z; - } - else - { - // Otherwise anywhere on the line. - s_cursorSnapped.x = linePos.x; - s_cursorSnapped.z = linePos.z; - } - } - return true; - } - return false; - } - - void snapToGrid(Vec3f* pos, bool view2d) - { - // Holding alt disables snap to grid. - if (TFE_Input::keyDown(KEY_LALT) || TFE_Input::keyDown(KEY_RALT)) - { - return; - } - - if (view2d) - { - f32 gridScale = s_gridSize / s_subGridSize; - - Vec2f posGridSpace = { pos->x / gridScale, pos->z / gridScale }; - pos->x = floorf(posGridSpace.x + 0.5f) * gridScale; - pos->z = floorf(posGridSpace.z + 0.5f) * gridScale; - } - else - { - Vec2f posGridSpace = { pos->x, pos->z }; - pos->x = floorf(posGridSpace.x + 0.5f); - pos->z = floorf(posGridSpace.z + 0.5f); - } - } - - // Given a ray (origin + dir); snap the distance to the grid. - // i.e. given the previous and next intersection points, find the closest. - // TODO: Change to find where segment intersects with grid points while moving along the direction. - f32 snapToGrid(const Vec3f* pos, const Vec3f* dir, f32 dist, bool view2d) - { - // Holding alt disables snap to grid. - if (TFE_Input::keyDown(KEY_LALT) || TFE_Input::keyDown(KEY_RALT)) - { - return dist; - } - - f32 gridScale; - if (view2d) - { - gridScale = s_gridSize / s_subGridSize; - } - else - { - gridScale = 1.0f; - } - - // get nearest X intersection. - f32 dX = FLT_MAX; - f32 dZ = FLT_MAX; - - if (fabsf(dir->x) > FLT_EPSILON) - { - f32 curX = pos->x + dist * dir->x; - f32 gridSpaceX = curX / gridScale; - f32 snapX = floorf(gridSpaceX + 0.5f) * gridScale; - - dX = (snapX - pos->x) / dir->x; - } - if (fabsf(dir->z) > FLT_EPSILON) - { - f32 curZ = pos->z + dist * dir->z; - f32 gridSpaceZ = curZ / gridScale; - f32 snapZ = floorf(gridSpaceZ + 0.5f) * gridScale; - - dZ = (snapZ - pos->z) / dir->z; - } - - if (dX < FLT_MAX && fabsf(dX - dist) < fabsf(dZ - dist)) - { - return dX; - } - else if (dZ < FLT_MAX) - { - return dZ; - } - return dist; - } - - void moveVertices(s32 sectorId, s32 wallIndex, const Vec2f& vtxPos, const Vec2f& newPos) - { - if (wallIndex < 0) { return; } - - EditorSector* sectorNext = &s_levelData->sectors[sectorId]; - sectorNext->needsUpdate = true; - - EditorWall& wall = sectorNext->walls[wallIndex]; - if (vec2Equals(vtxPos, sectorNext->vertices[wall.i0])) - { - sectorNext->vertices[wall.i0] = newPos; - } - else if (vec2Equals(vtxPos, sectorNext->vertices[wall.i1])) - { - sectorNext->vertices[wall.i1] = newPos; - } - } - - void handleWallMove(bool view2d) - { - if (s_selectedWall < 0) - { - s_moveWall = false; - return; - } - - EditorSector* sector = s_levelData->sectors.data() + s_selectedWallSector; - const EditorWall* wall = sector->walls.data() + s_selectedWall; - Vec2f* vtx = sector->vertices.data(); - sector->needsUpdate = true; - - Vec3f hit; - if (view2d) - { - hit = s_cursor3d; - } - else - { - Vec3f dir = { s_cursor3d.x - s_camera.pos.x, s_cursor3d.y - s_camera.pos.y, s_cursor3d.z - s_camera.pos.z }; - dir = TFE_Math::normalize(&dir); - if (!rayPlaneHit(s_camera.pos, dir, &hit)) { return; } - } - - // Get the wall normal. - const s32 i0 = wall->i0; - const s32 i1 = wall->i1; - Vec2f* v0 = &vtx[i0]; - Vec2f* v1 = &vtx[i1]; - - Vec3f normal; - normal.x = -(v1->z - v0->z); - normal.y = 0.0f; - normal.z = v1->x - v0->x; - normal = TFE_Math::normalize(&normal); - - // TODO: This snapping doesn't actually work in 2D - though it is fine in 3D, revisit. - Vec3f offset = { hit.x - s_drawPlaneOrg.x, hit.y - s_drawPlaneOrg.y, hit.z - s_drawPlaneOrg.z }; - f32 dist = TFE_Math::dot(&offset, &normal); - dist = snapToGrid(&s_drawPlaneOrg, &normal, dist, view2d); - - Vec2f vtx0 = *v0; - Vec2f vtx1 = *v1; - - // now compute the movement along the normal direction. - *v0 = { s_drawBaseVtx[0].x + normal.x * dist, s_drawBaseVtx[0].z + normal.z * dist }; - *v1 = { s_drawBaseVtx[1].x + normal.x * dist, s_drawBaseVtx[1].z + normal.z * dist }; - - // Next handle any sectors across adjoins that have been moved. - const size_t wallCount = sector->walls.size(); - for (size_t w = 0; w < wallCount; w++) - { - if ((sector->walls[w].i0 == i0 || sector->walls[w].i1 == i0) && sector->walls[w].adjoin >= 0) - { - moveVertices(sector->walls[w].adjoin, sector->walls[w].mirror, vtx0, *v0); - } - if ((sector->walls[w].i0 == i1 || sector->walls[w].i1 == i1) && sector->walls[w].adjoin >= 0) - { - moveVertices(sector->walls[w].adjoin, sector->walls[w].mirror, vtx1, *v1); - } - } - - LevelEditorData::updateSectors(); - } - - void handleVertexMove(bool view2d) - { - if (s_selectedVertex < 0) - { - s_moveVertex = false; - return; - } - - // first determine the real hit location on the edit plane. - Vec3f hit; - if (view2d) - { - hit = s_cursor3d; - } - else - { - Vec3f dir = { s_cursor3d.x - s_camera.pos.x, s_cursor3d.y - s_camera.pos.y, s_cursor3d.z - s_camera.pos.z }; - dir = TFE_Math::normalize(&dir); - if (!rayPlaneHit(s_camera.pos, dir, &hit)) { return; } - } - snapToGrid(&hit, view2d); - - EditorSector& sector = s_levelData->sectors[s_selectedVertexSector]; - sector.needsUpdate = true; - - Vec2f vtxPos = sector.vertices[s_selectedVertex]; - sector.vertices[s_selectedVertex] = { hit.x, hit.z }; - - // Next handle any sectors across adjoins that have been moved. - const size_t wallCount = sector.walls.size(); - for (size_t w = 0; w < wallCount; w++) - { - if ((sector.walls[w].i0 == s_selectedVertex || sector.walls[w].i1 == s_selectedVertex) && sector.walls[w].adjoin >= 0) - { - moveVertices(sector.walls[w].adjoin, sector.walls[w].mirror, vtxPos, { hit.x,hit.z }); - } - } - - LevelEditorData::updateSectors(); - } - - void editWinControls3d(s32 mx, s32 my, s32 rtWidth, s32 rtHeight) - { - s_hoveredSector = -1; - s_hoveredWall = -1; - s_hoveredVertex = -1; - s_hoveredVertexSector = -1; - s_hoveredEntity = -1; - if (!TFE_Input::relativeModeEnabled() && s_hideFrames == 0) - { - s_rayDir = getWorldDir(mx - (s32)s_editWinMapCorner.x, my - (s32)s_editWinMapCorner.z, rtWidth, rtHeight); - - const Ray ray = { s_camera.pos, s_rayDir, -1, 1000.0f, s_editMode == LEDIT_ENTITY, s_layerIndex + s_layerMin }; - RayHitInfoLE hitInfo; - if (LevelEditorData::traceRay(&ray, &hitInfo)) - { - s_cursor3d = hitInfo.hitPoint; - - if (s_editMode == LEDIT_SECTOR) - { - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedSector = hitInfo.hitSectorId; - } - else - { - s_hoveredSector = hitInfo.hitSectorId; - } - } - else if (s_editMode == LEDIT_WALL && hitInfo.hitWallId >= 0) - { - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedWallSector = hitInfo.hitSectorId; - s_selectedWall = hitInfo.hitWallId; - s_selectWallPart = hitInfo.hitPart; - - if (!s_moveWall) - { - s_moveWall = true; - // get the plane... - s_drawPlaneNrm = { 0.0f, 1.0f, 0.0f }; - s_drawPlaneOrg = s_cursor3d; - - EditorWall* wall = &s_levelData->sectors[s_selectedWallSector].walls[s_selectedWall]; - s_drawBaseVtx[0] = s_levelData->sectors[s_selectedWallSector].vertices[wall->i0]; - s_drawBaseVtx[1] = s_levelData->sectors[s_selectedWallSector].vertices[wall->i1]; - } - } - else if (!s_moveWall) - { - s_hoveredWallSector = hitInfo.hitSectorId; - s_hoveredWall = hitInfo.hitWallId; - s_hoveredWallPart = hitInfo.hitPart; - } - } - else if (s_editMode == LEDIT_WALL) - { - // In the last case, the ray hit a surface but not a wall. - // Since this is wall edit mode, see if there is a "hidden" wall close enough to select (i.e. an adjoin with no mask wall or upper/lower part). - const EditorSector* sector = s_levelData->sectors.data() + hitInfo.hitSectorId; - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - const u32 wallCount = (u32)sector->walls.size(); - - const Vec2f hitPoint2d = { hitInfo.hitPoint.x, hitInfo.hitPoint.z }; - const f32 distFromCam = TFE_Math::distance(&hitInfo.hitPoint, &s_camera.pos); - const f32 maxDist = distFromCam * 64.0f / f32(rtHeight); - const f32 maxDistSq = maxDist * maxDist; - - f32 closestDistSq = maxDistSq; - s32 closestWall = -1; - for (u32 w = 0; w < wallCount; w++, wall++) - { - if (wall->adjoin < 0) { continue; } - // Test to see if we should select the wall parts themselves. - EditorSector* next = s_levelData->sectors.data() + wall->adjoin; - if ((next->floorAlt < sector->floorAlt - 0.1f && hitInfo.hitPart == HIT_PART_FLOOR) || (next->ceilAlt > sector->ceilAlt + 0.1f && hitInfo.hitPart == HIT_PART_CEIL)) { continue; } - - Vec2f closest; - Geometry::closestPointOnLineSegment(vtx[wall->i0], vtx[wall->i1], hitPoint2d, &closest); - const Vec2f diff = { closest.x - hitPoint2d.x, closest.z - hitPoint2d.z }; - const f32 distSq = TFE_Math::dot(&diff, &diff); - if (distSq < closestDistSq) - { - closestDistSq = distSq; - closestWall = s32(w); - } - } - if (closestWall >= 0) - { - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedWallSector = hitInfo.hitSectorId; - s_selectedWall = closestWall; - s_selectWallPart = HIT_PART_MID; - } - else - { - s_hoveredWallSector = hitInfo.hitSectorId; - s_hoveredWall = closestWall; - s_hoveredWallPart = HIT_PART_MID; - } - } - else if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedWall = -1; - } - } - else if (s_editMode == LEDIT_VERTEX) - { - s_hoveredVertexSector = hitInfo.hitSectorId; - - // Check for the nearest vertex in the current sector. - // In the last case, the ray hit a surface but not a wall. - // Since this is wall edit mode, see if there is a "hidden" wall close enough to select (i.e. an adjoin with no mask wall or upper/lower part). - const EditorSector* sector = s_levelData->sectors.data() + hitInfo.hitSectorId; - const Vec2f* vtx = sector->vertices.data(); - const u32 vtxCount = (u32)sector->vertices.size(); - - const f32 distFromCam = TFE_Math::distance(&hitInfo.hitPoint, &s_camera.pos); - const f32 maxDist = distFromCam * 64.0f / f32(rtHeight); - f32 minDistSq = maxDist * maxDist; - s32 closestVtx = -1; - RayHitPart closestPart = HIT_PART_FLOOR; - - for (u32 v = 0; v < vtxCount; v++) - { - // Check against the floor and ceiling vertex of each vertex. - const Vec3f floorVtx = { vtx[v].x, sector->floorAlt, vtx[v].z }; - const Vec3f ceilVtx = { vtx[v].x, sector->ceilAlt, vtx[v].z }; - - const f32 floorDistSq = TFE_Math::distanceSq(&floorVtx, &hitInfo.hitPoint); - const f32 ceilDistSq = TFE_Math::distanceSq(&ceilVtx, &hitInfo.hitPoint); - if (floorDistSq < minDistSq) - { - minDistSq = floorDistSq; - closestVtx = v; - closestPart = HIT_PART_FLOOR; - } - if (ceilDistSq < minDistSq) - { - minDistSq = ceilDistSq; - closestVtx = v; - closestPart = HIT_PART_CEIL; - } - } - - if (closestVtx >= 0) - { - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedVertexSector = hitInfo.hitSectorId; - s_selectedVertex = closestVtx; - s_selectVertexPart = closestPart; - s_moveVertex = true; - // get the plane... - s_drawPlaneNrm = { 0.0f, 1.0f, 0.0f }; - s_drawPlaneOrg = s_cursor3d; - } - else if (!s_moveVertex) - { - s_hoveredVertex = closestVtx; - s_hoveredVertexPart = closestPart; - } - } - else if (TFE_Input::mousePressed(MBUTTON_LEFT) && !s_moveVertex) - { - s_selectedVertex = -1; - } - } - else if (s_editMode == LEDIT_ENTITY) - { - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedEntitySector = hitInfo.hitSectorId; - s_selectedEntity = hitInfo.hitObjectId; - } - s_hoveredEntity = hitInfo.hitObjectId; - s_hoveredEntitySector = hitInfo.hitSectorId; - } - - if (s_editMode != LEDIT_SECTOR) { s_selectedSector = -1; } - if (s_editMode != LEDIT_WALL) { s_selectedWall = -1; } - if (s_editMode != LEDIT_VERTEX) { s_selectedVertex = -1; } - if (s_editMode != LEDIT_ENTITY) { s_selectedEntity = -1; } - } - else if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedSector = -1; - s_selectedWall = -1; - s_selectedVertex = -1; - - // Intersect the ray with the grid plane. - s_cursor3d = rayGridPlaneHit(s_camera.pos, s_rayDir); - } - else - { - // Intersect the ray with the grid plane. - s_cursor3d = rayGridPlaneHit(s_camera.pos, s_rayDir); - } - - if (s_editMode == LEDIT_DRAW) - { - //handleDraw(s_cursor3d); - } - } - - if (s_hideFrames > 0) { s_hideFrames--; } - } - - // Controls for the main level edit window. - // This will only be called if the mouse is inside the area and its not covered by popups (like combo boxes). - void editWinControls(s32 rtWidth, s32 rtHeight) - { - // Edit controls. - s32 mx, my; - TFE_Input::getMousePos(&mx, &my); - if (!TFE_Input::relativeModeEnabled() && (mx < s_editWinPos.x || mx >= s_editWinPos.x + s_editWinSize.x || my < s_editWinPos.z || my >= s_editWinPos.z + s_editWinSize.z)) - { - return; - } - - bool relEnabled = false; - if (s_editView == EDIT_VIEW_2D) - { - cameraControl2d(mx, my); - editWinControls2d(mx, my); - } - else - { - relEnabled = cameraControl3d(mx, my); - editWinControls3d(mx, my, rtWidth, rtHeight); - TFE_Input::enableRelativeMode(relEnabled); - } - - // Vertex move - if (TFE_Input::mouseDown(MBUTTON_LEFT) && s_moveVertex && s_editMode == LEDIT_VERTEX && !relEnabled) - { - handleVertexMove(s_editView == EDIT_VIEW_2D); - } - else if (s_moveVertex) - { - LevelEditorData::updateSectors(); - s_moveVertex = false; - } - - if (TFE_Input::mouseDown(MBUTTON_LEFT) && s_moveWall && s_editMode == LEDIT_WALL && !relEnabled) - { - handleWallMove(s_editView == EDIT_VIEW_2D); - } - else if (s_moveWall) - { - LevelEditorData::updateSectors(); - s_moveWall = false; - } - - // Set the current grid height to the cursor height. - if ((TFE_Input::keyDown(KEY_LCTRL) || TFE_Input::keyDown(KEY_RCTRL)) && TFE_Input::keyPressed(KEY_G)) - { - s_gridHeight = s_cursor3d.y; - } - } - - void drawVertex(const Vec2f* vtx, const f32 scale, const u32* color) - { - Vec2f quad[8]; - // Outer Quad - quad[0].x = vtx->x - scale; - quad[0].z = vtx->z - scale; - - quad[1].x = quad[0].x + 2.0f * scale; - quad[1].z = quad[0].z; - - quad[2].x = quad[0].x + 2.0f * scale; - quad[2].z = quad[0].z + 2.0f * scale; - - quad[3].x = quad[0].x; - quad[3].z = quad[0].z + 2.0f * scale; - - // Inner Quad - quad[4].x = vtx->x - scale * 0.5f; - quad[4].z = vtx->z - scale * 0.5f; - - quad[5].x = quad[4].x + 2.0f * scale * 0.5f; - quad[5].z = quad[4].z; - - quad[6].x = quad[4].x + 2.0f * scale * 0.5f; - quad[6].z = quad[4].z + 2.0f * scale * 0.5f; - - quad[7].x = quad[4].x; - quad[7].z = quad[4].z + 2.0f * scale * 0.5f; - - Vec2f tri[12] = { quad[0], quad[1], quad[2], quad[0], quad[2], quad[3], - quad[4], quad[5], quad[6], quad[4], quad[6], quad[7] }; - TriColoredDraw2d::addTriangles(4, tri, color); - } - - void highlightWall(bool selected) - { - if ((selected && s_selectedWall < 0) || (!selected && s_hoveredWall < 0)) { return; } - - const s32 wallId = s_selectedWall >= 0 && selected ? s_selectedWall : s_hoveredWall; - const s32 sectorId = s_selectedWall >= 0 && selected ? s_selectedWallSector : s_hoveredWallSector; - - EditorSector* sector = s_levelData->sectors.data() + sectorId; - const EditorWall* wall = sector->walls.data() + wallId; - const Vec2f* vtx = sector->vertices.data(); - - Vec2f line[] = { vtx[wall->i0], vtx[wall->i1] }; - u32 lineClr; - if (s_selectedWall >= 0 && selected) - { - lineClr = wall->adjoin < 0 ? 0xffffA040 : 0xff805020; - } - else - { - lineClr = wall->adjoin < 0 ? 0xffffC080 : 0xff806040; - } - u32 color[] = { lineClr, lineClr }; - LineDraw2d::addLines(1, 2.0f, line, color); - - Vec2f nrm = { vtx[wall->i1].z - vtx[wall->i0].z, -(vtx[wall->i1].x - vtx[wall->i0].x) }; - nrm = TFE_Math::normalize(&nrm); - const f32 nScale = 8.0f * s_zoomVisual; - - line[0] = { (vtx[wall->i0].x + vtx[wall->i1].x) * 0.5f, (vtx[wall->i0].z + vtx[wall->i1].z) * 0.5f }; - line[1] = { line[0].x + nrm.x * nScale, line[0].z + nrm.z * nScale }; - LineDraw2d::addLines(1, 2.0f, line, color); - } - - void beginDraw2d(u32 rtWidth, u32 rtHeight) - { - TriColoredDraw2d::begin(rtWidth, rtHeight, s_zoomVisual, s_offsetVis.x, s_offsetVis.z); - TriTexturedDraw2d::begin(rtWidth, rtHeight, s_zoomVisual, s_offsetVis.x, s_offsetVis.z); - LineDraw2d::begin(rtWidth, rtHeight, s_zoomVisual, s_offsetVis.x, s_offsetVis.z); - } - - void flushTriangles() - { - TriTexturedDraw2d::drawTriangles(); - TriColoredDraw2d::drawTriangles(); - } - - struct InfWall - { - const EditorSector* sector; - u32 wallId; - u32 triggerType; - }; - static std::vector s_infWalls; - - void drawSectorWalls2d(s32 drawLayer, s32 layer, u8 infType) - { - if (infType != INF_NONE && infType != INF_ALL && drawLayer != layer) { return; } - - // First draw the non-INF affected walls. - const u32 sectorCount = (u32)s_levelData->sectors.size(); - EditorSector* sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != drawLayer || s_selectedSector == i || s_hoveredSector == i) { continue; } - if ((infType != INF_NONE || drawLayer == layer) && sector->infType != infType && infType != INF_ALL) { continue; } - - const u32 wallCount = (u32)sector->walls.size(); - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - - for (u32 w = 0; w < wallCount; w++, wall++) - { - Vec2f line[] = { vtx[wall->i0], vtx[wall->i1] }; - u32 lineClr; - - if (drawLayer != layer) - { - u32 alpha = 0x40 / (layer - drawLayer); - lineClr = 0x00808000 | (alpha << 24); - } - else - { - if (infType == INF_NONE || infType == INF_ALL) { lineClr = wall->adjoin < 0 ? 0xffffffff : 0xff808080; } - else if (infType == INF_SELF) { lineClr = wall->adjoin < 0 ? 0xffff80ff : 0xff804080; } - else if (infType == INF_OTHER) { lineClr = wall->adjoin < 0 ? 0xffffff80 : 0xff808020; } - } - - u32 color[] = { lineClr, lineClr }; - LineDraw2d::addLines(1, 1.5f, line, color); - - if (s_showSectorColors && sector->layer == layer && wall->infType != INF_NONE) - { - s_infWalls.push_back({ sector, w, (u32)wall->triggerType }); - } - } - } - } - - void drawLineToTarget2d(const Vec2f* p0, s32 sectorId, s32 wallId, f32 width, u32 color) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const Vec2f* vtx = sector->vertices.data(); - Vec2f target = { 0 }; - - if (wallId >= 0) - { - const EditorWall* wall = sector->walls.data() + wallId; - target.x = (vtx[wall->i0].x + vtx[wall->i1].x) * 0.5f; - target.z = (vtx[wall->i0].z + vtx[wall->i1].z) * 0.5f; - } - else - { - const u32 vtxCount = (u32)sector->vertices.size(); - for (u32 v = 0; v < vtxCount; v++) - { - target.x += vtx[v].x; - target.z += vtx[v].z; - } - const f32 scale = 1.0f / f32(vtxCount); - target.x *= scale; - target.z *= scale; - } - Vec2f line[] = { *p0, target }; - u32 colors[] = { color, color }; - LineDraw2d::addLine(width, line, colors); - } - - // If the selected wall or sector has an INF script, draw lines towards - // 1. Any objects it effects (targets and clients). - // 2. Any slaves (sector). - void drawTargetsAndClientLines2d(s32 sectorId, f32 width) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const EditorInfItem* item = sector->infItem; - if (!item) { return; } - - Vec2f lineStart = { 0 }; - const Vec2f* vtx = sector->vertices.data(); - const u32 vtxCount = (u32)sector->vertices.size(); - for (u32 v = 0; v < vtxCount; v++) - { - lineStart.x += vtx[v].x; - lineStart.z += vtx[v].z; - } - const f32 scale = 1.0f / f32(vtxCount); - lineStart.x *= scale; - lineStart.z *= scale; - - for (u32 c = 0; c < (u32)item->classData.size(); c++) - { - const EditorInfClassData* cdata = &item->classData[c]; - u32 stopCount = 0; - if (cdata->iclass == INF_CLASS_TRIGGER) - { - stopCount = 1; - } - else if (cdata->iclass == INF_CLASS_ELEVATOR) - { - stopCount = (u32)cdata->stop.size(); - } - - for (u32 s = 0; s < stopCount; s++) - { - const u32 funcCount = (u32)cdata->stop[s].func.size(); - for (u32 f = 0; f < funcCount; f++) - { - // func | clientCount << 8 | argCount << 16 (top bot available). - const u32 funcId = cdata->stop[s].func[f].funcId; - const u32 clientCount = (u32)cdata->stop[s].func[f].client.size(); - for (u32 cl = 0; cl < clientCount; cl++) - { - const EditorSector* clientSector = LevelEditorData::getSector(cdata->stop[s].func[f].client[cl].sectorName.c_str()); - const s32 clientWallId = cdata->stop[s].func[f].client[cl].wallId; - if (!clientSector) { continue; } - - if (clientWallId >= 0) - { - drawLineToTarget2d(&lineStart, clientSector->id, clientWallId, width, 0xffff2020); - } - else - { - drawLineToTarget2d(&lineStart, clientSector->id, -1, width, 0xffff2020); - } - } - - // Draw to the adjoining lines. - if (funcId == INF_MSG_ADJOIN) - { - drawLineToTarget2d(&lineStart, LevelEditorData::getSector(cdata->stop[s].func[f].arg[0].sValue.c_str())->id, cdata->stop[s].func[f].arg[1].iValue, width, 0xff2020ff); - drawLineToTarget2d(&lineStart, LevelEditorData::getSector(cdata->stop[s].func[f].arg[2].sValue.c_str())->id, cdata->stop[s].func[f].arg[3].iValue, width, 0xff2020ff); - } - } - } - } - } - - void drawTargetsAndClientLines2d(s32 sectorId, s32 wallId, f32 width) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const Vec2f* vtx = sector->vertices.data(); - const EditorWall* wall = sector->walls.data() + wallId; - const EditorInfItem* item = wall->infItem; - - Vec2f lineStart; - lineStart.x = (vtx[wall->i0].x + vtx[wall->i1].x) * 0.5f; - lineStart.z = (vtx[wall->i0].z + vtx[wall->i1].z) * 0.5f; - - for (u32 c = 0; c < (u32)item->classData.size(); c++) - { - const EditorInfClassData* cdata = &item->classData[c]; - u32 stopCount = 0; - if (cdata->iclass == INF_CLASS_TRIGGER) - { - stopCount = 1; - } - else if (cdata->iclass == INF_CLASS_ELEVATOR) - { - stopCount = (u32)cdata->stop.size(); - } - - for (u32 s = 0; s < stopCount; s++) - { - const u32 funcCount = (u32)cdata->stop[s].func.size(); - for (u32 f = 0; f < funcCount; f++) - { - const u32 clientCount = (u32)cdata->stop[s].func[f].client.size(); - for (u32 cl = 0; cl < clientCount; cl++) - { - const EditorSector* clientSector = LevelEditorData::getSector(cdata->stop[s].func[f].client[cl].sectorName.c_str()); - const s32 clientWallId = cdata->stop[s].func[f].client[cl].wallId; - if (!clientSector) { continue; } - - if (clientWallId >= 0) - { - drawLineToTarget2d(&lineStart, clientSector->id, clientWallId, width, 0xffff2020); - } - else - { - drawLineToTarget2d(&lineStart, clientSector->id, -1, width, 0xffff2020); - } - } - } - } - } - } - - void drawTargetsAndClientSlaves2d(s32 sectorId, f32 width) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const EditorInfItem* item = sector->infItem; - if (!item) { return; } - - Vec2f lineStart = { 0 }; - const Vec2f* vtx = sector->vertices.data(); - const u32 vtxCount = (u32)sector->vertices.size(); - for (u32 v = 0; v < vtxCount; v++) - { - lineStart.x += vtx[v].x; - lineStart.z += vtx[v].z; - } - const f32 scale = 1.0f / f32(vtxCount); - lineStart.x *= scale; - lineStart.z *= scale; - - for (u32 c = 0; c < (u32)item->classData.size(); c++) - { - const EditorInfClassData* cdata = &item->classData[c]; - for (u32 s = 0; s < (u32)cdata->slaves.size(); s++) - { - const EditorSector* slaveSector = LevelEditorData::getSector(cdata->slaves[s].c_str()); - drawLineToTarget2d(&lineStart, slaveSector->id, -1, width, 0xff20ff20); - } - } - } - - void drawSectorOutline2d(const EditorSector* sector, u32 adjoinColor, u32 baseColor, bool closed) - { - const s32 wallCount = closed ? (s32)sector->walls.size() : (s32)sector->walls.size() - 1; - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - - for (s32 w = 0; w < wallCount; w++, wall++) - { - Vec2f line[] = { vtx[wall->i0], vtx[wall->i1] }; - u32 lineClr = wall->adjoin < 0 ? adjoinColor : baseColor; - u32 color[] = { lineClr, lineClr }; - LineDraw2d::addLines(1, 2.0f, line, color); - } - } - - void drawLevel2d(u32 rtWidth, u32 rtHeight) - { - if (!s_levelData || s_sectorDrawMode == SDM_WIREFRAME || (s_layerIndex + s_layerMin < s_levelData->layerMin)) - { - // Draw the grid. - Grid2d::blitToScreen(rtWidth, rtHeight, s_gridSize, s_subGridSize, s_zoomVisual, s_offsetVis.x, s_offsetVis.z, s_gridOpacity); - } - - // Draw the level. - if (!s_levelData) { return; } - - const u32 sectorCount = (u32)s_levelData->sectors.size(); - const EditorSector* sector = s_levelData->sectors.data(); - s32 layer = s_layerIndex + s_layerMin; - - beginDraw2d(rtWidth, rtHeight); - - // Loop through all layers, bottom to current - only draw walls for all but the current layer. - s_infWalls.clear(); - s32 startLayer = s_showLowerLayers ? s_levelData->layerMin : layer; - for (s32 l = startLayer; l <= layer; l++) - { - // Draw the solid sectors before drawing walls. - if (s_sectorDrawMode == SDM_LIGHTING && l == layer) - { - sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - - u32 L = u32(sector->ambient); - L = s_fullbright ? 255u : std::max(0u, std::min(CONV_5bitTo8bit(L), 255u)); - const u32 Lrg = L * 7 / 8; - const u32 lighting = Lrg | (Lrg << 8u) | (L << 16u) | 0xff000000; - drawSectorPolygon(sector, false, lighting); - } - } - else if ((s_sectorDrawMode == SDM_TEXTURED_FLOOR || s_sectorDrawMode == SDM_TEXTURED_CEIL) && l == layer) - { - sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - - u32 L = u32(sector->ambient); - L = s_fullbright ? 255u : std::max(0u, std::min(CONV_5bitTo8bit(L), 255u)); - const u32 lighting = L | (L << 8u) | (L << 16u) | 0xff000000; - drawTexturedSectorPolygon(sector, lighting, s_sectorDrawMode == SDM_TEXTURED_FLOOR); - } - } - - if (l == layer && s_sectorDrawMode != SDM_WIREFRAME) - { - // Draw the grid. - flushTriangles(); - Grid2d::blitToScreen(rtWidth, rtHeight, s_gridSize, s_subGridSize, s_zoomVisual, s_offsetVis.x, s_offsetVis.z, s_gridOpacity); - } - - // Draw the selected sector before drawing the walls. - if (l == layer && (s_selectedSector >= 0 || s_hoveredSector >= 0)) - { - if (s_selectedSector >= 0) { drawSectorPolygon(s_levelData->sectors.data() + s_selectedSector, false); } - if (s_hoveredSector >= 0) { drawSectorPolygon(s_levelData->sectors.data() + s_hoveredSector, true); } - flushTriangles(); - } - else if (l == layer && s_editMode == LEDIT_DRAW) // Draw the interior of the sector being drawn. - { - drawSectorPolygon(&s_newSector, false); - } - - // Walls - if (s_showSectorColors) - { - drawSectorWalls2d(l, layer, INF_NONE); - - // Draw INF walls. - if (l == layer) - { - drawSectorWalls2d(l, layer, INF_SELF); - drawSectorWalls2d(l, layer, INF_OTHER); - - const size_t iWallCount = s_infWalls.size(); - const InfWall* infWall = s_infWalls.data(); - for (size_t w = 0; w < iWallCount; w++, infWall++) - { - const EditorWall* wall = infWall->sector->walls.data() + infWall->wallId; - const Vec2f* vtx = infWall->sector->vertices.data(); - - Vec2f line[] = { vtx[wall->i0], vtx[wall->i1] }; - u32 lineClr = wall->adjoin < 0 ? 0xff2020ff : 0xff101080; - u32 color[] = { lineClr, lineClr }; - LineDraw2d::addLines(1, 1.5f, line, color); - - Vec2f nrm = { vtx[wall->i1].z - vtx[wall->i0].z, -(vtx[wall->i1].x - vtx[wall->i0].x) }; - nrm = TFE_Math::normalize(&nrm); - const f32 nScale = 4.0f * s_zoomVisual; - - line[0] = { (vtx[wall->i0].x + vtx[wall->i1].x) * 0.5f, (vtx[wall->i0].z + vtx[wall->i1].z) * 0.5f }; - line[1] = { line[0].x + nrm.x * nScale, line[0].z + nrm.z * nScale }; - LineDraw2d::addLines(1, 2.0f, line, color); - } - } - } - else - { - drawSectorWalls2d(l, layer, INF_ALL); - } - - if (l == layer && s_selectedSector >= 0) - { - sector = s_levelData->sectors.data() + s_selectedSector; - drawSectorOutline2d(sector, 0xffffA040, 0xff805020, true); - } - if (l == layer && s_hoveredSector >= 0) - { - sector = s_levelData->sectors.data() + s_hoveredSector; - drawSectorOutline2d(sector, 0xffffC080, 0xff806040, true); - } - if (l == layer && s_editMode == LEDIT_DRAW) - { - drawSectorOutline2d(&s_newSector, 0xffffA040, 0xff805020, false); - } - // Draw the selected sector before drawing the walls. - if (l == layer && (s_selectedWall >= 0 || s_hoveredWall >= 0)) - { - highlightWall(true); - highlightWall(false); - } - if (s_selectedSector >= 0 && s_levelData->sectors[s_selectedSector].infType != INF_NONE) - { - // If the selected wall or sector has an INF script, draw lines towards - drawTargetsAndClientLines2d(s_selectedSector, 2.0f); - drawTargetsAndClientSlaves2d(s_selectedSector, 2.0f); - } - else if (s_selectedWall >= 0 && s_levelData->sectors[s_selectedWallSector].walls[s_selectedWall].infType != INF_NONE) - { - drawTargetsAndClientLines2d(s_selectedWallSector, s_selectedWall, 2.0f); - } - - LineDraw2d::drawLines(); - } - - // Objects - const u32 alphaFg = s_editMode == LEDIT_ENTITY ? 0xff000000 : 0xA0000000; - const u32 alphaBg = s_editMode == LEDIT_ENTITY ? 0xA0000000 : 0x60000000; - sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - - // For now just draw a quad + image. - const u32 objCount = (u32)sector->objects.size(); - const EditorLevelObject* obj = sector->objects.data(); - for (u32 o = 0; o < objCount; o++, obj++) - { - const bool selected = s_selectedEntity == o && s_selectedEntitySector == i; - const bool highlight = (s_hoveredEntity == o && s_hoveredEntitySector == i) || selected; - const u32 clrBg = highlight ? (0xffae8653 | alphaBg) : (0x0051331a | alphaBg); - - if (obj->oclass == CLASS_3D) - { - const Vec2f pos = { obj->pos.x, obj->pos.z }; - TFE_EditorRender::drawModel2d_Bounds(obj->displayModel, &obj->pos, &obj->rotMtx, clrBg, highlight); - TFE_EditorRender::drawModel2d(sector, obj->displayModel, &pos, &obj->rotMtx, s_palette->colors, alphaFg); - } - else - { - f32 width = obj->display ? (f32)obj->display->width : 1.0f; - f32 height = obj->display ? (f32)obj->display->height : 1.0f; - - f32 x0 = -obj->worldExt.x, z0 = -obj->worldExt.z; - f32 x1 = obj->worldExt.x, z1 = obj->worldExt.z; - if (height > width) - { - const f32 dx = obj->worldExt.x * width / height; - x0 = -dx; - x1 = x0 + 2.0f * dx; - } - else if (width > height) - { - const f32 dz = obj->worldExt.z * height / width; - z0 = -dz; - z1 = z0 + 2.0f * dz; - } - - const Vec2f vtxTex[6]= - { - {obj->worldCen.x + x0, obj->worldCen.z + z0}, - {obj->worldCen.x + x1, obj->worldCen.z + z0}, - {obj->worldCen.x + x1, obj->worldCen.z + z1}, - - {obj->worldCen.x + x0, obj->worldCen.z + z0}, - {obj->worldCen.x + x1, obj->worldCen.z + z1}, - {obj->worldCen.x + x0, obj->worldCen.z + z1}, - }; - - const f32 scale = highlight ? 1.25f : 1.0f; - Vec2f vtxClr[6]= - { - {obj->worldCen.x - obj->worldExt.x*scale, obj->worldCen.z - obj->worldExt.z*scale}, - {obj->worldCen.x + obj->worldExt.x*scale, obj->worldCen.z - obj->worldExt.z*scale}, - {obj->worldCen.x + obj->worldExt.x*scale, obj->worldCen.z + obj->worldExt.z*scale}, - - {obj->worldCen.x - obj->worldExt.x*scale, obj->worldCen.z - obj->worldExt.z*scale}, - {obj->worldCen.x + obj->worldExt.x*scale, obj->worldCen.z + obj->worldExt.z*scale}, - {obj->worldCen.x - obj->worldExt.x*scale, obj->worldCen.z + obj->worldExt.z*scale}, - }; - - const Vec2f uv[6] = - { - {0.0f, 1.0f}, - {1.0f, 1.0f}, - {1.0f, 0.0f}, - - {0.0f, 1.0f}, - {1.0f, 0.0f}, - {0.0f, 0.0f}, - }; - const u32 baseRGB = selected ? 0x00ffa0a0 : 0x00ffffff; - const u32 colorFg[2] = { baseRGB | alphaFg, baseRGB | alphaFg }; - const u32 colorBg[2] = { clrBg, clrBg }; - - TriColoredDraw2d::addTriangles(2, vtxClr, colorBg); - if (obj->display) { TriTexturedDraw2d::addTriangles(2, vtxTex, uv, colorFg, obj->display->texture); } - - // Draw a direction. - const f32 angle = obj->orientation.y * PI / 180.0f; - Vec2f dir = { sinf(angle), cosf(angle) }; - - // Make an arrow. - f32 dx = dir.x * obj->worldExt.x; - f32 dz = dir.z * obj->worldExt.z; - f32 cx = obj->pos.x + dx; - f32 cz = obj->pos.z + dz; - f32 tx = -dir.z * obj->worldExt.x * 0.5f; - f32 tz = dir.x * obj->worldExt.z * 0.5f; - - Vec2f vtx[]= - { - {cx, cz}, {cx + tx - dx * 0.25f, cz + tz - dz * 0.25f}, - {cx, cz}, {cx - tx - dx * 0.25f, cz - tz - dz * 0.25f}, - }; - - const u32 alphaArrow = s_editMode == LEDIT_ENTITY ? (highlight ? 0xA0000000 : 0x60000000) : 0x30000000; - u32 baseRGBArrow = 0x00ffff00; - u32 baseClrArrow = baseRGBArrow | alphaArrow; - u32 color[] = { baseClrArrow, baseClrArrow, baseClrArrow, baseClrArrow }; - LineDraw2d::addLines(2, 2.0f, vtx, color); - } - } - } - TriColoredDraw2d::drawTriangles(); - TriTexturedDraw2d::drawTriangles(); - LineDraw2d::drawLines(); - - // Vertices - const u32 color[4] = { 0xffae8653, 0xffae8653, 0xff51331a, 0xff51331a }; - const u32 colorSelected[4] = { 0xffffc379, 0xffffc379, 0xff764a26, 0xff764a26 }; - - const f32 scaleMax = s_zoomVisual * 4.0f; - const f32 scaleMin = s_zoomVisual * 1.0f; - const f32 scale = std::max(scaleMin, std::min(scaleMax, 0.5f)); - - sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - - const u32 wallCount = (u32)sector->walls.size(); - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - - for (u32 w = 0; w < wallCount; w++, wall++) - { - drawVertex(&vtx[wall->i0], scale, color); - } - } - if (s_hoveredVertex >= 0 && s_hoveredVertex < (s32)s_levelData->sectors[s_hoveredVertexSector].vertices.size()) - { - const Vec2f* vtx = &s_levelData->sectors[s_hoveredVertexSector].vertices[s_hoveredVertex]; - drawVertex(vtx, scale * 1.5f, colorSelected); - } - if (s_selectedVertex >= 0 && s_selectedVertex < (s32)s_levelData->sectors[s_selectedVertexSector].vertices.size()) - { - const Vec2f* vtx = &s_levelData->sectors[s_selectedVertexSector].vertices[s_selectedVertex]; - drawVertex(vtx, scale * 1.5f, colorSelected); - } - - // Draw the 2d cursor in "Draw Mode" - if (s_editMode == LEDIT_DRAW) - { - Vec2f pos = { s_cursorSnapped.x, s_cursorSnapped.z }; - drawVertex(&pos, scale * 1.5f, colorSelected); - } - - flushTriangles(); - } - - void drawSectorFloorAndCeilColor(const EditorSector* sector, const SectorTriangles* poly, const u32* color, bool blend) - { - const u32 triCount = poly->count; - const Vec2f* vtx = poly->vtx.data(); - for (u32 t = 0; t < triCount; t++, vtx += 3) - { - const Vec3f floorCeilVtx[6] = - { - {vtx[0].x, sector->floorAlt, vtx[0].z}, - {vtx[2].x, sector->floorAlt, vtx[2].z}, - {vtx[1].x, sector->floorAlt, vtx[1].z}, - - {vtx[0].x, sector->ceilAlt, vtx[0].z}, - {vtx[1].x, sector->ceilAlt, vtx[1].z}, - {vtx[2].x, sector->ceilAlt, vtx[2].z}, - }; - const Vec2f floorUv[6] = - { - {vtx[0].x, vtx[0].z}, - {vtx[2].x, vtx[2].z}, - {vtx[1].x, vtx[1].z}, - - {vtx[0].x, vtx[0].z}, - {vtx[1].x, vtx[1].z}, - {vtx[2].x, vtx[2].z}, - }; - TrianglesColor3d::addTriangles(2, floorCeilVtx, floorUv, color, blend); - } - } - - void drawSectorFloorAndCeilTextured(const EditorSector* sector, const SectorTriangles* poly, u32 color) - { - const bool hasFloorTex = sector->floorTexture.tex != nullptr; - const bool hasCeilTex = sector->ceilTexture.tex != nullptr; - - const f32* floorOff = §or->floorTexture.offsetX; - const f32* ceilOff = §or->ceilTexture.offsetX; - const TextureGpu* floorTex = hasFloorTex ? sector->floorTexture.tex->texture : nullptr; - const TextureGpu* ceilTex = hasCeilTex ? sector->ceilTexture.tex->texture : nullptr; - const f32 scaleFloorX = hasFloorTex ? -8.0f / f32(sector->floorTexture.tex->width) : 1.0f; - const f32 scaleFloorZ = hasFloorTex ? -8.0f / f32(sector->floorTexture.tex->height) : 1.0f; - const f32 scaleCeilX = hasCeilTex ? -8.0f / f32(sector->ceilTexture.tex->width) : 1.0f; - const f32 scaleCeilZ = hasCeilTex ? -8.0f / f32(sector->ceilTexture.tex->height) : 1.0f; - - const u32 triCount = poly->count; - - // Two passes, one for floor and ceiling to avoid changing textures too often... - const Vec2f* vtx = poly->vtx.data(); - for (u32 t = 0; t < triCount; t++, vtx += 3) - { - const Vec3f floorCeilVtx[6] = - { - {vtx[0].x, sector->floorAlt, vtx[0].z}, - {vtx[2].x, sector->floorAlt, vtx[2].z}, - {vtx[1].x, sector->floorAlt, vtx[1].z}, - }; - const Vec2f floorUv[6] = - { - {vtx[0].x, vtx[0].z}, - {vtx[2].x, vtx[2].z}, - {vtx[1].x, vtx[1].z}, - }; - const Vec2f floorUv1[6] = - { - {(vtx[0].x - floorOff[0]) * scaleFloorX, (vtx[0].z - floorOff[1]) * scaleFloorZ}, - {(vtx[2].x - floorOff[0]) * scaleFloorX, (vtx[2].z - floorOff[1]) * scaleFloorZ}, - {(vtx[1].x - floorOff[0]) * scaleFloorX, (vtx[1].z - floorOff[1]) * scaleFloorZ}, - }; - - TrianglesColor3d::addTexturedTriangle(floorCeilVtx, floorUv, floorUv1, color, floorTex); - } - - vtx = poly->vtx.data(); - for (u32 t = 0; t < triCount; t++, vtx += 3) - { - const Vec3f floorCeilVtx[6] = - { - {vtx[0].x, sector->ceilAlt, vtx[0].z}, - {vtx[1].x, sector->ceilAlt, vtx[1].z}, - {vtx[2].x, sector->ceilAlt, vtx[2].z}, - }; - const Vec2f floorUv[6] = - { - {vtx[0].x, vtx[0].z}, - {vtx[1].x, vtx[1].z}, - {vtx[2].x, vtx[2].z}, - }; - const Vec2f floorUv1[6] = - { - {(vtx[0].x - ceilOff[0]) * scaleCeilX, (vtx[0].z - ceilOff[1]) * scaleCeilZ}, - {(vtx[1].x - ceilOff[0]) * scaleCeilX, (vtx[1].z - ceilOff[1]) * scaleCeilZ}, - {(vtx[2].x - ceilOff[0]) * scaleCeilX, (vtx[2].z - ceilOff[1]) * scaleCeilZ}, - }; - - TrianglesColor3d::addTexturedTriangle(floorCeilVtx, floorUv, floorUv1, color, ceilTex); - } - } - - f32 wallLength(const EditorWall* wall, const EditorSector* sector) - { - const Vec2f* vtx = sector->vertices.data(); - const Vec2f offset = { vtx[wall->i1].x - vtx[wall->i0].x, vtx[wall->i1].z - vtx[wall->i0].z }; - return sqrtf(offset.x * offset.x + offset.z * offset.z); - } - - void buildWallVertices(f32 floorAlt, f32 ceilAlt, const Vec2f* v0, const Vec2f* v1, Vec3f* wallVertex, Vec2f* wallUv) - { - const f32 dx = fabsf(v1->x - v0->x); - const f32 dz = fabsf(v1->z - v0->z); - - wallVertex[0] = { v0->x, ceilAlt, v0->z }; - wallVertex[1] = { v1->x, ceilAlt, v1->z }; - wallVertex[2] = { v1->x, floorAlt, v1->z }; - - wallVertex[3] = { v0->x, ceilAlt, v0->z }; - wallVertex[4] = { v1->x, floorAlt, v1->z }; - wallVertex[5] = { v0->x, floorAlt, v0->z }; - - wallUv[0] = { (dx >= dz) ? v0->x : v0->z, ceilAlt }; - wallUv[1] = { (dx >= dz) ? v1->x : v1->z, ceilAlt }; - wallUv[2] = { (dx >= dz) ? v1->x : v1->z, floorAlt }; - - wallUv[3] = { (dx >= dz) ? v0->x : v0->z, ceilAlt }; - wallUv[4] = { (dx >= dz) ? v1->x : v1->z, floorAlt }; - wallUv[5] = { (dx >= dz) ? v0->x : v0->z, floorAlt }; - } - - void buildWallTextureVertices(const EditorSectorTexture* stex, f32 wallLen, f32 h, bool flipHorz, u32 texWidth, u32 texHeight, Vec2f* wallUv1) - { - f32 u0 = (stex->offsetX) * c_worldToTexelScale; - f32 u1 = u0 + wallLen; - f32 v0 = (-stex->offsetY - h) * c_worldToTexelScale; - f32 v1 = (-stex->offsetY) * c_worldToTexelScale; - - const f32 textureScaleX = 1.0f / f32(texWidth); - const f32 textureScaleY = 1.0f / f32(texHeight); - u0 = u0 * textureScaleX; - u1 = u1 * textureScaleX; - v0 = v0 * textureScaleY; - v1 = v1 * textureScaleY; - - if (flipHorz) { u0 = 1.0f - u0; u1 = 1.0f - u1; } - - wallUv1[0] = { u0, v0 }; - wallUv1[1] = { u1, v0 }; - wallUv1[2] = { u1, v1 }; - - wallUv1[3] = { u0, v0 }; - wallUv1[4] = { u1, v1 }; - wallUv1[5] = { u0, v1 }; - } - - void buildSignTextureVertices(const EditorSectorTexture* sbaseTex, const EditorSectorTexture* sTex, f32 wallLen, f32 h, u32 texWidth, u32 texHeight, Vec2f* wallUv1) - { - const f32 offsetX = sbaseTex->offsetX - sTex->offsetX; - // The way the base offset Y is factored in is quite strange but has been arrived at by looking at the data... - const f32 offsetY = -TFE_Math::fract(std::max(sbaseTex->offsetY, 0.0f)) + sTex->offsetY; - - f32 u0 = offsetX * c_worldToTexelScale; - f32 u1 = u0 + wallLen; - f32 v0 = (-offsetY - h) * c_worldToTexelScale; - f32 v1 = (-offsetY) * c_worldToTexelScale; - - const f32 textureScaleX = 1.0f / f32(texWidth); - const f32 textureScaleY = 1.0f / f32(texHeight); - u0 = u0 * textureScaleX; - u1 = u1 * textureScaleX; - v0 = 1.0f + v0 * textureScaleY; - v1 = 1.0f + v1 * textureScaleY; - - wallUv1[0] = { u0, v0 }; - wallUv1[1] = { u1, v0 }; - wallUv1[2] = { u1, v1 }; - - wallUv1[3] = { u0, v0 }; - wallUv1[4] = { u1, v1 }; - wallUv1[5] = { u0, v1 }; - } - - void drawWallColor(const EditorSector* sector, const Vec2f* vtx, const EditorWall* wall, const u32* color, bool blend, RayHitPart part, bool showAllWallsOnBlend) - { - const Vec2f* v0 = &vtx[wall->i0]; - const Vec2f* v1 = &vtx[wall->i1]; - - Vec3f wallVertex[6]; - Vec2f wallUv[6]; - if (wall->adjoin < 0 && (part == HIT_PART_UNKNOWN || part == HIT_PART_MID)) - { - // No adjoin - a single quad. - buildWallVertices(sector->floorAlt, sector->ceilAlt, v0, v1, wallVertex, wallUv); - TrianglesColor3d::addTriangles(2, wallVertex, wallUv, color, blend); - } - else - { - // lower - f32 nextFloorAlt = s_levelData->sectors[wall->adjoin].floorAlt; - if (nextFloorAlt < sector->floorAlt && (part == HIT_PART_UNKNOWN || part == HIT_PART_BOT)) - { - buildWallVertices(sector->floorAlt, nextFloorAlt, v0, v1, wallVertex, wallUv); - TrianglesColor3d::addTriangles(2, wallVertex, wallUv, color, blend); - } - - // upper - f32 nextCeilAlt = s_levelData->sectors[wall->adjoin].ceilAlt; - if (nextCeilAlt > sector->ceilAlt && (part == HIT_PART_UNKNOWN || part == HIT_PART_TOP)) - { - buildWallVertices(nextCeilAlt, sector->ceilAlt, v0, v1, wallVertex, wallUv); - TrianglesColor3d::addTriangles(2, wallVertex, wallUv, color, blend); - } - - // mask wall or highlight. - if (((wall->flags[0] & WF1_ADJ_MID_TEX) || (blend && showAllWallsOnBlend)) && (part == HIT_PART_UNKNOWN || part == HIT_PART_MID)) - { - const f32 ceilAlt = std::max(nextCeilAlt, sector->ceilAlt); - const f32 floorAlt = std::min(nextFloorAlt, sector->floorAlt); - - buildWallVertices(floorAlt, ceilAlt, v0, v1, wallVertex, wallUv); - TrianglesColor3d::addTriangles(2, wallVertex, wallUv, color, blend); - } - } - } - - void drawWallTexture(const EditorSector* sector, const Vec2f* vtx, const EditorWall* wall, u32 wallIndex, const u32* color) - { - const Vec2f* v0 = &vtx[wall->i0]; - const Vec2f* v1 = &vtx[wall->i1]; - const f32 wallLen = wallLength(wall, sector) * c_worldToTexelScale; - const bool flipHorz = (wall->flags[0] & WF1_FLIP_HORIZ) != 0u; - - const u32 fullbright[] = { 0xffffffff, 0xffffffff }; - - Vec3f wallVertex[6]; - Vec2f wallUv[6]; - Vec2f wallUv1[6]; - if (wall->adjoin < 0) - { - const f32 h = sector->floorAlt - sector->ceilAlt; - - buildWallVertices(sector->floorAlt, sector->ceilAlt, v0, v1, wallVertex, wallUv); - buildWallTextureVertices(&wall->mid, wallLen, h, flipHorz, wall->mid.tex->width, wall->mid.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, color, wall->mid.tex->texture); - - if (wall->sign.tex) - { - const u32* sgnColor = (wall->flags[0] & WF1_ILLUM_SIGN) ? fullbright : color; - buildSignTextureVertices(&wall->mid, &wall->sign, wallLen, h, wall->sign.tex->width, wall->sign.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, sgnColor, wall->sign.tex->texture, Tri3dTrans::TRANS_CLAMP); - } - } - else - { - const EditorSector* next = s_levelData->sectors.data() + wall->adjoin; - - // lower - if (next->floorAlt < sector->floorAlt && wall->bot.tex) - { - const f32 h = sector->floorAlt - next->floorAlt; - - buildWallVertices(sector->floorAlt, next->floorAlt, v0, v1, wallVertex, wallUv); - buildWallTextureVertices(&wall->bot, wallLen, h, flipHorz, wall->bot.tex->width, wall->bot.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, color, wall->bot.tex->texture); - - if (wall->sign.tex) - { - const u32* sgnColor = (wall->flags[0] & WF1_ILLUM_SIGN) ? fullbright : color; - buildSignTextureVertices(&wall->bot, &wall->sign, wallLen, h, wall->sign.tex->width, wall->sign.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, sgnColor, wall->sign.tex->texture, Tri3dTrans::TRANS_CLAMP); - } - } - - // upper - if (next->ceilAlt > sector->ceilAlt && wall->top.tex) - { - const f32 h = next->ceilAlt - sector->ceilAlt; - - buildWallVertices(next->ceilAlt, sector->ceilAlt, v0, v1, wallVertex, wallUv); - buildWallTextureVertices(&wall->top, wallLen, h, flipHorz, wall->top.tex->width, wall->top.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, color, wall->top.tex->texture); - - // no upper sign if a lower sign was rendered. - if (wall->sign.tex && next->floorAlt >= sector->floorAlt) - { - const u32* sgnColor = (wall->flags[0] & WF1_ILLUM_SIGN) ? fullbright : color; - buildSignTextureVertices(&wall->top, &wall->sign, wallLen, h, wall->sign.tex->width, wall->sign.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, sgnColor, wall->sign.tex->texture, Tri3dTrans::TRANS_CLAMP); - } - } - - // mask wall - if (wall->flags[0] & WF1_ADJ_MID_TEX) - { - const f32 ceilAlt = std::max(next->ceilAlt, sector->ceilAlt); - const f32 floorAlt = std::min(next->floorAlt, sector->floorAlt); - const f32 h = floorAlt - ceilAlt; - - buildWallVertices(floorAlt, ceilAlt, v0, v1, wallVertex, wallUv); - buildWallTextureVertices(&wall->mid, wallLen, h, flipHorz, wall->mid.tex->width, wall->mid.tex->height, wallUv1); - TrianglesColor3d::addTexturedTriangles(2, wallVertex, wallUv, wallUv1, color, wall->mid.tex->texture, Tri3dTrans::TRANS_CUTOUT); - } - } - } - - static f32 c_editorCameraFov = 1.57079632679489661923f; - - void drawScreenQuad(const Vec3f* center, f32 side, u32 color) - { - const f32 w = side * 0.5f; - const Vec3f r = { s_camera.viewMtx.m0.x * w, s_camera.viewMtx.m0.y * w, s_camera.viewMtx.m0.z * w }; - const Vec3f u = { s_camera.viewMtx.m1.x * w, s_camera.viewMtx.m1.y * w, s_camera.viewMtx.m1.z * w }; - - const Vec3f vtx[]= - { - {center->x - r.x - u.x, center->y - r.y - u.y, center->z - r.z - u.z}, - {center->x + r.x - u.x, center->y + r.y - u.y, center->z + r.z - u.z}, - {center->x + r.x + u.x, center->y + r.y + u.y, center->z + r.z + u.z}, - - {center->x - r.x - u.x, center->y - r.y - u.y, center->z - r.z - u.z}, - {center->x + r.x + u.x, center->y + r.y + u.y, center->z + r.z + u.z}, - {center->x - r.x + u.x, center->y - r.y + u.y, center->z - r.z + u.z}, - }; - - u32 colors[2]; - for (u32 i = 0; i < 2; i++) - { - colors[i] = color; - } - - TrianglesColor3d::addTriangles(2, vtx, nullptr, colors, true); - } - - void drawScreenQuadOutline(const Vec3f* center, f32 side, f32 lineWidth, u32 color) - { - const f32 w = side * 0.5f; - const Vec3f r = { s_camera.viewMtx.m0.x * w, s_camera.viewMtx.m0.y * w, s_camera.viewMtx.m0.z * w }; - const Vec3f u = { s_camera.viewMtx.m1.x * w, s_camera.viewMtx.m1.y * w, s_camera.viewMtx.m1.z * w }; - - const Vec3f lines[] = - { - {center->x - r.x - u.x, center->y - r.y - u.y, center->z - r.z - u.z}, {center->x + r.x - u.x, center->y + r.y - u.y, center->z + r.z - u.z}, - {center->x + r.x - u.x, center->y + r.y - u.y, center->z + r.z - u.z}, {center->x + r.x + u.x, center->y + r.y + u.y, center->z + r.z + u.z}, - {center->x + r.x + u.x, center->y + r.y + u.y, center->z + r.z + u.z}, {center->x - r.x + u.x, center->y - r.y + u.y, center->z - r.z + u.z}, - {center->x - r.x + u.x, center->y - r.y + u.y, center->z - r.z + u.z}, {center->x - r.x - u.x, center->y - r.y - u.y, center->z - r.z - u.z}, - }; - - u32 colors[4]; - for (u32 i = 0; i < 4; i++) - { - colors[i] = color; - } - - LineDraw3d::addLines(4, lineWidth, lines, colors); - } - - void drawBox(const Vec3f* center, f32 side, f32 lineWidth, u32 color) - { - const f32 w = side * 0.5f; - const Vec3f lines[]= - { - {center->x - w, center->y - w, center->z - w}, {center->x + w, center->y - w, center->z - w}, - {center->x + w, center->y - w, center->z - w}, {center->x + w, center->y - w, center->z + w}, - {center->x + w, center->y - w, center->z + w}, {center->x - w, center->y - w, center->z + w}, - {center->x - w, center->y - w, center->z + w}, {center->x - w, center->y - w, center->z - w}, - - {center->x - w, center->y + w, center->z - w}, {center->x + w, center->y + w, center->z - w}, - {center->x + w, center->y + w, center->z - w}, {center->x + w, center->y + w, center->z + w}, - {center->x + w, center->y + w, center->z + w}, {center->x - w, center->y + w, center->z + w}, - {center->x - w, center->y + w, center->z + w}, {center->x - w, center->y + w, center->z - w}, - - {center->x - w, center->y - w, center->z - w}, {center->x - w, center->y + w, center->z - w}, - {center->x + w, center->y - w, center->z - w}, {center->x + w, center->y + w, center->z - w}, - {center->x + w, center->y - w, center->z + w}, {center->x + w, center->y + w, center->z + w}, - {center->x - w, center->y - w, center->z + w}, {center->x - w, center->y + w, center->z + w}, - }; - u32 colors[12]; - for (u32 i = 0; i < 12; i++) - { - colors[i] = color; - } - - LineDraw3d::addLines(12, lineWidth, lines, colors); - } - - void drawBounds(const Vec3f* center, const Vec3f* ext, f32 lineWidth, u32 color) - { - const Vec3f lines[] = - { - {center->x - ext->x, center->y + ext->y, center->z - ext->z}, {center->x + ext->x, center->y + ext->y, center->z - ext->z}, - {center->x + ext->x, center->y + ext->y, center->z - ext->z}, {center->x + ext->x, center->y + ext->y, center->z + ext->z}, - {center->x + ext->x, center->y + ext->y, center->z + ext->z}, {center->x - ext->x, center->y + ext->y, center->z + ext->z}, - {center->x - ext->x, center->y + ext->y, center->z + ext->z}, {center->x - ext->x, center->y + ext->y, center->z - ext->z}, - - {center->x - ext->x, center->y - ext->y, center->z - ext->z}, {center->x + ext->x, center->y - ext->y, center->z - ext->z}, - {center->x + ext->x, center->y - ext->y, center->z - ext->z}, {center->x + ext->x, center->y - ext->y, center->z + ext->z}, - {center->x + ext->x, center->y - ext->y, center->z + ext->z}, {center->x - ext->x, center->y - ext->y, center->z + ext->z}, - {center->x - ext->x, center->y - ext->y, center->z + ext->z}, {center->x - ext->x, center->y - ext->y, center->z - ext->z}, - - {center->x - ext->x, center->y + ext->y, center->z - ext->z}, {center->x - ext->x, center->y - ext->y, center->z - ext->z}, - {center->x + ext->x, center->y + ext->y, center->z - ext->z}, {center->x + ext->x, center->y - ext->y, center->z - ext->z}, - {center->x + ext->x, center->y + ext->y, center->z + ext->z}, {center->x + ext->x, center->y - ext->y, center->z + ext->z}, - {center->x - ext->x, center->y + ext->y, center->z + ext->z}, {center->x - ext->x, center->y - ext->y, center->z + ext->z}, - }; - u32 colors[12]; - for (u32 i = 0; i < 12; i++) - { - colors[i] = color; - } - - LineDraw3d::addLines(12, lineWidth, lines, colors); - } - - void drawSector3d(const EditorSector* sector, const SectorTriangles* poly, bool overlay, bool hover, bool lowerLayer) - { - // Draw the floor and ceiling polygons. - const u32 triCount = poly->count; - const Vec2f* vtx = poly->vtx.data(); - - u32 color[4]; - const bool textured = s_sectorDrawMode == SDM_TEXTURED_FLOOR || s_sectorDrawMode == SDM_TEXTURED_CEIL; - const bool blend = overlay;// || (!textured && lowerLayer); - - if (lowerLayer) - { - for (u32 t = 0; t < 4; t++) { color[t] = textured ? 0x80ffff20 : 0xa0ffa020; } - } - else if (overlay) - { - for (u32 t = 0; t < 4; t++) { color[t] = hover ? 0x40ff8020 : 0x40ff4020; } - } - else if (s_sectorDrawMode != SDM_WIREFRAME) - { - u32 L = u32(sector->ambient); - L = s_fullbright ? 255u : std::max(0u, std::min(CONV_5bitTo8bit(L), 255u)); - const u32 Lrg = s_sectorDrawMode == SDM_LIGHTING ? L * 7 / 8 : L; - const u32 lighting = Lrg | (Lrg << 8u) | (L << 16u) | 0xff000000; - - for (u32 t = 0; t < 4; t++) { color[t] = lighting; } - } - else - { - for (u32 t = 0; t < 4; t++) { color[t] = 0xff1a0f0d; } - } - - if (s_sectorDrawMode == SDM_WIREFRAME || s_sectorDrawMode == SDM_LIGHTING || overlay) - { - drawSectorFloorAndCeilColor(sector, poly, color, blend); - } - else - { - drawSectorFloorAndCeilTextured(sector, poly, color[0]); - } - - // Draw quads for each wall. - const u32 wallCount = (u32)sector->walls.size(); - const EditorWall* wall = sector->walls.data(); - vtx = sector->vertices.data(); - for (u32 w = 0; w < wallCount; w++, wall++) - { - if (lowerLayer) - { - for (u32 t = 0; t < 4; t++) { color[t] = textured ? 0x80ffff20 : 0x80ffa020; } - } - else if (overlay) - { - for (u32 t = 0; t < 4; t++) { color[t] = hover ? 0x40ff8020 : 0x40ff4020; } - } - else if (s_sectorDrawMode != SDM_WIREFRAME) - { - const s32 wallLight = sector->ambient < 31 ? wall->light : 0; - - u32 L = u32(std::max(sector->ambient + wallLight, 0)); - L = s_fullbright ? 255u : std::max(0u, std::min(CONV_5bitTo8bit(L), 255u)); - const u32 Lrg = s_sectorDrawMode == SDM_LIGHTING ? L * 7 / 8 : L; - const u32 lighting = Lrg | (Lrg << 8u) | (L << 16u) | 0xff000000; - - for (u32 t = 0; t < 4; t++) { color[t] = lighting; } - } - else - { - for (u32 t = 0; t < 4; t++) { color[t] = 0xff1a0f0d; } - } - - if (s_sectorDrawMode == SDM_WIREFRAME || s_sectorDrawMode == SDM_LIGHTING || overlay) - { - drawWallColor(sector, vtx, wall, color, blend, HIT_PART_UNKNOWN, !lowerLayer); - } - else - { - drawWallTexture(sector, vtx, wall, w, color); - } - } - } - - void highlightWall3d(bool selected, f32 width) - { - if ((selected && s_selectedWall < 0) || (!selected && s_hoveredWall < 0)) { return; } - - s32 sectorId = selected ? s_selectedWallSector : s_hoveredWallSector; - s32 wallId = selected ? s_selectedWall : s_hoveredWall; - RayHitPart part = selected ? s_selectWallPart : s_hoveredWallPart; - const u32 color = selected ? 0xffffA040 : 0xffffC080; - const u32 colors[] = { color, color, color, color }; - - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const EditorWall* wall = sector->walls.data() + wallId; - const Vec2f* vtx = sector->vertices.data(); - - const EditorSector* next = wall->adjoin >= 0 ? s_levelData->sectors.data() + wall->adjoin : nullptr; - f32 floorHeight, ceilHeight; - if (part == HIT_PART_MID || part == HIT_PART_UNKNOWN || !next) - { - floorHeight = next ? std::min(sector->floorAlt, next->floorAlt) : sector->floorAlt; - ceilHeight = next ? std::max(sector->ceilAlt, next->ceilAlt) : sector->ceilAlt; - } - else if (part == HIT_PART_BOT) - { - floorHeight = sector->floorAlt; - ceilHeight = next->floorAlt; - } - else if (part == HIT_PART_TOP) - { - floorHeight = next->ceilAlt; - ceilHeight = sector->ceilAlt; - } - - const Vec2f* v0 = &vtx[wall->i0]; - const Vec2f* v1 = &vtx[wall->i1]; - - Vec3f lines[8]= - { - {v0->x, ceilHeight, v0->z}, {v1->x, ceilHeight, v1->z}, - {v1->x, ceilHeight, v1->z}, {v1->x, floorHeight, v1->z}, - {v1->x, floorHeight, v1->z}, {v0->x, floorHeight, v0->z}, - {v0->x, floorHeight, v0->z}, {v0->x, ceilHeight, v0->z} - }; - LineDraw3d::addLines(4, width, lines, colors); - } - - void drawInfWalls3d(f32 width, u32 color) - { - const u32 colors[] = { color, color, color, color }; - - const u32 count = (u32)s_infWalls.size(); - const InfWall* infWall = s_infWalls.data(); - for (u32 w = 0; w < count; w++, infWall++) - { - const EditorSector* sector = infWall->sector; - const EditorWall* wall = sector->walls.data() + infWall->wallId; - const Vec2f* vtx = sector->vertices.data(); - - // TODO: Draw based on trigger type? - f32 y0, y1; - if (infWall->triggerType == TRIGGER_LINE && wall->adjoin >= 0) - { - const EditorSector* next = s_levelData->sectors.data() + wall->adjoin; - y0 = std::min(next->floorAlt, sector->floorAlt); - y1 = std::max(next->ceilAlt, sector->ceilAlt); - } - else - { - // Switch of some type. - if (wall->adjoin < 0) - { - const f32 h = sector->floorAlt - sector->ceilAlt; - y0 = sector->floorAlt; - y1 = sector->ceilAlt; - } - else - { - const EditorSector* next = s_levelData->sectors.data() + wall->adjoin; - - if (next->floorAlt < sector->floorAlt) // lower - { - y0 = next->floorAlt; - y1 = sector->floorAlt; - } - else if (next->ceilAlt > sector->ceilAlt) // upper - { - y0 = next->ceilAlt; - y1 = sector->ceilAlt; - } - else // mid - { - y0 = sector->floorAlt; - y1 = sector->ceilAlt; - } - } - } - Vec3f lines[8]; - lines[0] = { vtx[wall->i0].x, y0, vtx[wall->i0].z }; - lines[1] = { vtx[wall->i1].x, y0, vtx[wall->i1].z }; - - lines[2] = { vtx[wall->i1].x, y0, vtx[wall->i1].z }; - lines[3] = { vtx[wall->i1].x, y1, vtx[wall->i1].z }; - - lines[4] = { vtx[wall->i1].x, y1, vtx[wall->i1].z }; - lines[5] = { vtx[wall->i0].x, y1, vtx[wall->i0].z }; - - lines[6] = { vtx[wall->i0].x, y1, vtx[wall->i0].z }; - lines[7] = { vtx[wall->i0].x, y0, vtx[wall->i0].z }; - - LineDraw3d::addLines(4, width, lines, colors); - } - } - - void drawSector3d_Lines(const EditorSector* sector, f32 width, u32 color, bool overlay, bool hover) - { - const u32 colors[] = { color, color, color, color, color }; - - // Draw the walls - const u32 wallCount = (u32)sector->walls.size(); - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - for (u32 w = 0; w < wallCount; w++, wall++) - { - if (s_showSectorColors && wall->infType != INF_NONE) - { - // Only add the wall if we are on the "correct" side. - Vec2f dir = { vtx[wall->i1].x - vtx[wall->i0].x, vtx[wall->i1].z - vtx[wall->i0].z }; - Vec2f camDir = { s_camera.pos.x - vtx[wall->i0].x, s_camera.pos.z - vtx[wall->i0].z }; - Vec2f nrm = { -dir.z, dir.x }; - if (nrm.x*camDir.x + nrm.z*camDir.z < 0.0f) - { - s_infWalls.push_back({ sector, w, (u32)wall->triggerType }); - } - } - - // Draw the floor piece. - Vec3f lines[10]; - // floor - lines[0] = { vtx[wall->i0].x, sector->floorAlt, vtx[wall->i0].z }; - lines[1] = { vtx[wall->i1].x, sector->floorAlt, vtx[wall->i1].z }; - // ceiling - u32 count = 1; - if (wall->adjoin < 0 || s_levelData->sectors[wall->adjoin].ceilAlt != sector->ceilAlt || s_camera.pos.y > sector->ceilAlt) - { - lines[2] = { vtx[wall->i0].x, sector->ceilAlt, vtx[wall->i0].z }; - lines[3] = { vtx[wall->i1].x, sector->ceilAlt, vtx[wall->i1].z }; - count++; - } - - if (wall->adjoin < 0) - { - lines[count * 2 + 0] = { vtx[wall->i0].x, sector->floorAlt, vtx[wall->i0].z }; - lines[count * 2 + 1] = { vtx[wall->i0].x, sector->ceilAlt, vtx[wall->i0].z }; - count++; - - if (overlay || hover || color != 0xffffffff) - { - lines[count * 2 + 0] = { vtx[wall->i1].x, sector->floorAlt, vtx[wall->i1].z }; - lines[count * 2 + 1] = { vtx[wall->i1].x, sector->ceilAlt, vtx[wall->i1].z }; - count++; - } - } - else - { - // lower - f32 nextFloorAlt = s_levelData->sectors[wall->adjoin].floorAlt; - if (nextFloorAlt < sector->floorAlt) - { - lines[count * 2 + 0] = { vtx[wall->i0].x, sector->floorAlt, vtx[wall->i0].z }; - lines[count * 2 + 1] = { vtx[wall->i0].x, nextFloorAlt, vtx[wall->i0].z }; - count++; - } - - // upper - f32 nextCeilAlt = s_levelData->sectors[wall->adjoin].ceilAlt; - if (nextCeilAlt > sector->ceilAlt) - { - lines[count * 2 + 0] = { vtx[wall->i0].x, sector->ceilAlt, vtx[wall->i0].z }; - lines[count * 2 + 1] = { vtx[wall->i0].x, nextCeilAlt, vtx[wall->i0].z }; - count++; - } - } - LineDraw3d::addLines(count, width, lines, colors); - } - } - - void drawLineToTarget3d(const Vec3f* p0, s32 sectorId, s32 wallId, f32 width, u32 color) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const Vec2f* vtx = sector->vertices.data(); - Vec3f target = { 0 }; - target.y = (sector->floorAlt + sector->ceilAlt) * 0.5f; - - if (wallId >= 0) - { - const EditorWall* wall = sector->walls.data() + wallId; - target.x = (vtx[wall->i0].x + vtx[wall->i1].x) * 0.5f; - target.z = (vtx[wall->i0].z + vtx[wall->i1].z) * 0.5f; - } - else - { - const u32 vtxCount = (u32)sector->vertices.size(); - for (u32 v = 0; v < vtxCount; v++) - { - target.x += vtx[v].x; - target.z += vtx[v].z; - } - const f32 scale = 1.0f / f32(vtxCount); - target.x *= scale; - target.z *= scale; - } - Vec3f line[] = { *p0, target }; - LineDraw3d::addLine(width, line, &color); - } - - // If the selected wall or sector has an INF script, draw lines towards - // 1. Any objects it effects (targets and clients). - // 2. Any slaves (sector). - void drawTargetsAndClientLines3d(s32 sectorId, f32 width) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const EditorInfItem* item = sector->infItem; - if (!item) { return; } - - Vec3f lineStart = { 0 }; - lineStart.y = (sector->floorAlt + sector->ceilAlt) * 0.5f; - const Vec2f* vtx = sector->vertices.data(); - const u32 vtxCount = (u32)sector->vertices.size(); - for (u32 v = 0; v < vtxCount; v++) - { - lineStart.x += vtx[v].x; - lineStart.z += vtx[v].z; - } - const f32 scale = 1.0f / f32(vtxCount); - lineStart.x *= scale; - lineStart.z *= scale; - - for (u32 c = 0; c < (u32)item->classData.size(); c++) - { - const EditorInfClassData* cdata = &item->classData[c]; - u32 stopCount = 0; - if (cdata->iclass == INF_CLASS_TRIGGER) - { - stopCount = 1; - } - else if (cdata->iclass == INF_CLASS_ELEVATOR) - { - stopCount = (u32)cdata->stop.size(); - } - - for (u32 s = 0; s < stopCount; s++) - { - const u32 funcCount = (u32)cdata->stop[s].func.size(); - for (u32 f = 0; f < funcCount; f++) - { - const u32 funcId = cdata->stop[s].func[f].funcId; - const u32 clientCount = (u32)cdata->stop[s].func[f].client.size(); - for (u32 cl = 0; cl < clientCount; cl++) - { - const EditorSector* clientSector = LevelEditorData::getSector(cdata->stop[s].func[f].client[cl].sectorName.c_str()); - const s32 clientWallId = cdata->stop[s].func[f].client[cl].wallId; - if (!clientSector) { continue; } - - if (clientWallId >= 0) - { - drawLineToTarget3d(&lineStart, clientSector->id, clientWallId, 1.5f * width, 0xffff2020); - } - else - { - drawLineToTarget3d(&lineStart, clientSector->id, -1, 1.5f * width, 0xffff2020); - } - } - - // Draw to the adjoining lines. - if (funcId == INF_MSG_ADJOIN) - { - drawLineToTarget3d(&lineStart, LevelEditorData::getSector(cdata->stop[s].func[f].arg[0].sValue.c_str())->id, cdata->stop[s].func[f].arg[1].iValue, 1.5f * width, 0xff2020ff); - drawLineToTarget3d(&lineStart, LevelEditorData::getSector(cdata->stop[s].func[f].arg[2].sValue.c_str())->id, cdata->stop[s].func[f].arg[3].iValue, 1.5f * width, 0xff2020ff); - } - } - } - } - } - - void drawTargetsAndClientLines3d(s32 sectorId, s32 wallId, f32 width) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const Vec2f* vtx = sector->vertices.data(); - const EditorWall* wall = sector->walls.data() + wallId; - const EditorInfItem* item = wall->infItem; - - Vec3f lineStart; - lineStart.x = (vtx[wall->i0].x + vtx[wall->i1].x) * 0.5f; - lineStart.y = (sector->floorAlt + sector->ceilAlt) * 0.5f; - lineStart.z = (vtx[wall->i0].z + vtx[wall->i1].z) * 0.5f; - - for (u32 c = 0; c < (u32)item->classData.size(); c++) - { - const EditorInfClassData* cdata = &item->classData[c]; - u32 stopCount = 0; - if (cdata->iclass == INF_CLASS_TRIGGER) - { - stopCount = 1; - } - else if (cdata->iclass == INF_CLASS_ELEVATOR) - { - stopCount = (u32)cdata->stop.size(); - } - - for (u32 s = 0; s < stopCount; s++) - { - const u32 funcCount = (u32)cdata->stop[s].func.size(); - for (u32 f = 0; f < funcCount; f++) - { - const u32 clientCount = (u32)cdata->stop[s].func[f].client.size(); - for (u32 cl = 0; cl < clientCount; cl++) - { - const EditorSector* clientSector = LevelEditorData::getSector(cdata->stop[s].func[f].client[cl].sectorName.c_str()); - const s32 clientWallId = cdata->stop[s].func[f].client[cl].wallId; - if (!clientSector) { continue; } - - if (clientWallId >= 0) - { - drawLineToTarget3d(&lineStart, clientSector->id, clientWallId, 1.5f * width, 0xffff2020); - } - else - { - drawLineToTarget3d(&lineStart, clientSector->id, -1, 1.5f * width, 0xffff2020); - } - } - } - } - } - } - - void drawTargetsAndClientSlaves3d(s32 sectorId, f32 width) - { - const EditorSector* sector = s_levelData->sectors.data() + sectorId; - const EditorInfItem* item = sector->infItem; - if (!item) { return; } - - Vec3f lineStart = { 0 }; - lineStart.y = (sector->floorAlt + sector->ceilAlt) * 0.5f; - const Vec2f* vtx = sector->vertices.data(); - const u32 vtxCount = (u32)sector->vertices.size(); - for (u32 v = 0; v < vtxCount; v++) - { - lineStart.x += vtx[v].x; - lineStart.z += vtx[v].z; - } - const f32 scale = 1.0f / f32(vtxCount); - lineStart.x *= scale; - lineStart.z *= scale; - - for (u32 c = 0; c < (u32)item->classData.size(); c++) - { - const EditorInfClassData* cdata = &item->classData[c]; - for (u32 s = 0; s < (u32)cdata->slaves.size(); s++) - { - const EditorSector* slaveSector = LevelEditorData::getSector(cdata->slaves[s].c_str()); - if (!slaveSector) { continue; } - - drawLineToTarget3d(&lineStart, slaveSector->id, -1, 1.25f * width, 0xff20ff20); - } - } - } - - void drawLevel3d(u32 rtWidth, u32 rtHeight) - { - Vec3f upDir = { 0.0f, 1.0f, 0.0f }; - Vec3f lookDir = { sinf(s_camera.yaw) * cosf(s_camera.pitch), sinf(s_camera.pitch), cosf(s_camera.yaw) * cosf(s_camera.pitch) }; - - s_camera.viewMtx = TFE_Math::computeViewMatrix(&lookDir, &upDir); - s_camera.projMtx = TFE_Math::computeProjMatrix(c_editorCameraFov, f32(rtWidth) / f32(rtHeight), 0.01f, 5000.0f); - s_camera.invProj = TFE_Math::computeInvProjMatrix(s_camera.projMtx); - - // Get the current sector (top-down only) - const s32 layer = s_layerIndex + s_layerMin; - const Vec2f topDownPos = { s_camera.pos.x, s_camera.pos.z }; - s32 overSector = LevelEditorData::findSector(layer, &topDownPos); - if (overSector >= 0 && s_levelData->sectors[overSector].floorAlt < s_camera.pos.y) - { - overSector = -1; - } - - if (s_levelData && s_showLowerLayers) - { - u32 sectorCount = (u32)s_levelData->sectors.size(); - EditorSector* sector = s_levelData->sectors.data(); - - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer >= layer) { continue; } - drawSector3d(sector, §or->triangles, false, false, true); - } - TrianglesColor3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, true, s_showGridInSector ? s_gridHeight : c_gridInvisibleHeight); - TFE_RenderBackend::clearRenderTargetDepth(s_view3d, 1.0f); - } - - f32 pixelSize = 1.0f / (f32)rtHeight; - if (!s_levelData) - { - Grid3d::draw(s_gridSize, s_gridHeight, s_subGridSize, s_gridOpacity, pixelSize, &s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx); - } - - if (!s_levelData) { return; } - u32 sectorCount = (u32)s_levelData->sectors.size(); - EditorSector* sector = s_levelData->sectors.data(); - // Draw the sector faces. - u32 color[] = { 0xff1a0f0d, 0xff1a0f0d, 0xff1a0f0d, 0xff1a0f0d }; - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - drawSector3d(sector, §or->triangles); - } - TrianglesColor3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, true, s_showGridInSector ? s_gridHeight : c_gridInvisibleHeight); - - const f32 width = 3.0f / f32(rtHeight); - // Walls - if (s_showSectorColors) - { - const u32 sectorClr[] = { 0xffffffff, 0xffff80ff, 0xffffff80 }; - s_infWalls.clear(); - for (u32 i = 0; i < INF_COUNT; i++) - { - sector = s_levelData->sectors.data(); - for (u32 s = 0; s < sectorCount; s++, sector++) - { - if (sector->layer != layer || sector->infType != i) { continue; } - drawSector3d_Lines(sector, width, sectorClr[i]); - } - } - drawInfWalls3d(width, 0xff2020ff); - } - else - { - sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - drawSector3d_Lines(sector, width, 0xffffffff); - } - } - - // Draw the 3d cursor in "Draw Mode" - if (s_editMode == LEDIT_DRAW) - { - const f32 distFromCam = TFE_Math::distance(&s_cursor3d, &s_camera.pos); - const f32 size = distFromCam * 16.0f / f32(rtHeight); - - drawBox(&s_cursor3d, size, 3.0f / f32(rtHeight), 0x80ff8020); - } - - LineDraw3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx); - - // Draw selected or hovered elements. - if (s_editMode == LEDIT_SECTOR && (s_hoveredSector >= 0 || s_selectedSector >= 0)) - { - // Draw solid sector. - if (s_selectedSector >= 0) - { - sector = s_levelData->sectors.data() + s_selectedSector; - drawSector3d(sector, §or->triangles, true, false); - } - if (s_hoveredSector >= 0) - { - sector = s_levelData->sectors.data() + s_hoveredSector; - drawSector3d(sector, §or->triangles, true, true); - } - TrianglesColor3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, true, s_showGridInSector ? s_gridHeight : c_gridInvisibleHeight); - - // Draw outline (no depth buffer). - if (s_selectedSector >= 0) - { - sector = s_levelData->sectors.data() + s_selectedSector; - drawSector3d_Lines(sector, width * 1.25f, 0xffffA040); - } - if (s_hoveredSector >= 0) - { - sector = s_levelData->sectors.data() + s_hoveredSector; - drawSector3d_Lines(sector, width * 1.25f, 0xffffC080); - } - LineDraw3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, false); - } - if (s_editMode == LEDIT_WALL && (s_hoveredWall >= 0 || s_selectedWall >= 0)) - { - // Draw solid wall. - if (s_selectedWall >= 0) - { - u32 color[] = { 0x40ff4020, 0x40ff4020 }; - sector = s_levelData->sectors.data() + s_selectedWallSector; - drawWallColor(sector, sector->vertices.data(), sector->walls.data() + s_selectedWall, color, true, s_selectWallPart); - } - if (s_hoveredWall >= 0) - { - u32 color[] = { 0x40ff8020, 0x40ff8020 }; - sector = s_levelData->sectors.data() + s_hoveredWallSector; - drawWallColor(sector, sector->vertices.data(), sector->walls.data() + s_hoveredWall, color, true, s_hoveredWallPart); - } - TrianglesColor3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, true, s_showGridInSector ? s_gridHeight : c_gridInvisibleHeight); - - // Draw the selected sector before drawing the walls. - if (s_selectedWall >= 0 || s_hoveredWall >= 0) - { - highlightWall3d(true, width*1.25f); - highlightWall3d(false, width*1.25f); - } - LineDraw3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, false); - } - if (s_editMode == LEDIT_VERTEX && (s_hoveredVertex >= 0 || s_selectedVertex >= 0)) - { - // Draw the selected sector before drawing the walls. - if (s_selectedVertex >= 0 || s_hoveredVertex >= 0) - { - if (s_selectedVertex >= 0) - { - sector = s_levelData->sectors.data() + s_selectedVertexSector; - const Vec2f* vtx = sector->vertices.data() + s_selectedVertex; - const Vec3f pos = { vtx->x, s_selectVertexPart == HIT_PART_FLOOR ? sector->floorAlt : sector->ceilAlt , vtx->z }; - - const f32 distFromCam = TFE_Math::distance(&pos, &s_camera.pos); - const f32 size = distFromCam * 16.0f / f32(rtHeight); - - // Add a screen aligned quad. - drawScreenQuad(&pos, size, 0xA0ff4020); - drawScreenQuadOutline(&pos, size, width, 0xffffA040); - } - if (s_hoveredVertex >= 0) - { - sector = s_levelData->sectors.data() + s_hoveredVertexSector; - const Vec2f* vtx = sector->vertices.data() + s_hoveredVertex; - const Vec3f pos = { vtx->x, s_hoveredVertexPart == HIT_PART_FLOOR ? sector->floorAlt : sector->ceilAlt , vtx->z }; - - const f32 distFromCam = TFE_Math::distance(&pos, &s_camera.pos); - const f32 size = distFromCam * 16.0f / f32(rtHeight); - - drawScreenQuad(&pos, size, 0xA0ff8020); - drawScreenQuadOutline(&pos, size, width, 0xffffC080); - } - } - TrianglesColor3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, false, s_showGridInSector ? s_gridHeight : c_gridInvisibleHeight); - LineDraw3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, false); - } - - if (s_selectedSector >= 0 && s_levelData->sectors[s_selectedSector].infType != INF_NONE) - { - // If the selected wall or sector has an INF script, draw lines towards - drawTargetsAndClientLines3d(s_selectedSector, width); - drawTargetsAndClientSlaves3d(s_selectedSector, width); - } - else if (s_selectedWall >= 0 && s_levelData->sectors[s_selectedWallSector].walls[s_selectedWall].infType != INF_NONE) - { - drawTargetsAndClientLines3d(s_selectedWallSector, s_selectedWall, width); - } - LineDraw3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, false); - - // Objects - u32 alphaFg = s_editMode == LEDIT_ENTITY ? 0xff000000 : 0xA0000000; - u32 alphaBg = s_editMode == LEDIT_ENTITY ? 0xA0000000 : 0x60000000; - sector = s_levelData->sectors.data(); - for (u32 i = 0; i < sectorCount; i++, sector++) - { - if (sector->layer != layer) { continue; } - - // For now just draw a quad + image. - const u32 objCount = (u32)sector->objects.size(); - const EditorLevelObject* obj = sector->objects.data(); - for (u32 o = 0; o < objCount; o++, obj++) - { - f32 bwidth = 3.0f / f32(rtHeight); - u32 bcolor = 0x00ffd7a4 | alphaBg; - const bool selected = s_selectedEntity == o && s_selectedEntitySector == i; - if ((s_hoveredEntity == o && s_hoveredEntitySector == i) || selected) - { - bwidth *= 1.25f; - bcolor = 0x00ffe7b4 | alphaFg; - } - - if (obj->oclass == CLASS_3D) - { - TFE_EditorRender::drawModel3d(sector, obj->displayModel, &obj->pos, &obj->rotMtx, s_palette->colors, alphaFg); - TFE_EditorRender::drawModel3d_Bounds(obj->displayModel, &obj->pos, &obj->rotMtx, bwidth, bcolor); - } - else - { - // Draw the bounding box. - drawBounds(&obj->worldCen, &obj->worldExt, bwidth, bcolor); - - if (obj->display) - { - const Vec3f r = s_camera.viewMtx.m0; - const Vec3f u = { 0.0f, 1.0f, 0.0f }; - const Vec3f vtx[] = - { - {obj->worldCen.x - obj->worldExt.x * r.x, obj->worldCen.y - obj->worldExt.x * r.y - obj->worldExt.y * u.y, obj->worldCen.z - obj->worldExt.z * r.z }, - {obj->worldCen.x + obj->worldExt.x * r.x, obj->worldCen.y + obj->worldExt.x * r.y - obj->worldExt.y * u.y, obj->worldCen.z + obj->worldExt.z * r.z }, - {obj->worldCen.x + obj->worldExt.x * r.x, obj->worldCen.y + obj->worldExt.x * r.y + obj->worldExt.y * u.y, obj->worldCen.z + obj->worldExt.z * r.z }, - - {obj->worldCen.x - obj->worldExt.x * r.x, obj->worldCen.y - obj->worldExt.x * r.y - obj->worldExt.y * u.y, obj->worldCen.z - obj->worldExt.z * r.z }, - {obj->worldCen.x + obj->worldExt.x * r.x, obj->worldCen.y + obj->worldExt.x * r.y + obj->worldExt.y * u.y, obj->worldCen.z + obj->worldExt.z * r.z }, - {obj->worldCen.x - obj->worldExt.x * r.x, obj->worldCen.y - obj->worldExt.x * r.y + obj->worldExt.y * u.y, obj->worldCen.z - obj->worldExt.z * r.z }, - }; - - const Vec2f uv[6] = - { - {0.0f, 0.0f}, - {1.0f, 0.0f}, - {1.0f, 1.0f}, - - {0.0f, 0.0f}, - {1.0f, 1.0f}, - {0.0f, 1.0f}, - }; - u32 baseRGB = selected ? 0x00ffa0a0 : 0x00ffffff; - u32 colorFg[2] = { baseRGB | alphaFg, baseRGB | alphaFg }; - TrianglesColor3d::addTexturedTriangles(2, vtx, uv, uv, colorFg, obj->display->texture, TrianglesColor3d::TRANS_BLEND_CLAMP); - - // Draw a direction. - const f32 angle = obj->orientation.y * PI / 180.0f; - const Vec3f dir = { sinf(angle), 0.0f, cosf(angle) }; - - // Make an arrow. - Vec3f dP = { dir.x * obj->worldExt.x, obj->worldExt.y, dir.z * obj->worldExt.z }; - Vec3f cen = { obj->worldCen.x + dP.x, obj->worldCen.y + dP.y, obj->worldCen.z + dP.z }; - Vec3f tan = { -dir.z * obj->worldExt.x * 0.5f, 0.0f, dir.x * obj->worldExt.z * 0.5f }; - // Make sure the direction arrow is visible. - cen.y = std::min(cen.y, sector->floorAlt - 0.1f); - - Vec3f arrowVtx[] = - { - cen, {cen.x + tan.x - dP.x * 0.25f, cen.y, cen.z + tan.z - dP.z * 0.25f}, - cen, {cen.x - tan.x - dP.x * 0.25f, cen.y, cen.z - tan.z - dP.z * 0.25f}, - }; - - const bool highlight = (s_hoveredEntity == o && s_hoveredEntitySector == i) || selected; - const u32 alphaArrow = s_editMode == LEDIT_ENTITY ? (highlight ? 0xA0000000 : 0x60000000) : 0x30000000; - u32 baseRGBArrow = 0x00ffff00; - u32 baseClrArrow = baseRGBArrow | alphaArrow; - u32 color[] = { baseClrArrow, baseClrArrow, baseClrArrow, baseClrArrow }; - LineDraw3d::addLines(2, bwidth, arrowVtx, color); - } - } - } - } - TrianglesColor3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, true, s_showGridInSector ? s_gridHeight : c_gridInvisibleHeight); - LineDraw3d::draw(&s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx, true, false); - - if (overSector >= 0 && s_gridAutoAdjust) - { - s_gridHeight = s_levelData->sectors[overSector].floorAlt; - } - if (overSector < 0 || s_showGridInSector) - { - Grid3d::draw(s_gridSize, s_gridHeight, s_subGridSize, s_gridOpacity, pixelSize, &s_camera.pos, &s_camera.viewMtx, &s_camera.projMtx); - } - } - - void saveDosBoxConfig() - { - char srcConfigPath[TFE_MAX_PATH]; - char dstConfigPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_EMULATOR, "Dosbox.conf", srcConfigPath); - TFE_Paths::appendPath(TFE_PathType::PATH_EMULATOR, "Dosbox_Temp.conf", dstConfigPath); - - FileUtil::copyFile(srcConfigPath, dstConfigPath); - } - - void restoreDosBoxConfig() - { - char srcConfigPath[TFE_MAX_PATH]; - char dstConfigPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_EMULATOR, "Dosbox_Temp.conf", srcConfigPath); - TFE_Paths::appendPath(TFE_PathType::PATH_EMULATOR, "Dosbox.conf", dstConfigPath); - - FileUtil::copyFile(srcConfigPath, dstConfigPath); - FileUtil::deleteFile(srcConfigPath); - } - - bool writeDosBoxConfig(const char* levelName) - { - // Read the existing config. - char srcConfigPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "DosBox/DefaultDosBoxConfig.txt", srcConfigPath); - - FileStream srcConfig; - if (!srcConfig.open(srcConfigPath, FileStream::MODE_READ)) - { - return false; - } - - const size_t len = srcConfig.getSize(); - std::vector dosBoxConfig(len + 512); - srcConfig.readBuffer(dosBoxConfig.data(), (u32)len); - srcConfig.close(); - - char* newConfig = dosBoxConfig.data(); - char commandLine[512]; - sprintf(commandLine, "dark.exe -uEDITOR.GOB -l%s -c\r\nexit\r\n", levelName); - strcat(newConfig, commandLine); - - char dstConfigPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_EMULATOR, "Dosbox.conf", dstConfigPath); - - FileStream config; - if (!config.open(dstConfigPath, FileStream::MODE_WRITE)) - { - return false; - } - config.writeBuffer(newConfig, (u32)strlen(newConfig)); - config.close(); - - return true; - } - - void play(bool playFromDos) - { - bool res = LevelEditorData::generateLevelData(); - res &= LevelEditorData::generateInfAsset(); - res &= LevelEditorData::generateObjects(); - if (res) - { - Vec2f pos2d = { s_camera.pos.x, s_camera.pos.z }; - s32 sectorId = LevelEditorData::findSector(s_layerIndex + s_layerMin, &pos2d); - LevelObjectData* levelObj = TFE_LevelObjects::getLevelObjectData(); - - if (playFromDos) - { - // Temporarily move the start point. - s32 startIndex = -1; - Vec3f originalStartPos; - f32 originalAngle; - LevelObject* obj = levelObj->objects.data(); - for (u32 i = 0; i < levelObj->objectCount; i++, obj++) - { - if (obj->oclass == CLASS_SPIRIT && obj->logics.size() && obj->logics[0].type == LOGIC_PLAYER) - { - startIndex = s32(i); - originalStartPos = obj->pos; - originalAngle = obj->orientation.y; - obj->pos = s_camera.pos; - obj->orientation.y = 180.0f + 360.0f * s_camera.yaw / (2.0f * PI); - } - } - - // Create GOB - char gobPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(PATH_SOURCE_DATA, "editor.gob", gobPath); - Archive::deleteCustomArchive(s_outGob); - s_outGob = Archive::createCustomArchive(ARCHIVE_GOB, gobPath); - - char basePath[TFE_MAX_PATH]; - TFE_Paths::appendPath(PATH_PROGRAM_DATA, s_levelData->name.c_str(), basePath); - - char levName[TFE_MAX_PATH]; - char objName[TFE_MAX_PATH]; - char infName[TFE_MAX_PATH]; - sprintf(levName, "%s.LEV", s_levelData->name.c_str()); - sprintf(objName, "%s.O", s_levelData->name.c_str()); - sprintf(infName, "%s.INF", s_levelData->name.c_str()); - - char levPath[TFE_MAX_PATH]; - char objPath[TFE_MAX_PATH]; - char infPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(PATH_PROGRAM_DATA, levName, levPath); - TFE_Paths::appendPath(PATH_PROGRAM_DATA, objName, objPath); - TFE_Paths::appendPath(PATH_PROGRAM_DATA, infName, infPath); - - TFE_LevelAsset::save(s_levelData->name.c_str(), levPath); - //TFE_InfAsset::save(infName, infPath); - TFE_LevelObjects::save(s_levelData->name.c_str(), objPath); - - s_outGob->addFile(levName, levPath); - s_outGob->addFile(objName, objPath); - //s_outGob->addFile(infName, infPath); - - // Run - saveDosBoxConfig(); - writeDosBoxConfig(s_levelData->name.c_str()); - - char dosBoxPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_EMULATOR, "Dosbox.exe", dosBoxPath); - TFE_System::osShellExecute(dosBoxPath, TFE_Paths::getPath(TFE_PathType::PATH_EMULATOR), nullptr, true); - - restoreDosBoxConfig(); - if (startIndex >= 0) - { - LevelObject* obj = levelObj->objects.data() + startIndex; - obj->pos = originalStartPos; - obj->orientation.y = originalAngle; - } - } - else - { - u32 w = 320, h = 200; - if (TFE_GameLoop::startLevelFromExisting(&s_camera.pos, -s_camera.yaw + PI, sectorId, s_palette, levelObj, s_renderer, w, h)) - { - s_runLevel = true; - TFE_Input::enableRelativeMode(true); - s_renderer->enableScreenClear(false); - } - } - } - } - - void draw(bool* isActive) - { - if (s_runLevel) - { - return; - } - - // Draw the tool bar. - toolbarBegin(); - { - if (drawToolbarButton(s_editCtrlToolbarData, 0, false)) - { - play(false); - } - ImGui::SameLine(0.0f, 32.0f); - - for (u32 i = 1; i < 6; i++) - { - if (drawToolbarButton(s_editCtrlToolbarData, i, i == s_editMode)) - { - s_editMode = i; - s_enableInfEditor = false; - s_drawStarted = false; - s_moveVertex = false; - - clearNewSector(); - } - ImGui::SameLine(); - } - ImGui::SameLine(0.0f, 32.0f); - - for (u32 i = 0; i < 6; i++) - { - if (drawToolbarButton(s_booleanToolbarData, i, i == s_boolMode)) - { - s_boolMode = i; - } - ImGui::SameLine(); - } - - // TODO: Toolbar for rendering mode: - // Wireframe, Shaded, Textured, Textured & Shaded - - ImGui::SameLine(0.0f, 32.0f); - ImGui::PushItemWidth(64.0f); - if (ImGui::Combo("Grid Size", &s_gridIndex, c_gridSizes, IM_ARRAYSIZE(c_gridSizes))) - { - s_gridSize = c_gridSizeMap[s_gridIndex]; - } - ImGui::PopItemWidth(); - // Get the "Grid Size" combo position to align the message panel later. - const ImVec2 itemPos = ImGui::GetItemRectMin(); - - ImGui::SameLine(0.0f, 32.0f); - ImGui::PushItemWidth(64.0f); - ImGui::Combo("Layer", &s_layerIndex, s_layerStr, IM_ARRAYSIZE(s_layerStr)); - ImGui::PopItemWidth(); - - // Message Panel - messagePanel(itemPos); - } - toolbarEnd(); - - // Draw the info bars. - s_infoHeight = 486; - - infoToolBegin(s_infoHeight); - { - if (s_hoveredVertex >= 0 || s_selectedVertex >= 0) - { - infoPanelVertex(); - } - else if (s_hoveredSector >= 0 || s_selectedSector >= 0) - { - infoPanelSector(); - } - else if (s_hoveredWall >= 0 || s_selectedWall >= 0) - { - infoPanelWall(); - } - else if (s_hoveredEntity >= 0 || s_selectedEntity >= 0) - { - infoPanelEntity(); - } - else - { - infoPanelMap(); - } - } - infoToolEnd(); - // Browser - browserBegin(s_infoHeight); - { - if (s_editMode == LEDIT_ENTITY) - { - browseEntities(); - } - else - { - browseTextures(); - } - } - browserEnd(); - - // Draw the grid. - bool recreateRendertarget = !s_view3d; - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - const u32 curWidth = displayInfo.width - 480 - 16; - const u32 curHeight = displayInfo.height - 68 - 18; - if (s_view3d) - { - u32 width, height; - TFE_RenderBackend::getRenderTargetDim(s_view3d, &width, &height); - - if (curWidth != width || curHeight != height) - { - TFE_RenderBackend::freeRenderTarget(s_view3d); - s_view3d = nullptr; - recreateRendertarget = true; - } - } - if (recreateRendertarget) - { - s_view3d = TFE_RenderBackend::createRenderTarget(curWidth, curHeight, true); - } - TFE_RenderBackend::bindRenderTarget(s_view3d); - { - const f32 clearColor[] = { 0.05f, 0.06f, 0.1f, 1.0f }; - TFE_RenderBackend::clearRenderTarget(s_view3d, clearColor, 1.0f); - TFE_RenderState::setColorMask(CMASK_RGB); - - // Calculate the sub-grid size. - if (s_gridSize > 1.0f) - { - s_subGridSize = floorf(log2f(1.0f / s_zoomVisual)); - s_subGridSize = powf(2.0f, s_subGridSize); - - f32 scaledGrid = s_gridSize / s_subGridSize; - if (floorf(scaledGrid * 100.0f)*0.01f != scaledGrid) - { - s_subGridSize = s_gridSize * 4.0f; - } - } - else - { - s_subGridSize = std::min(floorf(log10f(0.1f / s_zoomVisual)), 2.0f); - s_subGridSize = powf(10.0f, s_subGridSize); - } - s_subGridSize = std::max(0.0f, s_subGridSize); - - u32 rtWidth, rtHeight; - TFE_RenderBackend::getRenderTargetDim(s_view3d, &rtWidth, &rtHeight); - if (s_editView == EDIT_VIEW_2D) { drawLevel2d(rtWidth, rtHeight); } - else if (s_editView == EDIT_VIEW_3D) { drawLevel3d(rtWidth, rtHeight); } - } - TFE_RenderBackend::unbindRenderTarget(); - TFE_RenderState::setColorMask(CMASK_ALL); - - // Draw the edit window - levelEditWinBegin(); - { - const TextureGpu* texture = TFE_RenderBackend::getRenderTargetTexture(s_view3d); - ImGui::ImageButton(TFE_RenderBackend::getGpuPtr(texture), { (f32)curWidth, (f32)curHeight }, { 0.0f, 0.0f }, { 1.0f, 1.0f }, 0, { 0.0f, 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }); - const ImVec2 itemPos = ImGui::GetItemRectMin(); - s_editWinMapCorner = { itemPos.x, itemPos.y }; - - s_hoveredSector = -1; - s_hoveredWall = -1; - if ((ImGui::IsWindowHovered() || ImGui::IsWindowFocused()) && (!HelpWindow::isOpen() || HelpWindow::isMinimized())) - { - editWinControls((s32)curWidth, (s32)curHeight); - } - - // Draw the position of the currently hovered vertex. - if (s_hoveredVertex >= 0 && s_hoveredVertex < s_levelData->sectors[s_hoveredVertexSector].vertices.size() && s_editView == EDIT_VIEW_2D) - { - const EditorSector* sector = s_levelData->sectors.data() + s_hoveredVertexSector; - const Vec2f* vtx = sector->vertices.data() + s_hoveredVertex; - const f32 rcpZoom = 1.0f / s_zoomVisual; - s32 x = s32(( vtx->x - s_offset.x) * rcpZoom + s_editWinMapCorner.x ) - 56; - s32 y = s32((-vtx->z - s_offset.z) * rcpZoom + s_editWinMapCorner.z ) - 40; - x = std::min(s32(s_editWinMapCorner.x + s_editWinSize.x) - 128, std::max((s32)s_editWinMapCorner.x, x)); - y = std::min(s32(s_editWinMapCorner.z + s_editWinSize.z) - 32, std::max((s32)s_editWinMapCorner.z, y)); - - const ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoInputs; - - ImVec4 windowBg = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); - windowBg.w *= 0.75f; - ImGui::PushStyleColor(ImGuiCol_ChildBg, windowBg); - ImGui::SetNextWindowPos({ f32(x), f32(y) }); - ImGui::BeginChild("Coordinates", ImVec2(128, 32), true, window_flags); - { - ImGui::TextColored({ 1.0f, 1.0f, 1.0f, 0.75f }, "%0.2f, %0.2f", vtx->x, vtx->z); - } - ImGui::EndChild(); - ImGui::PopStyleColor(); - } - } - levelEditWinEnd(); - - // Show the error popup if needed. - showErrorPopup(); - - // Load and other actions. - if (s_loadLevel) - { - loadLevel(); - s_loadLevel = false; - } - } - - void menu() - { - if (ImGui::BeginMenu("File")) - { - if (ImGui::MenuItem("New", "Ctrl+N", (bool*)NULL)) - { - // GOB (creates a new Gob if it doesn't exist) - // Name - // Slot (SECBASE, TALAY, etc.) - // Resources (TEXTURE.GOB, SPRITES.GOB, SOUNDS.GOB, DARK.GOB, ...) - } - if (ImGui::MenuItem("Copy Level", NULL, (bool*)NULL)) - { - // Source GOB - // Select Level - // Destination GOB - // New Map from copy (same as New Level) - } - if (ImGui::MenuItem("Open", "Ctrl+O", (bool*)NULL)) - { - // Open GOB - // Open Level - } - ImGui::Separator(); - if (ImGui::MenuItem("Close", NULL, (bool*)NULL)) - { - } - ImGui::Separator(); - if (ImGui::MenuItem("Save", "Ctrl+S", (bool*)NULL)) - { - } - ImGui::Separator(); - // Path to Gob : filename - if (ImGui::BeginMenu("Recent")) - { - for (u32 i = 0; i < s_recentCount; i++) - { - char recent[TFE_MAX_PATH]; - sprintf(recent, "%s: \"%s\" (%s)", s_recentLevels[i].gobName, s_recentLevels[i].levelName, s_recentLevels[i].levelFilename); - if (ImGui::MenuItem(recent, NULL, (bool*)NULL)) - { - strcpy(s_gobFile, s_recentLevels[i].gobPath); - strcpy(s_levelFile, s_recentLevels[i].levelFilename); - strcpy(s_levelName, s_recentLevels[i].levelName); - s_loadLevel = true; - } - } - ImGui::EndMenu(); - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Edit")) - { - if (ImGui::MenuItem("Undo", "Ctrl+Z", (bool*)NULL)) - { - } - if (ImGui::MenuItem("Redo", "Ctrl+Y", (bool*)NULL)) - { - } - ImGui::Separator(); - if (ImGui::MenuItem("Cut", "Ctrl+X", (bool*)NULL)) - { - } - if (ImGui::MenuItem("Copy", "Ctrl+C", (bool*)NULL)) - { - } - if (ImGui::MenuItem("Paste", "Ctrl+V", (bool*)NULL)) - { - } - if (ImGui::MenuItem("Duplicate", "Ctrl+D", (bool*)NULL)) - { - } - if (ImGui::MenuItem("Delete", "Del", (bool*)NULL)) - { - } - ImGui::Separator(); - if (ImGui::MenuItem("Clear Selection", "Backspace", (bool*)NULL)) - { - s_selectedSector = -1; - s_selectedVertex = -1; - s_selectedWall = -1; - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("View")) - { - if (ImGui::MenuItem("2D", "Ctrl+1", s_editView == EDIT_VIEW_2D)) - { - if (s_editView == EDIT_VIEW_3D) - { - const Vec2f scale = { s_editWinSize.x*0.5f, s_editWinSize.z*0.5f }; - s_offset.x = s_camera.pos.x - scale.x*s_zoomVisual; - s_offset.z = -s_camera.pos.z - scale.z*s_zoomVisual; - } - s_editView = EDIT_VIEW_2D; - s_drawStarted = false; - } - if (ImGui::MenuItem("3D (Editor)", "Ctrl+2", s_editView == EDIT_VIEW_3D)) - { - if (s_editView == EDIT_VIEW_2D) - { - const Vec2f scale = { s_editWinSize.x*0.5f, s_editWinSize.z*0.5f }; - s_camera.pos.x = s_offset.x + scale.x*s_zoomVisual; - s_camera.pos.z = -s_offset.z - scale.z*s_zoomVisual; - } - s_editView = EDIT_VIEW_3D; - s_drawStarted = false; - } - if (ImGui::MenuItem("3D (Game)", "Ctrl+3", s_editView == EDIT_VIEW_3D_GAME)) - { - s_editView = EDIT_VIEW_3D_GAME; - } - ImGui::Separator(); - if (ImGui::MenuItem("Show Lower Layers", "Ctrl+L", s_showLowerLayers)) - { - s_showLowerLayers = !s_showLowerLayers; - } - ImGui::Separator(); - if (ImGui::MenuItem("Wireframe", "Ctrl+F1", s_sectorDrawMode == SDM_WIREFRAME)) - { - s_sectorDrawMode = SDM_WIREFRAME; - } - if (ImGui::MenuItem("Lighting", "Ctrl+F2", s_sectorDrawMode == SDM_LIGHTING)) - { - s_sectorDrawMode = SDM_LIGHTING; - } - if (ImGui::MenuItem("Textured (Floor)", "Ctrl+F3", s_sectorDrawMode == SDM_TEXTURED_FLOOR)) - { - s_sectorDrawMode = SDM_TEXTURED_FLOOR; - } - if (ImGui::MenuItem("Textured (Ceiling)", "Ctrl+F4", s_sectorDrawMode == SDM_TEXTURED_CEIL)) - { - s_sectorDrawMode = SDM_TEXTURED_CEIL; - } - if (ImGui::MenuItem("Fullbright", "Ctrl+F5", s_fullbright)) - { - s_fullbright = !s_fullbright; - } - ImGui::Separator(); - if (ImGui::MenuItem("Display Sector Colors", "", s_showSectorColors)) - { - s_showSectorColors = !s_showSectorColors; - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Run")) - { - if (ImGui::MenuItem("Run [The Force Engine]", "Ctrl+R", (bool*)NULL)) - { - play(false); - } - if (ImGui::MenuItem("Run [Dark Forces]", "Ctrl+T", (bool*)NULL)) - { - play(true); - } - ImGui::EndMenu(); - } - } - - void toolbarBegin() - { - bool toolbarActive = true; - - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - ImGui::SetWindowPos("MainToolbar", { 0.0f, 19.0f }); - ImGui::SetWindowSize("MainToolbar", { (f32)displayInfo.width - 480.0f, 48.0f }); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus; - - ImGui::Begin("MainToolbar", &toolbarActive, window_flags); - } - - void toolbarEnd() - { - ImGui::End(); - } - - void levelEditWinBegin() - { - bool gridActive = true; - - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - s_editWinSize = { (f32)displayInfo.width - 480.0f, (f32)displayInfo.height - 68.0f }; - - ImGui::SetWindowPos("LevelEditWin", { s_editWinPos.x, s_editWinPos.z }); - ImGui::SetWindowSize("LevelEditWin", { s_editWinSize.x, s_editWinSize.z }); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus; - - ImGui::Begin("LevelEditWin", &gridActive, window_flags); - } - - void levelEditWinEnd() - { - ImGui::End(); - } - - void messagePanel(ImVec2 pos) - { - bool msgPanel = true; - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground; - - ImGui::SetNextWindowPos({ pos.x, pos.y + 24.0f }); - ImGui::BeginChild("MsgPanel", { 256.0f, 20.0f }, false, window_flags); - - s32 mx, my; - TFE_Input::getMousePos(&mx, &my); - if (mx >= s_editWinPos.x && mx < s_editWinPos.x + s_editWinSize.x && my >= s_editWinPos.z && my < s_editWinPos.z + s_editWinSize.z) - { - // We want to zoom into the mouse position. - s32 relX = s32(mx - s_editWinMapCorner.x); - s32 relY = s32(my - s_editWinMapCorner.z); - // Old position in world units. - Vec2f worldPos; - worldPos.x = s_offset.x + f32(relX) * s_zoomVisual; - worldPos.z = s_offset.z + f32(relY) * s_zoomVisual; - if (s_editView == EDIT_VIEW_2D) - { - ImGui::TextColored({ 0.5f, 0.5f, 0.5f, 0.75f }, "Pos %0.2f, %0.2f Sub-grid %0.2f", worldPos.x, -worldPos.z, s_gridSize / s_subGridSize); - } - else - { - ImGui::TextColored({ 0.5f, 0.5f, 0.5f, 0.75f }, "Dir %0.3f, %0.3f, %0.3f Sub-grid %0.2f", s_rayDir.x, s_rayDir.y, s_rayDir.z, s_gridSize / s_subGridSize); - } - } - - ImGui::EndChild(); - } - - void infoToolBegin(s32 height) - { - bool infoTool = true; - - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - ImGui::SetWindowPos("Info Panel", { (f32)displayInfo.width - 480.0f, 19.0f }); - ImGui::SetWindowSize("Info Panel", { 480.0f, f32(height) }); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus; - - ImGui::Begin("Info Panel", &infoTool, window_flags); ImGui::SameLine(); - } - - void infoPanelMap() - { - if (!s_levelData) { return; } - - ImGui::Text("Level Name:"); ImGui::SameLine(); ImGui::InputText("", s_levelName, 64); - ImGui::Text("Gob File: %s", s_gobFile); - ImGui::Text("Level File: %s", s_levelFile); - ImGui::Text("Sector Count: %u", s_levelData->sectors.size()); - ImGui::Text("Layer Range: %d, %d", s_levelData->layerMin, s_levelData->layerMax); - ImGui::Separator(); - ImGui::LabelText("##GridLabel", "Grid Height"); - ImGui::SetNextItemWidth(196.0f); - ImGui::InputFloat("##GridHeight", &s_gridHeight, 0.0f, 0.0f, "%0.2f", ImGuiInputTextFlags_CharsDecimal); - ImGui::Checkbox("Grid Auto Adjust", &s_gridAutoAdjust); - ImGui::Checkbox("Show Grid When Camera Is Inside a Sector", &s_showGridInSector); - } - - void infoPanelVertex() - { - if (!s_levelData || (s_selectedVertex < 0 && s_hoveredVertex < 0)) { return; } - EditorSector* sector = s_levelData->sectors.data() + ( (s_selectedVertex >= 0) ? s_selectedVertexSector : s_hoveredVertexSector ); - s32 index = s_selectedVertex >= 0 ? s_selectedVertex : s_hoveredVertex; - if (index < 0 || !sector) { return; } - - Vec2f* vtx = sector->vertices.data() + index; - - ImGui::Text("Vertex %d of Sector %d", index, sector->id); - char s_vtxPosX_str[64]; - char s_vtxPosZ_str[64]; - sprintf(s_vtxPosX_str, "%0.2f", vtx->x); - sprintf(s_vtxPosZ_str, "%0.2f", vtx->z); - - ImGui::NewLine(); - ImGui::PushItemWidth(64.0f); - ImGui::LabelText("##PositionLabel", "Position"); - ImGui::PopItemWidth(); - - ImGui::SameLine(); - ImGui::PushItemWidth(196.0f); - ImGui::InputFloat2("##VertexPosition", &vtx->x, "%0.2f", ImGuiInputTextFlags_CharsDecimal); - ImGui::PopItemWidth(); - } - - void infoLabel(const char* labelId, const char* labelText, u32 width) - { - ImGui::PushItemWidth(f32(width)); - ImGui::LabelText(labelId, labelText); - ImGui::PopItemWidth(); - ImGui::SameLine(); - } - - void infoIntInput(const char* labelId, u32 width, s32* value) - { - ImGui::PushItemWidth(f32(width)); - ImGui::InputInt(labelId, value); - ImGui::PopItemWidth(); - } - - void infoUIntInput(const char* labelId, u32 width, u32* value) - { - ImGui::PushItemWidth(f32(width)); - ImGui::InputUInt(labelId, value); - ImGui::PopItemWidth(); - } - - void infoFloatInput(const char* labelId, u32 width, f32* value) - { - ImGui::PushItemWidth(f32(width)); - ImGui::InputFloat(labelId, value, 0.0f, 0.0f, "%.2f"); - ImGui::PopItemWidth(); - } - - void infoPanelWall() - { - EditorSector* sector; - EditorWall* wall; - - s32 wallId; - if (s_selectedWall >= 0) { sector = s_levelData->sectors.data() + s_selectedWallSector; wallId = s_selectedWall; } - else if (s_hoveredWall >= 0) { sector = s_levelData->sectors.data() + s_hoveredWallSector; wallId = s_hoveredWall; } - else { return; } - wall = sector->walls.data() + wallId; - - if (s_enableInfEditor) - { - infoPanelInfWall(sector, wallId); - return; - } - - Vec2f* vertices = sector->vertices.data(); - f32 len = TFE_Math::distance(&vertices[wall->i0], &vertices[wall->i1]); - - ImGui::Text("Wall ID: %d Sector ID: %d Length: %2.2f", wallId, sector->id, len); - ImGui::Text("Vertices: [%d](%2.2f, %2.2f), [%d](%2.2f, %2.2f)", wall->i0, vertices[wall->i0].x, vertices[wall->i0].z, wall->i1, vertices[wall->i1].x, vertices[wall->i1].z); - ImGui::Separator(); - - // Adjoin data (should be carefully and rarely edited directly). - ImGui::LabelText("##SectorAdjoin", "Adjoin"); ImGui::SameLine(64.0f); - infoIntInput("##SectorAdjoinInput", 96, &wall->adjoin); ImGui::SameLine(180.0f); - ImGui::LabelText("##SectorWalk", "Walk"); ImGui::SameLine(224.0f); - infoIntInput("##SectorWalkInput", 96, &wall->walk); ImGui::SameLine(335.0f); - ImGui::LabelText("##SectorMirror", "Mirror"); ImGui::SameLine(384); - infoIntInput("##SectorMirrorInput", 96, &wall->mirror); - - s32 light = wall->light; - ImGui::LabelText("##SectorLight", "Light Adjustment"); ImGui::SameLine(138.0f); - infoIntInput("##SectorLightInput", 96, &light); - wall->light = (s16)light; - - ImGui::SameLine(); - if (ImGui::Button("Edit INF Script##Wall")) - { - if (isValidName(sector->name)) - { - // Enable the editor. - s_enableInfEditor = true; - } - else - { - // Popup a message box. - popupErrorMessage("INF script functionality relies on sector names for identification. Please give the sector a unique name (in this level) before proceeding."); - } - } - - ImGui::Separator(); - - // Flags - infoLabel("##Flags1Label", "Flags1", 48); - infoUIntInput("##Flags1", 128, &wall->flags[0]); - ImGui::SameLine(); - - infoLabel("##Flags3Label", "Flags3", 48); - infoUIntInput("##Flags3", 128, &wall->flags[2]); - - const f32 column[] = { 0.0f, 160.0f, 320.0f }; - - ImGui::CheckboxFlags("Mask Wall##WallFlag", &wall->flags[0], WF1_ADJ_MID_TEX); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Illum Sign##WallFlag", &wall->flags[0], WF1_ILLUM_SIGN); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Horz Flip Texture##SectorFlag", &wall->flags[0], WF1_FLIP_HORIZ); - - ImGui::CheckboxFlags("Change WallLight##WallFlag", &wall->flags[0], WF1_CHANGE_WALL_LIGHT); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Tex Anchored##WallFlag", &wall->flags[0], WF1_TEX_ANCHORED); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Wall Morphs##SectorFlag", &wall->flags[0], WF1_WALL_MORPHS); - - ImGui::CheckboxFlags("Scroll Top Tex##WallFlag", &wall->flags[0], WF1_SCROLL_TOP_TEX); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Scroll Mid Tex##WallFlag", &wall->flags[0], WF1_SCROLL_MID_TEX); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Scroll Bottom Tex##SectorFlag", &wall->flags[0], WF1_SCROLL_BOT_TEX); - - ImGui::CheckboxFlags("Scroll Sign##WallFlag", &wall->flags[0], WF1_SCROLL_SIGN_TEX); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Hide On Map##WallFlag", &wall->flags[0], WF1_HIDE_ON_MAP); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Show On Map##SectorFlag", &wall->flags[0], WF1_SHOW_NORMAL_ON_MAP); - - ImGui::CheckboxFlags("Sign Anchored##WallFlag", &wall->flags[0], WF1_SIGN_ANCHORED); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Damage Wall##WallFlag", &wall->flags[0], WF1_DAMAGE_WALL); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Show As Ledge##SectorFlag", &wall->flags[0], WF1_SHOW_AS_LEDGE_ON_MAP); - - ImGui::CheckboxFlags("Show As Door##WallFlag", &wall->flags[0], WF1_SHOW_AS_DOOR_ON_MAP); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Always Walk##WallFlag", &wall->flags[2], WF3_ALWAYS_WALK); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Solid Wall##SectorFlag", &wall->flags[2], WF3_SOLID_WALL); - - ImGui::CheckboxFlags("Player Walk Only##WallFlag", &wall->flags[2], WF3_PLAYER_WALK_ONLY); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Cannot Shoot Thru##WallFlag", &wall->flags[2], WF3_CANNOT_FIRE_THROUGH); - - ImGui::Separator(); - - EditorTexture* midTex = wall->mid.tex; - EditorTexture* topTex = wall->top.tex; - EditorTexture* botTex = wall->bot.tex; - EditorTexture* sgnTex = wall->sign.tex; - - const f32 texCol = 150.0f; - // Labels - ImGui::Text("Mid Texture"); ImGui::SameLine(texCol); - ImGui::Text("Sign Texture"); - - // Textures - Mid / Sign - const f32 midScale = midTex ? 1.0f / (f32)std::max(midTex->width, midTex->height) : 0.0f; - const f32 sgnScale = sgnTex ? 1.0f / (f32)std::max(sgnTex->width, sgnTex->height) : 0.0f; - const f32 aspectMid[] = { midTex ? f32(midTex->width) * midScale : 1.0f, midTex ? f32(midTex->height) * midScale : 1.0f }; - const f32 aspectSgn[] = { sgnTex ? f32(sgnTex->width) * sgnScale : 1.0f, sgnTex ? f32(sgnTex->height) * sgnScale : 1.0f }; - - ImGui::ImageButton(midTex ? TFE_RenderBackend::getGpuPtr(midTex->texture) : nullptr, { 128.0f * aspectMid[0], 128.0f * aspectMid[1] }); - ImGui::SameLine(texCol); - ImGui::ImageButton(sgnTex ? TFE_RenderBackend::getGpuPtr(sgnTex->texture) : nullptr, { 128.0f * aspectSgn[0], 128.0f * aspectSgn[1] }); - const ImVec2 imageLeft0 = ImGui::GetItemRectMin(); - const ImVec2 imageRight0 = ImGui::GetItemRectMax(); - - // Names - ImGui::Text("%s %dx%d", midTex ? midTex->name : "NONE", midTex ? midTex->width : 0, midTex ? midTex->height : 0); ImGui::SameLine(texCol); - ImGui::Text("%s %dx%d", sgnTex ? sgnTex->name : "NONE", sgnTex ? sgnTex->width : 0, sgnTex ? sgnTex->height : 0); - - ImVec2 imageLeft1, imageRight1; - if (wall->adjoin >= 0) - { - ImGui::NewLine(); - - // Textures - Top / Bottom - // Labels - ImGui::Text("Top Texture"); ImGui::SameLine(texCol); ImGui::Text("Bottom Texture"); - - const f32 topScale = topTex ? 1.0f / (f32)std::max(topTex->width, topTex->height) : 0.0f; - const f32 botScale = botTex ? 1.0f / (f32)std::max(botTex->width, botTex->height) : 0.0f; - const f32 aspectTop[] = { topTex ? f32(topTex->width) * topScale : 1.0f, topTex ? f32(topTex->height) * topScale : 1.0f }; - const f32 aspectBot[] = { botTex ? f32(botTex->width) * botScale : 1.0f, botTex ? f32(botTex->height) * botScale : 1.0f }; - - ImGui::ImageButton(topTex ? TFE_RenderBackend::getGpuPtr(topTex->texture) : nullptr, { 128.0f * aspectTop[0], 128.0f * aspectTop[1] }); - ImGui::SameLine(texCol); - ImGui::ImageButton(botTex ? TFE_RenderBackend::getGpuPtr(botTex->texture) : nullptr, { 128.0f * aspectBot[0], 128.0f * aspectBot[1] }); - imageLeft1 = ImGui::GetItemRectMin(); - imageRight1 = ImGui::GetItemRectMax(); - - // Names - ImGui::Text("%s %dx%d", topTex ? topTex->name : "NONE", topTex ? topTex->width : 0, topTex ? topTex->height : 0); ImGui::SameLine(texCol); - ImGui::Text("%s %dx%d", botTex ? botTex->name : "NONE", botTex ? botTex->width : 0, botTex ? botTex->height : 0); - } - - // Texture Offsets - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - // Set 0 - ImVec2 offsetLeft = { imageLeft0.x + texCol + 8.0f, imageLeft0.y + 8.0f }; - ImVec2 offsetSize = { displayInfo.width - (imageLeft0.x + texCol + 16.0f), 128.0f }; - ImGui::SetNextWindowPos(offsetLeft); - // A child window is used here in order to place the controls in the desired position - to the right of the image buttons. - ImGui::BeginChild("##TextureOffsets0Wall", offsetSize); - { - ImGui::Text("Mid Offset"); - ImGui::PushItemWidth(128.0f); - ImGui::InputFloat2("##MidOffsetInput", &wall->mid.offsetX, "%.2f"); - ImGui::PopItemWidth(); - - ImGui::NewLine(); - - ImGui::Text("Sign Offset"); - ImGui::PushItemWidth(128.0f); - ImGui::InputFloat2("##SignOffsetInput", &wall->sign.offsetX, "%.2f"); - ImGui::PopItemWidth(); - } - ImGui::EndChild(); - - // Set 1 - if (wall->adjoin >= 0) - { - offsetLeft = { imageLeft1.x + texCol + 8.0f, imageLeft1.y + 8.0f }; - offsetSize = { displayInfo.width - (imageLeft1.x + texCol + 16.0f), 128.0f }; - ImGui::SetNextWindowPos(offsetLeft); - // A child window is used here in order to place the controls in the desired position - to the right of the image buttons. - ImGui::BeginChild("##TextureOffsets1Wall", offsetSize); - { - ImGui::Text("Top Offset"); - ImGui::PushItemWidth(128.0f); - ImGui::InputFloat2("##TopOffsetInput", &wall->top.offsetX, "%.2f"); - ImGui::PopItemWidth(); - - ImGui::NewLine(); - - ImGui::Text("Bottom Offset"); - ImGui::PushItemWidth(128.0f); - ImGui::InputFloat2("##BotOffsetInput", &wall->bot.offsetX, "%.2f"); - ImGui::PopItemWidth(); - } - ImGui::EndChild(); - } - } - - bool isValidName(const char* name) - { - if (strlen(name) > 0 && name[0] > 32 && name[0] < 127) { return true; } - return false; - } - - void addFuncText(EditorInfClassData* cdata, u32 stopIndex, u32 funcIndex, char** itemList, s32& itemCount, bool inclTarget) - { - const EditorInfFunction* func = &cdata->stop[stopIndex].func[funcIndex]; - const u32 funcId = func->funcId; - const u32 clientCount = (u32)func->client.size(); - const u32 argCount = (u32)func->arg.size(); - - const char* funcName = TFE_InfAsset::getFuncName(funcId); - if (funcId < INF_MSG_LIGHTS) - { - char client[256]; - EditorSector* sector = LevelEditorData::getSector(func->client[0].sectorName.c_str()); - if (!sector) { return; } - - u32 sectorId = sector->id; - s32 wallId = func->client[0].wallId; - if (inclTarget) - { - if (wallId < 0) { sprintf(client, "%s", sector->name); } - else { sprintf(client, "%s(%d)", sector->name, wallId); } - } - - char funcText[256]; - if (argCount) - { - sprintf(funcText, "%s(", funcName); - for (u32 a = 0; a < argCount; a++) - { - char argText[64]; - if (a < argCount - 1) - { - sprintf(argText, "%d, ", func->arg[a].iValue); - } - else - { - sprintf(argText, "%d", func->arg[a].iValue); - } - strcat(funcText, argText); - } - strcat(funcText, ")"); - } - else - { - sprintf(funcText, "%s", funcName); - } - - if (inclTarget) { sprintf(itemList[itemCount], " Func: %s Target: %s", funcText, client); } - else { sprintf(itemList[itemCount], " Func: %s", funcText); } - - itemCount++; - } - else - { - if (funcId == INF_MSG_LIGHTS) - { - sprintf(itemList[itemCount], " Func: lights"); - itemCount++; - } - else if (funcId == INF_MSG_ADJOIN) - { - sprintf(itemList[itemCount], " Func: adjoin(%s, %d, %s, %d)", - func->arg[0].sValue.c_str(), func->arg[1].iValue, - func->arg[2].sValue.c_str(), func->arg[3].iValue); - itemCount++; - } - else if (funcId == INF_MSG_PAGE) - { - // This is supposed to be a string - Sounds are TODO. - sprintf(itemList[itemCount], " Func: page(TODO)"); - itemCount++; - } - else if (funcId == INF_MSG_TEXT) - { - sprintf(itemList[itemCount], " Func: text(%d)", func->arg[0].iValue); - itemCount++; - } - else if (funcId == INF_MSG_TEXTURE) - { - sprintf(itemList[itemCount], " Func: texture(%d, %s)", func->arg[0].iValue, func->arg[1].sValue.c_str()); - itemCount++; - } - } - } - - char* getEventMaskList(u32 mask, char* buffer, bool wall) - { - buffer[0] = 0; - if (!mask) { return buffer; } - - if (mask & (INF_EVENT_ANY)) - { - strcat(buffer, "("); - if (mask & INF_EVENT_CROSS_LINE_FRONT) { strcat(buffer, "cross front, "); } - if (mask & INF_EVENT_CROSS_LINE_BACK) { strcat(buffer, "cross back, "); } - if (mask & INF_EVENT_ENTER_SECTOR) { strcat(buffer, "enter, "); } - if (mask & INF_EVENT_LEAVE_SECTOR) { strcat(buffer, "leave, "); } - if (mask & INF_EVENT_NUDGE_FRONT) { strcat(buffer, wall ? "nudge front, " : "nudge inside, "); } - if (mask & INF_EVENT_NUDGE_BACK) { strcat(buffer, wall ? "nudge back, " : "nudge outside, "); } - if (mask & INF_EVENT_EXPLOSION) { strcat(buffer, "explosion, "); } - if (mask & INF_EVENT_SHOOT_LINE) { strcat(buffer, "shoot, "); } - if (mask & INF_EVENT_LAND) { strcat(buffer, "land, "); } - buffer[strlen(buffer) - 2] = 0; - strcat(buffer, ")"); - } - - return buffer; - } - - char* getEntityMaskList(u32 mask, char* buffer) - { - buffer[0] = 0; - if (!mask) { return buffer; } - - strcat(buffer, "("); - if (mask & INF_ENTITY_ENEMY) { strcat(buffer, "enemy, "); } - if (mask & INF_ENTITY_WEAPON) { strcat(buffer, "weapon, "); } - if (mask & INF_ENTITY_PLAYER) { strcat(buffer, "player, "); } - size_t len = strlen(buffer); - if (len > 2) { buffer[len - 2] = 0; } - strcat(buffer, ")"); - - return buffer; - } - - char* getKeyList(u32 keys, char* buffer) - { - buffer[0] = 0; - if (!keys) { return buffer; } - - strcat(buffer, "("); - if (keys & KEY_RED) { strcat(buffer, "red, "); } - if (keys & KEY_YELLOW) { strcat(buffer, "yellow, "); } - if (keys & KEY_BLUE) { strcat(buffer, "blue, "); } - buffer[strlen(buffer) - 2] = 0; - strcat(buffer, ")"); - - return buffer; - } - - bool isElevatorFloorCeil(u32 sclass) - { - return sclass == ELEVATOR_BASIC || sclass == ELEVATOR_INV || sclass == ELEVATOR_MOVE_FLOOR || sclass == ELEVATOR_MOVE_CEILING || sclass == ELEVATOR_MOVE_FC || sclass == ELEVATOR_MOVE_OFFSET || sclass == ELEVATOR_BASIC_AUTO; - } - - bool isDoor(u32 sclass) - { - return sclass == ELEVATOR_DOOR || sclass == ELEVATOR_DOOR_MID || sclass == ELEVATOR_DOOR_INV; - } - - void infEditor(EditorInfItem* item, bool wall) - { - InfEditState* infEditState = LevelEditorData::getInfEditState(); - - // There will be context sensitive controls here, such as adding classes. - - // Get the current list of items. - s32 itemCount = 0; - strcpy(infEditState->itemList[itemCount], "Seq"); itemCount++; - // Go through the data here... - if (item) - { - const u32 classCount = (u32)item->classData.size(); - for (u32 c = 0; c < classCount; c++) - { - EditorInfClassData* cdata = &item->classData[c]; - const u32 iclass = cdata->iclass; - const u32 sclass = cdata->isubclass; - - sprintf(infEditState->itemList[itemCount], " Class: %s %s", - TFE_InfAsset::getClassName(iclass), TFE_InfAsset::getSubclassName(iclass, sclass)); itemCount++; - - if (iclass == INF_CLASS_ELEVATOR) - { - if (!isDoor(sclass)) - { - const f32 sgn = isElevatorFloorCeil(sclass) ? -1.0f : 1.0f; - for (u32 s = 0; s < (u32)cdata->stop.size(); s++) - { - const u32 stop0Type = cdata->stop[s].stopValue0Type; - const u32 stop1Type = cdata->stop[s].stopValue1Type; - const u32 funcCount = (u32)cdata->stop[s].func.size(); - - char value0[256]; - char value1[256]; - if (stop0Type == INF_STOP0_SECTORNAME) - { - sprintf(value0, "\"%s\"", cdata->stop[s].value0.sValue.c_str()); - } - else if (stop0Type == INF_STOP0_ABSOLUTE) - { - // Show the values in the same coordinate space as the level. - sprintf(value0, "%2.2f", cdata->stop[s].value0.fValue * sgn); - } - else if (stop0Type == INF_STOP0_RELATIVE) - { - sprintf(value0, "@%2.2f", cdata->stop[s].value0.fValue * sgn); - } - - if (stop1Type == INF_STOP1_TIME) - { - sprintf(value1, "%2.2f", cdata->stop[s].time); - } - else if (stop1Type == INF_STOP1_HOLD) - { - sprintf(value1, "hold"); - } - else if (stop1Type == INF_STOP1_TERMINATE) - { - sprintf(value1, "terminate"); - } - else if (stop1Type == INF_STOP1_COMPLETE) - { - sprintf(value1, "complete"); - } - - sprintf(infEditState->itemList[itemCount], " Stop %d: %s %s", s, value0, value1); itemCount++; - - for (u32 f = 0; f < funcCount; f++) - { - addFuncText(cdata, s, f, infEditState->itemList.data(), itemCount, true); - } - } - } - } - else if (iclass == INF_CLASS_TRIGGER) - { - // Functions - const u32 funcCount = (u32)cdata->stop[0].func.size(); - for (u32 f = 0; f < funcCount; f++) - { - addFuncText(cdata, 0, f, infEditState->itemList.data(), itemCount, false); - } - // Clients. - const EditorInfFunction* func = &cdata->stop[0].func[0]; - const u32 clientCount = (u32)func->client.size(); - if (clientCount) - { - sprintf(infEditState->itemList[itemCount], " Clients %u", clientCount); itemCount++; - for (u32 c = 0; c < clientCount; c++) - { - const s32 wallId = func->client[c].wallId; - if (wallId < 0) - { - sprintf(infEditState->itemList[itemCount], " %s", func->client[c].sectorName.c_str()); itemCount++; - } - else - { - sprintf(infEditState->itemList[itemCount], " %s(%d)", func->client[c].sectorName.c_str(), wallId); itemCount++; - } - } - } - } - else - { - sprintf(infEditState->itemList[itemCount], " Target: %s", cdata->var.target.c_str()); itemCount++; - } - - // Slaves - if (iclass == INF_CLASS_ELEVATOR) - { - const u32 slaveCount = (u32)cdata->slaves.size(); - sprintf(infEditState->itemList[itemCount], " Slaves %u", slaveCount); itemCount++; - for (u32 s = 0; s < slaveCount; s++) - { - sprintf(infEditState->itemList[itemCount], " %s", cdata->slaves[s].c_str()); itemCount++; - } - } - - // Variables. - u32 defaultEventMask = 0; - if (iclass == INF_CLASS_ELEVATOR && (sclass == ELEVATOR_DOOR || sclass == ELEVATOR_DOOR_INV || sclass == ELEVATOR_DOOR_MID)) - { - defaultEventMask = INF_EVENT_NUDGE_BACK; - } - else if (iclass == INF_CLASS_ELEVATOR && (sclass == ELEVATOR_BASIC || sclass == ELEVATOR_INV || sclass == ELEVATOR_BASIC_AUTO)) - { - defaultEventMask = 52; - } - else if (iclass == INF_CLASS_ELEVATOR && (sclass == ELEVATOR_MORPH_MOVE1 || sclass == ELEVATOR_MORPH_MOVE2 || sclass == ELEVATOR_MORPH_SPIN1 || sclass == ELEVATOR_MORPH_SPIN2)) - { - defaultEventMask = 60; - } - else if (iclass == INF_CLASS_TRIGGER) - { - defaultEventMask = INF_EVENT_CROSS_LINE_FRONT | INF_EVENT_CROSS_LINE_BACK | INF_EVENT_ENTER_SECTOR | INF_EVENT_LEAVE_SECTOR | INF_EVENT_NUDGE_FRONT | INF_EVENT_NUDGE_BACK | INF_EVENT_LAND; - } - - char buffer[128]; - sprintf(infEditState->itemList[itemCount], " Variables"); itemCount++; - if (!cdata->var.master) - { - sprintf(infEditState->itemList[itemCount], " master: off"); - itemCount++; - } - if (cdata->var.event_mask != defaultEventMask) - { - sprintf(infEditState->itemList[itemCount], " event_mask: %u %s", cdata->var.event_mask, getEventMaskList(cdata->var.event_mask, buffer, wall)); - itemCount++; - } - if (cdata->var.event) - { - sprintf(infEditState->itemList[itemCount], " event: %u", cdata->var.event); - itemCount++; - } - if (cdata->var.entity_mask != INF_ENTITY_PLAYER) - { - sprintf(infEditState->itemList[itemCount], " entity_mask: %u %s", cdata->var.entity_mask, getEntityMaskList(cdata->var.entity_mask, buffer)); - itemCount++; - } - if (cdata->var.speed != 30.0f && iclass == INF_CLASS_ELEVATOR) - { - sprintf(infEditState->itemList[itemCount], " speed: %2.2f", cdata->var.speed); - itemCount++; - } - if (cdata->var.start != 0 && iclass == INF_CLASS_ELEVATOR) - { - sprintf(infEditState->itemList[itemCount], " start: %d", cdata->var.start); - itemCount++; - } - if (sclass == ELEVATOR_MORPH_SPIN1 || sclass == ELEVATOR_MORPH_SPIN2 || sclass == ELEVATOR_ROTATE_WALL) - { - sprintf(infEditState->itemList[itemCount], " center: %2.2f, %2.2f", cdata->var.center.x, cdata->var.center.z); - itemCount++; - } - if (sclass == ELEVATOR_MORPH_MOVE1 || sclass == ELEVATOR_MORPH_MOVE2 || sclass == ELEVATOR_MOVE_WALL || sclass == ELEVATOR_SCROLL_WALL) - { - sprintf(infEditState->itemList[itemCount], " angle: %2.2f", cdata->var.angle); - itemCount++; - } - if (cdata->var.key != 0) - { - sprintf(infEditState->itemList[itemCount], " key: %u %s", cdata->var.key, getKeyList(cdata->var.key, buffer)); - itemCount++; - } - u32 flagsDefault = 0; - if (iclass == INF_CLASS_ELEVATOR && (sclass == ELEVATOR_SCROLL_FLOOR || sclass == ELEVATOR_MORPH_MOVE2 || sclass == ELEVATOR_MORPH_SPIN2)) - { - flagsDefault = INF_MOVE_FLOOR | INF_MOVE_SECALT; - } - if (cdata->var.flags != flagsDefault) - { - sprintf(infEditState->itemList[itemCount], " flags: %u", cdata->var.flags); - itemCount++; - } - if (cdata->var.target != "") - { - sprintf(infEditState->itemList[itemCount], " target: %s", cdata->var.target.c_str()); - itemCount++; - } - // Skip sound for now. - // Skip "object_mask" for now. - } - } - strcpy(infEditState->itemList[itemCount], "Seqend"); itemCount++; - - ImGui::SetNextItemWidth(440.0f); - ImGui::ListBox("##InfDescrSector", &infEditState->editIndex, infEditState->itemList.data(), itemCount, 20); - } - - void infoPanelInfSector(EditorSector* sector) - { - if (!isValidName(sector->name)) - { - s_enableInfEditor = false; - return; - } - InfEditState* infEditState = LevelEditorData::getInfEditState(); - if (infEditState->sector != sector || infEditState->wallId >= 0) - { - infEditState->sector = sector; - infEditState->wallId = -1; - infEditState->item = sector->infItem; - infEditState->editIndex = 0; - - infEditState->itemMem.resize(1024 * 64); - infEditState->itemList.resize(1024); - char* itemMem = infEditState->itemMem.data(); - for (u32 i = 0; i < 1024; i++, itemMem += 64) - { - infEditState->itemList[i] = itemMem; - } - } - - // Sector Name (optional, used by INF) - infoLabel("##NameLabel", "Name", 32); - ImGui::PushItemWidth(240.0f); - ImGui::InputText("##NameSector", sector->name, 32); - ImGui::PopItemWidth(); - ImGui::SameLine(); - - if (ImGui::Button("Return to Properties##Sector")) - { - s_enableInfEditor = false; - } - ImGui::Separator(); - - infEditor(infEditState->item, false); - } - - void infoPanelInfWall(EditorSector* sector, u32 wallId) - { - if (!isValidName(sector->name)) - { - s_enableInfEditor = false; - return; - } - InfEditState* infEditState = LevelEditorData::getInfEditState(); - if (infEditState->sector != sector || infEditState->wallId != wallId) - { - infEditState->sector = sector; - infEditState->wallId = wallId; - infEditState->item = sector->walls[wallId].infItem; - infEditState->editIndex = 0; - - infEditState->itemMem.resize(1024 * 64); - infEditState->itemList.resize(1024); - char* itemMem = infEditState->itemMem.data(); - for (u32 i = 0; i < 1024; i++, itemMem += 64) - { - infEditState->itemList[i] = itemMem; - } - } - - ImGui::Text("Wall ID: %d Sector: %s", wallId, sector->name); - if (ImGui::Button("Return to Properties##Wall")) - { - s_enableInfEditor = false; - } - ImGui::Separator(); - - infEditor(infEditState->item, true); - } - - void infoPanelSector() - { - EditorSector* sector; - if (s_selectedSector >= 0) { sector = s_levelData->sectors.data() + s_selectedSector; } - else if (s_hoveredSector >= 0) { sector = s_levelData->sectors.data() + s_hoveredSector; } - else { return; } - - if (s_enableInfEditor) - { - infoPanelInfSector(sector); - return; - } - - ImGui::Text("Sector ID: %d Wall Count: %u", sector->id, (u32)sector->walls.size()); - ImGui::Separator(); - - // Sector Name (optional, used by INF) - infoLabel("##NameLabel", "Name", 32); - ImGui::PushItemWidth(240.0f); - ImGui::InputText("##NameSector", sector->name, 32); - ImGui::PopItemWidth(); - ImGui::SameLine(); - if (ImGui::Button("Edit INF Script##Sector")) - { - if (isValidName(sector->name)) - { - // Enable the editor. - s_enableInfEditor = true; - } - else - { - // Popup a message box. - popupErrorMessage("INF script functionality relies on sector names for identification. Please give the sector a unique name (in this level) before proceeding."); - } - } - - // Layer and Ambient - s32 layer = sector->layer; - infoLabel("##LayerLabel", "Layer", 32); - infoIntInput("##LayerSector", 96, &layer); - if (layer != sector->layer) - { - sector->layer = layer; - // Adjust layer range. - s_levelData->layerMin = std::min(s_levelData->layerMin, (s8)layer); - s_levelData->layerMax = std::max(s_levelData->layerMax, (s8)layer); - // Change the current layer so we can still see the sector. - s_layerIndex = layer - s_layerMin; - } - - ImGui::SameLine(0.0f, 16.0f); - - s32 ambient = (s32)sector->ambient; - infoLabel("##AmbientLabel", "Ambient", 48); - infoIntInput("##AmbientSector", 96, &ambient); - sector->ambient = std::max(0, std::min(31, ambient)); - - // Heights - infoLabel("##HeightLabel", "Heights", 64); - - infoLabel("##FloorHeightLabel", "Floor", 32); - infoFloatInput("##FloorHeight", 64, §or->floorAlt); - ImGui::SameLine(); - - infoLabel("##SecondHeightLabel", "Second", 44); - infoFloatInput("##SecondHeight", 64, §or->secAlt); - ImGui::SameLine(); - - infoLabel("##CeilHeightLabel", "Ceiling", 48); - infoFloatInput("##CeilHeight", 64, §or->ceilAlt); - - ImGui::Separator(); - - // Flags - infoLabel("##Flags1Label", "Flags1", 48); - infoUIntInput("##Flags1", 128, §or->flags[0]); - ImGui::SameLine(); - - infoLabel("##Flags2Label", "Flags2", 48); - infoUIntInput("##Flags2", 128, §or->flags[1]); - - infoLabel("##Flags3Label", "Flags3", 48); - infoUIntInput("##Flags3", 128, §or->flags[2]); - - const f32 column[] = { 0.0f, 160.0f, 320.0f }; - - ImGui::CheckboxFlags("Exterior##SectorFlag", §or->flags[0], SEC_FLAGS1_EXTERIOR); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Pit##SectorFlag", §or->flags[0], SEC_FLAGS1_PIT); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("No Walls##SectorFlag", §or->flags[0], SEC_FLAGS1_NOWALL_DRAW); - - ImGui::CheckboxFlags("Exterior Ceil Adj##SectorFlag", §or->flags[0], SEC_FLAGS1_EXT_ADJ); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Exterior Floor Adj##SectorFlag", §or->flags[0], SEC_FLAGS1_EXT_FLOOR_ADJ); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Secret##SectorFlag", §or->flags[0], SEC_FLAGS1_SECRET); - - ImGui::CheckboxFlags("Door##SectorFlag", §or->flags[0], SEC_FLAGS1_DOOR); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Ice Floor##SectorFlag", §or->flags[0], SEC_FLAGS1_ICE_FLOOR); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Snow Floor##SectorFlag", §or->flags[0], SEC_FLAGS1_SNOW_FLOOR); - - ImGui::CheckboxFlags("Crushing##SectorFlag", §or->flags[0], SEC_FLAGS1_CRUSHING); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Low Damage##SectorFlag", §or->flags[0], SEC_FLAGS1_LOW_DAMAGE); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("High Damage##SectorFlag", §or->flags[0], SEC_FLAGS1_HIGH_DAMAGE); - - ImGui::CheckboxFlags("No Smart Obj##SectorFlag", §or->flags[0], SEC_FLAGS1_NO_SMART_OBJ); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Smart Obj##SectorFlag", §or->flags[0], SEC_FLAGS1_SMART_OBJ); ImGui::SameLine(column[2]); - ImGui::CheckboxFlags("Safe Sector##SectorFlag", §or->flags[0], SEC_FLAGS1_SAFESECTOR); - - ImGui::CheckboxFlags("Mag Seal##SectorFlag", §or->flags[0], SEC_FLAGS1_MAG_SEAL); ImGui::SameLine(column[1]); - ImGui::CheckboxFlags("Exploding Wall##SectorFlag", §or->flags[0], SEC_FLAGS1_EXP_WALL); - - ImGui::Separator(); - - // Textures - EditorTexture* floorTex = sector->floorTexture.tex; - EditorTexture* ceilTex = sector->ceilTexture.tex; - - void* floorPtr = floorTex ? TFE_RenderBackend::getGpuPtr(floorTex->texture) : nullptr; - void* ceilPtr = ceilTex ? TFE_RenderBackend::getGpuPtr(ceilTex->texture) : nullptr; - - const f32 texCol = 150.0f; - // Labels - ImGui::Text("Floor Texture"); ImGui::SameLine(texCol); - ImGui::Text("Ceiling Texture"); - - // Textures - const f32 floorScale = floorTex ? 1.0f / (f32)std::max(floorTex->width, floorTex->height) : 1.0f; - const f32 ceilScale = ceilTex ? 1.0f / (f32)std::max(ceilTex->width, ceilTex->height) : 1.0f; - const f32 aspectFloor[] = { floorTex ? f32(floorTex->width) * floorScale : 1.0f, floorTex ? f32(floorTex->height) * floorScale : 1.0f }; - const f32 aspectCeil[] = { ceilTex ? f32(ceilTex->width) * ceilScale : 1.0f, ceilTex ? f32(ceilTex->height) * ceilScale : 1.0f }; - - ImGui::ImageButton(floorPtr, { 128.0f * aspectFloor[0], 128.0f * aspectFloor[1] }); - ImGui::SameLine(texCol); - ImGui::ImageButton(ceilPtr, { 128.0f * aspectCeil[0], 128.0f * aspectCeil[1] }); - const ImVec2 imageLeft = ImGui::GetItemRectMin(); - const ImVec2 imageRight = ImGui::GetItemRectMax(); - - // Names - if (floorTex) - { - ImGui::Text("%s %dx%d", floorTex->name, floorTex->width, floorTex->height); ImGui::SameLine(texCol); - } - if (ceilTex) - { - ImGui::Text("%s %dx%d", ceilTex->name, ceilTex->width, ceilTex->height); ImGui::SameLine(); - } - - // Texture Offsets - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - ImVec2 offsetLeft = { imageLeft.x + texCol + 8.0f, imageLeft.y + 8.0f }; - ImVec2 offsetSize = { displayInfo.width - (imageLeft.x + texCol + 16.0f), 128.0f }; - ImGui::SetNextWindowPos(offsetLeft); - // A child window is used here in order to place the controls in the desired position - to the right of the image buttons. - ImGui::BeginChild("##TextureOffsetsSector", offsetSize); - { - ImGui::Text("Floor Offset"); - ImGui::PushItemWidth(128.0f); - ImGui::InputFloat2("##FloorOffsetInput", §or->floorTexture.offsetX, "%.2f"); - ImGui::PopItemWidth(); - - ImGui::NewLine(); - - ImGui::Text("Ceil Offset"); - ImGui::PushItemWidth(128.0f); - ImGui::InputFloat2("##CeilOffsetInput", §or->ceilTexture.offsetX, "%.2f"); - ImGui::PopItemWidth(); - } - ImGui::EndChild(); - } - - void infoPanelEntity() - { - s32 entityId = s_selectedEntity >= 0 ? s_selectedEntity : s_hoveredEntity; - if (entityId < 0 || !s_levelData) { return; } - - EditorSector* sector = s_levelData->sectors.data() + (s_selectedEntity >= 0 ? s_selectedEntitySector : s_hoveredEntitySector); - EditorLevelObject* obj = sector->objects.data() + entityId; - - // difficulty: -3, -2, -1, 0, 1, 2, 3 <+ 3> = 0, 1, 2, 3, 4, 5, 6 - const s32 diffToFlagMap[] = { DIFF_EASY | DIFF_MEDIUM | DIFF_HARD, DIFF_EASY | DIFF_MEDIUM, DIFF_EASY, DIFF_EASY | DIFF_MEDIUM | DIFF_HARD, DIFF_EASY | DIFF_MEDIUM | DIFF_HARD, DIFF_MEDIUM | DIFF_HARD, DIFF_HARD }; - u32 diffFlags = diffToFlagMap[obj->difficulty + 3]; - - // Entity name = resource. - ImGui::LabelText("##Entity", "Entity: %s", obj->dataFile.c_str()); - // Class. - ImGui::LabelText("##EntityClass", "Class: %s", c_objectClassName[obj->oclass]); - // Difficulty. - ImGui::LabelText("##EntityDiff", "Difficulty: Easy"); ImGui::SameLine(136.0f); - ImGui::CheckboxFlags("##EntityDiffEasy", &diffFlags, DIFF_EASY); ImGui::SameLine(168.0f); - ImGui::LabelText("##EntityDiffM", "Medium"); ImGui::SameLine(220.0f); - ImGui::CheckboxFlags("##EntityDiffMed", &diffFlags, DIFF_MEDIUM); ImGui::SameLine(252.0f); - ImGui::LabelText("##EntityDiffH", "Hard"); ImGui::SameLine(290.0f); - ImGui::CheckboxFlags("##EntityDiffHard", &diffFlags, DIFF_HARD); - // Position. - ImGui::LabelText("##EntityClass", "Position:"); ImGui::SameLine(96.0f); - ImGui::InputFloat3("##EntityPos", obj->pos.m, "%0.2f"); - // Orientation. - ImGui::PushItemWidth(64.0f); - ImGui::LabelText("##EntityAngleLabel", "Angle"); ImGui::SameLine(64.0f); - ImGui::InputFloat("##EntityAngle", &obj->orientation.y, 0.0f, 0.0f, "%0.2f"); ImGui::SameLine(150.0f); - ImGui::LabelText("##EntityPitchLabel", "Pitch"); ImGui::SameLine(204.0f); - ImGui::InputFloat("##EntityPitch", &obj->orientation.x, 0.0f, 0.0f, "%0.2f"); ImGui::SameLine(290.0f); - ImGui::LabelText("##EntityRollLabel", "Roll"); ImGui::SameLine(344.0f); - ImGui::InputFloat("##EntityRoll", &obj->orientation.z, 0.0f, 0.0f, "%0.2f"); - ImGui::PopItemWidth(); - ImGui::Separator(); - ImGui::Text("Logics"); - // TODO: Visual controls for orientation (on the map). - // TODO: Logic and Variable editing. - const u32 logicCount = (u32)obj->logics.size(); - Logic* logic = obj->logics.data(); - for (u32 i = 0; i < logicCount; i++, logic++) - { - ImGui::Text(" %s", c_logicName[logic->type]); - if (logic->type == LOGIC_UPDATE) - { - char updateFlags[256]=""; - if (logic->flags & 8) - { - strcat(updateFlags, "X-Axis"); - if (logic->flags > 8) { strcat(updateFlags, "|"); } - } - if (logic->flags & 16) - { - strcat(updateFlags, "Y-Axis"); - if (logic->flags > 16) { strcat(updateFlags, "|"); } - } - if (logic->flags & 32) - { - strcat(updateFlags, "Z-Axis"); - } - - ImGui::LabelText("##UpdateFlags", " FLAGS: %u (%s)", logic->flags, updateFlags); - if (logic->flags & 8) - { - ImGui::LabelText("##UpdatePitch", " D_PITCH:"); - ImGui::SameLine(96.0f); - ImGui::SetNextItemWidth(96.0f); - ImGui::InputFloat("##UpdatePitchInput", &logic->rotation.x, 0.0f, 0.0f, "%.2f"); - } - if (logic->flags & 16) - { - ImGui::LabelText("##UpdateYaw", " D_YAW:"); - ImGui::SameLine(96.0f); - ImGui::SetNextItemWidth(96.0f); - ImGui::InputFloat("##UpdateYawInput", &logic->rotation.y, 0.0f, 0.0f, "%.2f"); - } - if (logic->flags & 32) - { - ImGui::LabelText("##UpdateRoll", " D_ROLL:"); - ImGui::SameLine(96.0f); - ImGui::SetNextItemWidth(96.0f); - ImGui::InputFloat("##UpdateRollInput", &logic->rotation.z, 0.0f, 0.0f, "%.2f"); - } - } - else if (logic->type == LOGIC_KEY) - { - ImGui::Text(" VUE: %s %s", logic->vue->name, TFE_VueAsset::getTransformName(logic->vue, logic->vueId)); - ImGui::Text(" VUE_APPEND: %s %s", logic->vueAppend->name, TFE_VueAsset::getTransformName(logic->vueAppend, logic->vueAppendId)); - ImGui::Text(" PAUSE: %s", obj->comFlags & LCF_PAUSE ? "true" : "false"); - ImGui::Text(" FRAME_RATE: %2.2f", logic->frameRate); - } - } - const u32 genCount = (u32)obj->generators.size(); - EnemyGenerator* gen = obj->generators.data(); - for (u32 i = 0; i < genCount; i++, gen++) - { - ImGui::Text(" Generator %s", c_logicName[gen->type]); - } - ImGui::Separator(); - ImGui::Text("Common Variables"); - - ImGui::LabelText("##EntityEYELabel", " EYE"); ImGui::SameLine(48.0f); - ImGui::CheckboxFlags("##EntityEYE", &obj->comFlags, LCF_EYE); ImGui::SameLine(108.0f); - - ImGui::LabelText("##EntityBOSSLabel", " BOSS"); ImGui::SameLine(156.0f); - ImGui::CheckboxFlags("##EntityBOSS", &obj->comFlags, LCF_BOSS); - - if (obj->radius >= 0.0f) - { - ImGui::LabelText("##EntityRadius", " RADIUS:"); ImGui::SameLine(96.0f); - ImGui::SetNextItemWidth(96.0f); - ImGui::InputFloat("##EntityRadiusInput", &obj->radius, 0.0f, 0.0f, "%.2f"); - } - - ImGui::LabelText("##EntityHeight", " HEIGHT:"); ImGui::SameLine(96.0f); - ImGui::SetNextItemWidth(96.0f); - ImGui::InputFloat("##EntityHeightInput", &obj->height, 0.0f, 0.0f, "%.2f"); - - // Correct the bounding box center if needed. - obj->worldCen = obj->pos; - obj->worldCen.y = obj->pos.y - obj->worldExt.y; - if (obj->oclass != CLASS_SPIRIT && obj->oclass != CLASS_SAFE && obj->oclass != CLASS_SOUND && obj->display) - { - obj->worldCen.y += obj->display->scale.z * fabsf(obj->display->rect[1]) * c_spriteTexelToWorldScale; - } - - // Fixup difficulty - if (diffFlags == (DIFF_EASY | DIFF_MEDIUM | DIFF_HARD)) - { - obj->difficulty = 0; - } - else if (diffFlags == (DIFF_EASY | DIFF_MEDIUM)) - { - obj->difficulty = -2; - } - else if (diffFlags == (DIFF_MEDIUM | DIFF_HARD)) - { - obj->difficulty = 2; - } - else if (diffFlags == DIFF_EASY) - { - obj->difficulty = -1; - } - else if (diffFlags == DIFF_MEDIUM) - { - // This is not actually valid, so pick medium + easy. - obj->difficulty = -2; - } - else if (diffFlags == DIFF_HARD) - { - obj->difficulty = 3; - } - } - - void infoToolEnd() - { - ImGui::End(); - } - - void browserBegin(s32 offset) - { - bool browser = true; - - DisplayInfo displayInfo; - TFE_RenderBackend::getDisplayInfo(&displayInfo); - - ImGui::SetWindowPos("Browser", { (f32)displayInfo.width - 480.0f, 19.0f + f32(offset)}); - ImGui::SetWindowSize("Browser", { 480.0f, (f32)displayInfo.height - f32(offset+20) }); - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus; - - ImGui::Begin("Browser", &browser, window_flags); - } - - void browseTextures() - { - if (!s_levelData) { return; } - - u32 count = (u32)s_levelData->textures.size(); - u32 rows = count / 6; - u32 leftOver = count - rows * 6; - f32 y = 0.0f; - for (u32 i = 0; i < rows; i++) - { - for (u32 t = 0; t < 6; t++) - { - EditorTexture* texture = &s_levelData->textures[i * 6 + t]; - void* ptr = TFE_RenderBackend::getGpuPtr(texture->texture); - u32 w = 64, h = 64; - if (texture->width > texture->height) - { - w = 64; - h = 64 * texture->height / texture->width; - } - else if (texture->width < texture->height) - { - h = 64; - w = 64 * texture->width / texture->height; - } - - if (ImGui::ImageButton(ptr, ImVec2(f32(w), f32(h)), ImVec2(0.0f,0.0f), ImVec2(1.0f, 1.0f), (64 - s32(w))/2 + 2)) - { - // TODO: select textures. - // TODO: add hover functionality (tool tip - but show full texture + file name + size) - } - ImGui::SameLine(); - } - ImGui::NewLine(); - } - } - - void browseEntities() - { - } - - void browserEnd() - { - ImGui::End(); - } - - void loadLevel() - { - TFE_LevelList::unload(); - s_selectedSector = -1; - - // First setup the GOB - for now assume DARK.GOB - if (strcasecmp("DARK.GOB", s_gobFile) == 0) - { - TFE_AssetSystem::clearCustomArchive(); - } - else - { - char gobPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_SOURCE_DATA, s_gobFile, gobPath); - - char extension[TFE_MAX_PATH]; - FileUtil::getFileExtension(s_gobFile, extension); - - ArchiveType type = ARCHIVE_COUNT; - if (strcasecmp(extension, "gob") == 0) { type = ARCHIVE_GOB; } - else if (strcasecmp(extension, "lfd") == 0) { type = ARCHIVE_LFD; } - else { assert(0); } - - Archive* archive = Archive::getArchive(type, s_gobFile, gobPath); - TFE_AssetSystem::setCustomArchive(archive); - } - - TFE_LevelList::load(); - if (TFE_LevelAsset::load(s_levelFile)) - { - const LevelData* levelData = TFE_LevelAsset::getLevelData(); - - char infFile[64]; - strcpy(infFile, s_levelFile); - const size_t len = strlen(s_levelFile); - infFile[len - 3] = 'I'; - infFile[len - 2] = 'N'; - infFile[len - 1] = 'F'; - TFE_InfAsset::load(infFile); - const InfData* levelInf = TFE_InfAsset::getInfData(); - - // Load Objects. - char objFile[64]; - strcpy(objFile, s_levelFile); - objFile[len - 3] = 'O'; - objFile[len - 2] = 0; - objFile[len - 1] = 0; - TFE_LevelObjects::load(objFile); - const LevelObjectData* levelObj = TFE_LevelObjects::getLevelObjectData(); - - // Get the palette. - char palFile[64]; - strcpy(palFile, s_levelFile); - palFile[len - 3] = 'P'; - palFile[len - 2] = 'A'; - palFile[len - 1] = 'L'; - s_palette = TFE_Palette::get256(palFile); - s_renderer->setPalette(s_palette); - - s_levelData = nullptr; - if (LevelEditorData::convertLevelDataToEditor(levelData, s_palette, levelInf, levelObj)) - { - s_levelData = LevelEditorData::getEditorLevelData(); - } - } - } - - void drawSectorPolygon(const EditorSector* sector, bool hover, u32 colorOverride) - { - if (!sector || sector->triangles.count == 0) { return; } - - const SectorTriangles* poly = §or->triangles; - const u32 triCount = poly->count; - const Vec2f* vtx = poly->vtx.data(); - - // Draw the sector polygon which has already been triangulated. - u32 color = hover ? 0x40ff8020 : 0x40ff4020; - if (colorOverride > 0) { color = colorOverride; } - - for (u32 p = 0; p < triCount; p++, vtx += 3) - { - TriColoredDraw2d::addTriangles(1, vtx, &color); - } - } - - void drawTexturedSectorPolygon(const EditorSector* sector, u32 color, bool floorTex) - { - if (!sector || sector->triangles.count == 0) { return; } - - const SectorTriangles* poly = §or->triangles; - const EditorTexture* texture = floorTex ? sector->floorTexture.tex : sector->ceilTexture.tex; - const u32 triCount = poly->count; - const Vec2f* vtx = poly->vtx.data(); - - const f32* texOffsets = floorTex ? §or->floorTexture.offsetX : §or->ceilTexture.offsetX; - const f32 scaleX = texture ? -8.0f / f32(texture->width) : 1.0f; - const f32 scaleZ = texture ? -8.0f / f32(texture->height) : 1.0f; - - // Draw the sector polygon which has already been triangulated. - for (u32 p = 0; p < triCount; p++, vtx += 3) - { - Vec2f uv[3] = { { (vtx[0].x - texOffsets[0]) * scaleX, (vtx[0].z - texOffsets[1]) * scaleZ }, - { (vtx[1].x - texOffsets[0]) * scaleX, (vtx[1].z - texOffsets[1]) * scaleZ }, - { (vtx[2].x - texOffsets[0]) * scaleX, (vtx[2].z - texOffsets[1]) * scaleZ } }; - TriTexturedDraw2d::addTriangles(1, vtx, uv, &color, texture ? texture->texture : nullptr); - } - } - - void popupErrorMessage(const char* errorMessage) - { - strcpy(s_errorMessage, errorMessage); - s_showError = true; - } - - void showErrorPopup() - { - if (!s_showError) { return; } - - bool keepOpen = true; - ImGui::OpenPopup("Error##Popup"); - - ImGui::SetNextWindowSize({ 384, 128 }); - if (ImGui::BeginPopupModal("Error##Popup", &keepOpen)) - { - TFE_Markdown::draw(s_errorMessage); - ImGui::EndPopup(); - } - - if (!keepOpen) { s_showError = false; } - } - - ///////////////////////////////////////////////////////////////////// - // 2D Viewport Editing - ///////////////////////////////////////////////////////////////////// - void editSector2d(Vec2f worldPos, s32 sectorId) - { - if (s_editMode != LEDIT_SECTOR || !s_levelData) - { - return; - } - - // Select sector. - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedSector = sectorId; - } - else if (TFE_Input::keyPressed(KEY_DELETE) && s_selectedSector >= 0) - { - deleteSector(s_levelData->sectors.data() + s_selectedSector); - } - else - { - s_hoveredSector = sectorId; - } - } - - void editWalls2d(Vec2f worldPos) - { - if (s_editMode != LEDIT_WALL || !s_levelData) - { - s_selectedWall = -1; - s_selectedWallSector = -1; - return; - } - - // Select Wall. - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedWallSector = LevelEditorData::findSector(s_layerIndex + s_layerMin, &worldPos); - s_selectedWall = LevelEditorData::findClosestWall(&s_selectedWallSector, s_layerIndex + s_layerMin, &worldPos, s_zoomVisual * 32.0f); - if (!s_moveWall && s_selectedWall >= 0) - { - s_moveWall = true; - // get the plane... - s_drawPlaneNrm = { 0.0f, 1.0f, 0.0f }; - s_drawPlaneOrg = s_cursor3d; - - EditorWall* wall = &s_levelData->sectors[s_selectedWallSector].walls[s_selectedWall]; - s_drawBaseVtx[0] = s_levelData->sectors[s_selectedWallSector].vertices[wall->i0]; - s_drawBaseVtx[1] = s_levelData->sectors[s_selectedWallSector].vertices[wall->i1]; - } - } - else if (!s_moveWall) - { - s_hoveredWallSector = LevelEditorData::findSector(s_layerIndex + s_layerMin, &worldPos); - s_hoveredWall = LevelEditorData::findClosestWall(&s_hoveredWallSector, s_layerIndex + s_layerMin, &worldPos, s_zoomVisual * 32.0f); - } - } - - void editVertices2d(Vec2f worldPos) - { - // Find the closest vertex (if in vertex mode)... - // Note this should be optimized. - s_hoveredVertex = -1; - if (s_editMode != LEDIT_VERTEX || !s_levelData) - { - return; - } - - const s32 sectorCount = (s32)s_levelData->sectors.size(); - const EditorSector* sector = s_levelData->sectors.data(); - const f32 maxValidDistSq = s_zoomVisual * s_zoomVisual * 256.0f; - f32 minDistSq = maxValidDistSq; - - s32 curVtx = -1, curVtxSector = -1; - for (s32 s = 0; s < sectorCount; s++, sector++) - { - if (sector->layer != s_layerIndex + s_layerMin) { continue; } - - const Vec2f* vtx = sector->vertices.data(); - const s32 vtxCount = (s32)sector->vertices.size(); - for (s32 v = 0; v < vtxCount; v++, vtx++) - { - const Vec2f diff = { vtx->x - worldPos.x, vtx->z - worldPos.z }; - const f32 distSq = diff.x*diff.x + diff.z*diff.z; - if (distSq < minDistSq && distSq < maxValidDistSq) - { - minDistSq = distSq; - curVtx = v; - curVtxSector = s; - } - } - } - - if (curVtx >= 0) - { - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedVertexSector = curVtxSector; - s_selectedVertex = curVtx; - s_moveVertex = true; - // get the plane... - s_drawPlaneNrm = { 0.0f, 1.0f, 0.0f }; - s_drawPlaneOrg = s_cursor3d; - } - else if (!s_moveVertex) - { - s_hoveredVertexSector = curVtxSector; - s_hoveredVertex = curVtx; - } - } - else if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedVertexSector = -1; - s_selectedVertex = -1; - } - } - - void editEntities2d(Vec2f worldPos) - { - s_hoveredEntity = -1; - if (s_editMode != LEDIT_ENTITY || !s_levelData) - { - return; - } - - s_hoveredEntitySector = LevelEditorData::findSector(s_layerIndex + s_layerMin, &worldPos); - if (s_hoveredEntitySector >= 0) - { - const EditorSector* sector = s_levelData->sectors.data() + s_hoveredEntitySector; - const u32 count = (u32)sector->objects.size(); - const EditorLevelObject* obj = sector->objects.data(); - for (u32 i = 0; i < count; i++, obj++) - { - const f32 width = obj->display ? (f32)obj->display->width : 1.0f; - const f32 height = obj->display ? (f32)obj->display->height : 1.0f; - // Half width - f32 w; - if (obj->oclass == CLASS_SPIRIT || obj->oclass == CLASS_SAFE || obj->oclass == CLASS_SOUND) { w = 1.0f; } - else if (obj->oclass == CLASS_3D && obj->displayModel) - { - if (worldPos.x >= obj->displayModel->localAabb[0].x + obj->pos.x && worldPos.x < obj->displayModel->localAabb[1].x + obj->pos.x && - worldPos.z >= obj->displayModel->localAabb[0].z + obj->pos.z && worldPos.z < obj->displayModel->localAabb[1].z + obj->pos.z) - { - s_hoveredEntity = i; - break; - } - } - else { w = obj->display ? (f32)obj->display->width * obj->display->scale.x / 16.0f : 1.0f; } - - if (obj->oclass != CLASS_3D) - { - const f32 x0 = obj->worldCen.x - obj->worldExt.x, x1 = obj->worldCen.x + obj->worldExt.x; - const f32 z0 = obj->worldCen.z - obj->worldExt.z, z1 = obj->worldCen.z + obj->worldExt.z; - if (worldPos.x >= x0 && worldPos.x < x1 && worldPos.z >= z0 && worldPos.z < z1) - { - s_hoveredEntity = i; - break; - } - } - } - } - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - s_selectedEntity = s_hoveredEntity; - s_selectedEntitySector = s_hoveredEntitySector; - } - } - - bool pointInAABB2d(const Vec3f* p, const Vec3f* aabb) - { - if (p->x < aabb[0].x || p->x > aabb[1].x || p->z < aabb[0].z || p->z > aabb[1].z) - { - return false; - } - return true; - } - - bool pointInAABB2d(const Vec2f* p, const Vec3f* aabb) - { - if (p->x < aabb[0].x || p->x > aabb[1].x || p->z < aabb[0].z || p->z > aabb[1].z) - { - return false; - } - return true; - } - - bool aabbOverlap2d(const Vec3f* aabb0, const Vec3f* aabb1) - { - return aabb0[0].z < aabb1[1].z && aabb0[1].z > aabb1[0].z && aabb0[0].x < aabb1[1].x && aabb0[1].x > aabb1[0].x; - } - - bool wallsOverlapVertices(const EditorWall* w0, const EditorWall* w1, const Vec2f* vtx0, const Vec2f* vtx1) - { - const Vec2f& v0 = vtx0[w0->i0]; - const Vec2f& v1 = vtx0[w0->i1]; - - const Vec2f& v2 = vtx1[w1->i0]; - const Vec2f& v3 = vtx1[w1->i1]; - - // The walls should be going in opposite directions. - if (fabsf(v0.x - v3.x) < 0.005f && fabsf(v1.x - v2.x) < 0.005f && - fabsf(v0.z - v3.z) < 0.005f && fabsf(v1.z - v2.z) < 0.005f) - { - return true; - } - return false; - } - - bool editInsertVertex2d(Vec2f worldPos, s32 sectorId, s32 wallId) - { - EditorSector* sector = s_levelData->sectors.data() + sectorId; - // If the wall has an adjoin, than that wall will also need to be split and the adjoins fixed up. - if (sector->walls[wallId].adjoin >= 0) - { - // TODO - return false; - } - else - { - EditorWall* wall = §or->walls[wallId]; - Vec2f* vtx = sector->vertices.data(); - Vec2f pOffset = { worldPos.x - vtx[wall->i0].x, worldPos.z - vtx[wall->i0].z }; - Vec2f wallDir = { vtx[wall->i1].x - vtx[wall->i0].x, vtx[wall->i1].z - vtx[wall->i0].z }; - wallDir = TFE_Math::normalize(&wallDir); - - // Projection of the cursor position onto the wall which gives the parametric coordinate along the line. - f32 proj = pOffset.x*wallDir.x + pOffset.z*wallDir.z; - - // Given the parametric coordinate, compute the new vertex. - Vec2f newVtx = { vtx[wall->i0].x + proj * wallDir.x, vtx[wall->i0].z + proj * wallDir.z }; - - // Then the vertex must be inserted in the list and walls adjusted. - s32 prevWallCount = (s32)sector->walls.size(); - s32 prevVtxCount = (s32)sector->vertices.size(); - sector->walls.resize(sector->walls.size() + 1); - sector->vertices.push_back(newVtx); - - // baseWall doesn't change. - EditorWall* baseWall = §or->walls[wallId]; - // Move all walls beyond baseWall "up" one. - for (s32 w = prevWallCount; w > wallId + 1; w--) - { - sector->walls[w] = sector->walls[w - 1]; - } - sector->walls[wallId + 1] = sector->walls[wallId]; - sector->walls[wallId].i1 = prevVtxCount; - sector->walls[wallId + 1].i0 = prevVtxCount; - - sector->needsUpdate = true; - } - return true; - } - - bool editInsertVertex2d(Vec2f worldPos) - { - s32 sectorId = -1; - s32 wallId = LevelEditorData::findClosestWall(§orId, s_layerIndex + s_layerMin, &worldPos, s_zoomVisual * 32.0f); - if (wallId < 0 || sectorId < 0) { return false; } - - return editInsertVertex2d(worldPos, sectorId, wallId); - } - - void deleteSector(EditorSector* sector) - { - // Delete sectors. - u32 sectorCount = (u32)s_levelData->sectors.size(); - for (u32 s = sector->id; s < sectorCount - 1; s++) - { - s_levelData->sectors[s] = s_levelData->sectors[s + 1]; - s_levelData->sectors[s].id = s; - } - s_levelData->sectors.resize(s_levelData->sectors.size() - 1); - sectorCount--; - - // Adjust adjoin Ids. - EditorSector* fixSec = s_levelData->sectors.data(); - for (u32 s = 0; s < sectorCount; s++, fixSec++) - { - const u32 wallCount = (u32)fixSec->walls.size(); - EditorWall* wall = fixSec->walls.data(); - - for (u32 w = 0; w < wallCount; w++, wall++) - { - if (wall->adjoin == s_selectedSector) - { - wall->adjoin = -1; - wall->walk = -1; - fixSec->needsUpdate = true; - } - else if (wall->adjoin > s_selectedSector) - { - wall->adjoin--; - wall->walk = wall->adjoin; - fixSec->needsUpdate = true; - } - } - } - - // Clear selection. - s_selectedWall = -1; - s_selectedSector = -1; - LevelEditorData::updateSectors(); - } - - bool isPointOnWallOrVertex(const Vec2f* point, const EditorSector* sector, s32* wallId) - { - const u32 count = (u32)sector->walls.size(); - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - const f32 eps = 0.01f; - const f32 epsSq = eps * eps; - for (u32 w = 0; w < count; w++, wall++) - { - // first check vertex 0. - if (TFE_Math::distanceSq(point, &vtx[wall->i0]) < epsSq) - { - *wallId = w; - return true; - } - - // then check the line segment. - Vec2f closest; - Geometry::closestPointOnLineSegment(vtx[wall->i0], vtx[wall->i1], *point, &closest); - if (TFE_Math::distanceSq(point, &closest) < epsSq) - { - *wallId = w; - return true; - } - } - - return false; - } - - s32 splitSide(const Vec2f& v0, const Vec2f& normal, const Vec2f& point) - { - const Vec2f offset = { point.x - v0.x, point.z - v0.z }; - return (offset.x*normal.x + offset.z*normal.z) > -0.005f ? 0 : 1; - } - - u16 addVertex(const Vec2f& vtx, std::vector& list) - { - // Just loop through the vertices for now. - const u32 count = (u32)list.size(); - const Vec2f* vtxList = list.data(); - for (u32 v = 0; v < count; v++) - { - f32 dx = fabsf(vtx.x - vtxList[v].x); - f32 dz = fabsf(vtx.z - vtxList[v].z); - if (dx < 0.01f && dz < 0.01f) - { - return u16(v); - } - } - - u16 index = u16(count); - list.push_back(vtx); - return index; - } - - void splitSector(EditorSector* sector, Vec2f v0, Vec2f v1, u32 insideVertexCount, const Vec2f* insideVtx) - { - EditorSector sec0 = *sector; - EditorSector sec1 = *sector; - sec0.vertices.clear(); - sec0.walls.clear(); - sec0.objects.clear(); - - sec1.vertices.clear(); - sec1.walls.clear(); - sec1.objects.clear(); - - const u32 wallCount = (u32)sector->walls.size(); - const Vec2f* vtx = sector->vertices.data(); - - s32 splitWallId0 = -1; - s32 splitWallId1 = -1; - - // Find out which wall that v0 is attached to. - // Then find out if the splitting line is aligned with the wall or going the opposite direction. - EditorWall* wall = sector->walls.data(); - /* - for (u32 w = 0; w < wallCount; w++, wall++) - { - Vec2f it; - Geometry::closestPointOnLineSegment(vtx[wall->i0], vtx[wall->i1], v0, &it); - if (TFE_Math::distanceSq(&v0, &it) <= 0.01f * 0.01f) - { - // If it is going the opposite direction, then flip the splitting line (and interior points). - //f32 alignment = (v1.x - v0.x)*(vtx[wall->i1].x - it.x) + (v1.z - v0.z)*(vtx[wall->i1].z - it.z); - f32 alignment = (v1.x - it.x)*(vtx[wall->i1].z - it.z) - (vtx[wall->i1].x - it.x)*(v1.z - it.z); - if (alignment < 0.0f) - { - std::swap(v0.x, v1.x); - std::swap(v0.z, v1.z); - } - break; - } - } - */ - - // Normal = {-dz, dx} - Vec2f normal = { v0.z - v1.z, v1.x - v0.x }; - normal = TFE_Math::normalize(&normal); - - if (insideVertexCount == 0) - { - // The most basic version... - // Determine which walls are on one side or the other. - // Determine which walls need to be split. - wall = sector->walls.data(); - for (u32 w = 0; w < wallCount; w++, wall++) - { - const Vec2f& w0 = vtx[wall->i0]; - const Vec2f& w1 = vtx[wall->i1]; - - const s32 side0 = splitSide(v0, normal, w0); - const s32 side1 = splitSide(v0, normal, w1); - - if (side0 == 0 && side1 == 0) - { - // Add to sector 0. - EditorWall newWall = sector->walls[w]; - newWall.i0 = addVertex(w0, sec0.vertices); - newWall.i1 = addVertex(w1, sec0.vertices); - - if (newWall.adjoin >= 0) - { - s_levelData->sectors[newWall.adjoin].walls[sector->walls[w].mirror].mirror = (s32)sec0.walls.size(); - } - sec0.walls.push_back(newWall); - } - else if (side0 == 1 && side1 == 1) - { - // Add to sector 1. - EditorWall newWall = sector->walls[w]; - newWall.i0 = addVertex(w0, sec1.vertices); - newWall.i1 = addVertex(w1, sec1.vertices); - - if (newWall.adjoin >= 0) - { - s_levelData->sectors[newWall.adjoin].walls[sector->walls[w].mirror].mirror = (s32)sec1.walls.size(); - s_levelData->sectors[newWall.adjoin].walls[sector->walls[w].mirror].adjoin = (s32)s_levelData->sectors.size(); - } - sec1.walls.push_back(newWall); - } - else - { - // Find the intersection, this point gets added to both sides. - f32 s, t; - Geometry::lineSegmentIntersect(&w0, &w1, &v0, &v1, &s, &t); - - // Find the intersection, this point gets added to both sides. - s = std::max(0.0f, std::min(1.0f, s)); - const Vec2f it = { w0.x + s*(w1.x - w0.x), w0.z + s*(w1.z - w0.z) }; - - s32 splitVtxIdx; - f32 dx = fabsf(v0.x - it.x); - f32 dz = fabsf(v0.z - it.z); - if (dx < 0.01f && dz < 0.01f) - { - splitVtxIdx = 0; - } - else - { - splitVtxIdx = 1; - } - - // Add the first vertex to the correct side. - EditorWall newWall0 = sector->walls[w]; - EditorWall newWall1 = sector->walls[w]; - if (side0 == 0) - { - newWall0.i0 = addVertex(w0, sec0.vertices); - newWall0.i1 = addVertex(it, sec0.vertices); - - newWall1.i0 = addVertex(it, sec1.vertices); - newWall1.i1 = addVertex(w1, sec1.vertices); - - if (sector->walls[w].adjoin >= 0) - { - // we need to split the mirror as well and then match up the adjoins. - EditorSector* adjoin = &s_levelData->sectors[sector->walls[w].adjoin]; - s32 mirror = sector->walls[w].mirror; - - // Split the mirror edge: i0 -> it -> i1 - // mirror: i0 -> it; mirror + 1: it -> i1 - s32 adjoinWallCount = (s32)adjoin->walls.size(); - adjoin->walls.resize(adjoin->walls.size() + 1); - for (s32 wA = adjoinWallCount; wA > mirror; wA--) - { - adjoin->walls[wA] = adjoin->walls[wA - 1]; - } - adjoin->walls[mirror].i1 = addVertex(it, adjoin->vertices); - adjoin->walls[mirror + 1].i0 = adjoin->walls[mirror].i1; - - // Setup mirrors. - // Which side is which? - if (splitSide(v0, normal, adjoin->vertices[adjoin->walls[mirror].i0]) == 0) - { - adjoin->walls[mirror].mirror = (s32)sec0.walls.size(); - adjoin->walls[mirror].adjoin = (s32)sector->id; - adjoin->walls[mirror].walk = (s32)sector->id; - newWall0.mirror = mirror; - - adjoin->walls[mirror + 1].mirror = (s32)sec1.walls.size(); - adjoin->walls[mirror + 1].adjoin = (s32)s_levelData->sectors.size(); - adjoin->walls[mirror + 1].walk = (s32)s_levelData->sectors.size(); - newWall1.mirror = mirror + 1; - } - else - { - adjoin->walls[mirror].mirror = (s32)sec1.walls.size(); - adjoin->walls[mirror].adjoin = (s32)s_levelData->sectors.size(); - adjoin->walls[mirror].walk = (s32)s_levelData->sectors.size(); - newWall1.mirror = mirror; - - adjoin->walls[mirror + 1].mirror = (s32)sec0.walls.size(); - adjoin->walls[mirror + 1].adjoin = (s32)sector->id; - adjoin->walls[mirror + 1].walk = (s32)sector->id; - newWall0.mirror = mirror + 1; - } - } - - sec0.walls.push_back(newWall0); - sec1.walls.push_back(newWall1); - - // Add the wall from this intersection to the previous point. - newWall0.i0 = newWall0.i1; - newWall0.i1 = addVertex(splitVtxIdx == 0 ? v1 : v0, sec0.vertices); - newWall0.adjoin = (s32)s_levelData->sectors.size(); - newWall0.walk = newWall0.adjoin; - newWall0.mirror = -1; // Will be filled out at the end. - splitWallId0 = (s32)sec0.walls.size(); - sec0.walls.push_back(newWall0); - } - else - { - newWall0.i0 = addVertex(it, sec0.vertices); - newWall0.i1 = addVertex(w1, sec0.vertices); - - newWall1.i0 = addVertex(w0, sec1.vertices); - newWall1.i1 = addVertex(it, sec1.vertices); - - if (sector->walls[w].adjoin >= 0) - { - // we need to split the mirror as well and then match up the adjoins. - EditorSector* adjoin = &s_levelData->sectors[sector->walls[w].adjoin]; - s32 mirror = sector->walls[w].mirror; - - // Split the mirror edge: i0 -> it -> i1 - // mirror: i0 -> it; mirror + 1: it -> i1 - s32 adjoinWallCount = (s32)adjoin->walls.size(); - adjoin->walls.resize(adjoin->walls.size() + 1); - for (s32 wA = adjoinWallCount; wA > mirror; wA--) - { - adjoin->walls[wA] = adjoin->walls[wA - 1]; - } - adjoin->walls[mirror].i1 = addVertex(it, adjoin->vertices); - adjoin->walls[mirror + 1].i0 = adjoin->walls[mirror].i1; - - // Setup mirrors. - // Which side is which? - if (splitSide(v0, normal, adjoin->vertices[adjoin->walls[mirror].i0]) == 0) - { - adjoin->walls[mirror].mirror = (s32)sec0.walls.size(); - adjoin->walls[mirror].adjoin = (s32)sector->id; - adjoin->walls[mirror].walk = (s32)sector->id; - newWall0.mirror = mirror; - - adjoin->walls[mirror + 1].mirror = (s32)sec1.walls.size(); - adjoin->walls[mirror + 1].adjoin = (s32)s_levelData->sectors.size(); - adjoin->walls[mirror + 1].walk = (s32)s_levelData->sectors.size(); - newWall1.mirror = mirror + 1; - } - else - { - adjoin->walls[mirror].mirror = (s32)sec1.walls.size(); - adjoin->walls[mirror].adjoin = (s32)s_levelData->sectors.size(); - adjoin->walls[mirror].walk = (s32)s_levelData->sectors.size(); - newWall1.mirror = mirror; - - adjoin->walls[mirror + 1].mirror = (s32)sec0.walls.size(); - adjoin->walls[mirror + 1].adjoin = (s32)sector->id; - adjoin->walls[mirror + 1].walk = (s32)sector->id; - newWall0.mirror = mirror + 1; - } - } - - sec0.walls.push_back(newWall0); - sec1.walls.push_back(newWall1); - - // Add the wall from this intersection to the previous point. - newWall1.i0 = newWall1.i1; - newWall1.i1 = addVertex(splitVtxIdx == 0 ? v1 : v0, sec1.vertices); - newWall1.adjoin = sector->id; - newWall1.walk = newWall1.adjoin; - newWall1.mirror = -1; // Will be filled out at the end. - splitWallId1 = (s32)sec1.walls.size(); - sec1.walls.push_back(newWall1); - } - } - } - } - else - { - } - - if (splitWallId0 >= 0) { sec0.walls[splitWallId0].mirror = splitWallId1; } - if (splitWallId1 >= 0) { sec1.walls[splitWallId1].mirror = splitWallId0; } - - *sector = sec0; - sector->needsUpdate = true; - - LevelEditorData::addNewSectorFullCopy(sec1); - LevelEditorData::updateSectors(); - } - - void insertSector2d() - { - // First determine the signed area and reverse the vertex/wall order if necessary. - // This way sectors can be drawn either clockwise or anticlockwise and achieve the same result. - const s32 srcVertexCount = (s32)s_newSector.vertices.size(); - const f32 signedArea = TFE_Polygon::signedArea((u32)srcVertexCount, s_newSector.vertices.data()); - if (signedArea < 0.0f) - { - std::vector srcVtx = s_newSector.vertices; - for (s32 v = 0; v < srcVertexCount; v++) - { - s_newSector.vertices[v] = srcVtx[srcVertexCount - v - 1]; - } - } - - // For now use the first texture to get default textures... - s32 count = (s32)s_levelData->sectors.size(); - EditorSector* sector = s_levelData->sectors.data(); - LevelEditorData::addNewSector(s_newSector, sector->floorTexture.tex, sector->ceilTexture.tex, sector->walls[0].mid.tex); - - sector = &s_levelData->sectors.back(); - const u32 srcWallCount = (u32)sector->walls.size(); - const s32 srcLayer = sector->layer; - // Source shape bounds are expanded slightly to robustly handle cases where only purely horizontal or vertical lines are overlapping. - const Vec3f srcAabb[2] = - { - { sector->aabb[0].x - 0.1f, sector->aabb[0].y, sector->aabb[0].z - 0.1f }, - { sector->aabb[1].x + 0.1f, sector->aabb[1].y, sector->aabb[1].z + 0.1f }, - }; - - // First determine if all vertices are inside of a single sector. - const Vec2f* vtx = s_newSector.vertices.data(); - EditorSector* neighbor = s_levelData->sectors.data(); - for (s32 s = 0; s < count; s++, neighbor++) - { - // Make sure the sector is on the correct layer. - if (srcLayer != neighbor->layer) { continue; } - - // See if the AABBs overlap. - if (!aabbOverlap2d(srcAabb, neighbor->aabb)) { continue; } - - u32 vSrcInside = 0; - u32 attachedCount = 0; - u32 insideCount = 0; - s32 wallAttach[1024]; - s32 inside[1024]; - for (s32 vSrc = 0; vSrc < srcVertexCount; vSrc++) - { - // See if the point is inside the sector AABB. - if (!pointInAABB2d(&vtx[vSrc], neighbor->aabb)) { break; } - - // Test if the point is inside the sector polygon. - s32 wallId; - if (isPointOnWallOrVertex(&vtx[vSrc], neighbor, &wallId)) - { - wallAttach[attachedCount++] = vSrc; - } - else if (!Geometry::pointInSector(&vtx[vSrc], (u32)neighbor->vertices.size(), neighbor->vertices.data(), (u32)neighbor->walls.size(), (u8*)neighbor->walls.data(), sizeof(EditorWall))) - { - break; - } - else - { - inside[insideCount++] = vSrc; - } - vSrcInside++; - } - - // Is the new sector or shape completely inside of this sector? - if (vSrcInside == srcVertexCount) - { - // TODO: We should verify that no edges of the new sector intersect edges of the neighbor sector. - // TODO: Check if any edges overlap edges with adjoins so they can be connected directly (i.e. making a staircase) - if (attachedCount > 1) - { - // If the new shape is touching the parent sector in at least two places, then what we really want to do is split that sector. - // If there are two attachment points only - then we just spit along that edge. - // If there are at least two attachment points and some interior points, then the split edges will be between the two attachment points that - // surround the interior points and go through those interior points. - // If degenerate cases, just pick a single valid case and go with it (the mapper can always use undo if we get this wrong and then better - // specify the split. - - // Split the sector in two along the straight edge. - if (attachedCount == 2 && insideCount == 0) - { - // Copy the vertices. - Vec2f v0 = sector->vertices[0]; - Vec2f v1 = sector->vertices[1]; - - // Delete the new sector. - s_levelData->sectors.resize(s_levelData->sectors.size() - 1); - - // Split the neighbor sector. - splitSector(neighbor, v0, v1); - } - // Split the sector in two with multiple interior adjoins. - else if (attachedCount == 2 && insideCount > 0) - { - // Copy the vertices. - Vec2f v0 = sector->vertices[wallAttach[0]]; - Vec2f v1 = sector->vertices[wallAttach[1]]; - - Vec2f insideVtx[128]; - u32 insideVertexCount = 0; - for (u32 v = 0; v < insideCount; v++) - { - if (inside[v] > wallAttach[0] && inside[v] < wallAttach[1]) - { - insideVtx[insideVertexCount++] = sector->vertices[inside[v]]; - } - } - - // Delete the new sector. - s_levelData->sectors.resize(s_levelData->sectors.size() - 1); - - // Split the neighbor sector. - splitSector(neighbor, v0, v1, insideVertexCount, insideVtx); - } - // Split the sector in two along a single edge, but we have to figure out what edge that is... - else if (attachedCount > 2 && insideCount == 0) - { - } - // Finally, the most complex case - split the sector in two with multiple interior adjoins, but we have to figure out which attachments/interior edges to use... - else if (attachedCount > 2 && insideCount > 0) - { - } - // If we get here then this is not cleanly resolvable, just return. - else - { - // Delete the new sector if it is invalid. This may happen when trying to split a sector but not getting the configuration right. - if (sector->vertices.size() < 3) - { - s_levelData->sectors.resize(s_levelData->sectors.size() - 1); - } - return; - } - } - else - { - // Delete the new sector if it is invalid. This may happen when trying to split a sector but not getting the configuration right. - if (sector->vertices.size() < 3) - { - s_levelData->sectors.resize(s_levelData->sectors.size() - 1); - return; - } - - // The wall the vertex is sitting on should be split at that vertex. Otherwise there are graphical artifacts. - if (attachedCount == 1) - { - // TODO: Split the wall, see above. - // Note that if the attachment is already a vertex, such a split is unnecessary, so check that first. - } - - // For the first pass, keep it simple and assume it is a self contained interior sector. - // 1. Add new edges to the neighbor sector going in the *opposite* direction. This is a hole in the "neighbor" sector polygon. - // 2. Link up adjoins between the hole and the new sector. - std::vector& srcVtx = s_newSector.vertices; - const u32 baseVertexIndex = (u32)neighbor->vertices.size(); - const u32 baseWallIndex = (u32)neighbor->walls.size(); - for (s32 v = 0; v < srcVertexCount; v++) - { - const s32 vRev = srcVertexCount - v - 1; - neighbor->vertices.push_back(srcVtx[vRev]); - - EditorWall newWall = sector->walls[vRev]; - newWall.i0 = baseVertexIndex + ((v > 0) ? (v - 1) : (srcVertexCount - 1)); - newWall.i1 = baseVertexIndex + v; - newWall.adjoin = sector->id; - newWall.walk = sector->id; - newWall.mirror = vRev; - - sector->walls[v].adjoin = s; - sector->walls[v].walk = s; - sector->walls[v].mirror = baseWallIndex + srcVertexCount - v - 1; - - neighbor->walls.push_back(newWall); - } - // Copy outer sector attributes to the sub-sector. - sector->ambient = neighbor->ambient; - sector->flags[0] = neighbor->flags[0]; - sector->flags[1] = neighbor->flags[1]; - sector->flags[2] = neighbor->flags[2]; - sector->floorAlt = neighbor->floorAlt; - sector->ceilAlt = neighbor->ceilAlt; - sector->floorTexture = neighbor->floorTexture; - sector->ceilTexture = neighbor->ceilTexture; - // The outer sector needs to be updated since new walls were added. - neighbor->needsUpdate = true; - } - - // We don't need to check for wall overlaps since this is either a sub-sector or splitting a sector. - LevelEditorData::updateSectors(); - return; - } - } - - // Then determine if any walls overlap. - for (u32 wSrc = 0; wSrc < srcWallCount; wSrc++) - { - const Vec2f* srcVtx = sector->vertices.data(); - EditorWall* srcWall = §or->walls[wSrc]; - - EditorSector* overlapSector = nullptr; - s32 overlapWall = -1; - // Once we have the new sector, see if there are any overlapping lines from other sectors such that: - // 1. The sectors are on the same layer. - // 2. The sectors do NOT overlap (? - how to determine this robustly) - // 3. A line overlaps with a line in the other sector. - EditorSector* neighbor = s_levelData->sectors.data(); - for (s32 s = 0; s < count && !overlapSector; s++, neighbor++) - { - // Make sure the sector is on the correct layer. - if (srcLayer != neighbor->layer) { continue; } - - // See if the AABBs overlap. - if (!aabbOverlap2d(srcAabb, neighbor->aabb)) { continue; } - - // Check the walls for overlap. - const u32 dstWallCount = (u32)neighbor->walls.size(); - const Vec2f* dstVtx = neighbor->vertices.data(); - for (u32 wDst = 0; wDst < dstWallCount; wDst++) - { - EditorWall* dstWall = &neighbor->walls[wDst]; - - // Next determine if the walls overlap vertices (the easy test). - if (wallsOverlapVertices(srcWall, dstWall, srcVtx, dstVtx)) - { - overlapSector = neighbor; - overlapWall = wDst; - break; - } - - // If the vertices don't overlap, do the segments overlap? Should we split the dstWall? - const Vec2f* w0 = &dstVtx[dstWall->i0]; - const Vec2f* w1 = &dstVtx[dstWall->i1]; - - const Vec2f* v0 = &srcVtx[srcWall->i0]; - const Vec2f* v1 = &srcVtx[srcWall->i1]; - - Vec2f p0, p1; - Geometry::closestPointOnLineSegment(*w0, *w1, *v0, &p0); - Geometry::closestPointOnLineSegment(*w0, *w1, *v1, &p1); - - f32 d0 = TFE_Math::distanceSq(v0, &p0); - f32 d1 = TFE_Math::distanceSq(v1, &p1); - if (fabsf(d0) < 0.02f && fabsf(d1) < 0.02f) - { - if (editInsertVertex2d(p1, s, wDst) && editInsertVertex2d(p0, s, wDst+1)) - { - overlapSector = neighbor; - overlapWall = wDst + 1; - break; - } - } - } - } - - if (overlapSector) - { - srcWall->adjoin = overlapSector->id; - srcWall->walk = srcWall->adjoin; - srcWall->mirror = overlapWall; - - EditorWall* dstWall = &overlapSector->walls[overlapWall]; - dstWall->adjoin = count; - dstWall->walk = dstWall->adjoin; - dstWall->mirror = wSrc; - - // Snap the vertices together just in case. - sector->vertices[srcWall->i0] = overlapSector->vertices[dstWall->i1]; - sector->vertices[srcWall->i1] = overlapSector->vertices[dstWall->i0]; - - sector->needsUpdate = true; - overlapSector->needsUpdate = true; - } - } - - LevelEditorData::updateSectors(); - } - - void clearNewSector() - { - s_newSector.vertices.clear(); - s_newSector.walls.clear(); - s_newSector.triangles.count = 0; - s_newSector.triangles.vtx.clear(); - } - - void editDrawSectors2d(Vec2f worldPos) - { - if (s_editMode != LEDIT_DRAW || !s_levelData) - { - return; - } - if (s_newSector.vertices.size() < 1) - { - s_newSector.vertices.resize(1); - } - - s_cursorSnapped = { s_cursor3d.x, s_gridHeight, s_cursor3d.z }; - if (!snapToGeometry(&s_cursorSnapped, true)) - { - snapToGrid(&s_cursorSnapped, true); - } - - s_newSector.vertices.back() = { s_cursorSnapped.x, s_cursorSnapped.z }; - - // If left mouse is pressed, add a new vertex. - if (TFE_Input::mousePressed(MBUTTON_LEFT)) - { - if (s_newSector.vertices.size() == 1) - { - s_newSector.floorAlt = s_gridHeight; - s_newSector.ceilAlt = s_gridHeight - 16.0f; - s_newSector.layer = s_layerIndex + s_layerMin; - s_newSector.ambient = 30; - } - - s_newSector.vertices.push_back({ s_cursorSnapped.x, s_cursorSnapped.z }); - - // Build walls. - size_t count = s_newSector.vertices.size(); - s_newSector.walls.resize(count); - for (size_t w = 0; w < count; w++) - { - s_newSector.walls[w].adjoin = -1; - s_newSector.walls[w].mirror = -1; - s_newSector.walls[w].walk = -1; - s_newSector.walls[w].i0 = u16(w); - s_newSector.walls[w].i1 = u16((w + 1) % count); - } - } - else if (TFE_Input::keyPressed(KEY_ESCAPE)) - { - // Clear the new sector. - clearNewSector(); - return; - } - else if (TFE_Input::mousePressed(MBUTTON_RIGHT) || TFE_Input::keyPressed(KEY_RETURN)) - { - if (s_newSector.walls.size() >= 3) - { - s_newSector.vertices.resize(s_newSector.vertices.size() - 1); - - s_newSector.walls.resize(s_newSector.walls.size() - 1); - EditorWall& lastWall = s_newSector.walls[s_newSector.walls.size() - 1]; - lastWall.i1 = 0; - - insertSector2d(); - } - - // Clear the new sector. - clearNewSector(); - return; - } - - // Triangulate - static Polygon contour; - contour.vtxCount = (s32)s_newSector.vertices.size(); - memcpy(contour.vtx, s_newSector.vertices.data(), sizeof(Vec2f) * contour.vtxCount); - if (fabsf(contour.vtx[contour.vtxCount - 1].x - contour.vtx[contour.vtxCount - 2].x) < 0.01f && fabsf(contour.vtx[contour.vtxCount - 1].z - contour.vtx[contour.vtxCount - 2].z) < 0.01f) - { - contour.vtxCount--; - } - if (contour.vtxCount < 3) - { - return; - } - - // Setup triangles - u32 polyCount; - const Triangle* tri = TFE_Polygon::decomposeComplexPolygon(1, &contour, &polyCount); - s_newSector.triangles.count = polyCount; - s_newSector.triangles.vtx.resize(polyCount * 3); - - u32 tIdx = 0; - for (u32 p = 0; p < polyCount; p++, tri++) - { - s_newSector.triangles.vtx[p * 3 + 0] = tri->vtx[0]; - s_newSector.triangles.vtx[p * 3 + 1] = tri->vtx[1]; - s_newSector.triangles.vtx[p * 3 + 2] = tri->vtx[2]; - } - } -} diff --git a/TheForceEngine/TFE_Editor/levelEditor.h b/TheForceEngine/TFE_Editor/levelEditor.h deleted file mode 100644 index 5c0a5e174..000000000 --- a/TheForceEngine/TFE_Editor/levelEditor.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include - -class TFE_Renderer; -namespace LevelEditor -{ - void init(TFE_Renderer* renderer); - void disable(); - - void draw(bool* isActive); - bool isFullscreen(); - - void menu(); - - // Returns true if a fullscreen blit is required. - bool render3dView(); -} diff --git a/TheForceEngine/TFE_Editor/levelEditorData.cpp b/TheForceEngine/TFE_Editor/levelEditorData.cpp deleted file mode 100644 index c20d06f39..000000000 --- a/TheForceEngine/TFE_Editor/levelEditorData.cpp +++ /dev/null @@ -1,1776 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// The Force Engine Level Editor Data -// The runtime has fixed sectors and INF data that doesn't change in size -// whereas the data the Level Editor needs to access and change is -// constantly malleable. So the LevelEditor needs to copy the tight -// runtime structures into more malleable structures and be able to reverse -// the process in order to test. -///////////////////////////////////////////////////////////////////////// -#include "levelEditorData.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -// Triangulation -#include -#include -#include - -namespace LevelEditorData -{ - static InfEditState s_infEditState = { 0 }; - - static EditorLevel s_editorLevel; - static EditorInfData s_editorInf; - static std::vector s_objIcons; - static std::vector s_textureBuffer; - - static const Palette256* s_pal = nullptr; - - void convertInfToEditor(const InfData* infData); - void convertObjectsToEditor(const LevelObjectData* objData); - void determineSectorTypes(); - EditorInfItem* findInfItem(const EditorSector* sector, s32 wall); - - EditorTexture* getEditorTexture(const char* srcName) - { - if (!srcName) { return nullptr; } - - TextureMap::iterator iTex = s_editorLevel.textureMap.find(srcName); - if (iTex != s_editorLevel.textureMap.end()) - { - return iTex->second; - } - return nullptr; - } - - EditorTexture* getEditorTexture(const Texture* src) - { - if (!src) { return nullptr; } - return getEditorTexture(src->name); - } - - u32* convertPalImageToTrueColor(u32 w, u32 h, const u8* image) - { - s_textureBuffer.resize(w * h); - u32* trueColor = s_textureBuffer.data(); - - const u32 pixelCount = w * h; - for (u32 y = 0; y < h; y++) - { - for (u32 x = 0; x < w; x++) - { - const u32 dstIndex = (h - y - 1)*w + x; - const u8 srcTexel = image[x*h + y]; - - trueColor[dstIndex] = s_pal->colors[srcTexel]; - if (srcTexel != 0u) - { - trueColor[dstIndex] |= 0xff000000; - } - else - { - trueColor[dstIndex] &= 0x00ffffff; - } - } - } - - return trueColor; - } - - EditorTexture* createTexture(const Texture* src) - { - if (!src) { return nullptr; } - - EditorTexture* tex = getEditorTexture(src->name); - if (tex) { return tex; } - if (s_objIcons.capacity() == 0) { s_objIcons.reserve(4096u); } - - s_objIcons.push_back({}); - tex = &s_objIcons.back(); - tex->scale = { 1.0f, 1.0f }; - - const u32* trueColor = convertPalImageToTrueColor(src->frames[0].width, src->frames[0].height, src->frames[0].image); - tex->texture = TFE_RenderBackend::createTexture(src->frames[0].width, src->frames[0].height, trueColor); - tex->width = src->frames[0].width; - tex->height = src->frames[0].height; - strcpy(tex->name, src->name); - - tex->scale.x = 1.0f; - tex->scale.z = 1.0f; - tex->rect[0] = 0.0f; - tex->rect[1] = 0.0f; - tex->rect[2] = 0.0f; - tex->rect[3] = 0.0f; - - s_editorLevel.textureMap[tex->name] = tex; - return tex; - } - - EditorTexture* createObjectTexture(ObjectClass oclass, const char* dataFile) - { - EditorTexture* tex = getEditorTexture(dataFile); - if (tex) { return tex; } - if (s_objIcons.capacity() == 0) { s_objIcons.reserve(4096u); } - - char imagePath[TFE_MAX_PATH]; - switch (oclass) - { - case CLASS_SPIRIT: - { - tex = getEditorTexture("SpiritObject.png"); - if (tex) { return tex; } - - TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/SpiritObject.png", imagePath, TFE_MAX_PATH); - SDL_Surface* image = TFE_Image::get(imagePath); - if (image) - { - s_objIcons.push_back({}); - tex = &s_objIcons.back(); - tex->scale = { 1.0f, 1.0f }; - - tex->texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); - tex->width = image->w; - tex->height = image->h; - strcpy(tex->name, "SpiritObject.png"); - - s_editorLevel.textureMap[tex->name] = tex; - } - - } break; - case CLASS_SAFE: - { - tex = getEditorTexture("SafeObject.png"); - if (tex) { return tex; } - - TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/SafeObject.png", imagePath, TFE_MAX_PATH); - SDL_Surface* image = TFE_Image::get(imagePath); - if (image) - { - s_objIcons.push_back({}); - tex = &s_objIcons.back(); - tex->scale = { 1.0f, 1.0f }; - - tex->texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); - tex->width = image->w; - tex->height = image->h; - strcpy(tex->name, "SafeObject.png"); - - s_editorLevel.textureMap[tex->name] = tex; - } - } break; - case CLASS_SPRITE: - { - const Sprite* sprite = TFE_Sprite::getSprite(dataFile); - if (sprite) - { - s_objIcons.push_back({}); - tex = &s_objIcons.back(); - tex->scale = { 1.0f, 1.0f }; - - const u32* trueColor = convertPalImageToTrueColor(sprite->frames[0].width, sprite->frames[0].height, sprite->frames[0].image); - tex->texture = TFE_RenderBackend::createTexture(sprite->frames[0].width, sprite->frames[0].height, trueColor); - tex->width = sprite->frames[0].width; - tex->height = sprite->frames[0].height; - strcpy(tex->name, dataFile); - - //tex->scale.x = f32(sprite->anim[0].worldWidth) * c_spriteWorldScale; - //tex->scale.z = f32(sprite->anim[0].worldHeight) * c_spriteWorldScale; - tex->rect[0] = (f32)sprite->frames[0].rect[0]; - tex->rect[1] = (f32)sprite->frames[0].rect[1]; - tex->rect[2] = (f32)sprite->frames[0].rect[2]; - tex->rect[3] = (f32)sprite->frames[0].rect[3]; - - s_editorLevel.textureMap[tex->name] = tex; - } - } break; - case CLASS_FRAME: - { - const Frame* frame = TFE_Sprite::getFrame(dataFile); - if (frame) - { - s_objIcons.push_back({}); - tex = &s_objIcons.back(); - tex->scale = { 1.0f, 1.0f }; - - const u32* trueColor = convertPalImageToTrueColor(frame->width, frame->height, frame->image); - tex->texture = TFE_RenderBackend::createTexture(frame->width, frame->height, trueColor); - tex->width = frame->width; - tex->height = frame->height; - strcpy(tex->name, dataFile); - - tex->rect[0] = (f32)frame->rect[0]; - tex->rect[1] = (f32)frame->rect[1]; - tex->rect[2] = (f32)frame->rect[2]; - tex->rect[3] = (f32)frame->rect[3]; - - s_editorLevel.textureMap[tex->name] = tex; - } - } break; - case CLASS_3D: - { - } break; - case CLASS_SOUND: - { - tex = getEditorTexture("SoundObject.png"); - if (tex) { return tex; } - - TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/SoundObject.png", imagePath, TFE_MAX_PATH); - SDL_Surface* image = TFE_Image::get(imagePath); - if (image) - { - s_objIcons.push_back({}); - tex = &s_objIcons.back(); - tex->scale = { 1.0f, 1.0f }; - - tex->texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); - tex->width = image->w; - tex->height = image->h; - strcpy(tex->name, "SoundObject.png"); - - s_editorLevel.textureMap[tex->name] = tex; - } - } break; - }; - return tex; - } - - void freeTextures() - { - const size_t count = s_editorLevel.textures.size(); - for (size_t t = 0; t < count; t++) - { - TFE_RenderBackend::freeTexture(s_editorLevel.textures[t].texture); - } - const size_t iconCount = s_objIcons.size(); - for (size_t t = 0; t < iconCount; t++) - { - TFE_RenderBackend::freeTexture(s_objIcons[t].texture); - } - s_objIcons.clear(); - s_editorLevel.textures.clear(); - s_editorLevel.textureMap.clear(); - } - - void loadTextures(const Palette256* pal) - { - freeTextures(); - s_pal = pal; - - // Load textures from custom GOBs - - // Load the textures from the resources (TEXTURES.GOB by default). - char textureGobPath[TFE_MAX_PATH]; - TFE_Paths::appendPath(TFE_PathType::PATH_SOURCE_DATA, "TEXTURES.GOB", textureGobPath); - Archive* textureArchive = Archive::getArchive(ARCHIVE_GOB, "TEXTURES.GOB", textureGobPath); - - const u32 fileCount = textureArchive->getFileCount(); - s_editorLevel.textures.clear(); - s_editorLevel.textures.reserve(fileCount); - // Skip ahead past weapon textures. - for (u32 i = TEXTURES_GOB_START_TEX; i < fileCount; i++) - { - const char* name = textureArchive->getFileName(i); - const size_t len = strlen(name); - if (name[len - 2] != 'B' || name[len - 1] != 'M') { continue; } - - const Texture* texture = TFE_Texture::get(name); - const u32 w = texture->frames[0].width; - const u32 h = texture->frames[0].height; - - s_textureBuffer.resize(w * h); - u32* trueColor = s_textureBuffer.data(); - - const u32 pixelCount = w * h; - for (u32 y = 0; y < h; y++) - { - for (u32 x = 0; x < w; x++) - { - const u32 dstIndex = (h - y - 1)*w + x; - const u8 srcTexel = texture->frames[0].image[x*h + y]; - - trueColor[dstIndex] = pal->colors[srcTexel]; - if (srcTexel != 0u || texture->frames[0].opacity != OPACITY_TRANS) - { - trueColor[dstIndex] |= 0xff000000; - } - else - { - trueColor[dstIndex] &= 0x00ffffff; - } - } - } - - TextureGpu* textureGpu = TFE_RenderBackend::createTexture(w, h, trueColor); - EditorTexture editorTexture = - { - textureGpu, - w, h - }; - strcpy(editorTexture.name, name); - // The texture vector was pre-allocated, so pointers stay valid. - s_editorLevel.textures.push_back(editorTexture); - s_editorLevel.textureMap[name] = &s_editorLevel.textures.back(); - } - } - - void copyTexture(EditorSectorTexture* dst, const SectorTexture* src, const LevelData* levelData) - { - const bool hasTex = src->texId >= 0 && levelData->textures[src->texId]; - - dst->offsetX = hasTex ? src->offsetX : 0; - dst->offsetY = hasTex ? src->offsetY : 0; - dst->flag = hasTex ? src->flag : 0; - dst->frame = hasTex ? src->frame : 0; - dst->tex = hasTex ? getEditorTexture(levelData->textures[src->texId]) : nullptr; - } - - void setNewTexture(EditorSectorTexture* dstTex, EditorTexture* srcTex) - { - dstTex->flag = 0; - dstTex->frame = 0; - dstTex->offsetX = 0.0f; - dstTex->offsetY = 0.0f; - dstTex->tex = srcTex; - } - - // In this case, newSector has the correct textures already assigned. - void addNewSectorFullCopy(const EditorSector& newSector) - { - const size_t sectorCount = s_editorLevel.sectors.size() + 1; - s_editorLevel.sectors.resize(sectorCount); - - EditorSector* dst = s_editorLevel.sectors.data() + (sectorCount - 1); - - dst->id = u32(sectorCount - 1); - dst->objects.clear(); - dst->name[0] = 0; - - dst->ambient = newSector.ambient; - // Floor Texture - dst->floorTexture = newSector.floorTexture; - // Ceiling Texture - dst->ceilTexture = newSector.ceilTexture; - - dst->floorAlt = newSector.floorAlt; - dst->ceilAlt = newSector.ceilAlt; - dst->secAlt = newSector.secAlt; - dst->layer = newSector.layer; - dst->infType = INF_NONE; - dst->flags[0] = newSector.flags[0]; - dst->flags[1] = newSector.flags[1]; - dst->flags[2] = newSector.flags[2]; - - // Dynamically resizable, self-contained geometry data. - dst->walls.resize(newSector.walls.size()); - dst->vertices.resize(newSector.vertices.size()); - - const EditorWall* srcWall = newSector.walls.data(); - const Vec2f* srcVtx = newSector.vertices.data(); - memcpy(dst->vertices.data(), srcVtx, sizeof(Vec2f) * newSector.vertices.size()); - EditorWall* dstWall = dst->walls.data(); - - for (u32 w = 0; w < (u32)newSector.walls.size(); w++, srcWall++, dstWall++) - { - dstWall->mid = newSector.walls[w].mid; - dstWall->top = newSector.walls[w].top; - dstWall->bot = newSector.walls[w].bot; - dstWall->sign = newSector.walls[w].sign; - - dstWall->i0 = srcWall->i0; - dstWall->i1 = srcWall->i1; - dstWall->adjoin = srcWall->adjoin; - dstWall->walk = srcWall->walk; - dstWall->mirror = srcWall->mirror; - dstWall->light = newSector.walls[w].light; - dstWall->infType = newSector.walls[w].infType; - dstWall->infItem = newSector.walls[w].infItem; - dstWall->flags[0] = newSector.walls[w].flags[0]; - dstWall->flags[1] = newSector.walls[w].flags[1]; - dstWall->flags[2] = newSector.walls[w].flags[2]; - dstWall->flags[3] = 0; - } - - // Compute sector bounds - dst->aabb[0] = { srcVtx[0].x, newSector.floorAlt, srcVtx[0].z }; - dst->aabb[1] = { srcVtx[0].x, newSector.ceilAlt, srcVtx[0].z }; - for (u32 v = 1; v < (u32)newSector.vertices.size(); v++) - { - dst->aabb[0].x = std::min(dst->aabb[0].x, newSector.vertices[v].x); - dst->aabb[0].z = std::min(dst->aabb[0].z, newSector.vertices[v].z); - - dst->aabb[1].x = std::max(dst->aabb[1].x, newSector.vertices[v].x); - dst->aabb[1].z = std::max(dst->aabb[1].z, newSector.vertices[v].z); - } - - // Polygon data. - triangulateSector(dst, &dst->triangles); - dst->needsUpdate = false; - } - - void addNewSector(const EditorSector& newSector, EditorTexture* floorTex, EditorTexture* ceilTex, EditorTexture* wallTex) - { - const size_t sectorCount = s_editorLevel.sectors.size() + 1; - s_editorLevel.sectors.resize(sectorCount); - - EditorSector* dst = s_editorLevel.sectors.data() + (sectorCount - 1); - - dst->id = u32(sectorCount - 1); - dst->objects.clear(); - dst->name[0] = 0; - - dst->ambient = newSector.ambient; - // Floor Texture - setNewTexture(&dst->floorTexture, floorTex); - // Ceiling Texture - setNewTexture(&dst->ceilTexture, ceilTex); - - dst->floorAlt = newSector.floorAlt; - dst->ceilAlt = newSector.ceilAlt; - dst->secAlt = 0.0f; - dst->layer = newSector.layer; - dst->infType = INF_NONE; - dst->flags[0] = 0; - dst->flags[1] = 0; - dst->flags[2] = 0; - - // Dynamically resizable, self-contained geometry data. - dst->walls.resize(newSector.walls.size()); - dst->vertices.resize(newSector.vertices.size()); - - const EditorWall* srcWall = newSector.walls.data(); - const Vec2f* srcVtx = newSector.vertices.data(); - memcpy(dst->vertices.data(), srcVtx, sizeof(Vec2f) * newSector.vertices.size()); - EditorWall* dstWall = dst->walls.data(); - - for (u32 w = 0; w < (u32)newSector.walls.size(); w++, srcWall++, dstWall++) - { - setNewTexture(&dstWall->mid, wallTex); - setNewTexture(&dstWall->top, wallTex); - setNewTexture(&dstWall->bot, wallTex); - setNewTexture(&dstWall->sign, nullptr); - - dstWall->i0 = srcWall->i0; - dstWall->i1 = srcWall->i1; - dstWall->adjoin = srcWall->adjoin; - dstWall->walk = srcWall->walk; - dstWall->mirror = srcWall->mirror; - dstWall->light = 0; - dstWall->infType = INF_NONE; - dstWall->flags[0] = 0; - dstWall->flags[1] = 0; - dstWall->flags[2] = 0; - dstWall->flags[3] = 0; - } - - // Compute sector bounds - dst->aabb[0] = { srcVtx[0].x, newSector.floorAlt, srcVtx[0].z }; - dst->aabb[1] = { srcVtx[0].x, newSector.ceilAlt, srcVtx[0].z }; - for (u32 v = 1; v < (u32)newSector.vertices.size(); v++) - { - dst->aabb[0].x = std::min(dst->aabb[0].x, newSector.vertices[v].x); - dst->aabb[0].z = std::min(dst->aabb[0].z, newSector.vertices[v].z); - - dst->aabb[1].x = std::max(dst->aabb[1].x, newSector.vertices[v].x); - dst->aabb[1].z = std::max(dst->aabb[1].z, newSector.vertices[v].z); - } - - // Polygon data. - triangulateSector(dst, &dst->triangles); - dst->needsUpdate = false; - } - - bool convertLevelDataToEditor(const LevelData* levelData, const Palette256* palette, const InfData* infData, const LevelObjectData* objData) - { - if (!levelData) { return false; } - loadTextures(palette); - - const size_t sectorCount = levelData->sectors.size(); - s_editorLevel.sectors.resize(sectorCount); - - s_editorLevel.layerMin = levelData->layerMin; - s_editorLevel.layerMax = levelData->layerMax; - s_editorLevel.name = levelData->name; - s_editorLevel.parallax[0] = levelData->parallax[0]; - s_editorLevel.parallax[1] = levelData->parallax[1]; - - const Sector* src = levelData->sectors.data(); - EditorSector* dst = s_editorLevel.sectors.data(); - for (size_t s = 0; s < sectorCount; s++, src++, dst++) - { - dst->id = u32(s); - dst->objects.clear(); - - if (src->name[0]) { strcpy(dst->name, src->name); } - else { dst->name[0] = 0; } - - dst->ambient = src->ambient; - copyTexture(&dst->floorTexture, &src->floorTexture, levelData); - copyTexture(&dst->ceilTexture, &src->ceilTexture, levelData); - - dst->floorAlt = src->floorAlt; - dst->ceilAlt = src->ceilAlt; - dst->secAlt = src->secAlt; - dst->layer = src->layer; - dst->infType = INF_NONE; - memcpy(dst->flags, src->flags, sizeof(u32) * 3); - - // Dynamically resizable, self-contained geometry data. - dst->walls.resize(src->wallCount); - dst->vertices.resize(src->vtxCount); - - const SectorWall* srcWall = levelData->walls.data() + src->wallOffset; - const Vec2f* srcVtx = levelData->vertices.data() + src->vtxOffset; - memcpy(dst->vertices.data(), srcVtx, sizeof(Vec2f) * src->vtxCount); - EditorWall* dstWall = dst->walls.data(); - - for (u32 w = 0; w < src->wallCount; w++, srcWall++, dstWall++) - { - copyTexture(&dstWall->mid, &srcWall->mid, levelData); - copyTexture(&dstWall->top, &srcWall->top, levelData); - copyTexture(&dstWall->bot, &srcWall->bot, levelData); - copyTexture(&dstWall->sign, &srcWall->sign, levelData); - dstWall->i0 = srcWall->i0; - dstWall->i1 = srcWall->i1; - dstWall->adjoin = srcWall->adjoin; - dstWall->walk = srcWall->walk; - dstWall->mirror = srcWall->mirror; - dstWall->light = srcWall->light; - dstWall->infType = INF_NONE; - memcpy(dstWall->flags, srcWall->flags, sizeof(u32) * 4); - } - - // Compute sector bounds - dst->aabb[0] = { srcVtx[0].x, src->floorAlt, srcVtx[0].z }; - dst->aabb[1] = { srcVtx[0].x, src->ceilAlt, srcVtx[0].z }; - for (u32 v = 1; v < src->vtxCount; v++) - { - dst->aabb[0].x = std::min(dst->aabb[0].x, srcVtx[v].x); - dst->aabb[0].z = std::min(dst->aabb[0].z, srcVtx[v].z); - - dst->aabb[1].x = std::max(dst->aabb[1].x, srcVtx[v].x); - dst->aabb[1].z = std::max(dst->aabb[1].z, srcVtx[v].z); - } - - // Polygon data. - triangulateSector(dst, &dst->triangles); - dst->needsUpdate = false; - } - - convertInfToEditor(infData); - convertObjectsToEditor(objData); - - // Go through the sectors and walls and assign INF items. - dst = s_editorLevel.sectors.data(); - for (size_t s = 0; s < sectorCount; s++, src++, dst++) - { - dst->infItem = findInfItem(dst, -1); - - const s32 wallCount = (s32)dst->walls.size(); - for (s32 w = 0; w < wallCount; w++) - { - dst->walls[w].infItem = findInfItem(dst, w); - } - } - determineSectorTypes(); - - return true; - } - - void updateSectors() - { - const size_t sectorCount = s_editorLevel.sectors.size(); - EditorSector* sector = s_editorLevel.sectors.data(); - for (size_t s = 0; s < sectorCount; s++, sector++) - { - if (sector->needsUpdate) - { - sector->triangles.count = 0; - sector->triangles.vtx.clear(); - - triangulateSector(sector, §or->triangles); - sector->needsUpdate = false; - } - } - } - - s32 loadRuntimeTexture(const char* name, LevelData* output) - { - // is it already in the list? - const size_t texCount = output->textures.size(); - Texture** textures = output->textures.data(); - for (size_t t = 0; t < texCount; t++) - { - if (strcasecmp(name, textures[t]->name) == 0) - { - return s32(t); - } - } - - s32 texId = -1; - Texture* tex = TFE_Texture::get(name); - if (tex) - { - texId = (s32)texCount; - output->textures.push_back(tex); - } - return texId; - } - - void copyTexture(SectorTexture* dst, const EditorSectorTexture* src, LevelData* output) - { - const bool hasTex = src->tex; - - dst->offsetX = hasTex ? src->offsetX : 0; - dst->offsetY = hasTex ? src->offsetY : 0; - dst->baseOffsetX = dst->offsetX; - dst->baseOffsetY = dst->offsetY; - dst->flag = hasTex ? src->flag : 0; - dst->frame = hasTex ? src->frame : 0; - - dst->texId = -1; - if (hasTex) - { - dst->texId = loadRuntimeTexture(src->tex->name, output); - } - } - - bool generateLevelData() - { - if (s_editorLevel.sectors.empty()) - { - return false; - } - - // Unload the level asset once it has been converted. - TFE_LevelAsset::unload(); - LevelData* output = TFE_LevelAsset::getLevelData(); - output->textures.clear(); - output->layerMin = s_editorLevel.layerMin; - output->layerMax = s_editorLevel.layerMax; - strcpy(output->name, s_editorLevel.name.c_str()); - output->parallax[0] = s_editorLevel.parallax[0]; - output->parallax[1] = s_editorLevel.parallax[1]; - - const u32 sectorCount = (u32)s_editorLevel.sectors.size(); - output->sectors.resize(sectorCount); - // Get the total wall and vertex counts. - u32 vertexCount = 0; - u32 wallCount = 0; - const EditorSector* srcSector = s_editorLevel.sectors.data(); - Sector* dstSector = output->sectors.data(); - for (u32 s = 0; s < sectorCount; s++, srcSector++, dstSector++) - { - dstSector->vtxOffset = vertexCount; - dstSector->wallOffset = wallCount; - dstSector->vtxCount = (u32)srcSector->vertices.size(); - dstSector->wallCount = (u32)srcSector->walls.size(); - - vertexCount += dstSector->vtxCount; - wallCount += dstSector->wallCount; - - dstSector->ambient = srcSector->ambient; - dstSector->floorAlt = srcSector->floorAlt; - dstSector->ceilAlt = srcSector->ceilAlt; - dstSector->secAlt = srcSector->secAlt; - dstSector->layer = srcSector->layer; - dstSector->id = srcSector->id; - strcpy(dstSector->name, srcSector->name); - memcpy(dstSector->flags, srcSector->flags, sizeof(u32) * 3); - - copyTexture(&dstSector->floorTexture, &srcSector->floorTexture, output); - copyTexture(&dstSector->ceilTexture, &srcSector->ceilTexture, output); - } - - output->vertices.resize(vertexCount); - output->walls.resize(wallCount); - srcSector = s_editorLevel.sectors.data(); - dstSector = output->sectors.data(); - for (u32 s = 0; s < sectorCount; s++, srcSector++, dstSector++) - { - Vec2f* outVtx = output->vertices.data() + dstSector->vtxOffset; - memcpy(outVtx, srcSector->vertices.data(), dstSector->vtxCount * sizeof(Vec2f)); - - const EditorWall* srcWall = srcSector->walls.data(); - SectorWall* outWall = output->walls.data() + dstSector->wallOffset; - for (u32 w = 0; w < dstSector->wallCount; w++, srcWall++, outWall++) - { - outWall->i0 = srcWall->i0; - outWall->i1 = srcWall->i1; - outWall->adjoin = srcWall->adjoin; - outWall->walk = srcWall->walk; - outWall->mirror = srcWall->mirror; - outWall->light = srcWall->light; - memcpy(outWall->flags, srcWall->flags, sizeof(u32) * 4); - - copyTexture(&outWall->mid, &srcWall->mid, output); - copyTexture(&outWall->top, &srcWall->top, output); - copyTexture(&outWall->bot, &srcWall->bot, output); - copyTexture(&outWall->sign, &srcWall->sign, output); - } - } - - // Convert editor level data to runtime level data. - return true; - } - - u32 getObjectDataOffset(const char* dataFile, ObjectClass oclass, LevelObjectData* output) - { - u32 dataOffset = 0u; - if (oclass == CLASS_SPRITE) - { - const u32 count = (u32)output->sprites.size(); - for (u32 i = 0; i < count; i++) - { - if (strcasecmp(output->sprites[i].c_str(), dataFile) == 0) - { - return i; - } - } - dataOffset = (u32)output->sprites.size(); - output->sprites.push_back(dataFile); - } - else if (oclass == CLASS_FRAME) - { - const u32 count = (u32)output->frames.size(); - for (u32 i = 0; i < count; i++) - { - if (strcasecmp(output->frames[i].c_str(), dataFile) == 0) - { - return i; - } - } - dataOffset = (u32)output->frames.size(); - output->frames.push_back(dataFile); - } - else if (oclass == CLASS_3D) - { - const u32 count = (u32)output->pods.size(); - for (u32 i = 0; i < count; i++) - { - if (strcasecmp(output->pods[i].c_str(), dataFile) == 0) - { - return i; - } - } - dataOffset = (u32)output->pods.size(); - output->pods.push_back(dataFile); - } - else if (oclass == CLASS_SOUND) - { - const u32 count = (u32)output->sounds.size(); - for (u32 i = 0; i < count; i++) - { - if (strcasecmp(output->sounds[i].c_str(), dataFile) == 0) - { - return i; - } - } - dataOffset = (u32)output->sounds.size(); - output->sounds.push_back(dataFile); - } - - return dataOffset; - } - - bool generateObjects() - { - TFE_LevelObjects::unload(); - LevelObjectData* output = TFE_LevelObjects::getLevelObjectData(); - - u32 objCount = 0; - const u32 sectorCount = (u32)s_editorLevel.sectors.size(); - const EditorSector* sector = s_editorLevel.sectors.data(); - for (u32 s = 0; s < sectorCount; s++, sector++) - { - objCount += (u32)sector->objects.size(); - } - - output->objects.resize(objCount); - output->objectCount = objCount; - - sector = s_editorLevel.sectors.data(); - LevelObject* dstObj = output->objects.data(); - for (u32 s = 0; s < sectorCount; s++, sector++) - { - const u32 objCount = (u32)sector->objects.size(); - const EditorLevelObject* srcObj = sector->objects.data(); - for (u32 i = 0; i < objCount; i++, srcObj++, dstObj++) - { - dstObj->dataOffset = getObjectDataOffset(srcObj->dataFile.c_str(), srcObj->oclass, output); - - dstObj->oclass = srcObj->oclass; - dstObj->pos = srcObj->pos; - dstObj->orientation = srcObj->orientation; - dstObj->difficulty = srcObj->difficulty; - dstObj->logics = srcObj->logics; - dstObj->generators = srcObj->generators; - - dstObj->comFlags = srcObj->comFlags; - dstObj->radius = srcObj->radius; - dstObj->height = srcObj->height; - } - } - - return true; - } - - bool generateInfAsset() - { - if (s_editorInf.item.empty()) { return false; } - // Clear the INF data and initialize the memory pool. - TFE_InfAsset::unload(); - InfData* output = TFE_InfAsset::getInfData(); - MemoryPool* memoryPool = TFE_InfAsset::getMemoryPool(true); - - output->itemCount = (u32)s_editorInf.item.size(); - output->completeId = -1; - - const u32 secFlagDoorCount = TFE_InfAsset::countSectorFlagDoors(); - output->item = (InfItem*)memoryPool->allocate(sizeof(InfItem) * (output->itemCount + secFlagDoorCount)); - - InfItem* dstItem = output->item; - const EditorInfItem* srcItem = s_editorInf.item.data(); - for (u32 i = 0; i < output->itemCount; i++, srcItem++, dstItem++) - { - if (srcItem->sectorName.empty()) - { - dstItem->id = 0xffffu; - } - else - { - dstItem->id = getSector(srcItem->sectorName.c_str())->id; - } - - if (strcasecmp(srcItem->sectorName.c_str(), "complete") == 0) - { - output->completeId = i; - } - - if (srcItem->wallId >= 0) - { - dstItem->id |= (srcItem->wallId << 16u); - } - else - { - dstItem->id |= (0xffffu << 16u); - } - - dstItem->type = srcItem->type; - dstItem->classCount = (u32)srcItem->classData.size(); - dstItem->classData = (InfClassData*)memoryPool->allocate(sizeof(InfClassData) * dstItem->classCount); - - InfClassData* dstClass = dstItem->classData; - const EditorInfClassData* srcClass = srcItem->classData.data(); - for (u32 c = 0; c < dstItem->classCount; c++, srcClass++, dstClass++) - { - dstClass->iclass = srcClass->iclass; - dstClass->isubclass = srcClass->isubclass; - dstClass->stateIndex = 0; - - //Variables. - dstClass->var.master = srcClass->var.master; - dstClass->var.event = srcClass->var.event; - dstClass->var.start = srcClass->var.start; - dstClass->var.event_mask = srcClass->var.event_mask; - dstClass->var.entity_mask = srcClass->var.entity_mask; - dstClass->var.key = srcClass->var.key; - dstClass->var.flags = srcClass->var.flags; - dstClass->var.center = srcClass->var.center; - dstClass->var.angle = srcClass->var.angle; - dstClass->var.speed = srcClass->var.speed; - for (u32 s = 0; s < 3; s++) - { - dstClass->var.sound[s] = srcClass->var.sound[s]; - } - dstClass->var.target = srcClass->var.target != "" ? getSector(srcClass->var.target.c_str())->id : -1; - - //Stops. - dstClass->stopCount = (u32)srcClass->stop.size(); - dstClass->stop = (InfStop*)memoryPool->allocate(sizeof(InfStop) * dstClass->stopCount); - InfStop* dstStop = dstClass->stop; - const EditorInfStop* srcStop = srcClass->stop.data(); - for (u32 s = 0; s < dstClass->stopCount; s++, srcStop++, dstStop++) - { - const u32 funcCount = (u32)srcStop->func.size(); - dstStop->code = srcStop->stopValue0Type | (srcStop->stopValue1Type << 4u) | (funcCount << 8u); - dstStop->time = srcStop->time; - - if (srcStop->stopValue0Type == INF_STOP0_SECTORNAME) - { - dstStop->value0.iValue = getSector(srcStop->value0.sValue.c_str())->id; - } - else - { - dstStop->value0.fValue = srcStop->value0.fValue; - } - - dstStop->func = (InfFunction*)memoryPool->allocate(sizeof(InfFunction) * funcCount); - InfFunction* dstFunc = dstStop->func; - const EditorInfFunction* srcFunc = srcStop->func.data(); - for (u32 f = 0; f < funcCount; f++, srcFunc++, dstFunc++) - { - const u32 clientCount = (u32)srcFunc->client.size(); - const u32 argCount = (u32)srcFunc->arg.size(); - dstFunc->code = srcFunc->funcId | (clientCount << 8u) | (argCount << 16u); - - dstFunc->client = (u32*)memoryPool->allocate(sizeof(u32) * clientCount); - dstFunc->arg = (InfArg*)memoryPool->allocate(sizeof(InfArg) * argCount); - for (u32 j = 0; j < clientCount; j++) - { - const u32 sectorId = srcFunc->client[j].sectorName != "" ? getSector(srcFunc->client[j].sectorName.c_str())->id : 0xffffu; - const u32 wallId = srcFunc->client[j].wallId >= 0 ? (u32)srcFunc->client[j].wallId : 0xffffu; - dstFunc->client[j] = sectorId | (wallId << 16u); - } - - if (srcFunc->funcId < INF_MSG_LIGHTS) - { - for (u32 j = 0; j < argCount; j++) - { - dstFunc->arg[j].iValue = srcFunc->arg[j].iValue; - } - } - else if (srcFunc->funcId == INF_MSG_ADJOIN) - { - dstFunc->arg[0].iValue = getSector(srcFunc->arg[0].sValue.c_str())->id; - dstFunc->arg[1].iValue = srcFunc->arg[1].iValue; - dstFunc->arg[2].iValue = getSector(srcFunc->arg[2].sValue.c_str())->id; - dstFunc->arg[3].iValue = srcFunc->arg[3].iValue; - } - else if (srcFunc->funcId == INF_MSG_PAGE) - { - // TODO: This is wrong, fix me. - dstFunc->arg[0].iValue = srcFunc->arg[0].iValue; - } - else if (srcFunc->funcId == INF_MSG_TEXT) - { - dstFunc->arg[0].iValue = srcFunc->arg[0].iValue; - } - else if (srcFunc->funcId == INF_MSG_TEXTURE) - { - dstFunc->arg[0].iValue = srcFunc->arg[0].iValue; - dstFunc->arg[1].iValue = getSector(srcFunc->arg[1].sValue.c_str())->id; - } - } - } - - //Slaves. - dstClass->mergeStart = -1; - dstClass->slaveCount = 0; - dstClass->slaves = nullptr; - - if (dstItem->type == INF_ITEM_SECTOR) - { - // Search for all sectors with the same name as the current but different ids. - // These will be added to the slaves at the "merge sectors" position. - std::vector mergeSectors; - const u32 sectorCount = (u32)s_editorLevel.sectors.size(); - const EditorSector* sector = s_editorLevel.sectors.data(); - const char* name = srcItem->sectorName.c_str(); - const u32 curSectorId = dstItem->id & 0xffffu; - if (name[0]) - { - for (u32 s = 0; s < sectorCount; s++, sector++) - { - if (sector->name[0] && strcasecmp(name, sector->name) == 0 && sector->id != curSectorId) - { - mergeSectors.push_back(s); - } - } - } - - if (!mergeSectors.empty()) - { - dstClass->mergeStart = (s32)srcClass->slaves.size(); - } - - dstClass->slaveCount = u32(srcClass->slaves.size() + mergeSectors.size()); - dstClass->slaves = (u16*)memoryPool->allocate(sizeof(u16)*dstClass->slaveCount); - - for (u32 s = 0; s < srcClass->slaves.size(); s++) - { - dstClass->slaves[s] = getSector(srcClass->slaves[s].c_str())->id; - } - for (u32 s = 0; s < mergeSectors.size(); s++) - { - dstClass->slaves[s + dstClass->mergeStart] = mergeSectors[s]; - } - } - } - } - TFE_InfAsset::setupDoors(); - - return true; - } - - EditorLevel* getEditorLevelData() - { - return &s_editorLevel; - } - - EditorInfItem* findInfItem(const EditorSector* sector, s32 wall) - { - if (sector->name[0] == 0) { return nullptr; } - - // This sector may have the same name as another... - // For INF, we take only the first name in the list. - const size_t sectorCount = s_editorLevel.sectors.size(); - const EditorSector* testSector = s_editorLevel.sectors.data(); - for (size_t s = 0; s < sectorCount; s++, testSector++) - { - if (strcasecmp(testSector->name, sector->name) == 0 && sector->id > testSector->id) - { - return nullptr; - } - } - - // Once that is resolved, look for a matching INF item. - const size_t count = s_editorInf.item.size(); - EditorInfItem* item = s_editorInf.item.data(); - for (u32 i = 0; i < count; i++, item++) - { - if (strcasecmp(item->sectorName.c_str(), sector->name) == 0 && item->wallId == wall) - { - return item; - } - } - return nullptr; - } - - InfEditState* getInfEditState() - { - return &s_infEditState; - } - - void determineSectorTypes() - { - const u32 sectorCount = (u32)s_editorLevel.sectors.size(); - EditorSector* sector = s_editorLevel.sectors.data(); - for (u32 s = 0; s < sectorCount; s++, sector++) - { - sector->infType = INF_NONE; - const EditorInfItem* sectorItem = sector->infItem; - if (sectorItem) - { - // Check to see if there are any messages or stops. - sector->infType = INF_SELF; - for (u32 c = 0; c < (u32)sectorItem->classData.size(); c++) - { - if (!sectorItem->classData[c].stop.empty()) - { - sector->infType = INF_OTHER; - break; - } - } - } - if (sector->flags[0] & SEC_FLAGS1_DOOR) - { - sector->infType = INF_OTHER; - } - - const u32 wallCount = (u32)sector->walls.size(); - EditorWall* wall = sector->walls.data(); - for (u32 w = 0; w < wallCount; w++, wall++) - { - EditorInfItem* wallItem = wall->infItem; - if (wallItem) - { - wall->infType = INF_OTHER; - wall->triggerType = wallItem->classData[0].isubclass < TRIGGER_SWITCH1 ? TRIGGER_LINE : TRIGGER_SWITCH; - } - else - { - wall->infType = INF_NONE; - } - } - } - } - - // Pre-triangulate sectors and modify as need during editing. - void triangulateSector(const EditorSector* sector, SectorTriangles* outTri) - { - const u32 wallCount = (u32)sector->walls.size(); - const Vec2f* vtx = sector->vertices.data(); - - // TODO: Fuel Station sectors 376, 377 and 388 have strange contours that are specified out of order. - // This causes the resulting polygons to be incorrect. - - // Find the contours. - static Polygon contours[128]; - const EditorWall* wall = sector->walls.data(); - u32 start = wall->i0; - u32 contourCount = 0; - Polygon* curCon = &contours[contourCount]; - curCon->vtxCount = 0; - contourCount++; - - for (u32 w = 0; w < wallCount; w++, wall++) - { - // Keep going until i1 == start - curCon->vtx[curCon->vtxCount++] = vtx[wall->i0]; - if (wall->i1 == start) - { - if (w < wallCount - 1) - { - start = (wall + 1)->i0; - curCon = &contours[contourCount]; - curCon->vtxCount = 0; - contourCount++; - } - } - } - - u32 triCount = 0; - Triangle* triangle = TFE_Polygon::decomposeComplexPolygon(contourCount, contours, &triCount); - if (!triangle || triCount == 0) { return; } - - // Count the number of triangles - outTri->count = triCount; - outTri->vtx.resize(triCount * 3); - - u32 tIdx = 0; - for (u32 p = 0; p < triCount; p++, triangle++) - { - outTri->vtx[p * 3 + 0] = triangle->vtx[0]; - outTri->vtx[p * 3 + 1] = triangle->vtx[1]; - outTri->vtx[p * 3 + 2] = triangle->vtx[2]; - } - } - - EditorSector* getSector(const char* name) - { - if (s_editorLevel.sectors.empty()) { return nullptr; } - - const s32 sectorCount = (s32)s_editorLevel.sectors.size(); - EditorSector* sector = s_editorLevel.sectors.data(); - - for (s32 i = 0; i < sectorCount; i++, sector++) - { - if (strcasecmp(sector->name, name) == 0) - { - return sector; - } - } - return nullptr; - } - - s32 findSector(s32 layer, const Vec2f* pos) - { - if (s_editorLevel.sectors.empty()) { return -1; } - - const s32 sectorCount = (s32)s_editorLevel.sectors.size(); - const EditorSector* sectors = s_editorLevel.sectors.data(); - - for (s32 i = 0; i < sectorCount; i++) - { - if (sectors[i].layer != layer) { continue; } - if (Geometry::pointInSector(pos, (u32)sectors[i].vertices.size(), sectors[i].vertices.data(), (u32)sectors[i].walls.size(), (u8*)sectors[i].walls.data(), sizeof(EditorWall))) - { - return i; - } - } - return -1; - } - - #define HEIGHT_EPS 0.5f - - s32 findSector(const Vec3f* pos) - { - const s32 sectorCount = (s32)s_editorLevel.sectors.size(); - const EditorSector* sectors = s_editorLevel.sectors.data(); - - const Vec2f mapPos = { pos->x, pos->z }; - s32 insideCount = 0; - s32 insideIndices[256]; - - // sometimes objects can be in multiple valid sectors, so pick the best one. - for (s32 i = 0; i < sectorCount; i++) - { - if (Geometry::pointInSector(&mapPos, (u32)sectors[i].vertices.size(), sectors[i].vertices.data(), (u32)sectors[i].walls.size(), (u8*)sectors[i].walls.data(), sizeof(EditorWall))) - { - assert(insideCount < 256); - insideIndices[insideCount++] = i; - } - } - // if the object isn't inside a sector than return. - if (!insideCount) { return -1; } - - // First see if its actually inside any sectors based on height. - // If so, pick the sector where it is closest to the floor. - f32 minHeightDiff = FLT_MAX; - s32 closestFit = -1; - for (s32 i = 0; i < insideCount; i++) - { - const EditorSector* sector = §ors[insideIndices[i]]; - if (pos->y >= sector->ceilAlt - HEIGHT_EPS && pos->y <= sector->floorAlt + HEIGHT_EPS) - { - f32 diff = fabsf(pos->y - sector->floorAlt); - if (diff < minHeightDiff) - { - minHeightDiff = diff; - closestFit = insideIndices[i]; - } - } - } - if (closestFit >= 0) - { - return closestFit; - } - - // If no valid height range is found, just pick whatever is closest and hope for the best. - for (s32 i = 0; i < insideCount; i++) - { - const EditorSector* sector = §ors[insideIndices[i]]; - const f32 diff = fabsf(pos->y - sector->floorAlt); - if (diff < minHeightDiff) - { - minHeightDiff = diff; - closestFit = insideIndices[i]; - } - } - - //assert(0); - return closestFit; - } - - s32 findClosestWallInSector(const EditorSector* sector, const Vec2f* pos, f32 maxDistSq, f32* minDistToWallSq) - { - const u32 count = (u32)sector->walls.size(); - f32 minDistSq = FLT_MAX; - s32 closestId = -1; - const EditorWall* walls = sector->walls.data(); - const Vec2f* vertices = sector->vertices.data(); - for (u32 w = 0; w < count; w++) - { - const Vec2f* v0 = &vertices[walls[w].i0]; - const Vec2f* v1 = &vertices[walls[w].i1]; - - Vec2f pointOnSeg; - Geometry::closestPointOnLineSegment(*v0, *v1, *pos, &pointOnSeg); - const Vec2f diff = { pointOnSeg.x - pos->x, pointOnSeg.z - pos->z }; - const f32 distSq = diff.x*diff.x + diff.z*diff.z; - - if (distSq < maxDistSq && distSq < minDistSq && (!minDistToWallSq || distSq < *minDistToWallSq)) - { - minDistSq = distSq; - closestId = s32(w); - } - } - if (minDistToWallSq) - { - *minDistToWallSq = std::min(*minDistToWallSq, minDistSq); - } - return closestId; - } - - // Find the closest wall to 'pos' that lies within sector 'sectorId' - // Only accept walls within 'maxDist' and in sectors on layer 'layer' - // Pass -1 to sectorId to choose any sector on the layer, sectorId will be set to the sector. - s32 findClosestWall(s32* sectorId, s32 layer, const Vec2f* pos, f32 maxDist) - { - assert(sectorId && pos); - const f32 maxDistSq = maxDist * maxDist; - if (*sectorId >= 0) - { - return findClosestWallInSector(&s_editorLevel.sectors[*sectorId], pos, maxDistSq, nullptr); - } - - const s32 sectorCount = (s32)s_editorLevel.sectors.size(); - const EditorSector* sectors = s_editorLevel.sectors.data(); - - f32 minDistSq = FLT_MAX; - s32 closestId = -1; - for (s32 i = 0; i < sectorCount; i++) - { - if (sectors[i].layer != layer) { continue; } - const s32 id = findClosestWallInSector(§ors[i], pos, maxDistSq, &minDistSq); - if (id >= 0) { *sectorId = i; closestId = id; } - } - - return closestId; - } - - f32 rayAabbIntersect(const Vec3f* aabb, const Vec3f* rayInv, const Vec3f* rayOrigin) - { - const Vec3f t0 = { (aabb[0].x - rayOrigin->x) * rayInv->x, (aabb[0].y - rayOrigin->y) * rayInv->y, (aabb[0].z - rayOrigin->z) * rayInv->z }; - const Vec3f t1 = { (aabb[1].x - rayOrigin->x) * rayInv->x, (aabb[1].y - rayOrigin->y) * rayInv->y, (aabb[1].z - rayOrigin->z) * rayInv->z }; - - f32 tMin = std::min(t0.x, t1.x); - tMin = std::max(tMin, std::min(t0.y, t1.y)); - tMin = std::max(tMin, std::min(t0.z, t1.z)); - - f32 tMax = std::max(t0.x, t1.x); - tMax = std::min(tMax, std::max(t0.y, t1.y)); - tMax = std::min(tMax, std::max(t0.z, t1.z)); - if (tMax < tMin) { return -1.0f; } - - return tMin >= 0.0f ? tMin : tMax; - } - - // Traces a ray from outside the level. - // The ray needs to ignore backfaces and report the first face/sector hit and position. - bool traceRay(const Ray* ray, RayHitInfoLE* hitInfo) - { - if (s_editorLevel.sectors.empty()) { return false; } - - // start with a naive test. - const s32 sectorCount = (s32)s_editorLevel.sectors.size(); - const EditorSector* sector = s_editorLevel.sectors.data(); - - f32 maxDist = ray->maxDist; - Vec3f origin = ray->origin; - Vec2f p0xz = { origin.x, origin.z }; - Vec2f p1xz = { p0xz.x + ray->dir.x * maxDist, p0xz.z + ray->dir.z * maxDist }; - Vec2f dirxz = { ray->dir.x, ray->dir.z }; - - f32 overallClosestHit = FLT_MAX; - hitInfo->hitSectorId = -1; - hitInfo->hitWallId = -1; - hitInfo->hitPart = HIT_PART_MID; // 0 = mid, 1 = lower, 2 = upper OR 0 = floor, 1 = ceiling - hitInfo->hitPoint = { 0 }; - hitInfo->hitObjectId = -1; - - // TODO: Compute bounds for each sector and test ray vs. bounds before testing against the walls and planes. - // See reference: https://github.com/erich666/GraphicsGems/blob/master/gems/RayBox.c - // 1. Keep an AABB for each sector (3d) - // 2. pick 3 candidate planes from the ray direction. - // For each sector: - // 1. compute plane intersections (if they exist) if (dir[i] != 0.0) { (plane[i] - origin[i])/dir[i] } - // 2. find the maximum intersection. - // 3. check to see if the intersection is actually inside the box. - // Note if selecting entities, all of them in a sector can be added if the ray hits the box. - for (s32 s = 0; s < sectorCount; s++, sector++) - { - if (sector->layer != ray->layer && ray->layer > -256) { continue; } - - const u32 wallCount = (u32)sector->walls.size(); - const EditorWall* wall = sector->walls.data(); - const Vec2f* vtx = sector->vertices.data(); - - // Check the ray against all of the walls and take the closest hit, if any. - f32 closestHit = FLT_MAX; - s32 closestWallId = -1; - for (u32 w = 0; w < wallCount; w++, wall++) - { - const s32 i0 = wall->i0; - const s32 i1 = wall->i1; - const Vec2f* v0 = &vtx[i0]; - const Vec2f* v1 = &vtx[i1]; - - // Is the wall backfacing? - Vec2f nrm = { -(v1->z - v0->z), v1->x - v0->x }; - if (TFE_Math::dot(&dirxz, &nrm) < 0.0f) { continue; } - - f32 s, t; - if (Geometry::lineSegmentIntersect(&p0xz, &p1xz, v0, v1, &s, &t)) - { - if (s < closestHit) - { - // Make sure it isn't "above" the ray. - const f32 yAtHit = origin.y + ray->dir.y * s * maxDist; - if (yAtHit < sector->floorAlt + FLT_EPSILON && yAtHit > sector->ceilAlt - FLT_EPSILON) - { - // If this is an adjoin, make sure he shouldn't just keep going... - bool canHit = true; - if (wall->adjoin >= 0) - { - const EditorSector* next = &s_editorLevel.sectors[wall->adjoin]; - canHit = (yAtHit >= next->floorAlt) || (yAtHit <= next->ceilAlt) || (wall->flags[0] & WF1_ADJ_MID_TEX); - } - if (canHit) - { - closestHit = s; - closestWallId = w; - } - } - } - } - } - - wall = sector->walls.data(); - - // Test the closest wall. - if (closestWallId >= 0) - { - closestHit *= maxDist; - const Vec3f hitPoint = { origin.x + ray->dir.x*closestHit, origin.y + ray->dir.y*closestHit, origin.z + ray->dir.z*closestHit }; - - if (wall[closestWallId].adjoin >= 0) - { - // given the hit point, is it below the next floor or above the next ceiling? - const EditorSector* next = &s_editorLevel.sectors[wall[closestWallId].adjoin]; - if ((hitPoint.y >= next->floorAlt || hitPoint.y <= next->ceilAlt) && closestHit < overallClosestHit) - { - overallClosestHit = closestHit; - hitInfo->hitSectorId = s; - hitInfo->hitWallId = closestWallId; - hitInfo->hitPart = hitPoint.y >= next->floorAlt ? HIT_PART_BOT : HIT_PART_TOP; - hitInfo->hitPoint = hitPoint; - } - else if ((wall[closestWallId].flags[0] & WF1_ADJ_MID_TEX) && closestHit < overallClosestHit) - { - overallClosestHit = closestHit; - hitInfo->hitSectorId = s; - hitInfo->hitWallId = closestWallId; - hitInfo->hitPart = HIT_PART_MID; - hitInfo->hitPoint = hitPoint; - } - } - else if (closestHit < overallClosestHit) - { - overallClosestHit = closestHit; - hitInfo->hitSectorId = s; - hitInfo->hitWallId = closestWallId; - hitInfo->hitPart = HIT_PART_MID; - hitInfo->hitPoint = hitPoint; - } - } - - // Test the floor and ceiling planes. - const Vec3f planeTest = { origin.x + ray->dir.x*maxDist, origin.y + ray->dir.y*maxDist, origin.z + ray->dir.z*maxDist }; - Vec3f hitPoint; - if (origin.y < sector->floorAlt && ray->dir.y > 0.0f && Geometry::lineYPlaneIntersect(&origin, &planeTest, sector->floorAlt, &hitPoint)) - { - const Vec3f diff = { hitPoint.x - origin.x, hitPoint.y - origin.y, hitPoint.z - origin.z }; - const f32 distSq = TFE_Math::dot(&diff, &diff); - if (overallClosestHit == FLT_MAX || distSq < overallClosestHit*overallClosestHit) - { - // The ray hit the plane but is the intersect point actually inside the sector? - const Vec2f testPt = { hitPoint.x, hitPoint.z }; - if (Geometry::pointInSector(&testPt, (u32)sector->vertices.size(), vtx, wallCount, (u8*)wall, sizeof(EditorWall))) - { - overallClosestHit = sqrtf(distSq); - hitInfo->hitSectorId = s; - hitInfo->hitWallId = -1; - hitInfo->hitPart = HIT_PART_FLOOR; - hitInfo->hitPoint = hitPoint; - } - } - } - if (origin.y > sector->ceilAlt && ray->dir.y < 0.0f && Geometry::lineYPlaneIntersect(&origin, &planeTest, sector->ceilAlt, &hitPoint)) - { - const Vec3f diff = { hitPoint.x - origin.x, hitPoint.y - origin.y, hitPoint.z - origin.z }; - const f32 distSq = TFE_Math::dot(&diff, &diff); - if (overallClosestHit == FLT_MAX || distSq < overallClosestHit*overallClosestHit) - { - // The ray hit the plane but is the intersect point actually inside the sector? - const Vec2f testPt = { hitPoint.x, hitPoint.z }; - if (Geometry::pointInSector(&testPt, (u32)sector->vertices.size(), vtx, wallCount, (u8*)wall, sizeof(EditorWall))) - { - overallClosestHit = sqrtf(distSq); - hitInfo->hitSectorId = s; - hitInfo->hitWallId = -1; - hitInfo->hitPart = HIT_PART_CEIL; - hitInfo->hitPoint = hitPoint; - } - } - } - } - - // Hit objects. - if (ray->objSelect) - { - const Vec3f rayInv = { 1.0f/ray->dir.x, 1.0f/ray->dir.y, 1.0f/ray->dir.z }; - f32 hitDist = (hitInfo->hitSectorId >= 0) ? TFE_Math::distance(&ray->origin, &hitInfo->hitPoint) : ray->maxDist; - - sector = s_editorLevel.sectors.data(); - for (s32 s = 0; s < sectorCount; s++, sector++) - { - if (sector->layer != ray->layer && ray->layer > -256) { continue; } - const size_t objCount = sector->objects.size(); - if (!objCount) { continue; } - - const EditorLevelObject* obj = sector->objects.data(); - for (size_t o = 0; o < objCount; o++, obj++) - { - if (obj->oclass != CLASS_3D) - { - // Test ray against AABB. - const Vec3f aabb[] = { {obj->worldCen.x - obj->worldExt.x, obj->worldCen.y - obj->worldExt.y, obj->worldCen.z - obj->worldExt.z}, - {obj->worldCen.x + obj->worldExt.x, obj->worldCen.y + obj->worldExt.y, obj->worldCen.z + obj->worldExt.z} }; - const f32 i = rayAabbIntersect(aabb, &rayInv, &ray->origin); - if (i > 0.0f && i < hitDist) - { - hitDist = i; - hitInfo->hitSectorId = s; - hitInfo->hitObjectId = s32(o); - hitInfo->hitWallId = -1; - hitInfo->hitPoint = {ray->origin.x + ray->dir.x*i, ray->origin.y + ray->dir.y*i, ray->origin.z + ray->dir.z*i }; - } - } - else - { - // Transform the ray into object space and test against the local AABB. - // This is the same as intersecting the ray with the OOBB in world space. - const Vec3f* mat33 = obj->rotMtxT.m; - Vec3f newDir; - newDir.x = ray->dir.x*mat33[0].x + ray->dir.y*mat33[0].y + ray->dir.z*mat33[0].z; - newDir.y = ray->dir.x*mat33[1].x + ray->dir.y*mat33[1].y + ray->dir.z*mat33[1].z; - newDir.z = ray->dir.x*mat33[2].x + ray->dir.y*mat33[2].y + ray->dir.z*mat33[2].z; - - const Vec3f relRayOrigin = { ray->origin.x - obj->pos.x, ray->origin.y - obj->pos.y, ray->origin.z - obj->pos.z }; - Vec3f localRayOrigin; - localRayOrigin.x = relRayOrigin.x*mat33[0].x + relRayOrigin.y*mat33[0].y + relRayOrigin.z*mat33[0].z; - localRayOrigin.y = relRayOrigin.x*mat33[1].x + relRayOrigin.y*mat33[1].y + relRayOrigin.z*mat33[1].z; - localRayOrigin.z = relRayOrigin.x*mat33[2].x + relRayOrigin.y*mat33[2].y + relRayOrigin.z*mat33[2].z; - - const Vec3f newRayInv = { 1.0f / newDir.x, 1.0f / newDir.y, 1.0f / newDir.z }; - const f32 i = rayAabbIntersect(obj->displayModel->localAabb, &newRayInv, &localRayOrigin); - if (i > 0.0f && i < hitDist) - { - hitDist = i; - hitInfo->hitSectorId = s; - hitInfo->hitObjectId = s32(o); - hitInfo->hitWallId = -1; - hitInfo->hitPoint = { ray->origin.x + ray->dir.x*i, ray->origin.y + ray->dir.y*i, ray->origin.z + ray->dir.z*i }; - } - } - } - } - } - - return hitInfo->hitSectorId >= 0; - } - - void convertObjectsToEditor(const LevelObjectData* objData) - { - const u32 count = objData->objectCount; - const LevelObject* srcObj = objData->objects.data(); - for (u32 i = 0; i < objData->objectCount; i++, srcObj++) - { - // For each object, find the parent sector. - const s32 sectorId = findSector(&srcObj->pos); - if (sectorId >= 0) - { - s_editorLevel.sectors[sectorId].objects.push_back({}); - - EditorLevelObject& dstObj = s_editorLevel.sectors[sectorId].objects.back(); - dstObj.oclass = srcObj->oclass; - dstObj.pos = srcObj->pos; - dstObj.orientation = srcObj->orientation; - dstObj.difficulty = srcObj->difficulty; - dstObj.logics = srcObj->logics; - dstObj.generators = srcObj->generators; - - dstObj.comFlags = srcObj->comFlags; - dstObj.radius = srcObj->radius; - dstObj.height = srcObj->height; - - if (srcObj->oclass == CLASS_SPRITE) - { - dstObj.dataFile = objData->sprites[srcObj->dataOffset]; - } - else if (srcObj->oclass == CLASS_FRAME) - { - dstObj.dataFile = objData->frames[srcObj->dataOffset]; - } - else if (srcObj->oclass == CLASS_3D) - { - dstObj.dataFile = objData->pods[srcObj->dataOffset]; - } - else if (srcObj->oclass == CLASS_SOUND) - { - dstObj.dataFile = objData->sounds[srcObj->dataOffset]; - } - else - { - dstObj.dataFile.clear(); - } - - dstObj.display = nullptr; - dstObj.displayModel = nullptr; - - if (srcObj->oclass == CLASS_3D) - { - dstObj.displayModel = TFE_Model::get(dstObj.dataFile.c_str()); - - const f32 yaw = dstObj.orientation.y * PI / 180.0f; - const f32 pitch = dstObj.orientation.x * PI / 180.0f; - const f32 roll = dstObj.orientation.z * PI / 180.0f; - TFE_Math::buildRotationMatrix({ roll, yaw, pitch }, dstObj.rotMtx.m); - dstObj.rotMtxT = TFE_Math::transpose(dstObj.rotMtx); - } - else - { - dstObj.display = createObjectTexture(srcObj->oclass, dstObj.dataFile.c_str()); - - f32 width = dstObj.display ? (f32)dstObj.display->width : 1.0f; - f32 height = dstObj.display ? (f32)dstObj.display->height : 1.0f; - // Half width - f32 w = dstObj.display ? (f32)dstObj.display->width * dstObj.display->scale.x / 8.0f : 1.0f; - f32 h = dstObj.display ? (f32)dstObj.display->height * dstObj.display->scale.z / 8.0f : 1.0f; - f32 y0 = dstObj.pos.y; - if (dstObj.oclass == CLASS_SPIRIT || dstObj.oclass == CLASS_SAFE || dstObj.oclass == CLASS_SOUND) - { - w = 3.0f; - h = 3.0f; - if (dstObj.radius > 0.0f) - { - w = dstObj.radius * 2.0f; - } - if (dstObj.height != 0) - { - h = dstObj.height; - } - } - else if (dstObj.display) - { - //w = dstObj.display->scale.x * fabsf(dstObj.display->rect[0] - dstObj.display->rect[2]) * c_spriteTexelToWorldScale; - //h = dstObj.display->scale.z * fabsf(dstObj.display->rect[1] - dstObj.display->rect[3]) * c_spriteTexelToWorldScale; - //y0 += dstObj.display->scale.z * fabsf(dstObj.display->rect[1]) * c_spriteTexelToWorldScale; - } - - // AABB - dstObj.worldCen = { dstObj.pos.x, y0 - h*0.5f, dstObj.pos.z }; - dstObj.worldExt = { w*0.5f, h*0.5f, w*0.5f }; - } - } - } - } - - void convertInfToEditor(const InfData* infData) - { - if (!infData) - { - s_editorInf.item.clear(); - return; - } - - // Do not add flag based doors to the editor INF. - const u32 itemCount = infData->doorStart >= 0 ? infData->doorStart : infData->itemCount; - - s_editorInf.item.resize(itemCount); - EditorInfItem* dst = s_editorInf.item.data(); - const InfItem* src = infData->item; - for (u32 i = 0; i < itemCount; i++, src++, dst++) - { - const u32 sectorId = src->id & 0xffffu; - const u32 srcWallId = (src->id >> 16u) & 0xffffu; - const s32 wallId = srcWallId == 0xffffu ? -1 : (s32)srcWallId; - - if (sectorId < 0xffffu && s_editorLevel.sectors[sectorId].name[0]) - dst->sectorName = s_editorLevel.sectors[sectorId].name; - else - dst->sectorName.clear(); - - dst->wallId = wallId; - dst->type = src->type; - dst->classData.resize(src->classCount); - - EditorInfClassData* dstClass = dst->classData.data(); - const InfClassData* srcClass = src->classData; - for (u32 c = 0; c < src->classCount; c++, srcClass++, dstClass++) - { - dstClass->iclass = srcClass->iclass; - dstClass->isubclass = srcClass->isubclass; - - //Variables. - dstClass->var.master = srcClass->var.master; - dstClass->var.event = srcClass->var.event; - dstClass->var.start = srcClass->var.start; - dstClass->var.event_mask = srcClass->var.event_mask; - dstClass->var.entity_mask = srcClass->var.entity_mask; - dstClass->var.key = srcClass->var.key; - dstClass->var.flags = srcClass->var.flags; - dstClass->var.center = srcClass->var.center; - dstClass->var.angle = srcClass->var.angle; - dstClass->var.speed = srcClass->var.speed; - for (u32 s = 0; s < 3; s++) - { - dstClass->var.sound[s] = srcClass->var.sound[s]; - } - dstClass->var.target = srcClass->var.target >= 0 ? s_editorLevel.sectors[srcClass->var.target].name : ""; - - //Stops. - dstClass->stop.resize(srcClass->stopCount); - EditorInfStop* dstStop = dstClass->stop.data(); - const InfStop* srcStop = srcClass->stop; - for (u32 s = 0; s < srcClass->stopCount; s++, srcStop++, dstStop++) - { - const u32 funcCount = srcStop->code >> 8u; - dstStop->stopValue0Type = srcStop->code & 0x0fu; - dstStop->stopValue1Type = (srcStop->code >> 4u) & 0x0fu; - dstStop->time = srcStop->time; - - if (dstStop->stopValue0Type == INF_STOP0_SECTORNAME) - { - dstStop->value0.sValue = s_editorLevel.sectors[srcStop->value0.iValue].name; - } - else - { - dstStop->value0.fValue = srcStop->value0.fValue; - } - - dstStop->func.resize(funcCount); - EditorInfFunction* dstFunc = dstStop->func.data(); - const InfFunction* srcFunc = srcStop->func; - for (u32 f = 0; f < funcCount; f++, srcFunc++, dstFunc++) - { - const u32 funcId = (srcFunc->code) & 0xffu; - const u32 clientCount = (srcFunc->code >> 8u) & 0xffu; - const u32 argCount = srcFunc->code >> 16u; - - dstFunc->funcId = funcId; - dstFunc->client.resize(clientCount); - dstFunc->arg.resize(argCount); - - for (u32 j = 0; j < clientCount; j++) - { - const u32 sectorId = srcFunc->client[j] & 0xffffu; - const u32 wallId = (srcFunc->client[j] >> 16u) & 0xffffu; - - dstFunc->client[j].sectorName = sectorId < 0xffffu ? s_editorLevel.sectors[sectorId].name : ""; - dstFunc->client[j].wallId = wallId == 0xffffu ? -1 : s32(wallId); - } - - if (funcId < INF_MSG_LIGHTS) - { - for (u32 j = 0; j < argCount; j++) - { - dstFunc->arg[j].iValue = srcFunc->arg[j].iValue; - } - } - else if (funcId == INF_MSG_ADJOIN) - { - dstFunc->arg[0].sValue = s_editorLevel.sectors[srcFunc->arg[0].iValue].name; - dstFunc->arg[1].iValue = srcFunc->arg[1].iValue; - dstFunc->arg[2].sValue = s_editorLevel.sectors[srcFunc->arg[2].iValue].name; - dstFunc->arg[3].iValue = srcFunc->arg[3].iValue; - } - else if (funcId == INF_MSG_PAGE) - { - // TODO: This is wrong, fix me. - dstFunc->arg[0].iValue = srcFunc->arg[0].iValue; - } - else if (funcId == INF_MSG_TEXT) - { - dstFunc->arg[0].iValue = srcFunc->arg[0].iValue; - } - else if (funcId == INF_MSG_TEXTURE) - { - dstFunc->arg[0].iValue = srcFunc->arg[0].iValue; - dstFunc->arg[1].sValue = s_editorLevel.sectors[srcFunc->arg[1].iValue].name; - } - } - } - - //Slaves. - dstClass->slaves.clear(); - dstClass->slaves.reserve(srcClass->slaveCount); - for (u32 s = 0; s < srcClass->slaveCount; s++) - { - const std::string name = s_editorLevel.sectors[srcClass->slaves[s]].name; - if (strcasecmp(name.c_str(), dst->sectorName.c_str()) != 0) - { - dstClass->slaves.push_back(name); - } - } - } - } - } -} diff --git a/TheForceEngine/TFE_Editor/levelEditorData.h b/TheForceEngine/TFE_Editor/levelEditorData.h deleted file mode 100644 index 0e63191e2..000000000 --- a/TheForceEngine/TFE_Editor/levelEditorData.h +++ /dev/null @@ -1,304 +0,0 @@ -#pragma once -///////////////////////////////////////////////////////////////////////// -// The Force Engine Level Editor Data -// The runtime has fixed sectors and INF data that doesn't change in size -// whereas the data the Level Editor needs to access and change is -// constantly malleable. So the LevelEditor needs to copy the tight -// runtime structures into more malleable structures and be able to reverse -// the process in order to test. -///////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// TODO: -// Implement conversion routine back to runtime data. -// Add conversion from INF to editor and back. -// Convert the level editor to use this instead of the source data directly. - -#define TEXTURES_GOB_START_TEX 41 -struct Model; - -enum InfType -{ - INF_NONE = 0, - INF_SELF, - INF_OTHER, - INF_COUNT, - INF_ALL = INF_COUNT -}; - -enum InfTriggerType -{ - TRIGGER_LINE = 0, - TRIGGER_SWITCH -}; - -struct Target -{ - std::string sectorName; - s32 wallId; -}; - -struct EditorInfArg -{ - union - { - s32 iValue; - f32 fValue; - }; - std::string sValue; -}; - -struct EditorInfFunction -{ - u32 funcId; - std::vector client; - std::vector arg; -}; - -// A trigger will have 1 stop with code = 0 | funcCount << 8, time = 0 -struct EditorInfStop -{ - u8 stopValue0Type; - u8 stopValue1Type; - EditorInfArg value0; - f32 time; // time at stop or 0. - std::vector func; -}; - -struct EditorInfVariables -{ - bool master = true; // Determines if an elevator or trigger can function. - u32 event = 0; // Custom event value(s) for trigger. - s32 start = 0; // Determines which stop an elevator starts at on level load. - /////////////////////// Masks /////////////////////// - u32 event_mask = 0; // (InfEventMask) Determines if an event will operate on an elevator or trigger. Defaults: 52 (elev basic, inv, basic_auto), 60 (morph1/2, spin1/2), other elev 0; trigger 0xffffffff - u32 entity_mask = // (InfEntityMask) Defines the type of entities that can activate a Trigger. - INF_ENTITY_PLAYER; - //////////////////////// Flags & keys /////////////////////// - u32 key = 0; // Key required to activate an elevator (yellow, blue, red). - u32 flags = 0; // (InfMoveFlags) Determines whether the player moves with morphing or scrolling elevators. Defaults: 3 (scroll_floor, morph2, spin2) otherwise 0. - /////////////////////// Movement & rotation /////////////////////// - Vec2f center = // Center coordinates for rotation. - { 0.0f, 0.0f }; - f32 angle = 0.0f; // Direction of texture scrolling or horizontal elevators. For walls 0 = down others 0 = north. - f32 speed = 0.0f; // Speed an elevator moves between stops. 0 = instant. - f32 speed_addon[2]; // Addon for door_mid - /////////////////////// Sound /////////////////////// - u32 sound[3]; // index | soundAssetId << 8 (TODO: Fill in with defaults) - /////////////////////// Target/Slave /////////////////////// - std::string target; // Target sector for teleport. -}; - -struct EditorInfClassData -{ - u8 iclass, isubclass; - u8 pad8[2]; - - EditorInfVariables var; - std::vector stop; - std::vector slaves; -}; - -struct EditorInfItem -{ - std::string sectorName; - s32 wallId; - - u8 type; - u8 pad8[3]; - - std::vector classData; -}; - -struct EditorInfData -{ - std::vector item; -}; - -struct EditorTexture -{ - TextureGpu* texture = nullptr; - u32 width = 0; - u32 height = 0; - f32 rect[4]; - Vec2f scale = { 1.0f, 1.0f }; - char name[64] = ""; -}; - -struct EditorLevelObject -{ - // Render Data - ObjectClass oclass; - std::string dataFile; - Vec3f pos; - Vec3f orientation; - s32 difficulty; - - // Editor display - EditorTexture* display; - Model* displayModel; - // Bounds - Vec3f worldCen; - Vec3f worldExt; - // Matrix - Mat3 rotMtx; - Mat3 rotMtxT; - - // Common Variables. - u32 comFlags = 0; // common flags - see LogicCommonFlags. - f32 radius = 0.0f; - f32 height = 0.0f; - - // Logics - std::vector logics; - std::vector generators; -}; - -struct EditorSectorTexture -{ - EditorTexture* tex; - u16 flag; - f32 offsetX, offsetY; - u32 frame; -}; - -struct EditorWall -{ - u16 i0, i1; - EditorSectorTexture mid; - EditorSectorTexture top; - EditorSectorTexture bot; - EditorSectorTexture sign; - s32 adjoin; // visible adjoin - s32 walk; // collision adjoin - s32 mirror; // wall in visible adjoin. - s16 light; // light level. - s16 pad16; - u32 flags[4]; - InfType infType; - InfTriggerType triggerType; - - // INF - EditorInfItem* infItem; -}; - -struct SectorTriangles -{ - u32 count; - u32 timestamp; - std::vector vtx; -}; - -struct EditorSector -{ - u32 id; - char name[32]; - u8 ambient; - EditorSectorTexture floorTexture; - EditorSectorTexture ceilTexture; - f32 floorAlt; - f32 ceilAlt; - f32 secAlt; - u32 flags[3]; - s8 layer; - InfType infType; - - // Dynamically resizable, self-contained geometry data. - std::vector walls; - std::vector vertices; - - // Objects - std::vector objects; - - // INF - EditorInfItem* infItem; - - // Polygon data. - SectorTriangles triangles; - - // Bounds - Vec3f aabb[2]; - - // Update flag - bool needsUpdate; -}; - -struct InfEditState -{ - EditorSector* sector; - EditorInfItem* item; - s32 wallId = -1; - std::vector itemMem; - std::vector itemList; - s32 editIndex; -}; - -typedef std::map TextureMap; - -struct EditorLevel -{ - std::string name; - f32 parallax[2]; - - s8 layerMin; - s8 layerMax; - u8 pad8[2]; - - std::vector textures; - TextureMap textureMap; - - std::vector sectors; -}; - -struct RayHitInfoLE -{ - Vec3f hitPoint; - s32 hitSectorId; - s32 hitWallId; - RayHitPart hitPart; - - s32 hitObjectId; -}; - -namespace LevelEditorData -{ - // Convert runtime level data to editor format. - bool convertLevelDataToEditor(const LevelData* levelData, const Palette256* palette, const InfData* infData, const LevelObjectData* objData); - - // Add a new sector. - void addNewSector(const EditorSector& newSector, EditorTexture* floorTex, EditorTexture* ceilTex, EditorTexture* wallTex); - void addNewSectorFullCopy(const EditorSector& newSector); - - // Update any sectors that have been flagged. This handles re-triangulation and any other updates needed for rendering. - void updateSectors(); - - // Convert runtime level data from editor format. - bool generateLevelData(); - bool generateInfAsset(); - bool generateObjects(); - - EditorTexture* createTexture(const Texture* src); - - // Get the editor level data. - EditorLevel* getEditorLevelData(); - - // Inf Edit State - InfEditState* getInfEditState(); - - s32 findSector(s32 layer, const Vec2f* pos); - EditorSector* getSector(const char* name); - - s32 findClosestWall(s32* sectorId, s32 layer, const Vec2f* pos, f32 maxDist); - bool traceRay(const Ray* ray, RayHitInfoLE* hitInfo); - - void triangulateSector(const EditorSector* sector, SectorTriangles* outTri); -} \ No newline at end of file diff --git a/TheForceEngine/TFE_Editor/perfWindow.cpp b/TheForceEngine/TFE_Editor/perfWindow.cpp deleted file mode 100644 index 0dcdf84c7..000000000 --- a/TheForceEngine/TFE_Editor/perfWindow.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "perfWindow.h" -#include -#include - -namespace PerfWindow -{ -static f64 s_aveDt = 0.0; -static f64 s_minDt = FLT_MAX, s_maxDt = -FLT_MAX; - -static f64 s_curAveDt = 0.0; -static f64 s_curRange[2] = { 0.0 }; - -void setCurrentDt(f64 dt, u32 frame) -{ - s_minDt = std::min(dt, s_minDt); - s_maxDt = std::max(dt, s_maxDt); - s_aveDt += dt; - - if ((frame & 15) == 0) - { - s_aveDt /= 16.0; - - s_curAveDt = s_aveDt; - s_curRange[0] = s_minDt; - s_curRange[1] = s_maxDt; - - s_aveDt = 0.0; - if ((frame & 63) == 0) - { - s_minDt = FLT_MAX; s_maxDt = -FLT_MAX; - } - } -} - -void draw(bool* isActive) -{ - ImGui::Begin("Performance", isActive); - ImVec2 windowPos = ImVec2(0.0f, 0.0f); - ImGui::SetWindowPos("Performance", windowPos); - - ImGui::Text("FPS: %05.2f", 1.0/s_curAveDt); - ImGui::Text("Frame Time: %05.2fms", s_curAveDt * 1000.0); - ImGui::Text("Frame Time Range: %05.2fms, %05.2fms", s_curRange[0] * 1000.0, s_curRange[1] * 1000.0); - ImGui::End(); -} - -} diff --git a/TheForceEngine/TFE_Editor/perfWindow.h b/TheForceEngine/TFE_Editor/perfWindow.h deleted file mode 100644 index 69126750b..000000000 --- a/TheForceEngine/TFE_Editor/perfWindow.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -namespace PerfWindow -{ - void draw(bool* isActive); - void setCurrentDt(f64 dt, u32 frame); -} diff --git a/TheForceEngine/TheForceEngine.vcxproj b/TheForceEngine/TheForceEngine.vcxproj index b911b9b43..453b4baab 100644 --- a/TheForceEngine/TheForceEngine.vcxproj +++ b/TheForceEngine/TheForceEngine.vcxproj @@ -444,16 +444,16 @@ echo ^)"; - + - - + + + + + + + - - - - - @@ -801,16 +801,16 @@ echo ^)"; - + - - + + + + + + + - - - - - diff --git a/TheForceEngine/TheForceEngine.vcxproj.filters b/TheForceEngine/TheForceEngine.vcxproj.filters index 9b06a6194..ea230169b 100644 --- a/TheForceEngine/TheForceEngine.vcxproj.filters +++ b/TheForceEngine/TheForceEngine.vcxproj.filters @@ -176,6 +176,12 @@ {7f1d4b6d-31c7-431d-8458-e47f7949c742} + + {59028c8c-f700-4749-b808-6603d9161958} + + + {39aec0b3-0a4e-4584-989b-a78fd6583de5} + @@ -1255,35 +1261,35 @@ Source\TFE_Editor - - Source\TFE_Editor - Source\TFE_FrontEndUI - - Source\TFE_Editor - Source\TFE_Editor - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset + + + Source\TFE_Editor\EditorAsset + + + Source\TFE_Editor\AssetBrowser @@ -2154,35 +2160,35 @@ Source\TFE_Editor - - Source\TFE_Editor - Source\TFE_FrontEndUI - - Source\TFE_Editor - Source\TFE_Editor - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset - - Source\TFE_Editor + + Source\TFE_Editor\EditorAsset + + + Source\TFE_Editor\EditorAsset + + + Source\TFE_Editor\AssetBrowser