diff --git a/BrowEdit3.vcxproj b/BrowEdit3.vcxproj index 28af1ebd..1e06bcbf 100644 --- a/BrowEdit3.vcxproj +++ b/BrowEdit3.vcxproj @@ -32,6 +32,7 @@ + @@ -72,6 +73,7 @@ + @@ -105,6 +107,7 @@ + @@ -163,6 +166,7 @@ + @@ -205,6 +209,7 @@ + @@ -266,6 +271,8 @@ + + @@ -371,8 +378,8 @@ MSVCRT - xcopy /y $(TargetPath) $(SolutionDir) -xcopy /y $(OutDir)BrowEdit3.pdb $(SolutionDir) + xcopy /y "$(TargetPath)" "$(SolutionDir)" +xcopy /y "$(OutDir)BrowEdit3.pdb" "$(SolutionDir)" diff --git a/BrowEdit3.vcxproj.filters b/BrowEdit3.vcxproj.filters index 082a1184..11e953c8 100644 --- a/BrowEdit3.vcxproj.filters +++ b/BrowEdit3.vcxproj.filters @@ -451,6 +451,15 @@ lib\glad + + browedit\windows + + + browedit + + + browedit\actions + @@ -780,6 +789,12 @@ lib\lzma + + browedit\actions + + + browedit\shaders + @@ -853,6 +868,12 @@ docs\formats + + data\shaders + + + data\shaders + diff --git a/browedit/BrowEdit.cpp b/browedit/BrowEdit.cpp index 94dfc492..f8e5caf7 100644 --- a/browedit/BrowEdit.cpp +++ b/browedit/BrowEdit.cpp @@ -276,6 +276,8 @@ void BrowEdit::run() showShadowEditWindow(); if (editMode == EditMode::Cinematic) showCinematicModeWindow(); + if (editMode == EditMode::Water) + showWaterEditWindow(); if (windowData.hotkeyEditWindowVisible) showHotkeyEditorWindow(); @@ -595,6 +597,8 @@ void BrowEdit::showMapWindow(MapView& mapView, float deltaTime) mapView.postRenderShadowMode(this); else if (editMode == EditMode::Cinematic) mapView.postRenderCinematicMode(this); + else if (editMode == EditMode::Water) + mapView.postRenderWaterMode(this); } diff --git a/browedit/BrowEdit.h b/browedit/BrowEdit.h index 40a876c8..bcd33026 100644 --- a/browedit/BrowEdit.h +++ b/browedit/BrowEdit.h @@ -227,6 +227,7 @@ class BrowEdit Shadow, Sprite, Cinematic, + Water, } editMode = EditMode::Gat; enum class SelectTool @@ -352,6 +353,7 @@ class BrowEdit void showColorEditWindow(); void showShadowEditWindow(); void showCinematicModeWindow(); + void showWaterEditWindow(); void copyTiles(); void copyGat(); diff --git a/browedit/HotkeyActions.cpp b/browedit/HotkeyActions.cpp index dd2d2550..8e872888 100644 --- a/browedit/HotkeyActions.cpp +++ b/browedit/HotkeyActions.cpp @@ -218,6 +218,7 @@ void BrowEdit::registerActions() HotkeyRegistry::registerAction(HotkeyAction::EditMode_Shadow, [this]() { editMode = EditMode::Shadow; }); HotkeyRegistry::registerAction(HotkeyAction::EditMode_Sprite, [this]() { editMode = EditMode::Sprite; }); HotkeyRegistry::registerAction(HotkeyAction::EditMode_Cinematic, [this]() { editMode = EditMode::Cinematic; }); + HotkeyRegistry::registerAction(HotkeyAction::EditMode_Water, [this]() { editMode = EditMode::Water; }); HotkeyRegistry::registerAction(HotkeyAction::View_ShadowMap, [this]() { activeMapView->viewLightmapShadow = !activeMapView->viewLightmapShadow; }, hasActiveMapView); HotkeyRegistry::registerAction(HotkeyAction::View_ColorMap, [this]() { activeMapView->viewLightmapColor = !activeMapView->viewLightmapColor; }, hasActiveMapView); diff --git a/browedit/HotkeyRegistry.h b/browedit/HotkeyRegistry.h index 8042ddc6..7fe9b707 100644 --- a/browedit/HotkeyRegistry.h +++ b/browedit/HotkeyRegistry.h @@ -128,6 +128,7 @@ enum class HotkeyAction EditMode_Shadow, EditMode_Sprite, EditMode_Cinematic, + EditMode_Water, View_ShadowMap, View_ColorMap, diff --git a/browedit/Map.h b/browedit/Map.h index ae3d3fcd..ac3dc01b 100644 --- a/browedit/Map.h +++ b/browedit/Map.h @@ -21,6 +21,7 @@ class Map std::vector selectedNodes; std::vector tileSelection; std::vector gatSelection; + std::vector waterSelection; bool changed = false; bool mapHasNoGnd = false; // This variable is meant to prevent the console from being filled with the "map has no gnd" error diff --git a/browedit/MapView.Gatmode.cpp b/browedit/MapView.Gatmode.cpp index 3c00790d..3734c1d3 100644 --- a/browedit/MapView.Gatmode.cpp +++ b/browedit/MapView.Gatmode.cpp @@ -402,7 +402,7 @@ void MapView::postRenderGatMode(BrowEdit* browEdit) if (gadgetHeight[i].axisClicked) { dragIndex = i; - mouseDragPlane.normal = glm::normalize(glm::vec3(nodeRenderContext.viewMatrix * glm::vec4(0, 0, 1, 1)) - glm::vec3(nodeRenderContext.viewMatrix * glm::vec4(0, 0, 0, 1))); + mouseDragPlane.normal = -mouseRay.dir; mouseDragPlane.normal.y = 0; mouseDragPlane.normal = glm::normalize(mouseDragPlane.normal); mouseDragPlane.D = -glm::dot(pos[i], mouseDragPlane.normal); diff --git a/browedit/MapView.Heightmode.cpp b/browedit/MapView.Heightmode.cpp index f954e20b..63888530 100644 --- a/browedit/MapView.Heightmode.cpp +++ b/browedit/MapView.Heightmode.cpp @@ -498,7 +498,7 @@ void MapView::postRenderHeightMode(BrowEdit* browEdit) if (gadgetHeight[i].axisClicked) { dragIndex = i; - mouseDragPlane.normal = glm::normalize(glm::vec3(nodeRenderContext.viewMatrix * glm::vec4(0, 0, 1, 1)) - glm::vec3(nodeRenderContext.viewMatrix * glm::vec4(0, 0, 0, 1))); + mouseDragPlane.normal = -mouseRay.dir; mouseDragPlane.normal.y = 0; mouseDragPlane.normal = glm::normalize(mouseDragPlane.normal); mouseDragPlane.D = -glm::dot(pos[i], mouseDragPlane.normal); diff --git a/browedit/MapView.Watermode.cpp b/browedit/MapView.Watermode.cpp new file mode 100644 index 00000000..ebe20c8d --- /dev/null +++ b/browedit/MapView.Watermode.cpp @@ -0,0 +1,496 @@ +#define IMGUI_DEFINE_MATH_OPERATORS +#include +#include "MapView.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 + +void MapView::rebuildWaterGrid(Rsw* rsw, Gnd* gnd, bool forced) +{ + std::vector verts; + glm::vec3 n(0, -1, 0); + + if (waterGridDirty || forced || rsw->water.splitHeight * rsw->water.splitWidth * 8 != waterGridVbo->size()) { + for (int x = 0; x < rsw->water.splitWidth; x++) + { + for (int y = 0; y < rsw->water.splitHeight; y++) + { + int xmin, xmax, ymin, ymax; + auto zone = &rsw->water.zones[x][y]; + + rsw->water.getBoundsFromGnd(x, y, gnd, &xmin, &xmax, &ymin, &ymax); + + VertexP3 v0 = VertexP3(glm::vec3(10 * xmin, -zone->height, 10 * gnd->height - 10 * ymin)); + VertexP3 v1 = VertexP3(glm::vec3(10 * xmax, -zone->height, 10 * gnd->height - 10 * ymax)); + VertexP3 v2 = VertexP3(glm::vec3(10 * xmax, -zone->height, 10 * gnd->height - 10 * ymin)); + VertexP3 v3 = VertexP3(glm::vec3(10 * xmin, -zone->height, 10 * gnd->height - 10 * ymax)); + + verts.push_back(v0); verts.push_back(v2); + verts.push_back(v0); verts.push_back(v3); + verts.push_back(v1); verts.push_back(v3); + verts.push_back(v1); verts.push_back(v2); + } + } + + waterGridVbo->setData(verts, GL_STATIC_DRAW); + waterGridDirty = false; + } +} + +void MapView::postRenderWaterMode(BrowEdit* browEdit) +{ + float gridSize = gridSizeTranslate; + float gridOffset = gridOffsetTranslate; + static bool isDragged = false; + + auto rsw = map->rootNode->getComponent(); + auto gnd = map->rootNode->getComponent(); + auto gndRenderer = map->rootNode->getComponent(); + auto waterRenderer = map->rootNode->getComponent(); + + if (!rsw || !gnd || !gndRenderer || !waterRenderer) + return; + + glUseProgram(0); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glm::value_ptr(nodeRenderContext.projectionMatrix)); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(glm::value_ptr(nodeRenderContext.viewMatrix)); + glColor3f(1, 0, 0); + fbo->bind(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDisable(GL_TEXTURE_2D); + + simpleShader->use(); + simpleShader->setUniform(SimpleShader::Uniforms::projectionMatrix, nodeRenderContext.projectionMatrix); + simpleShader->setUniform(SimpleShader::Uniforms::viewMatrix, nodeRenderContext.viewMatrix); + simpleShader->setUniform(SimpleShader::Uniforms::modelMatrix, glm::mat4(1.0f)); + simpleShader->setUniform(SimpleShader::Uniforms::textureFac, 0.0f); + glEnable(GL_BLEND); + glDepthMask(0); + bool canSelect = true; + glm::vec3 n(0, -1, 0); + + auto mouse3D = rsw->rayCastWater(mouseRay, gnd, viewEmptyTiles); + glm::ivec2 tileHovered; + + if (mouse3D == glm::vec3(std::numeric_limits::max())) { + tileHovered = glm::ivec2(-1, -1); + } + else { + rsw->water.getIndexFromGnd((int)glm::floor(mouse3D.x / 10), gnd->height - (int)glm::floor(mouse3D.z) / 10, gnd, &tileHovered.x, &tileHovered.y); + } + + ImGui::Begin("Statusbar"); + ImGui::SetNextItemWidth(100.0f); + ImGui::Text("Water zone: %d,%d", tileHovered.x, tileHovered.y); + ImGui::SameLine(); + ImGui::End(); + + bool snap = snapToGrid; + if (ImGui::GetIO().KeyShift) + snap = !snap; + + int perWidth = glm::max(1, gnd->width / glm::max(1, rsw->water.splitWidth)); + int perHeight = glm::max(1, gnd->height / glm::max(1, rsw->water.splitHeight)); + + std::vector waterSelection; + + // Always select the entire water if there are no split zones + if (gnd->version < 0x108 && map->waterSelection.size() == 0) + map->waterSelection.push_back(glm::ivec2(0, 0)); + + for (auto& tile : map->waterSelection) + { + // The selection can become invalid if the split zones count was changed + if (tile.x < 0 || tile.x >= rsw->water.splitWidth || + tile.y < 0 || tile.y >= rsw->water.splitHeight) + continue; + + waterSelection.push_back(tile); + } + + // Draw the white water grid, it's hard to see the zones otherwise + rebuildWaterGrid(rsw, gnd); + + if (showWaterGrid && !isDragged && waterGridVbo->size() > 0) { + waterGridVbo->bind(); + glEnableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + simpleShader->setUniform(SimpleShader::Uniforms::color, glm::vec4(1, 1, 1, 0.25f)); + glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3), (void*)(0 * sizeof(float))); + glDrawArrays(GL_LINES, 0, (int)waterGridVbo->size()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + waterGridVbo->unBind(); + } + + if (waterSelection.size() > 0 && canSelect) + { + std::vector verts; + std::vector vertsGrid; + + for (auto& tile : waterSelection) + { + int xmin, xmax, ymin, ymax; + auto zone = &rsw->water.zones[tile.x][tile.y]; + + rsw->water.getBoundsFromGnd(tile.x, tile.y, gnd, &xmin, &xmax, &ymin, &ymax); + + VertexP3 v0 = VertexP3(glm::vec3(10 * xmin, -zone->height, 10 * gnd->height - 10 * ymin)); + VertexP3 v1 = VertexP3(glm::vec3(10 * xmax, -zone->height, 10 * gnd->height - 10 * ymax)); + VertexP3 v2 = VertexP3(glm::vec3(10 * xmax, -zone->height, 10 * gnd->height - 10 * ymin)); + VertexP3 v3 = VertexP3(glm::vec3(10 * xmin, -zone->height, 10 * gnd->height - 10 * ymax)); + + verts.push_back(v0); + verts.push_back(v1); + verts.push_back(v2); + + verts.push_back(v3); + verts.push_back(v0); + verts.push_back(v1); + + vertsGrid.push_back(v0); vertsGrid.push_back(v2); + vertsGrid.push_back(v0); vertsGrid.push_back(v3); + vertsGrid.push_back(v1); vertsGrid.push_back(v3); + vertsGrid.push_back(v1); vertsGrid.push_back(v2); + } + + if (vertsGrid.size() > 0) { + glEnableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); + glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3), verts[0].data); + + glLineWidth(1.0f); + simpleShader->setUniform(SimpleShader::Uniforms::color, glm::vec4(1, 0, 0, (gnd->version >= 0x108 && showWaterSelectedOverlay) ? 0.15f : 0.0f)); + glDrawArrays(GL_TRIANGLES, 0, (int)verts.size()); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + simpleShader->setUniform(SimpleShader::Uniforms::color, glm::vec4(1, 0, 0, 1.0f)); + glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3), vertsGrid[0].data); + glDrawArrays(GL_LINES, 0, (int)vertsGrid.size()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + Gadget::setMatrices(nodeRenderContext.projectionMatrix, nodeRenderContext.viewMatrix); + glDepthMask(1); + + glm::ivec2 maxValues(-99999, -99999), minValues(999999, 9999999); + + for (auto& tile : waterSelection) + { + maxValues = glm::max(maxValues, tile); + minValues = glm::min(minValues, tile); + } + + static std::map originalValues; + static glm::vec3 clickedPos; + + int xmin = perWidth * minValues.x; + int xmax = perWidth * (maxValues.x + 1); + + if (maxValues.x == rsw->water.splitWidth - 1) + xmax = gnd->width; + + int ymin = perHeight * minValues.y - 1; + int ymax = perHeight * (maxValues.y + 1) - 1; + + if (maxValues.y == rsw->water.splitHeight - 1) + ymax = gnd->height - 1; + + glm::vec3 pos[5]; + glm::vec3 posGadget[5]; + posGadget[0] = pos[0] = glm::vec3(10 * xmin, -rsw->water.zones[minValues.x][minValues.y].height, 10 * gnd->height - 10 * ymin); + posGadget[1] = pos[1] = glm::vec3(10 * xmax, -rsw->water.zones[maxValues.x][minValues.y].height, 10 * gnd->height - 10 * ymin); + posGadget[2] = pos[2] = glm::vec3(10 * xmin, -rsw->water.zones[minValues.x][maxValues.y].height, 10 * gnd->height - 10 * ymax); + posGadget[3] = pos[3] = glm::vec3(10 * xmax, -rsw->water.zones[maxValues.x][maxValues.y].height, 10 * gnd->height - 10 * ymax); + + glm::vec3 center = (pos[0] + pos[1] + pos[2] + pos[3]) / 4.0f; + + int cx = (maxValues.x - minValues.x) / 2 + minValues.x; + int cy = (maxValues.y - minValues.y) / 2 + minValues.y; + center.y = -rsw->water.zones[cx][cy].height; + + posGadget[4] = pos[4] = center; + + glm::vec3 cameraPos = glm::inverse(nodeRenderContext.viewMatrix) * glm::vec4(0, 0, 0, 1); + int order[5] = { 0, 1, 2, 3, 4 }; + std::sort(std::begin(order), std::end(order), [&](int a, int b) + { + return glm::distance(cameraPos, pos[a]) < glm::distance(cameraPos, pos[b]); + }); + + static int dragIndex = -1; + for (int ii = 0; ii < 5; ii++) + { + if (gadgetScale == 0) + continue; + int i = order[ii]; + + if (!browEdit->windowData.heightEdit.showCornerArrows && i < 4) + continue; + if (!browEdit->windowData.heightEdit.showCenterArrow && i == 4) + continue; + if (!browEdit->windowData.heightEdit.showEdgeArrows && i > 4) + continue; + glm::mat4 mat = glm::translate(glm::mat4(1.0f), posGadget[i]); + + if (dragIndex == -1) + gadgetHeight[i].disabled = false; + else + gadgetHeight[i].disabled = dragIndex != i; + + gadgetHeight[i].draw(mouseRay, mat); + + if (gadgetHeight[i].axisClicked) + { + dragIndex = i; + mouseDragPlane.normal = -mouseRay.dir; + mouseDragPlane.normal.y = 0; + mouseDragPlane.normal = glm::normalize(mouseDragPlane.normal); + mouseDragPlane.D = -glm::dot(pos[i], mouseDragPlane.normal); + + float f; + mouseRay.planeIntersection(mouseDragPlane, f); + mouseDragStart = mouseRay.origin + f * mouseRay.dir; + + originalValues.clear(); + for (auto& t : waterSelection) + originalValues[&rsw->water.zones[t.x][t.y]] = rsw->water.zones[t.x][t.y].height; + + clickedPos = pos[i]; + + canSelect = false; + waterRenderer->renderFullWater = true; + waterRenderer->setDirty(); + } + else if (gadgetHeight[i].axisReleased) + { + dragIndex = -1; + canSelect = false; + isDragged = false; + + std::map newValues; + for (auto& t : originalValues) + newValues[t.first] = t.first->height; + map->doAction(new WaterHeightChangeAction(originalValues, newValues, waterSelection), browEdit); + waterRenderer->renderFullWater = false; + waterRenderer->setDirty(); + + rebuildWaterGrid(rsw, gnd, true); + } + else if (gadgetHeight[i].axisDragged) + { + isDragged = true; + + if (snap) + { + glm::mat4 mat(1.0f); + + glm::vec3 rounded = pos[i]; + if (!gridLocal) + rounded.y = glm::floor(rounded.y / gridSize) * gridSize; + + mat = glm::translate(mat, rounded); + mat = glm::rotate(mat, glm::radians(90.0f), glm::vec3(1, 0, 0)); + simpleShader->setUniform(SimpleShader::Uniforms::modelMatrix, mat); + simpleShader->setUniform(SimpleShader::Uniforms::color, glm::vec4(0, 0, 0, 1)); + glLineWidth(2); + gridVbo->bind(); + glEnableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); + glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3), (void*)(0 * sizeof(float))); + glDrawArrays(GL_LINES, 0, (int)gridVbo->size()); + gridVbo->unBind(); + } + + float f; + mouseRay.planeIntersection(mouseDragPlane, f); + glm::vec3 mouseOffset = (mouseRay.origin + f * mouseRay.dir) - mouseDragStart; + + if (snap && gridLocal) + mouseOffset = glm::round(mouseOffset / (float)gridSize) * (float)gridSize; + + canSelect = false; + + float offsetY = clickedPos.y - mouseOffset.y; + if (snap && !gridLocal) + { + offsetY += 2 * mouseOffset.y; + offsetY = glm::round(offsetY / gridSize) * gridSize; + offsetY = clickedPos.y + (clickedPos.y - offsetY); + } + + for (auto& t : waterSelection) + { + rsw->water.zones[t.x][t.y].height = originalValues[&rsw->water.zones[t.x][t.y]] + offsetY - clickedPos.y; + } + } + } + + simpleShader->setUniform(SimpleShader::Uniforms::modelMatrix, glm::mat4(1.0f)); + glDepthMask(0); + } + + if (hovered && canSelect) + { + if (ImGui::IsMouseDown(0)) + { + if (!mouseDown) + mouseDragStart = mouse3D; + mouseDown = true; + } + + if (ImGui::IsMouseReleased(0) && hovered) + { + auto mouseDragEnd = mouse3D; + mouseDown = false; + + std::map newSelection; + if (ImGui::GetIO().KeyShift || ImGui::GetIO().KeyCtrl) { + for (auto& tile : waterSelection) { + newSelection[tile.x + rsw->water.splitWidth * tile.y] = tile; + } + } + if (browEdit->selectTool == BrowEdit::SelectTool::Rectangle) + { + int waterMinX, waterMinY, waterMaxX, waterMaxY; + + rsw->water.getIndexFromGnd( + (int)glm::floor(glm::min(mouseDragStart.x, mouseDragEnd.x) / 10), + gnd->height - (int)glm::floor(glm::max(mouseDragStart.z, mouseDragEnd.z) / 10), + gnd, + &waterMinX, + &waterMinY); + + rsw->water.getIndexFromGnd( + (int)glm::floor(glm::max(mouseDragStart.x, mouseDragEnd.x) / 10), + gnd->height - (int)glm::floor(glm::min(mouseDragStart.z, mouseDragEnd.z) / 10), + gnd, + &waterMaxX, + &waterMaxY); + + if (waterMinX >= 0 && waterMaxX < rsw->water.splitWidth && waterMinY >= 0 && waterMaxY < rsw->water.splitHeight) + for (int x = waterMinX; x < waterMaxX + 1; x++) + { + for (int y = waterMinY; y < waterMaxY + 1; y++) + { + if (ImGui::GetIO().KeyCtrl) + { + if (newSelection.contains(x + rsw->water.splitWidth * y)) + newSelection.erase(x + rsw->water.splitWidth * y); + } + else if (!newSelection.contains(x + rsw->water.splitWidth * y)) + newSelection[x + rsw->water.splitWidth * y] = glm::ivec2(x, y); + } + } + } + + std::vector newSelection2; + + for (const auto& entry : newSelection) { + newSelection2.push_back(entry.second); + } + + if (waterSelection != newSelection2) + { + map->doAction(new WaterZoneSelectAction(map, newSelection2), browEdit); + } + } + } + + if (mouseDown) + { + auto mouseDragEnd = mouse3D; + std::vector verts; + float dist = 0.002f * cameraDistance; + int waterMinX, waterMinY, waterMaxX, waterMaxY; + + rsw->water.getIndexFromGnd( + (int)glm::floor(glm::min(mouseDragStart.x, mouseDragEnd.x) / 10), + gnd->height - (int)glm::floor(glm::max(mouseDragStart.z, mouseDragEnd.z) / 10), + gnd, + &waterMinX, + &waterMinY); + + rsw->water.getIndexFromGnd( + (int)glm::floor(glm::max(mouseDragStart.x, mouseDragEnd.x) / 10), + gnd->height - (int)glm::floor(glm::min(mouseDragStart.z, mouseDragEnd.z) / 10), + gnd, + &waterMaxX, + &waterMaxY); + + ImGui::Begin("Statusbar"); + ImGui::Text("Selection: (%d,%d) - (%d,%d)", waterMinX, waterMinY, waterMaxX, waterMaxY); + ImGui::End(); + + //if (browEdit->selectTool == BrowEdit::SelectTool::Rectangle) + //{ + if (waterMinX >= 0 && waterMaxX < rsw->water.splitWidth && waterMinY >= 0 && waterMaxY < rsw->water.splitHeight) + for (int x = waterMinX; x < waterMaxX + 1; x++) + { + for (int y = waterMinY; y < waterMaxY + 1; y++) + { + int xmin, xmax, ymin, ymax; + auto zone = &rsw->water.zones[x][y]; + + rsw->water.getBoundsFromGnd(x, y, gnd, &xmin, &xmax, &ymin, &ymax); + + verts.push_back(VertexP3(glm::vec3(10 * xmin, -zone->height + dist, 10 * gnd->height - 10 * ymin))); + verts.push_back(VertexP3(glm::vec3(10 * xmax, -zone->height + dist, 10 * gnd->height - 10 * ymax))); + verts.push_back(VertexP3(glm::vec3(10 * xmax, -zone->height + dist, 10 * gnd->height - 10 * ymin))); + + verts.push_back(VertexP3(glm::vec3(10 * xmin, -zone->height + dist, 10 * gnd->height - 10 * ymax))); + verts.push_back(VertexP3(glm::vec3(10 * xmin, -zone->height + dist, 10 * gnd->height - 10 * ymin))); + verts.push_back(VertexP3(glm::vec3(10 * xmax, -zone->height + dist, 10 * gnd->height - 10 * ymax))); + } + } + + if (verts.size() > 0) + { + glEnableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); + glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3), verts[0].data); + simpleShader->setUniform(SimpleShader::Uniforms::color, glm::vec4(1, 0, 0, 0.5f)); + glDrawArrays(GL_TRIANGLES, 0, (int)verts.size()); + } + //} + } + + glDepthMask(1); + fbo->unbind(); +} \ No newline at end of file diff --git a/browedit/MapView.cpp b/browedit/MapView.cpp index a9ea8fa4..9df6f628 100644 --- a/browedit/MapView.cpp +++ b/browedit/MapView.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,9 @@ extern float timeSelected; MapView::MapView(Map* map, const std::string &viewName) : map(map), viewName(viewName), mouseRay(glm::vec3(0,0,0), glm::vec3(0,0,0)) { - fbo = new gl::FBO(1920, 1080, true); + fbo = new gl::FBO(1920, 1080, false, 1, true); + outlineFbo = new gl::FBO(1920, 1080, false, 1, true); + //shader = new TestShader(); auto gnd = map->rootNode->getComponent(); @@ -73,6 +76,8 @@ MapView::MapView(Map* map, const std::string &viewName) : map(map), viewName(vie skyDomeMesh.init(); if (!simpleShader) simpleShader = util::ResourceManager::load(); + if (!outlineShader) + outlineShader = util::ResourceManager::load(); for(int i = 0; i < 9; i++) gadgetHeight[i].mode = Gadget::Mode::TranslateY; @@ -80,8 +85,11 @@ MapView::MapView(Map* map, const std::string &viewName) : map(map), viewName(vie gridVbo = new gl::VBO(); rotateGridVbo = new gl::VBO(); textureGridVbo = new gl::VBO(); + waterGridVbo = new gl::VBO(); + outlineVbo = new gl::VBO(); rebuildObjectModeGrid(); rebuildObjectRotateModeGrid(); + rebuildOutlineVbo(); } void MapView::toolbar(BrowEdit* browEdit) @@ -335,6 +343,11 @@ void MapView::toolbar(BrowEdit* browEdit) void MapView::render(BrowEdit* browEdit) { + outlineFbo->bind(); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + outlineFbo->unbind(); + fbo->bind(); glViewport(0, 0, fbo->getWidth(), fbo->getHeight()); glClearColor(browEdit->config.backgroundColor.r, browEdit->config.backgroundColor.g, browEdit->config.backgroundColor.b, 1.0f); @@ -487,8 +500,46 @@ void MapView::render(BrowEdit* browEdit) } map->rootNode->getComponent()->enabled = viewWater; + nodeRenderContext.mapView = this; + nodeRenderContext.time = (float)glfwGetTime(); + nodeRenderContext.fbo = fbo; + nodeRenderContext.outlineFbo = outlineFbo; NodeRenderer::render(map->rootNode, nodeRenderContext); + // Draw selection outline + outlineShader->use(); + outlineShader->setUniform(OutlineShader::Uniforms::iResolution, glm::vec2(outlineFbo->getWidth(), outlineFbo->getHeight())); + outlineShader->setUniform(OutlineShader::Uniforms::selectionOverlay, glm::vec4(1, 0, 0, 0.15f)); + outlineShader->setUniform(OutlineShader::Uniforms::selectionOutline, glm::vec4(1, 0, 0, 1)); + outlineShader->setUniform(OutlineShader::Uniforms::selectionOccludedOverlay, glm::vec4(1, 1, 1, 0)); + outlineShader->setUniform(OutlineShader::Uniforms::selectionOccludedOutline, glm::vec4(1, 1, 1, 0.5f)); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, fbo->depthTexture); + glUniform1i(glGetUniformLocation(outlineShader->programId, "s_depth_fbo"), 1); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, outlineFbo->depthTexture); + glUniform1i(glGetUniformLocation(outlineShader->programId, "s_depth_outline"), 2); + glActiveTexture(GL_TEXTURE0); + + outlineVbo->bind(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBindTexture(GL_TEXTURE_2D, outlineFbo->texid[0]); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); + + glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3T2), (void*)(0 * sizeof(float))); + glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(VertexP3T2), (void*)(3 * sizeof(float))); + + glDrawArrays(GL_TRIANGLES, 0, (int)outlineVbo->size()); + glEnable(GL_DEPTH_TEST); + outlineVbo->unBind(); + // position and draw the new nodes if (browEdit->newNodes.size() > 0 && hovered) { @@ -626,6 +677,8 @@ void MapView::render(BrowEdit* browEdit) //update just fixes the camera void MapView::update(BrowEdit* browEdit, const ImVec2 &size, float deltaTime) { + if (outlineFbo->getWidth() != (int)size.x || outlineFbo->getHeight() != (int)size.y) + outlineFbo->resize((int)size.x, (int)size.y); if (fbo->getWidth() != (int)size.x || fbo->getHeight() != (int)size.y) fbo->resize((int)size.x, (int)size.y); mouseState.position = glm::vec2(ImGui::GetMousePos().x - ImGui::GetCursorScreenPos().x, ImGui::GetMousePos().y - ImGui::GetCursorScreenPos().y); @@ -1024,9 +1077,17 @@ void MapView::drawLight(Node* n) } } - - - +void MapView::rebuildOutlineVbo() +{ + std::vector verts; + verts.push_back(VertexP3T2(glm::vec3(-1, -1, 0), glm::vec2(0, 0))); + verts.push_back(VertexP3T2(glm::vec3(1, -1, 0), glm::vec2(1, 0))); + verts.push_back(VertexP3T2(glm::vec3(1, 1, 0), glm::vec2(1, 1))); + verts.push_back(VertexP3T2(glm::vec3(1, 1, 0), glm::vec2(1, 1))); + verts.push_back(VertexP3T2(glm::vec3(-1, 1, 0), glm::vec2(0, 1))); + verts.push_back(VertexP3T2(glm::vec3(-1, -1, 0), glm::vec2(0, 0))); + outlineVbo->setData(verts, GL_STATIC_DRAW); +} void MapView::CubeMesh::buildVertices(std::vector &verts) {//https://dotnetfiddle.net/tPcv8S diff --git a/browedit/MapView.h b/browedit/MapView.h index 961839ea..5575c128 100644 --- a/browedit/MapView.h +++ b/browedit/MapView.h @@ -10,6 +10,7 @@ #include class BrowEdit; class Map; +class OutlineShader; struct ImVec2; namespace gl @@ -61,12 +62,15 @@ class MapView gl::VBO* gridVbo = nullptr; gl::VBO* rotateGridVbo = nullptr; + gl::VBO* waterGridVbo = nullptr; + gl::VBO* outlineVbo = nullptr; NodeRenderContext nodeRenderContext; Gadget gadget; Gadget gadgetHeight[9]; BillboardRenderer::BillboardShader* billboardShader; SimpleShader* simpleShader = nullptr; + OutlineShader* outlineShader = nullptr; static inline SphereMesh sphereMesh; static inline CubeMesh cubeMesh; static inline SkyBoxMesh skyBoxMesh; @@ -81,6 +85,7 @@ class MapView bool opened = true; gl::FBO* fbo; + gl::FBO* outlineFbo; bool showViewOptions = false; bool ortho = false; @@ -122,6 +127,7 @@ class MapView gl::VBO* textureGridVbo = nullptr; bool textureGridSmart = true; bool textureGridDirty = true; + bool waterGridDirty = true; int textureSelected = 0; glm::vec2 textureEditUv1 = glm::vec2(0.0f, 0.0f); @@ -192,6 +198,7 @@ class MapView void postRenderColorMode(BrowEdit* browEdit); void postRenderShadowMode(BrowEdit* browEdit); void postRenderCinematicMode(BrowEdit* browEdit); + void postRenderWaterMode(BrowEdit* browEdit); void gatEdit_adjustToGround(BrowEdit* browEdit); @@ -200,6 +207,8 @@ class MapView void rebuildObjectModeGrid(); void rebuildObjectRotateModeGrid(); + void rebuildWaterGrid(Rsw* rsw, Gnd* gnd, bool forced = false); + void rebuildOutlineVbo(); //todo, move this to a struct for better organisation bool viewLightmapShadow = true; @@ -224,6 +233,8 @@ class MapView bool enableLightQuickPreview = false; bool hideOtherLightmaps = false; + bool showWaterGrid = true; + bool showWaterSelectedOverlay = true; void focusSelection(); void drawLight(Node* n); diff --git a/browedit/ModelEditor.cpp b/browedit/ModelEditor.cpp index 9e0e12f2..11bd2617 100644 --- a/browedit/ModelEditor.cpp +++ b/browedit/ModelEditor.cpp @@ -169,8 +169,6 @@ void ModelEditor::run(BrowEdit* browEdit) if (m.fbo->getWidth() != size.x || m.fbo->getHeight() != size.y) m.fbo->resize((int)size.x, (int)size.y); - rsmRenderer->time = fmod(timeSelected/1000.0f, rsm->animLen/1000.0f); - if (size.x > 0 && size.y > 0) { m.fbo->bind(); @@ -196,6 +194,8 @@ void ModelEditor::run(BrowEdit* browEdit) nodeRenderContext.viewMatrix = glm::translate(nodeRenderContext.viewMatrix, glm::vec3(0, rsm->bbrange.y, 0)); else nodeRenderContext.viewMatrix = glm::translate(nodeRenderContext.viewMatrix, glm::vec3(0, -rsm->bbrange.y, 0)); + nodeRenderContext.time = fmod(timeSelected / 1000.0f, rsm->animLen / 1000.0f); + nodeRenderContext.fbo = m.fbo; // draw grid simpleShader->use(); diff --git a/browedit/NodeRenderer.cpp b/browedit/NodeRenderer.cpp index 71feaf87..b9555633 100644 --- a/browedit/NodeRenderer.cpp +++ b/browedit/NodeRenderer.cpp @@ -6,6 +6,8 @@ #include #include "Node.h" +class NodeRenderContext; + void NodeRenderer::begin() { @@ -45,11 +47,11 @@ void NodeRenderer::render(Node* rootNode, NodeRenderContext& context) { for (int phase = 0; phase < r->phases; phase++) { r->phase = phase; - r->preFrame(rootNode, context.projectionMatrix, context.viewMatrix); + r->preFrame(rootNode, context); for (auto renderer : renderers[r]) if (renderer->enabled && renderer->shouldRender(phase)) - renderer->render(); - r->postFrame(); + renderer->render(context); + r->postFrame(context); } } } \ No newline at end of file diff --git a/browedit/NodeRenderer.h b/browedit/NodeRenderer.h index bf711c86..b599edb6 100644 --- a/browedit/NodeRenderer.h +++ b/browedit/NodeRenderer.h @@ -4,8 +4,14 @@ #include #include #include + class Node; class NodeRenderContext; +class MapView; + +namespace gl { + class FBO; +} class NodeRenderer { @@ -20,8 +26,11 @@ class NodeRenderContext public: glm::mat4 viewMatrix; glm::mat4 projectionMatrix; + float time; + gl::FBO* fbo; + gl::FBO* outlineFbo; + MapView* mapView; std::map>> renderers; std::map> ordered; - }; \ No newline at end of file diff --git a/browedit/actions/ObjectChangeAction.h b/browedit/actions/ObjectChangeAction.h index eed9dfb3..844dec20 100644 --- a/browedit/actions/ObjectChangeAction.h +++ b/browedit/actions/ObjectChangeAction.h @@ -2,6 +2,7 @@ #include "Action.h" #include +#include #include #include #include @@ -37,6 +38,11 @@ class ObjectChangeAction : public Action if (waterRenderer) { waterRenderer->renderFullWater = false; waterRenderer->setDirty(); + + for (auto& mv : browEdit->mapViews) + if (mv.map == map) { + mv.waterGridDirty = true; + } } if ((std::string*)ptr == &(node->name)) node->onRename(map); @@ -54,6 +60,11 @@ class ObjectChangeAction : public Action if (waterRenderer) { waterRenderer->renderFullWater = false; waterRenderer->setDirty(); + + for (auto& mv : browEdit->mapViews) + if (mv.map == map) { + mv.waterGridDirty = true; + } } if ((std::string*)ptr == &(node->name)) node->onRename(map); diff --git a/browedit/actions/TileSelectAction.cpp b/browedit/actions/TileSelectAction.cpp index ffcbcad6..ea28cad0 100644 --- a/browedit/actions/TileSelectAction.cpp +++ b/browedit/actions/TileSelectAction.cpp @@ -75,3 +75,30 @@ std::string GatTileSelectAction::str() { return "Gat selection"; } + + + +///////////////// + +WaterZoneSelectAction::WaterZoneSelectAction(Map* map, const std::vector& newSelection) +{ + oldSelection = map->waterSelection; + this->newSelection = newSelection; +} + + +void WaterZoneSelectAction::perform(Map* map, BrowEdit* browEdit) +{ + map->waterSelection = newSelection; +} + +void WaterZoneSelectAction::undo(Map* map, BrowEdit* browEdit) +{ + map->waterSelection = oldSelection; +} + +std::string WaterZoneSelectAction::str() +{ + return "Water selection"; +} + diff --git a/browedit/actions/TileSelectAction.h b/browedit/actions/TileSelectAction.h index 3abf22cb..c0675636 100644 --- a/browedit/actions/TileSelectAction.h +++ b/browedit/actions/TileSelectAction.h @@ -29,3 +29,16 @@ class GatTileSelectAction : public Action virtual void undo(Map* map, BrowEdit* browEdit) override; virtual std::string str() override; }; + +class WaterZoneSelectAction : public Action +{ + std::vector oldSelection; + std::vector newSelection; +public: + WaterZoneSelectAction(Map* map, const std::vector& newSelection); + + virtual void perform(Map* map, BrowEdit* browEdit) override; + virtual void undo(Map* map, BrowEdit* browEdit) override; + virtual std::string str() override; +}; + diff --git a/browedit/actions/WaterHeightChangeAction.cpp b/browedit/actions/WaterHeightChangeAction.cpp new file mode 100644 index 00000000..ea4fc90b --- /dev/null +++ b/browedit/actions/WaterHeightChangeAction.cpp @@ -0,0 +1,47 @@ +#include "WaterHeightChangeAction.h" +#include +#include +#include +#include + +WaterHeightChangeAction::WaterHeightChangeAction(const std::map& oldValues, const std::map& newValues, const std::vector& selection) +{ + this->selection = selection; + this->oldValues = oldValues; + this->newValues = newValues; +} + +void WaterHeightChangeAction::perform(Map* map, BrowEdit* browEdit) +{ + for (auto kv : newValues) + kv.first->height = kv.second; + + auto waterRenderer = map->rootNode->getComponent(); + if (waterRenderer) + waterRenderer->setDirty(); + for (auto& mv : browEdit->mapViews) + if (mv.map == map) { + mv.textureGridDirty = true; + mv.waterGridDirty = true; + } +} + +void WaterHeightChangeAction::undo(Map* map, BrowEdit* browEdit) +{ + for (auto kv : oldValues) + kv.first->height = kv.second; + + auto waterRenderer = map->rootNode->getComponent(); + if (waterRenderer) + waterRenderer->setDirty(); + for (auto& mv : browEdit->mapViews) + if (mv.map == map) { + mv.textureGridDirty = true; + mv.waterGridDirty = true; + } +} + +std::string WaterHeightChangeAction::str() +{ + return "Change water height"; +} diff --git a/browedit/actions/WaterHeightChangeAction.h b/browedit/actions/WaterHeightChangeAction.h new file mode 100644 index 00000000..22d317e6 --- /dev/null +++ b/browedit/actions/WaterHeightChangeAction.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Action.h" +#include +#include + +struct Rsw::Water; + +class WaterHeightChangeAction : public Action +{ + std::map oldValues; + std::map newValues; + std::vector selection; +public: + WaterHeightChangeAction(const std::map& oldValues, const std::map& newValues, const std::vector& selection); + + virtual void perform(Map* map, BrowEdit* browEdit); + virtual void undo(Map* map, BrowEdit* browEdit); + virtual std::string str();; +}; \ No newline at end of file diff --git a/browedit/actions/WaterZoneSelectAction.cpp b/browedit/actions/WaterZoneSelectAction.cpp new file mode 100644 index 00000000..5fcf433f --- /dev/null +++ b/browedit/actions/WaterZoneSelectAction.cpp @@ -0,0 +1,77 @@ +#include +#include "TileSelectAction.h" + +#include + +TileSelectAction::TileSelectAction(Map* map, const glm::ivec2& pos, bool keepSelection, bool deSelect) +{ + oldSelection = map->tileSelection; + if (keepSelection) + newSelection = oldSelection; + + if (!deSelect) + newSelection.push_back(pos); + else + newSelection.erase(std::remove_if(newSelection.begin(), newSelection.end(), [&pos](const glm::ivec2& n) { return n == pos; })); +} + +TileSelectAction::TileSelectAction(Map* map, const std::vector& newSelection) +{ + oldSelection = map->tileSelection; + this->newSelection = newSelection; +} + + +void TileSelectAction::perform(Map* map, BrowEdit* browEdit) +{ + map->tileSelection = newSelection; +} + +void TileSelectAction::undo(Map* map, BrowEdit* browEdit) +{ + map->tileSelection = oldSelection; +} + +std::string TileSelectAction::str() +{ + return "Tile selection"; +} + + + +///////////////// + + +GatTileSelectAction::GatTileSelectAction(Map* map, const glm::ivec2& pos, bool keepSelection, bool deSelect) +{ + oldSelection = map->tileSelection; + if (keepSelection) + newSelection = oldSelection; + + if (!deSelect) + newSelection.push_back(pos); + else + newSelection.erase(std::remove_if(newSelection.begin(), newSelection.end(), [&pos](const glm::ivec2& n) { return n == pos; })); +} + +GatTileSelectAction::GatTileSelectAction(Map* map, const std::vector& newSelection) +{ + oldSelection = map->tileSelection; + this->newSelection = newSelection; +} + + +void GatTileSelectAction::perform(Map* map, BrowEdit* browEdit) +{ + map->gatSelection = newSelection; +} + +void GatTileSelectAction::undo(Map* map, BrowEdit* browEdit) +{ + map->gatSelection = oldSelection; +} + +std::string GatTileSelectAction::str() +{ + return "Gat selection"; +} diff --git a/browedit/actions/WaterZoneSelectAction.h b/browedit/actions/WaterZoneSelectAction.h new file mode 100644 index 00000000..3abf22cb --- /dev/null +++ b/browedit/actions/WaterZoneSelectAction.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Action.h" +#include +#include + +class TileSelectAction : public Action +{ + std::vector oldSelection; + std::vector newSelection; +public: + TileSelectAction(Map* map, const glm::ivec2& pos, bool keepSelection, bool deSelect); + TileSelectAction(Map* map, const std::vector& newSelection); + + virtual void perform(Map* map, BrowEdit* browEdit) override; + virtual void undo(Map* map, BrowEdit* browEdit) override; + virtual std::string str() override; +}; + +class GatTileSelectAction : public Action +{ + std::vector oldSelection; + std::vector newSelection; +public: + GatTileSelectAction(Map* map, const glm::ivec2& pos, bool keepSelection, bool deSelect); + GatTileSelectAction(Map* map, const std::vector& newSelection); + + virtual void perform(Map* map, BrowEdit* browEdit) override; + virtual void undo(Map* map, BrowEdit* browEdit) override; + virtual std::string str() override; +}; diff --git a/browedit/components/BillboardRenderer.cpp b/browedit/components/BillboardRenderer.cpp index 5782c94f..1faa6249 100644 --- a/browedit/components/BillboardRenderer.cpp +++ b/browedit/components/BillboardRenderer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ BillboardRenderer::~BillboardRenderer() } -void BillboardRenderer::render() +void BillboardRenderer::render(NodeRenderContext& context) { if (!rswObject) rswObject = node->getComponent(); @@ -82,14 +83,14 @@ BillboardRenderer::BillboardRenderContext::BillboardRenderContext() : shader(uti order = 3; } -void BillboardRenderer::BillboardRenderContext::preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) +void BillboardRenderer::BillboardRenderContext::preFrame(Node* rootNode, NodeRenderContext& context) { glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); shader->use(); - shader->setUniform(BillboardShader::Uniforms::projectionMatrix, projectionMatrix); - shader->setUniform(BillboardShader::Uniforms::cameraMatrix, viewMatrix); + shader->setUniform(BillboardShader::Uniforms::projectionMatrix, context.projectionMatrix); + shader->setUniform(BillboardShader::Uniforms::cameraMatrix, context.viewMatrix); shader->setUniform(BillboardShader::Uniforms::color, glm::vec4(1,1,1,1)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); diff --git a/browedit/components/BillboardRenderer.h b/browedit/components/BillboardRenderer.h index 5c400760..4a8ff2e5 100644 --- a/browedit/components/BillboardRenderer.h +++ b/browedit/components/BillboardRenderer.h @@ -7,6 +7,7 @@ namespace gl { class Texture; } class RswObject; class Gnd; +class NodeRenderContext; class BillboardRenderer : public Renderer { @@ -52,12 +53,12 @@ class BillboardRenderer : public Renderer bool viewLighting = true; BillboardRenderContext(); - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) override; + virtual void preFrame(Node* rootNode, NodeRenderContext& context) override; }; BillboardRenderer(const std::string& texture, const std::string& texture_selected = ""); ~BillboardRenderer(); - virtual void render(); + virtual void render(NodeRenderContext& context); bool selected = false; void setTexture(const std::string &texture); diff --git a/browedit/components/GatRenderer.cpp b/browedit/components/GatRenderer.cpp index f8c57ce7..0e50c674 100644 --- a/browedit/components/GatRenderer.cpp +++ b/browedit/components/GatRenderer.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ GatRenderer::~GatRenderer() delete c; } -void GatRenderer::render() +void GatRenderer::render(NodeRenderContext& context) { if (!this->gat) { @@ -65,12 +66,12 @@ GatRenderer::GatRenderContext::GatRenderContext() : shader(util::ResourceManager } -void GatRenderer::GatRenderContext::preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) +void GatRenderer::GatRenderContext::preFrame(Node* rootNode, NodeRenderContext& context) { texture->bind(); shader->use(); - shader->setUniform(SimpleShader::Uniforms::projectionMatrix, projectionMatrix); - shader->setUniform(SimpleShader::Uniforms::viewMatrix, viewMatrix); + shader->setUniform(SimpleShader::Uniforms::projectionMatrix, context.projectionMatrix); + shader->setUniform(SimpleShader::Uniforms::viewMatrix, context.viewMatrix); shader->setUniform(SimpleShader::Uniforms::textureFac, 1.0f); shader->setUniform(SimpleShader::Uniforms::lightMin, 0.5f); shader->setUniform(SimpleShader::Uniforms::color, glm::vec4(1, 1, 1, 1)); diff --git a/browedit/components/GatRenderer.h b/browedit/components/GatRenderer.h index e3ea4611..2bf38c64 100644 --- a/browedit/components/GatRenderer.h +++ b/browedit/components/GatRenderer.h @@ -27,7 +27,7 @@ class GatRenderer : public Renderer SimpleShader* shader = nullptr; gl::Texture* texture = nullptr; GatRenderContext(); - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) override; + virtual void preFrame(Node* rootNode, NodeRenderContext& context) override; }; class Chunk @@ -57,5 +57,5 @@ class GatRenderer : public Renderer GatRenderer(gl::Texture* texture); ~GatRenderer(); - void render() override; + void render(NodeRenderContext& context) override; }; \ No newline at end of file diff --git a/browedit/components/GndRenderer.cpp b/browedit/components/GndRenderer.cpp index f07d18af..40dfdae6 100644 --- a/browedit/components/GndRenderer.cpp +++ b/browedit/components/GndRenderer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ GndRenderer::~GndRenderer() delete c; } -void GndRenderer::render() +void GndRenderer::render(NodeRenderContext& context) { if (!this->gnd) { //todo: move a tryLoadGnd method @@ -188,11 +189,11 @@ GndRenderer::GndRenderContext::GndRenderContext() : shader(util::ResourceManager } -void GndRenderer::GndRenderContext::preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) +void GndRenderer::GndRenderContext::preFrame(Node* rootNode, NodeRenderContext& context) { shader->use(); - shader->setUniform(GndShader::Uniforms::ProjectionMatrix, projectionMatrix); - this->viewMatrix = viewMatrix; + shader->setUniform(GndShader::Uniforms::ProjectionMatrix, context.projectionMatrix); + this->viewMatrix = context.viewMatrix; glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); diff --git a/browedit/components/GndRenderer.h b/browedit/components/GndRenderer.h index bdc6b466..8b92685b 100644 --- a/browedit/components/GndRenderer.h +++ b/browedit/components/GndRenderer.h @@ -30,7 +30,7 @@ class GndRenderer : public Renderer glm::mat4 viewMatrix = glm::mat4(1.0f); GndRenderContext(); - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) override; + virtual void preFrame(Node* rootNode, NodeRenderContext& context) override; }; class VboIndex @@ -80,7 +80,7 @@ class GndRenderer : public Renderer GndRenderer(); ~GndRenderer(); - void render() override; + void render(NodeRenderContext& context) override; bool viewLightmapShadow = true; diff --git a/browedit/components/LubRenderer.cpp b/browedit/components/LubRenderer.cpp index 84346479..fe5db142 100644 --- a/browedit/components/LubRenderer.cpp +++ b/browedit/components/LubRenderer.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,7 @@ int d3dToOpenGlBlend(int d3d) return GL_ONE; } -void LubRenderer::render() +void LubRenderer::render(NodeRenderContext& context) { if (!rswObject) rswObject = node->getComponent(); @@ -219,12 +220,12 @@ LubRenderer::LubRenderContext::LubRenderContext() : shader(util::ResourceManager order = 4; } -void LubRenderer::LubRenderContext::preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) +void LubRenderer::LubRenderContext::preFrame(Node* rootNode, NodeRenderContext& context) { glEnable(GL_DEPTH_TEST); shader->use(); - shader->setUniform(LubShader::Uniforms::projectionMatrix, projectionMatrix); - shader->setUniform(LubShader::Uniforms::cameraMatrix, viewMatrix); + shader->setUniform(LubShader::Uniforms::projectionMatrix, context.projectionMatrix); + shader->setUniform(LubShader::Uniforms::cameraMatrix, context.viewMatrix); shader->setUniform(LubShader::Uniforms::color, glm::vec4(1,1,1,1)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); diff --git a/browedit/components/LubRenderer.h b/browedit/components/LubRenderer.h index 08b0ae66..cfe9e57f 100644 --- a/browedit/components/LubRenderer.h +++ b/browedit/components/LubRenderer.h @@ -78,12 +78,12 @@ class LubRenderer : public Renderer glm::mat4 viewMatrix = glm::mat4(1.0f); LubRenderContext(); - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) override; + virtual void preFrame(Node* rootNode, NodeRenderContext& context) override; }; LubRenderer(); ~LubRenderer(); - virtual void render(); + virtual void render(NodeRenderContext& context); bool selected = false; void setDirty() { this->dirty = true; } }; \ No newline at end of file diff --git a/browedit/components/Renderer.h b/browedit/components/Renderer.h index 8d0caf91..70890584 100644 --- a/browedit/components/Renderer.h +++ b/browedit/components/Renderer.h @@ -3,6 +3,8 @@ #include "Component.h" #include +class NodeRenderContext; + class Renderer : public Component { public: @@ -14,12 +16,12 @@ class Renderer : public Component int order = 0; int phases = 1; int phase = 0; - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) = 0; - virtual void postFrame() { } + virtual void preFrame(Node* rootNode, NodeRenderContext& context) = 0; + virtual void postFrame(NodeRenderContext& context) { } }; RenderContext* renderContext; - virtual void render() = 0; + virtual void render(NodeRenderContext& context) = 0; virtual bool shouldRender(int phase) { return phase == 0; } bool enabled = true; }; \ No newline at end of file diff --git a/browedit/components/Rsm.cpp b/browedit/components/Rsm.cpp index 97364cc6..afa37194 100644 --- a/browedit/components/Rsm.cpp +++ b/browedit/components/Rsm.cpp @@ -606,24 +606,6 @@ void Rsm::Mesh::calcMatrix1(int time) else { matrix2 = glm::mat4(1.0f); - if (scaleFrames.size() > 0) { - int tick = time % glm::max(1, model->animLen); - int prevIndex = -1; - int nextIndex = 0; - - for (; nextIndex < scaleFrames.size() && tick >= scaleFrames[nextIndex].time; nextIndex++) { - } - - prevIndex = nextIndex - 1; - float prevTick = (float)(prevIndex < 0 ? 0 : scaleFrames[prevIndex].time); - float nextTick = (float)(nextIndex == scaleFrames.size() ? model->animLen : scaleFrames[nextIndex].time); - glm::vec3 prev = prevIndex < 0 ? glm::vec3(1) : scaleFrames[prevIndex].scale; - glm::vec3 next = nextIndex == scaleFrames.size() ? scaleFrames[nextIndex - 1].scale : scaleFrames[nextIndex].scale; - - float mult = (tick - prevTick) / (nextTick - prevTick); - matrix1 = glm::scale(matrix1, mult * (next - prev) + prev); - } - if (rotFrames.size() > 0) { int tick = time % glm::max(1, model->animLen); @@ -653,9 +635,26 @@ void Rsm::Mesh::calcMatrix1(int time) } } - matrix2 = glm::mat4(matrix1); + if (scaleFrames.size() > 0) { + int tick = time % glm::max(1, model->animLen); + int prevIndex = -1; + int nextIndex = 0; + + for (; nextIndex < scaleFrames.size() && tick >= scaleFrames[nextIndex].time; nextIndex++) { + } + + prevIndex = nextIndex - 1; + float prevTick = (float)(prevIndex < 0 ? 0 : scaleFrames[prevIndex].time); + float nextTick = (float)(nextIndex == scaleFrames.size() ? model->animLen : scaleFrames[nextIndex].time); + glm::vec3 prev = prevIndex < 0 ? glm::vec3(1) : scaleFrames[prevIndex].scale; + glm::vec3 next = nextIndex == scaleFrames.size() ? scaleFrames[nextIndex - 1].scale : scaleFrames[nextIndex].scale; + + float mult = (tick - prevTick) / (nextTick - prevTick); + matrix1 = glm::scale(matrix1, mult * (next - prev) + prev); + } + glm::vec3 position; - + if (posFrames.size() > 0) { int tick = time % glm::max(1, model->animLen); int prevIndex = -1; @@ -684,25 +683,12 @@ void Rsm::Mesh::calcMatrix1(int time) position = pos_; } } - - matrix2[3].x = position.x; - matrix2[3].y = position.y; - matrix2[3].z = position.z; - - Mesh *mesh = this; - - while (mesh->parent != NULL) - { - mesh = mesh->parent; - matrix2 = mesh->matrix1 * matrix2; - } + matrix1 = glm::translate(glm::mat4(1.0f), position) * matrix1; + matrix2 = matrix1; + if (parent != NULL) - { - matrix2[3].x += parent->matrix2[3].x; - matrix2[3].y += parent->matrix2[3].y; - matrix2[3].z += parent->matrix2[3].z; - } + matrix2 = parent->matrix2 * matrix2; // Cull face check reverseCullFaceSub = cull < 0; diff --git a/browedit/components/RsmRenderer.cpp b/browedit/components/RsmRenderer.cpp index 8367b28c..ce4a22cd 100644 --- a/browedit/components/RsmRenderer.cpp +++ b/browedit/components/RsmRenderer.cpp @@ -7,6 +7,10 @@ #include #include #include +#include +#include +#include +#include #include RsmRenderer::RsmRenderer() @@ -42,7 +46,7 @@ void RsmRenderer::begin() renderInfo.clear(); } -void RsmRenderer::render() +void RsmRenderer::render(NodeRenderContext& context) { if (!this->rsm || !this->rsm->loaded) { @@ -70,6 +74,8 @@ void RsmRenderer::render() this->rsw = node->root->getComponent(); if (!this->rsm) return; + + time = context.time; if (!this->rsm->loaded) { @@ -97,6 +103,10 @@ void RsmRenderer::render() renderInfo[i].vbo.resize(renderContext->phases); renderInfo[i].indices.resize(renderContext->phases); } + if (textures.size() == 0) { + for (const auto& textureFilename : rsm->textures) + textures.push_back(util::ResourceManager::load("data\\texture\\" + textureFilename)); + } initMeshInfo(rsm->rootMesh); } @@ -146,10 +156,13 @@ void RsmRenderer::render() { matrixCache = glm::mat4(1.0f); matrixCache = glm::scale(matrixCache, glm::vec3(1, -1, 1)); - } - phase = dynamic_cast(renderContext)->phase; + if (rsm->version >= 0x202) + reverseCullFace = true; + } + phase = renderContext->phase; + auto shader = dynamic_cast(renderContext)->shader; shader->setUniform(RsmShader::Uniforms::shadeType, (int)rsm->shadeType); shader->setUniform(RsmShader::Uniforms::modelMatrix2, matrixCache); @@ -159,27 +172,29 @@ void RsmRenderer::render() else glFrontFace(GL_CCW); - if (selected) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glLineWidth(20.0f); - glDepthMask(GL_FALSE); - shader->setUniform(RsmShader::Uniforms::selection, 1.0f); - renderMesh(rsm->rootMesh, glm::mat4(1.0f), true); - - glDepthMask(GL_TRUE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + if (phase == 3) { + if (selected) { + auto rsmRenderContext = dynamic_cast(renderContext); + int current = ++rsmRenderContext->counter; + shader->setUniform(RsmShader::Uniforms::selectedColor, glm::vec4((current % 255) / 255.0f, (current / 255) / 255.0f, 0, 1)); + + for (int i = 0; i < 3; i++) { + phase = i; + if (i == 0) + shader->setUniform(RsmShader::Uniforms::discardAlphaValue, 0.8f); + else + shader->setUniform(RsmShader::Uniforms::discardAlphaValue, 0.0f); + + renderMesh(rsm->rootMesh, glm::mat4(1.0f), true); + } - if (phase > 0) { - glDepthMask(GL_FALSE); + phase = 3; } - shader->setUniform(RsmShader::Uniforms::selection, 0.25f); - renderMesh(rsm->rootMesh, glm::mat4(1.0f)); - shader->setUniform(RsmShader::Uniforms::selection, 0.0f); + return; } - else - renderMesh(rsm->rootMesh, glm::mat4(1.0f)); + + renderMesh(rsm->rootMesh, glm::mat4(1.0f)); } @@ -193,7 +208,8 @@ void RsmRenderer::initMeshInfo(Rsm::Mesh* mesh, const glm::mat4 &matrix) verts[mesh->faces[i].texId].push_back(VertexP3T2N3C1(mesh->vertices[mesh->faces[i].vertexIds[ii]], mesh->texCoords[mesh->faces[i].texCoordIds[ii]], mesh->faces[i].vertexNormals[ii], (float)mesh->faces[i].twoSided)); } - std::vector allVerts[3]; + std::vector allVerts[4]; + int phaseId = 0; for (std::map >::iterator it2 = verts.begin(); it2 != verts.end(); it2++) @@ -251,15 +267,10 @@ void RsmRenderer::renderMeshSub(Rsm::Mesh* mesh, bool selectionPhase) vbo->bind(); shader->setUniform(RsmShader::Uniforms::modelMatrix, renderInfo[mesh->index].matrix); shader->setUniform(RsmShader::Uniforms::reverseCullFace, mesh->reverseCullFace); - if (ri.selected || selectionPhase) - shader->setUniform(RsmShader::Uniforms::selection, 1.0f); - else if (!selectionPhase && selected) - shader->setUniform(RsmShader::Uniforms::selection, .25f); - else - shader->setUniform(RsmShader::Uniforms::selection, .0f); if (ri.selected) - glDisable(GL_DEPTH_TEST); - + shader->setUniform(RsmShader::Uniforms::selection, 0.25f); + else + shader->setUniform(RsmShader::Uniforms::selection, 0.0f); glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3T2N3C1), (void*)(0 * sizeof(float))); glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(VertexP3T2N3C1), (void*)(3 * sizeof(float))); glVertexAttribPointer(2, 3, GL_FLOAT, false, sizeof(VertexP3T2N3C1), (void*)(5 * sizeof(float))); @@ -361,18 +372,18 @@ void RsmRenderer::setMeshesDirty() { RsmRenderer::RsmRenderContext::RsmRenderContext() : shader(util::ResourceManager::load()) { order = 1; - phases = 3; + phases = 4; shader->use(); shader->setUniform(RsmShader::Uniforms::s_texture, 0); } -void RsmRenderer::RsmRenderContext::preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) +void RsmRenderer::RsmRenderContext::preFrame(Node* rootNode, NodeRenderContext& context) { shader->use(); if (phase == 0) { - shader->setUniform(RsmShader::Uniforms::projectionMatrix, projectionMatrix); - shader->setUniform(RsmShader::Uniforms::cameraMatrix, viewMatrix); + shader->setUniform(RsmShader::Uniforms::projectionMatrix, context.projectionMatrix); + shader->setUniform(RsmShader::Uniforms::cameraMatrix, context.viewMatrix); shader->setUniform(RsmShader::Uniforms::lightToggle, viewLighting); shader->setUniform(RsmShader::Uniforms::viewTextures, viewTextures); shader->setUniform(RsmShader::Uniforms::fogEnabled, viewFog); @@ -423,9 +434,20 @@ void RsmRenderer::RsmRenderContext::preFrame(Node* rootNode, const glm::mat4& pr shader->setUniform(RsmShader::Uniforms::enableCullFace, false); } + else if (phase == 3) { + if (context.outlineFbo == nullptr) + return; + + glDepthFunc(GL_LESS); + glDepthMask(true); + context.fbo->unbind(); + context.outlineFbo->bind(); + shader->setUniform(RsmShader::Uniforms::selected, true); + counter = 0; + } } -void RsmRenderer::RsmRenderContext::postFrame() +void RsmRenderer::RsmRenderContext::postFrame(NodeRenderContext& context) { if (phase == 0) { @@ -437,6 +459,14 @@ void RsmRenderer::RsmRenderContext::postFrame() glDepthMask(true); shader->setUniform(RsmShader::Uniforms::textureAnimToggle, false); } + else if (phase == 3) { + if (context.outlineFbo == nullptr) + return; + + shader->setUniform(RsmShader::Uniforms::selected, false); + context.outlineFbo->unbind(); + context.fbo->bind(); + } glFrontFace(GL_CCW); } \ No newline at end of file diff --git a/browedit/components/RsmRenderer.h b/browedit/components/RsmRenderer.h index 196a45f9..52016c90 100644 --- a/browedit/components/RsmRenderer.h +++ b/browedit/components/RsmRenderer.h @@ -27,10 +27,11 @@ class RsmRenderer : public Renderer bool viewTextures = true; bool viewFog = true; bool enableFaceCulling = true; + int counter = 0; RsmRenderContext(); - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) override; - virtual void postFrame() override; + virtual void preFrame(Node* rootNode, NodeRenderContext& context) override; + virtual void postFrame(NodeRenderContext& context) override; }; class VboIndex { @@ -77,7 +78,7 @@ class RsmRenderer : public Renderer RsmRenderer(); ~RsmRenderer(); void begin(); - virtual void render(); + virtual void render(NodeRenderContext& context) override; void initMeshInfo(Rsm::Mesh* mesh, const glm::mat4& matrix = glm::mat4(1.0f)); void renderMesh(Rsm::Mesh* mesh, const glm::mat4& matrix, bool selectionPhase = false, bool calcMatrix = true); void renderMeshSub(Rsm::Mesh* mesh, bool selectionPhase); diff --git a/browedit/components/Rsw.cpp b/browedit/components/Rsw.cpp index cd799d05..8b550b23 100644 --- a/browedit/components/Rsw.cpp +++ b/browedit/components/Rsw.cpp @@ -610,17 +610,28 @@ void Rsw::save(const std::string& fileName, BrowEdit* browEdit) extraFile << std::setw(2)< 0) { - std::cout << "Lub effects found, saving to " << browEdit->config.ropath << "data\\luafiles514\\lua files\\effecttool\\" << mapName << ".lub" << std::endl; - std::ofstream lubFile((browEdit->config.ropath + "data\\luafiles514\\lua files\\effecttool\\" + mapName + ".lub").c_str(), std::ios_base::out | std::ios_base::binary); + std::string mapName = fileName; + if (mapName.find(".rsw") != std::string::npos) + mapName = mapName.substr(0, mapName.find(".rsw")); + if (mapName.find("\\") != std::string::npos) + mapName = mapName.substr(mapName.rfind("\\")+1); + std::string luaMapName = util::replace(mapName, "@", ""); + std::string lubDirectory = browEdit->config.ropath + "data\\luafiles514\\lua files\\effecttool\\"; + + // Use the path from the fileName instead, in case the user exported the map elsewhere + if (fileName.find("\\") != std::string::npos) + lubDirectory = fileName.substr(0, fileName.rfind("\\")) + "\\luafiles514\\lua files\\effecttool\\"; + + std::string lubPath = lubDirectory + mapName + ".lub"; + + std::cout << "LUB: " + lubPath << std::endl; + if (!std::filesystem::exists(lubDirectory)) { + std::filesystem::create_directories(lubDirectory); + } + + std::ofstream lubFile(lubPath.c_str(), std::ios_base::out | std::ios_base::binary); lubFile << "_" << luaMapName << "_effect_version = "<activeMapView->map->rootNode->getComponent(); - - if (gnd && gnd->version >= 0x108) { - if (util::DragInt(browEdit, browEdit->activeMapView->map, node, "Split width", &water.splitWidth, 1, 1, 10, "", [&](int* ptr, int startValue) { - water.splitWidth = glm::max(1, water.splitWidth); - water.splitHeight = glm::max(1, water.splitHeight); - auto action = new WaterSplitChangeAction(water, startValue, water.splitHeight); - browEdit->activeMapView->map->doAction(action, browEdit); - })) { - water.resize(water.splitWidth, water.splitHeight); - auto waterRenderer = node->getComponent(); - waterRenderer->setDirty(); - } - - if (util::DragInt(browEdit, browEdit->activeMapView->map, node, "Split height", &water.splitHeight, 1, 1, 10, "", [&](int* ptr, int startValue) { - water.splitWidth = glm::max(1, water.splitWidth); - water.splitHeight = glm::max(1, water.splitHeight); - auto action = new WaterSplitChangeAction(water, glm::max(1, water.splitWidth), startValue); - browEdit->activeMapView->map->doAction(action, browEdit); - })) { - water.resize(water.splitWidth, water.splitHeight); - auto waterRenderer = node->getComponent(); - waterRenderer->setDirty(); - } - - if (gnd->version >= 0x109) { - for (int y = 0; y < water.splitHeight; y++) { - for (int x = 0; x < water.splitWidth; x++) { - ImGui::LabelText("", "Water zone: x:%d - y:%d", x, y); - - std::string uid = std::to_string(x) + "_" + std::to_string(y); - - if (util::DragInt(browEdit, browEdit->activeMapView->map, node, ("Type##" + uid).c_str(), &water.zones[x][y].type, 1, 0, 1000)) - { - auto waterRenderer = node->getComponent(); - waterRenderer->reloadTextures(); - } - if (util::DragFloat(browEdit, browEdit->activeMapView->map, node, ("Height##" + uid).c_str(), &water.zones[x][y].height, 0.1f, -100, 100)) { - auto waterRenderer = node->getComponent(); - - if (!waterRenderer->renderFullWater) { - waterRenderer->renderFullWater = true; - waterRenderer->setDirty(); - } - } - util::DragFloat(browEdit, browEdit->activeMapView->map, node, ("Wave Height##" + uid).c_str(), &water.zones[x][y].amplitude, 0.1f, -100, 100); - util::DragInt(browEdit, browEdit->activeMapView->map, node, ("Texture Animation Speed##" + uid).c_str(), &water.zones[x][y].textureAnimSpeed, 1, 0, 1000); - util::DragFloat(browEdit, browEdit->activeMapView->map, node, ("Wave Speed##" + uid).c_str(), &water.zones[x][y].waveSpeed, 0.1f, -100, 100); - util::DragFloat(browEdit, browEdit->activeMapView->map, node, ("Wave Pitch##" + uid).c_str(), &water.zones[x][y].wavePitch, 0.1f, -100, 100); - } - } - } - else { // 0x108 - if (util::DragInt(browEdit, browEdit->activeMapView->map, node, "Type", &water.zones[0][0].type, 1, 0, 1000)) - { - auto waterRenderer = node->getComponent(); - waterRenderer->reloadTextures(); - } - util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Wave Height", &water.zones[0][0].amplitude, 0.1f, -100, 100); - util::DragInt(browEdit, browEdit->activeMapView->map, node, "Texture Animation Speed", &water.zones[0][0].textureAnimSpeed, 1, 0, 1000); - util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Wave Speed", &water.zones[0][0].waveSpeed, 0.1f, -100, 100); - util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Wave Pitch", &water.zones[0][0].wavePitch, 0.1f, -100, 100); - - for (int y = 0; y < water.splitHeight; y++) { - for (int x = 0; x < water.splitWidth; x++) { - ImGui::LabelText("", "Water zone: x:%d - y:%d", x, y); - - std::string uid = std::to_string(x) + "_" + std::to_string(y); - - if (util::DragFloat(browEdit, browEdit->activeMapView->map, node, ("Height##" + uid).c_str(), &water.zones[x][y].height, 0.1f, -100, 100)) { - auto waterRenderer = node->getComponent(); - - if (!waterRenderer->renderFullWater) { - waterRenderer->renderFullWater = true; - waterRenderer->setDirty(); - } - } - } - } - } - } - else { - if (util::DragInt(browEdit, browEdit->activeMapView->map, node, "Type", &water.zones[0][0].type, 1, 0, 1000)) - { - auto waterRenderer = node->getComponent(); - waterRenderer->reloadTextures(); - } - if (util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Height", &water.zones[0][0].height, 0.1f, -100, 100)) { - auto waterRenderer = node->getComponent(); - - if (!waterRenderer->renderFullWater) { - waterRenderer->renderFullWater = true; - waterRenderer->setDirty(); - } - } - util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Wave Height", &water.zones[0][0].amplitude, 0.1f, -100, 100); - util::DragInt(browEdit, browEdit->activeMapView->map, node, "Texture Animation Speed", &water.zones[0][0].textureAnimSpeed, 1, 0, 1000); - util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Wave Speed", &water.zones[0][0].waveSpeed, 0.1f, -100, 100); - util::DragFloat(browEdit, browEdit->activeMapView->map, node, "Wave Pitch", &water.zones[0][0].wavePitch, 0.1f, -100, 100); - } + ImGui::Text("Water settings are now in the 'Water edit mode' tab."); } if (ImGui::CollapsingHeader("Fog", ImGuiTreeNodeFlags_DefaultOpen)) @@ -1506,7 +1418,29 @@ Rsw::Water* Rsw::WaterData::getFromGat(int x, int y, Gnd* gnd) { } Rsw::Water* Rsw::WaterData::getFromGnd(int x, int y, Gnd* gnd) { - return &zones[glm::min(splitWidth - 1, x / (gnd->width / splitWidth))][glm::min(splitHeight - 1, y / (gnd->height / splitHeight))]; + return &zones[glm::min(splitWidth - 1, x / (int)(gnd->width / splitWidth))][glm::min(splitHeight - 1, y / (int)(gnd->height / splitHeight))]; +} + +void Rsw::WaterData::getIndexFromGnd(int x, int y, Gnd* gnd, int* wx, int* wy) { + *wx = glm::min(splitWidth - 1, x / (int)(gnd->width / splitWidth)); + *wy = glm::min(splitHeight - 1, y / (int)(gnd->height / splitHeight)); +} + +void Rsw::WaterData::getBoundsFromGnd(int x, int y, Gnd* gnd, int* xmin, int* xmax, int* ymin, int* ymax) { + int perWidth = glm::max(1, gnd->width / glm::max(1, splitWidth)); + int perHeight = glm::max(1, gnd->height / glm::max(1, splitHeight)); + + *xmin = perWidth * x; + *xmax = perWidth * (x + 1); + + if (x == splitWidth - 1) + *xmax = gnd->width; + + *ymin = perHeight * y - 1; + *ymax = perHeight * (y + 1) - 1; + + if (y == splitHeight - 1) + *ymax = gnd->height - 1; } void Rsw::WaterData::resize(int width, int height) { @@ -1521,4 +1455,107 @@ void Rsw::WaterData::resize(int width, int height) { for (int y = (int)zones.size(); y < width; y++) { zones.push_back(zones[zones.size() - 1]); } +} + + + +glm::vec3 Rsw::rayCastWater(const math::Ray& ray, Gnd* gnd, bool emptyTiles, int xMin, int yMin, int xMax, int yMax, float rayOffset) +{ + if (version < 0x109) + return glm::vec3(std::numeric_limits::max()); + + if (water.zones.size() == 0 || water.splitWidth <= 0 || water.splitHeight <= 0) + return glm::vec3(std::numeric_limits::max()); + + if (xMax == -1) + xMax = water.splitWidth; + if (yMax == -1) + yMax = water.splitHeight; + + xMin = glm::max(0, xMin); + yMin = glm::max(0, yMin); + xMax = glm::min(xMax, water.splitWidth); + yMax = glm::min(yMax, water.splitHeight); + + const int chunkSize = 10; + + std::vector collisions; + float f = 0; + int height = gnd->height; + int width = gnd->width; + + int perWidth = width / glm::max(1, water.splitWidth); + int perHeight = height / glm::max(1, water.splitHeight); + + for (auto xx = xMin; xx < xMax; xx += chunkSize) + { + for (auto yy = yMin; yy < yMax; yy += chunkSize) + { + auto water0 = &water.zones[xx][yy]; + + int xmin0 = perWidth * xx; + int xmax0 = perWidth * (xx + chunkSize); + + if (xx + chunkSize >= water.splitWidth - 1) + xmax0 = width; + + int ymin0 = perHeight * yy - 1; + int ymax0 = perHeight * (yy + chunkSize) - 1; + + if (yy + chunkSize >= water.splitHeight - 1) + ymax0 = height - 1; + + math::AABB box(glm::vec3(10 * xmin0, -999999, 10 * height - 10 * ymax0), glm::vec3(10 * xmax0, 999999, 10 * height - 10 * ymin0)); + if (!box.hasRayCollision(ray, -999999, 9999999)) + continue; + for (int x = xx; x < glm::min(water.splitWidth, xx + chunkSize); x++) + { + for (int y = yy; y < glm::min(water.splitHeight, yy + chunkSize); y++) + { + auto water1 = &water.zones[x][y]; + + float waveHeight = -water1->height; + + int xmin1 = perWidth * x; + int xmax1 = perWidth * (x + 1); + + if (x == water.splitWidth - 1) + xmax1 = width; + + int ymin1 = perHeight * y - 1; + int ymax1 = perHeight * (y + 1) - 1; + + if (y == water.splitHeight - 1) + ymax1 = height - 1; + + glm::vec3 v1(10 * xmin1, waveHeight, 10 * height - 10 * ymin1); + glm::vec3 v2(10 * xmax1, waveHeight, 10 * height - 10 * ymin1); + glm::vec3 v3(10 * xmin1, waveHeight, 10 * height - 10 * ymax1); + glm::vec3 v4(10 * xmax1, waveHeight, 10 * height - 10 * ymax1); + + { + std::vector v{ v4, v2, v1 }; + if (ray.LineIntersectPolygon(v, f, 1e-6f)) + if (f >= rayOffset) + collisions.push_back(ray.origin + f * ray.dir); + } + { + std::vector v{ v4, v1, v3 }; + if (ray.LineIntersectPolygon(v, f, 1e-6f)) + if (f >= rayOffset) + collisions.push_back(ray.origin + f * ray.dir); + } + } + } + + } + } + if (collisions.size() == 0) + return glm::vec3(std::numeric_limits::max()); + + std::sort(collisions.begin(), collisions.end(), [&ray](const glm::vec3& a, const glm::vec3& b) { + return glm::distance(a, ray.origin) < glm::distance(b, ray.origin); + }); + + return collisions[0]; } \ No newline at end of file diff --git a/browedit/components/Rsw.h b/browedit/components/Rsw.h index 3306defd..70372e20 100644 --- a/browedit/components/Rsw.h +++ b/browedit/components/Rsw.h @@ -40,7 +40,7 @@ class Rsw : public Component, public ImguiProps void draw(int); }; - struct Water + struct Water : public Component { float height = 0; int type = 0; @@ -60,6 +60,8 @@ class Rsw : public Component, public ImguiProps Water* getFromGat(int x, int y, Gnd* gnd); Water* getFromGnd(int x, int y, Gnd* gnd); + void getIndexFromGnd(int x, int y, Gnd* gnd, int* wx, int* wy); + void getBoundsFromGnd(int x, int y, Gnd* gnd, int* xmin, int* xmax, int* ymin, int* ymax); void resize(int width, int height); }; @@ -167,6 +169,7 @@ class Rsw : public Component, public ImguiProps void newMap(const std::string& fileName, int width, int height, Map* map, BrowEdit* browEdit); void buildImGui(BrowEdit* browEdit) override; void recalculateQuadtree(QuadTreeNode* node = nullptr); + glm::vec3 rayCastWater(const math::Ray& ray, Gnd* gnd, bool emptyTiles = false, int xMin = 0, int yMin = 0, int xMax = -1, int yMax = -1, float offset = 0.0f); }; diff --git a/browedit/components/WaterRenderer.cpp b/browedit/components/WaterRenderer.cpp index 4f45c03a..4d732f72 100644 --- a/browedit/components/WaterRenderer.cpp +++ b/browedit/components/WaterRenderer.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -19,8 +21,9 @@ WaterRenderer::WaterRenderer() WaterRenderer::~WaterRenderer() { - for (auto t : textures) - util::ResourceManager::unload(t); + for (auto types : type2textures) + for (auto t : types.second) + util::ResourceManager::unload(t); } void WaterRenderer::setDirty() @@ -28,7 +31,7 @@ void WaterRenderer::setDirty() dirty = true; } -void WaterRenderer::render() +void WaterRenderer::render(NodeRenderContext& context) { if (!this->rsw || dirty) { //todo: move a tryLoadGnd method @@ -56,9 +59,9 @@ void WaterRenderer::render() vertIndices.clear(); std::vector verts; - for (int yy = rsw->water.splitHeight - 1; yy >= 0; yy--) { + for (int yy = 0; yy < rsw->water.splitHeight; yy++) { for (int xx = 0; xx < rsw->water.splitWidth; xx++) { - auto water = &rsw->water.zones[xx][rsw->water.splitHeight - yy - 1]; + auto water = &rsw->water.zones[xx][yy]; waveHeight = water->height - water->amplitude; @@ -69,32 +72,33 @@ void WaterRenderer::render() int ymax = perHeight * (yy + 1); - if (ymax == rsw->water.splitHeight - 1) + if (yy == rsw->water.splitHeight - 1) ymax = gnd->height; int vertsCount = 0; for (int x = perWidth * xx; x < xmax; x++) { for (int y = perHeight * yy; y < ymax; y++) { - auto c = gnd->cubes[x][gnd->height - y - 1]; + auto c = gnd->cubes[x][y]; if (!this->renderFullWater) { - if (c->tileUp == -1) - continue; + //if (c->tileUp == -1) + // continue; if (c->heights[0] <= waveHeight && c->heights[1] <= waveHeight && c->heights[2] <= waveHeight && c->heights[3] <= waveHeight) continue; } - verts.push_back(VertexP3T2(glm::vec3(10 * x, 0, 10 * (y+1)), glm::vec2((x % 4) * 0.25f + 0.00f, (y % 4) * 0.25f + 0.00f))); - verts.push_back(VertexP3T2(glm::vec3(10 * (x+1), 0, 10 * (y+1)), glm::vec2((x % 4) * 0.25f + 0.25f, (y % 4) * 0.25f + 0.00f))); - verts.push_back(VertexP3T2(glm::vec3(10 * (x+1), 0, 10 * (y+2)), glm::vec2((x % 4) * 0.25f + 0.25f, (y % 4) * 0.25f + 0.25f))); - verts.push_back(VertexP3T2(glm::vec3(10 * x, 0, 10 * (y+2)), glm::vec2((x % 4) * 0.25f + 0.00f, (y % 4) * 0.25f + 0.25f))); + int yyy = gnd->height - y - 1; + verts.push_back(VertexP3T2(glm::vec3(10 * x, 0, 10 * (yyy + 1)), glm::vec2((x % 4) * 0.25f + 0.00f, (y % 4) * 0.25f + 0.25f))); + verts.push_back(VertexP3T2(glm::vec3(10 * (x+1), 0, 10 * (yyy + 1)), glm::vec2((x % 4) * 0.25f + 0.25f, (y % 4) * 0.25f + 0.25f))); + verts.push_back(VertexP3T2(glm::vec3(10 * (x+1), 0, 10 * (yyy + 2)), glm::vec2((x % 4) * 0.25f + 0.25f, (y % 4) * 0.25f + 0.00f))); + verts.push_back(VertexP3T2(glm::vec3(10 * x, 0, 10 * (yyy + 2)), glm::vec2((x % 4) * 0.25f + 0.00f, (y % 4) * 0.25f + 0.00f))); vertsCount += 4; } } - vertIndices.push_back(VboIndex(32 * (int)vertIndices.size(), prevOffset, vertsCount)); + vertIndices.push_back(VboIndex(0, prevOffset, vertsCount)); prevOffset += vertsCount; } } @@ -106,10 +110,10 @@ void WaterRenderer::render() if (!this->rsw) return; - if (textures.size() == 0) + if (type2textures.size() == 0) return; - float time = (float)glfwGetTime(); + float time = context.time; auto shader = dynamic_cast(renderContext)->shader; shader->setUniform(WaterShader::Uniforms::time, time); @@ -144,7 +148,7 @@ void WaterRenderer::render() int vertIndex = y * rsw->water.splitWidth + x; int index = ((int)(time * 60 / water->textureAnimSpeed)) % 32; - textures[(gnd && gnd->version <= 0x108 ? 0 : vertIndices[vertIndex].texture) + index]->bind(); + type2textures[water->type][index]->bind(); glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(VertexP3T2), (void*)(0 * sizeof(float))); glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(VertexP3T2), (void*)(3 * sizeof(float))); glDrawArrays(GL_QUADS, (int)vertIndices[vertIndex].begin, (int)vertIndices[vertIndex].count); @@ -160,19 +164,13 @@ void WaterRenderer::reloadTextures() // Only reload necessary textures, it prevents lag issues for (int y = 0; y < rsw->water.splitHeight; y++) { for (int x = 0; x < rsw->water.splitWidth; x++) { - for (int i = 0; i < 32; i++) { - char buf[128]; - sprintf_s(buf, 128, "data/texture/¿öÅÍ/water%i%02i%s", rsw->water.zones[x][y].type, i, ".jpg"); + int waterType = rsw->water.zones[x][y].type; - int index = 32 * (y * rsw->water.splitWidth + x) + i; - if (index >= textures.size()) { - textures.push_back(util::ResourceManager::load(buf)); - } - else { - if (textures[index]->fileName != buf) { - util::ResourceManager::unload(textures[index]); - textures[index] = util::ResourceManager::load(buf); - } + if (type2textures.find(waterType) == type2textures.end()) { + for (int i = 0; i < 32; i++) { + char buf[128]; + sprintf_s(buf, 128, "data/texture/¿öÅÍ/water%i%02i%s", rsw->water.zones[x][y].type, i, ".jpg"); + type2textures[waterType].push_back(util::ResourceManager::load(buf)); } } } @@ -188,11 +186,11 @@ WaterRenderer::WaterRenderContext::WaterRenderContext() : shader(util::ResourceM } -void WaterRenderer::WaterRenderContext::preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) +void WaterRenderer::WaterRenderContext::preFrame(Node* rootNode, NodeRenderContext& context) { shader->use(); - shader->setUniform(WaterShader::Uniforms::ProjectionMatrix, projectionMatrix); - shader->setUniform(WaterShader::Uniforms::ViewMatrix, viewMatrix); + shader->setUniform(WaterShader::Uniforms::ProjectionMatrix, context.projectionMatrix); + shader->setUniform(WaterShader::Uniforms::ViewMatrix, context.viewMatrix); shader->setUniform(WaterShader::Uniforms::ModelMatrix, glm::mat4(1.0f)); glEnableVertexAttribArray(0); diff --git a/browedit/components/WaterRenderer.h b/browedit/components/WaterRenderer.h index 0eada853..21c5c44a 100644 --- a/browedit/components/WaterRenderer.h +++ b/browedit/components/WaterRenderer.h @@ -25,7 +25,7 @@ class WaterRenderer : public Renderer WaterShader* shader = nullptr; WaterRenderContext(); - virtual void preFrame(Node* rootNode, const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) override; + virtual void preFrame(Node* rootNode, NodeRenderContext& context) override; }; class VboIndex @@ -42,18 +42,18 @@ class WaterRenderer : public Renderer } }; - std::vector textures; Rsw* rsw; Gnd* gnd; gl::VBO* vbo = nullptr; std::vector vertIndices; + std::unordered_map> type2textures; bool dirty = true; bool viewFog = false; bool renderFullWater = false; WaterRenderer(); ~WaterRenderer(); - void render() override; + void render(NodeRenderContext& context) override; void reloadTextures(); void setDirty(); }; \ No newline at end of file diff --git a/browedit/gl/FBO.cpp b/browedit/gl/FBO.cpp index a1cbe03b..a3d0bcca 100644 --- a/browedit/gl/FBO.cpp +++ b/browedit/gl/FBO.cpp @@ -52,12 +52,11 @@ namespace gl glGenTextures(1, &texid[textureCount]); glBindTexture(GL_TEXTURE_2D, texid[textureCount]); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); @@ -68,6 +67,7 @@ namespace gl depthTexture = texid[textureCount]; } + unbind(); glBindTexture(GL_TEXTURE_2D, 0); } @@ -259,8 +259,7 @@ namespace gl if (depthTexture != 0) { glBindTexture(GL_TEXTURE_2D, depthTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); } glBindTexture(GL_TEXTURE_2D, 0); diff --git a/browedit/gl/FBO.h b/browedit/gl/FBO.h index 0176d00a..6168738e 100644 --- a/browedit/gl/FBO.h +++ b/browedit/gl/FBO.h @@ -12,12 +12,12 @@ namespace gl { int width; int height; - GLuint depthBuffer; - GLuint depthTexture; int textureCount; public: GLuint fboId; GLint oldFBO; + GLuint depthTexture; + GLuint depthBuffer; enum Type { Color, diff --git a/browedit/gl/Vertex.h b/browedit/gl/Vertex.h index de673ee4..1b436e14 100644 --- a/browedit/gl/Vertex.h +++ b/browedit/gl/Vertex.h @@ -155,6 +155,15 @@ } }; + class VertexP3 : public Vert<3> + { + public: + VertexP3(const glm::vec3& pos) + { + int index = 0; + set(pos, index); + } + }; class VertexP3T2 : public Vert<3 + 2> { diff --git a/browedit/math/Ray.cpp b/browedit/math/Ray.cpp index b0ee317a..79eb48eb 100644 --- a/browedit/math/Ray.cpp +++ b/browedit/math/Ray.cpp @@ -37,11 +37,9 @@ namespace math return true; } - bool Ray::LineIntersectPolygon(const std::span &vertices, float &t) const + bool Ray::LineIntersectPolygon(const std::span &vertices, float &t, const float epsilon) const { // Möller–Trumbore intersection algorithm - constexpr float epsilon = 0.001f; - glm::vec3 edge1 = vertices[1] - vertices[0]; glm::vec3 edge2 = vertices[2] - vertices[0]; glm::vec3 ray_cross_e2 = glm::cross(dir, edge2); diff --git a/browedit/math/Ray.h b/browedit/math/Ray.h index 220653b3..fee734a3 100644 --- a/browedit/math/Ray.h +++ b/browedit/math/Ray.h @@ -22,7 +22,7 @@ namespace math bool planeIntersection(const Plane &plane, float &t) const; - bool LineIntersectPolygon(const std::span &vertices, float &t) const; + bool LineIntersectPolygon(const std::span &vertices, float &t, const float espilon = 0.001f) const; Ray operator *(const glm::mat4 &matrix) const; diff --git a/browedit/shaders/OutlineShader.h b/browedit/shaders/OutlineShader.h new file mode 100644 index 00000000..ab6df5cd --- /dev/null +++ b/browedit/shaders/OutlineShader.h @@ -0,0 +1,34 @@ +#pragma once + +#include +class OutlineShader : public gl::Shader +{ +public: + OutlineShader() : gl::Shader("data/shaders/outline", Uniforms::End) { bindUniforms(); } + struct Uniforms + { + enum + { + s_texture, + s_depth_fbo, + s_depth_outline, + iResolution, + selectionOverlay, + selectionOutline, + selectionOccludedOverlay, + selectionOccludedOutline, + End + }; + }; + void bindUniforms() override + { + bindUniform(Uniforms::s_texture, "s_texture"); + bindUniform(Uniforms::s_depth_fbo, "s_depth_fbo"); + bindUniform(Uniforms::s_depth_outline, "s_depth_outline"); + bindUniform(Uniforms::iResolution, "iResolution"); + bindUniform(Uniforms::selectionOverlay, "selectionOverlay"); + bindUniform(Uniforms::selectionOutline, "selectionOutline"); + bindUniform(Uniforms::selectionOccludedOverlay, "selectionOccludedOverlay"); + bindUniform(Uniforms::selectionOccludedOutline, "selectionOccludedOutline"); + } +}; \ No newline at end of file diff --git a/browedit/shaders/RsmShader.h b/browedit/shaders/RsmShader.h index 2742fdcd..eb5929e7 100644 --- a/browedit/shaders/RsmShader.h +++ b/browedit/shaders/RsmShader.h @@ -20,7 +20,7 @@ class RsmShader : public gl::Shader lightAmbient, //lightIntensity, lightDirection, - selection, + selected, shadeType, discardAlphaValue, lightToggle, @@ -34,6 +34,8 @@ class RsmShader : public gl::Shader textureAnimToggle, texMat, reverseCullFace, + selectedColor, + selection, End }; }; @@ -48,7 +50,7 @@ class RsmShader : public gl::Shader bindUniform(Uniforms::lightDiffuse, "lightDiffuse"); //bindUniform(Uniforms::lightIntensity, "lightIntensity"); bindUniform(Uniforms::lightDirection, "lightDirection"); - bindUniform(Uniforms::selection, "selection"); + bindUniform(Uniforms::selected, "selected"); bindUniform(Uniforms::shadeType, "shadeType"); bindUniform(Uniforms::discardAlphaValue, "discardAlphaValue"); bindUniform(Uniforms::lightToggle, "lightToggle"); @@ -62,5 +64,7 @@ class RsmShader : public gl::Shader bindUniform(Uniforms::textureAnimToggle, "textureAnimToggle"); bindUniform(Uniforms::texMat, "texMat"); bindUniform(Uniforms::reverseCullFace, "reverseCullFace"); + bindUniform(Uniforms::selectedColor, "selectedColor"); + bindUniform(Uniforms::selection, "selection"); } }; \ No newline at end of file diff --git a/browedit/util/Util.cpp b/browedit/util/Util.cpp index dac97526..387f7507 100644 --- a/browedit/util/Util.cpp +++ b/browedit/util/Util.cpp @@ -252,16 +252,18 @@ namespace util bool DragInt(BrowEdit* browEdit, Map* map, Node* node, const char* label, int* ptr, float v_speed, int v_min, int v_max, const std::string& action, const std::function& editAction) { - static int startValue; + static std::unordered_map startValues; bool ret = ImGui::DragInt(label, ptr, v_speed, v_min, v_max); + ImGuiID id = ImGui::GetID(label); if (ImGui::IsItemActivated()) - startValue = *ptr; + startValues[id] = *ptr; if (ImGui::IsItemDeactivatedAfterEdit()) { if (editAction != nullptr) - editAction(ptr, startValue); + editAction(ptr, startValues[id]); else - map->doAction(new ObjectChangeAction(node, ptr, startValue, action == "" ? label : action), browEdit); + map->doAction(new ObjectChangeAction(node, ptr, startValues[id], action == "" ? label : action), browEdit); + startValues.erase(id); } ImGui::PushID(label); if (ImGui::BeginPopupContextItem("CopyPaste")) @@ -276,7 +278,7 @@ namespace util auto cb = ImGui::GetClipboardText(); if (cb) { - startValue = *ptr; + int startValue = *ptr; *ptr = std::stoi(cb); if (editAction != nullptr) editAction(ptr, startValue); @@ -727,6 +729,7 @@ namespace util template bool DragFloatMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, float v_speed, float v_min, float v_max); template bool DragFloatMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, float v_speed, float v_min, float v_max); template bool DragFloatMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, float v_speed, float v_min, float v_max); + template bool DragFloatMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, float v_speed, float v_min, float v_max); template @@ -793,6 +796,7 @@ namespace util template bool DragIntMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, int v_speed, int v_min, int v_max); template bool DragIntMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, int v_speed, int v_min, int v_max); template bool DragIntMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, int v_speed, int v_min, int v_max); + template bool DragIntMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, int v_speed, int v_min, int v_max); template diff --git a/browedit/windows/CropSettingsWindow.cpp b/browedit/windows/CropSettingsWindow.cpp index 70d3d432..1310dcf0 100644 --- a/browedit/windows/CropSettingsWindow.cpp +++ b/browedit/windows/CropSettingsWindow.cpp @@ -155,6 +155,9 @@ void BrowEdit::showCropSettingsWindow() delete rsw->quadtree; rsw->quadtree = new Rsw::QuadTreeNode(10 * -gnd->width / 2.0f, 10 * -gnd->height / 2.0f, (float)gnd->width * 10 - 1.0f, (float)gnd->height * 10 - 1.0f, 0); rsw->recalculateQuadtree(nullptr); + + rsw->water.splitHeight = glm::min(gnd->width, rsw->water.splitHeight); + rsw->water.splitWidth = glm::min(gnd->height, rsw->water.splitWidth); } } } diff --git a/browedit/windows/ObjectSelectWindow.cpp b/browedit/windows/ObjectSelectWindow.cpp index 41611020..8811c7a2 100644 --- a/browedit/windows/ObjectSelectWindow.cpp +++ b/browedit/windows/ObjectSelectWindow.cpp @@ -64,6 +64,8 @@ class ObjectWindowObject float ratio = fbo->getWidth() / (float)fbo->getHeight(); nodeRenderContext.projectionMatrix = glm::perspective(glm::radians(45.0f), ratio, 0.1f, 5000.0f); nodeRenderContext.viewMatrix = glm::lookAt(glm::vec3(-distance * glm::sin(glm::radians(rotation)), -distance, -distance * glm::cos(glm::radians(rotation))), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); + nodeRenderContext.time = (float)glfwGetTime(); + nodeRenderContext.fbo = fbo; RsmRenderer::RsmRenderContext::getInstance()->viewLighting = false; glm::mat4 mat = glm::mat4(1.0f); if (rsm->version >= 0x202) { diff --git a/browedit/windows/Toolbar.cpp b/browedit/windows/Toolbar.cpp index 0b2ae9c2..6433865d 100644 --- a/browedit/windows/Toolbar.cpp +++ b/browedit/windows/Toolbar.cpp @@ -46,6 +46,8 @@ void BrowEdit::toolbar() ImGui::Text("Sprite"); else if (editMode == EditMode::Cinematic) ImGui::Text("Cinematic"); + else if (editMode == EditMode::Water) + ImGui::Text("Water"); else ImGui::Text("???"); ImGui::SameLine(); @@ -68,7 +70,10 @@ void BrowEdit::toolbar() toolBarToggleButton("sprite", ICON_EDIT_SPRITE, editMode == EditMode::Sprite, "Sprite edit mode", HotkeyAction::EditMode_Sprite, config.toolbarButtonsWallEdit); ImGui::SameLine(); toolBarToggleButton("cinematic", ICON_EDIT_CINEMATIC, editMode == EditMode::Cinematic, "Cinematic Mode", HotkeyAction::EditMode_Cinematic, config.toolbarButtonsWallEdit); - ImGui::SameLine(130 + 9 * (config.toolbarButtonSize + 5) + 20 ); + ImGui::SameLine(); + toolBarToggleButton("watermode", ICON_VIEW_WATER_ON, editMode == EditMode::Water, "Water edit mode", HotkeyAction::EditMode_Water, config.toolbarButtonsWallEdit); + ImGuiContext& g = *GImGui; + ImGui::SameLine(125 + 10 * (config.toolbarButtonSize + g.Style.ItemSpacing.x)); if (editMode == EditMode::Object) { diff --git a/browedit/windows/WaterEditWindow.cpp b/browedit/windows/WaterEditWindow.cpp new file mode 100644 index 00000000..ac566eb6 --- /dev/null +++ b/browedit/windows/WaterEditWindow.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +template bool util::DragIntMulti( + BrowEdit* browEdit, + Map* map, + const std::vector& data, + const char* label, + const std::function& callback, + int v_speed, + int v_min, + int v_max); + +void BrowEdit::showWaterEditWindow() +{ + if (!activeMapView) + { + return; + } + + static bool showWaterOverlay = true; + + ImGui::Begin("Water Edit"); + + ImGui::Text("Water zones require GND version 0x108 or above"); + ImGui::Checkbox("Show grid", &this->activeMapView->showWaterGrid); + ImGui::Checkbox("Show selected overlay", &this->activeMapView->showWaterSelectedOverlay); + + // Allow brushes in the future? + //if (ImGui::TreeNodeEx("Tool", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) + //{ + // toolBarToggleButton("Rectangle", ICON_SELECT_RECTANGLE, !heightDoodle && selectTool == BrowEdit::SelectTool::Rectangle, "Rectangle Select", HotkeyAction::HeightEdit_Rectangle, ImVec4(1, 1, 1, 1)); + // ImGui::TreePop(); + //} + + auto gnd = this->activeMapView->map->rootNode->getComponent(); + auto rsw = this->activeMapView->map->rootNode->getComponent(); + auto rswNode = rsw->node; + auto water = &rsw->water; + auto waterRenderer = rswNode->getComponent(); + + if (ImGui::TreeNodeEx("Water", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed)) + { + if (gnd->version >= 0x108) { + if (util::DragInt(this, this->activeMapView->map, rswNode, "Split width", &water->splitWidth, 1, 1, gnd->width, "", [&](int* ptr, int startValue) { + water->splitWidth = glm::min(gnd->width, glm::max(1, water->splitWidth)); + water->splitHeight = glm::min(gnd->height, glm::max(1, water->splitHeight)); + auto action = new WaterSplitChangeAction(*water, startValue, water->splitHeight); + this->activeMapView->map->doAction(action, this); + })) { + water->resize(water->splitWidth, water->splitHeight); + waterRenderer->setDirty(); + } + + if (util::DragInt(this, this->activeMapView->map, rswNode, "Split height", &water->splitHeight, 1, 1, gnd->height, "", [&](int* ptr, int startValue) { + water->splitWidth = glm::min(gnd->width, glm::max(1, water->splitWidth)); + water->splitHeight = glm::min(gnd->height, glm::max(1, water->splitHeight)); + auto action = new WaterSplitChangeAction(*water, glm::max(1, water->splitWidth), startValue); + this->activeMapView->map->doAction(action, this); + })) { + water->resize(water->splitWidth, water->splitHeight); + waterRenderer->setDirty(); + } + + if (rsw->water.splitWidth > 1 || rsw->water.splitHeight) { + ImGui::Text("Zone width (in GND tile): %d", glm::max(1, (int)(gnd->width / glm::max(1, rsw->water.splitWidth)))); + ImGui::Text("Zone height (in GND tile): %d", glm::max(1, (int)(gnd->height / glm::max(1, rsw->water.splitHeight)))); + } + } + + if (gnd->version >= 0x108) { + if (activeMapView->map->waterSelection.size() == 0 && water->splitHeight * water->splitWidth == 1) { + activeMapView->map->waterSelection.push_back(glm::ivec2(0, 0)); + } + + std::vector selectedZones; + + for (auto& tile : this->activeMapView->map->waterSelection) { + // The selection can become invalid if the split zones count was changed + if (tile.x < 0 || tile.x >= rsw->water.splitWidth || + tile.y < 0 || tile.y >= rsw->water.splitHeight) + continue; + + // Cheat a little... copy the rsw's node so that the action will be able to redo/undo correctly. + auto zone = &rsw->water.zones[tile.x][tile.y]; + zone->node = rswNode; + selectedZones.push_back(zone); + } + + if (gnd->version == 0x108) { + if (util::DragInt(this, this->activeMapView->map, rswNode, "Type", &water->zones[0][0].type, 1, 0, 1000)) { + waterRenderer->reloadTextures(); + } + } + + if (selectedZones.size() > 0) { + if (gnd->version >= 0x109) { + if (util::DragIntMulti(this, this->activeMapView->map, selectedZones, "Type", [](Rsw::Water* m) { return &m->type; }, 1, 0, 1000)) { + waterRenderer->reloadTextures(); + } + } + + // Height edit is shared for both 0x108 and 0x109+ + if (util::DragFloatMulti(this, this->activeMapView->map, selectedZones, "Height", [](Rsw::Water* m) { return &m->height; }, 0.1f, -100, 100)) { + if (!waterRenderer->renderFullWater) { + waterRenderer->renderFullWater = true; + waterRenderer->setDirty(); + } + } + + if (gnd->version >= 0x109) { + util::DragFloatMulti(this, this->activeMapView->map, selectedZones, "Wave Height", [](Rsw::Water* m) { return &m->amplitude; }, 0.1f, -100, 100); + util::DragIntMulti(this, this->activeMapView->map, selectedZones, "Texture Animation Speed", [](Rsw::Water* m) { return &m->textureAnimSpeed; }, 1, 0, 1000); + util::DragFloatMulti(this, this->activeMapView->map, selectedZones, "Wave Speed", [](Rsw::Water* m) { return &m->waveSpeed; }, 0.1f, -100, 100); + util::DragFloatMulti(this, this->activeMapView->map, selectedZones, "Wave Pitch", [](Rsw::Water* m) { return &m->wavePitch; }, 0.1f, -100, 100); + } + } + + if (gnd->version == 0x108) { + util::DragFloat(this, this->activeMapView->map, rswNode, "Wave Height", &water->zones[0][0].amplitude, 0.1f, -100, 100); + util::DragInt(this, this->activeMapView->map, rswNode, "Texture Animation Speed", &water->zones[0][0].textureAnimSpeed, 1, 0, 1000); + util::DragFloat(this, this->activeMapView->map, rswNode, "Wave Speed", &water->zones[0][0].waveSpeed, 0.1f, -100, 100); + util::DragFloat(this, this->activeMapView->map, rswNode, "Wave Pitch", &water->zones[0][0].wavePitch, 0.1f, -100, 100); + } + } + else { + if (util::DragInt(this, this->activeMapView->map, rswNode, "Type", &water->zones[0][0].type, 1, 0, 1000)) { + waterRenderer->reloadTextures(); + } + + if (util::DragFloat(this, this->activeMapView->map, rswNode, "Height", &water->zones[0][0].height, 0.1f, -100, 100)) { + if (!waterRenderer->renderFullWater) { + waterRenderer->renderFullWater = true; + waterRenderer->setDirty(); + } + } + + util::DragFloat(this, this->activeMapView->map, rswNode, "Wave Height", &water->zones[0][0].amplitude, 0.1f, -100, 100); + util::DragInt(this, this->activeMapView->map, rswNode, "Texture Animation Speed", &water->zones[0][0].textureAnimSpeed, 1, 0, 1000); + util::DragFloat(this, this->activeMapView->map, rswNode, "Wave Speed", &water->zones[0][0].waveSpeed, 0.1f, -100, 100); + util::DragFloat(this, this->activeMapView->map, rswNode, "Wave Pitch", &water->zones[0][0].wavePitch, 0.1f, -100, 100); + } + + ImGui::TreePop(); + } + + ImGui::End(); +} \ No newline at end of file diff --git a/data/defaulthotkeys.json b/data/defaulthotkeys.json index 4dc81692..3417088d 100644 --- a/data/defaulthotkeys.json +++ b/data/defaulthotkeys.json @@ -1 +1 @@ -{"Camera_MoveXNegative":{"keyCode":324,"modifiers":0},"Camera_MoveXPositive":{"keyCode":326,"modifiers":0},"Camera_MoveYNegative":{"keyCode":329,"modifiers":0},"Camera_MoveYPositive":{"keyCode":327,"modifiers":0},"Camera_MoveZNegative":{"keyCode":322,"modifiers":0},"Camera_MoveZPositive":{"keyCode":328,"modifiers":0},"Camera_OrthoPerspective":{"keyCode":325,"modifiers":0},"Camera_RotateX45Negative":{"keyCode":323,"modifiers":0},"Camera_RotateX45Positive":{"keyCode":321,"modifiers":0},"Camera_RotateY45Negative":{"keyCode":330,"modifiers":0},"Camera_RotateY45Positive":{"keyCode":320,"modifiers":0},"EditMode_Cinematic":{"keyCode":298,"modifiers":0},"EditMode_Color":{"keyCode":295,"modifiers":0},"EditMode_Gat":{"keyCode":294,"modifiers":0},"EditMode_Height":{"keyCode":290,"modifiers":0},"EditMode_Object":{"keyCode":292,"modifiers":0},"EditMode_Shadow":{"keyCode":296,"modifiers":0},"EditMode_Sprite":{"keyCode":297,"modifiers":0},"EditMode_Texture":{"keyCode":291,"modifiers":0},"EditMode_Wall":{"keyCode":293,"modifiers":0},"GatEdit_NextTileType":{"keyCode":91,"modifiers":0},"GatEdit_PrevTileType":{"keyCode":93,"modifiers":0},"GatEdit_Tile0":{"keyCode":49,"modifiers":0},"GatEdit_Tile1":{"keyCode":50,"modifiers":0},"GatEdit_Tile2":{"keyCode":51,"modifiers":0},"GatEdit_Tile3":{"keyCode":52,"modifiers":0},"GatEdit_Tile4":{"keyCode":53,"modifiers":0},"GatEdit_Tile5":{"keyCode":54,"modifiers":0},"GatEdit_Tile6":{"keyCode":55,"modifiers":0},"GatEdit_Tile7":{"keyCode":56,"modifiers":0},"GatEdit_Tile8":{"keyCode":57,"modifiers":0},"GatEdit_Tile9":{"keyCode":48,"modifiers":0},"GatEdit_AdjustToGround":{"keyCode":32,"modifiers":1},"Global_CalculateLightmaps":{"keyCode":76,"modifiers":1},"Global_CalculateQuadtree":{"keyCode":81,"modifiers":1},"Global_Copy":{"keyCode":67,"modifiers":1},"Global_Exit":{"keyCode":27,"modifiers":0},"Global_HotkeyPopup":{"keyCode":32,"modifiers":0},"Global_Load":{"keyCode":79,"modifiers":1},"Global_New":{"keyCode":78,"modifiers":1},"Global_Paste":{"keyCode":86,"modifiers":1},"Global_PasteChangeHeight":{"keyCode":86,"modifiers":0},"Global_Redo":{"keyCode":90,"modifiers":3},"Global_ReloadModels":{"keyCode":82,"modifiers":2},"Global_ReloadTextures":{"keyCode":82,"modifiers":1},"Global_Save":{"keyCode":83,"modifiers":1},"Global_Settings":{"keyCode":80,"modifiers":1},"Global_Undo":{"keyCode":90,"modifiers":1},"HeightEdit_DecreaseHeight":{"keyCode":267,"modifiers":0},"HeightEdit_FlattenTiles":{"keyCode":70,"modifiers":0},"HeightEdit_IncreaseHeight":{"keyCode":266,"modifiers":0},"HeightEdit_SmoothTiles":{"keyCode":83,"modifiers":0},"ObjectEdit_CreatePrefab":{"keyCode":0,"modifiers":0},"ObjectEdit_Delete":{"keyCode":261,"modifiers":0},"ObjectEdit_FlipHorizontal":{"keyCode":72,"modifiers":0},"ObjectEdit_FlipVertical":{"keyCode":86,"modifiers":0},"ObjectEdit_FocusOnSelection":{"keyCode":70,"modifiers":0},"ObjectEdit_HighlightInObjectPicker":{"keyCode":0,"modifiers":0},"ObjectEdit_InvertScaleX":{"keyCode":88,"modifiers":0},"ObjectEdit_InvertScaleY":{"keyCode":89,"modifiers":0},"ObjectEdit_InvertScaleZ":{"keyCode":90,"modifiers":0},"ObjectEdit_InvertSelection":{"keyCode":73,"modifiers":1},"ObjectEdit_Move":{"keyCode":49,"modifiers":0},"ObjectEdit_NudgeXNeg":{"keyCode":263,"modifiers":0},"ObjectEdit_NudgeXPos":{"keyCode":262,"modifiers":0},"ObjectEdit_NudgeYNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_NudgeYPos":{"keyCode":0,"modifiers":0},"ObjectEdit_NudgeZNeg":{"keyCode":265,"modifiers":0},"ObjectEdit_NudgeZPos":{"keyCode":264,"modifiers":0},"ObjectEdit_RotXNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_RotXPos":{"keyCode":0,"modifiers":0},"ObjectEdit_RotYNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_RotYPos":{"keyCode":0,"modifiers":0},"ObjectEdit_RotZNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_RotZPos":{"keyCode":0,"modifiers":0},"ObjectEdit_Rotate":{"keyCode":50,"modifiers":0},"ObjectEdit_Scale":{"keyCode":51,"modifiers":0},"ObjectEdit_SelectAll":{"keyCode":65,"modifiers":1},"ObjectEdit_SelectAllEffects":{"keyCode":0,"modifiers":0},"ObjectEdit_SelectAllLights":{"keyCode":0,"modifiers":0},"ObjectEdit_SelectAllModels":{"keyCode":0,"modifiers":0},"ObjectEdit_SelectAllSounds":{"keyCode":0,"modifiers":0},"ObjectEdit_ToggleObjectWindow":{"keyCode":0,"modifiers":0},"TextureEdit_SwapBrushSize":{"keyCode":0,"modifiers":0},"TextureEdit_ToggleTextureWindow":{"keyCode":0,"modifiers":0},"Texture_NextTexture":{"keyCode":93,"modifiers":0},"Texture_PrevTexture":{"keyCode":91,"modifiers":0},"Texture_SelectFull":{"keyCode":70,"modifiers":0},"Texture_Delete":{"keyCode":259,"modifiers":0},"View_ColorMap":{"keyCode":0,"modifiers":0},"View_EmptyTiles":{"keyCode":0,"modifiers":0},"View_GatTiles":{"keyCode":0,"modifiers":0},"View_Lighting":{"keyCode":0,"modifiers":0},"View_Models":{"keyCode":77,"modifiers":0},"View_ShadowMap":{"keyCode":0,"modifiers":0},"View_SmoothColormap":{"keyCode":0,"modifiers":0},"View_Textures":{"keyCode":0,"modifiers":0},"View_TileColors":{"keyCode":0,"modifiers":0},"WallEdit_AddWall":{"keyCode":334,"modifiers":0},"WallEdit_OffsetLower":{"keyCode":263,"modifiers":0},"WallEdit_OffsetRaise":{"keyCode":262,"modifiers":0},"WallEdit_Preview":{"keyCode":80,"modifiers":0},"WallEdit_ReApply":{"keyCode":65,"modifiers":0},"WallEdit_RemoveWall":{"keyCode":333,"modifiers":0},"WallEdit_SizeLower":{"keyCode":263,"modifiers":2},"WallEdit_SizeRaise":{"keyCode":262,"modifiers":2}} \ No newline at end of file +{"Camera_MoveXNegative":{"keyCode":324,"modifiers":0},"Camera_MoveXPositive":{"keyCode":326,"modifiers":0},"Camera_MoveYNegative":{"keyCode":329,"modifiers":0},"Camera_MoveYPositive":{"keyCode":327,"modifiers":0},"Camera_MoveZNegative":{"keyCode":322,"modifiers":0},"Camera_MoveZPositive":{"keyCode":328,"modifiers":0},"Camera_OrthoPerspective":{"keyCode":325,"modifiers":0},"Camera_RotateX45Negative":{"keyCode":323,"modifiers":0},"Camera_RotateX45Positive":{"keyCode":321,"modifiers":0},"Camera_RotateY45Negative":{"keyCode":330,"modifiers":0},"Camera_RotateY45Positive":{"keyCode":320,"modifiers":0},"EditMode_Cinematic":{"keyCode":298,"modifiers":0},"EditMode_Color":{"keyCode":295,"modifiers":0},"EditMode_Gat":{"keyCode":294,"modifiers":0},"EditMode_Height":{"keyCode":290,"modifiers":0},"EditMode_Object":{"keyCode":292,"modifiers":0},"EditMode_Shadow":{"keyCode":296,"modifiers":0},"EditMode_Water":{"keyCode":299,"modifiers":0},"EditMode_Sprite":{"keyCode":297,"modifiers":0},"EditMode_Texture":{"keyCode":291,"modifiers":0},"EditMode_Wall":{"keyCode":293,"modifiers":0},"GatEdit_NextTileType":{"keyCode":91,"modifiers":0},"GatEdit_PrevTileType":{"keyCode":93,"modifiers":0},"GatEdit_Tile0":{"keyCode":49,"modifiers":0},"GatEdit_Tile1":{"keyCode":50,"modifiers":0},"GatEdit_Tile2":{"keyCode":51,"modifiers":0},"GatEdit_Tile3":{"keyCode":52,"modifiers":0},"GatEdit_Tile4":{"keyCode":53,"modifiers":0},"GatEdit_Tile5":{"keyCode":54,"modifiers":0},"GatEdit_Tile6":{"keyCode":55,"modifiers":0},"GatEdit_Tile7":{"keyCode":56,"modifiers":0},"GatEdit_Tile8":{"keyCode":57,"modifiers":0},"GatEdit_Tile9":{"keyCode":48,"modifiers":0},"GatEdit_AdjustToGround":{"keyCode":32,"modifiers":1},"Global_CalculateLightmaps":{"keyCode":76,"modifiers":1},"Global_CalculateQuadtree":{"keyCode":81,"modifiers":1},"Global_Copy":{"keyCode":67,"modifiers":1},"Global_Exit":{"keyCode":27,"modifiers":0},"Global_HotkeyPopup":{"keyCode":32,"modifiers":0},"Global_Load":{"keyCode":79,"modifiers":1},"Global_New":{"keyCode":78,"modifiers":1},"Global_Paste":{"keyCode":86,"modifiers":1},"Global_PasteChangeHeight":{"keyCode":86,"modifiers":0},"Global_Redo":{"keyCode":90,"modifiers":3},"Global_ReloadModels":{"keyCode":82,"modifiers":2},"Global_ReloadTextures":{"keyCode":82,"modifiers":1},"Global_Save":{"keyCode":83,"modifiers":1},"Global_Settings":{"keyCode":80,"modifiers":1},"Global_Undo":{"keyCode":90,"modifiers":1},"HeightEdit_DecreaseHeight":{"keyCode":267,"modifiers":0},"HeightEdit_FlattenTiles":{"keyCode":70,"modifiers":0},"HeightEdit_IncreaseHeight":{"keyCode":266,"modifiers":0},"HeightEdit_SmoothTiles":{"keyCode":83,"modifiers":0},"ObjectEdit_CreatePrefab":{"keyCode":0,"modifiers":0},"ObjectEdit_Delete":{"keyCode":261,"modifiers":0},"ObjectEdit_FlipHorizontal":{"keyCode":72,"modifiers":0},"ObjectEdit_FlipVertical":{"keyCode":86,"modifiers":0},"ObjectEdit_FocusOnSelection":{"keyCode":70,"modifiers":0},"ObjectEdit_HighlightInObjectPicker":{"keyCode":0,"modifiers":0},"ObjectEdit_InvertScaleX":{"keyCode":88,"modifiers":0},"ObjectEdit_InvertScaleY":{"keyCode":89,"modifiers":0},"ObjectEdit_InvertScaleZ":{"keyCode":90,"modifiers":0},"ObjectEdit_InvertSelection":{"keyCode":73,"modifiers":1},"ObjectEdit_Move":{"keyCode":49,"modifiers":0},"ObjectEdit_NudgeXNeg":{"keyCode":263,"modifiers":0},"ObjectEdit_NudgeXPos":{"keyCode":262,"modifiers":0},"ObjectEdit_NudgeYNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_NudgeYPos":{"keyCode":0,"modifiers":0},"ObjectEdit_NudgeZNeg":{"keyCode":265,"modifiers":0},"ObjectEdit_NudgeZPos":{"keyCode":264,"modifiers":0},"ObjectEdit_RotXNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_RotXPos":{"keyCode":0,"modifiers":0},"ObjectEdit_RotYNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_RotYPos":{"keyCode":0,"modifiers":0},"ObjectEdit_RotZNeg":{"keyCode":0,"modifiers":0},"ObjectEdit_RotZPos":{"keyCode":0,"modifiers":0},"ObjectEdit_Rotate":{"keyCode":50,"modifiers":0},"ObjectEdit_Scale":{"keyCode":51,"modifiers":0},"ObjectEdit_SelectAll":{"keyCode":65,"modifiers":1},"ObjectEdit_SelectAllEffects":{"keyCode":0,"modifiers":0},"ObjectEdit_SelectAllLights":{"keyCode":0,"modifiers":0},"ObjectEdit_SelectAllModels":{"keyCode":0,"modifiers":0},"ObjectEdit_SelectAllSounds":{"keyCode":0,"modifiers":0},"ObjectEdit_ToggleObjectWindow":{"keyCode":0,"modifiers":0},"TextureEdit_SwapBrushSize":{"keyCode":0,"modifiers":0},"TextureEdit_ToggleTextureWindow":{"keyCode":0,"modifiers":0},"Texture_NextTexture":{"keyCode":93,"modifiers":0},"Texture_PrevTexture":{"keyCode":91,"modifiers":0},"Texture_SelectFull":{"keyCode":70,"modifiers":0},"Texture_Delete":{"keyCode":259,"modifiers":0},"View_ColorMap":{"keyCode":0,"modifiers":0},"View_EmptyTiles":{"keyCode":0,"modifiers":0},"View_GatTiles":{"keyCode":0,"modifiers":0},"View_Lighting":{"keyCode":0,"modifiers":0},"View_Models":{"keyCode":77,"modifiers":0},"View_ShadowMap":{"keyCode":0,"modifiers":0},"View_SmoothColormap":{"keyCode":0,"modifiers":0},"View_Textures":{"keyCode":0,"modifiers":0},"View_TileColors":{"keyCode":0,"modifiers":0},"WallEdit_AddWall":{"keyCode":334,"modifiers":0},"WallEdit_OffsetLower":{"keyCode":263,"modifiers":0},"WallEdit_OffsetRaise":{"keyCode":262,"modifiers":0},"WallEdit_Preview":{"keyCode":80,"modifiers":0},"WallEdit_ReApply":{"keyCode":65,"modifiers":0},"WallEdit_RemoveWall":{"keyCode":333,"modifiers":0},"WallEdit_SizeLower":{"keyCode":263,"modifiers":2},"WallEdit_SizeRaise":{"keyCode":262,"modifiers":2}} \ No newline at end of file diff --git a/data/shaders/outline.fs b/data/shaders/outline.fs new file mode 100644 index 00000000..15c52eec --- /dev/null +++ b/data/shaders/outline.fs @@ -0,0 +1,85 @@ +#version 420 + +layout (location = 0) out vec4 frag; + +uniform sampler2D s_texture; +uniform sampler2D s_depth_fbo; +uniform sampler2D s_depth_outline; + +uniform vec2 iResolution; +uniform vec4 selectionOverlay; +uniform vec4 selectionOutline; +uniform vec4 selectionOccludedOverlay; +uniform vec4 selectionOccludedOutline; + +in vec2 uvTex; + +void main() +{ + float step_u = 1.0 / iResolution.x; + float step_v = 1.0 / iResolution.y; + vec2 texelSize = 1.0 / vec2(iResolution.x, iResolution.y); + + vec4 current_texel = texture(s_texture, uvTex); + + // 0 depth = close to camera + // 1 depth = furthest possible from camera + float depth_fbo = texture(s_depth_fbo, uvTex).r; + float depth_outline = texture(s_depth_outline, uvTex).r; + + bool current_hasColor = false; + bool current_occluded = false; + + frag = vec4(0, 0, 0, 0); + + if ((current_texel.r >= 0 || current_texel.g >= 0) && current_texel.a >= 1.0) { + current_hasColor = true; + frag = selectionOverlay; + + if (depth_fbo < depth_outline) { + frag = selectionOccludedOverlay; + } + } + + if (depth_fbo < depth_outline) { + current_occluded = true; + } + + int thickness = 1; + int result = 0; + + for (int x = -thickness; x <= thickness; x++) { + for (int y = -thickness; y <= thickness; y++) { + if (x == 0 && y == 0) + continue; + + vec2 target_uv = uvTex + vec2(x, y) * texelSize; + vec4 target_texel = texture(s_texture, target_uv); + + // Nearby texel has color + if ((target_texel.r >= 0.0 || target_texel.g >= 0.0) && target_texel.a >= 1.0) { + float target_depth_fbo = texture(s_depth_fbo, target_uv).r; + float target_depth_outline = texture(s_depth_outline, target_uv).r; + + bool target_occluded = target_depth_fbo < target_depth_outline; + + // Generic outline + if (!current_hasColor) { + result = max(result, target_occluded ? 1 : 2); + } + + // Outline for meshes intersection + if (current_texel != target_texel && + depth_outline > target_depth_outline) { + result = max(result, (target_occluded && current_occluded) ? 1 : 2); + } + } + } + + // The "red" visible outline should take priority over the occluded outline + if (result == 2) + frag = selectionOutline; + else if (result == 1) + frag = selectionOccludedOutline; + } +} \ No newline at end of file diff --git a/data/shaders/outline.vs b/data/shaders/outline.vs new file mode 100644 index 00000000..124004ae --- /dev/null +++ b/data/shaders/outline.vs @@ -0,0 +1,12 @@ +#version 420 + +layout (location = 0) in vec3 a_position; +layout (location = 1) in vec2 a_uv; + +out vec2 uvTex; + +void main() +{ + uvTex = a_uv; + gl_Position = vec4(a_position, 1.0f); +} \ No newline at end of file diff --git a/data/shaders/rsm.fs b/data/shaders/rsm.fs index 79d662c5..c45e185c 100644 --- a/data/shaders/rsm.fs +++ b/data/shaders/rsm.fs @@ -1,3 +1,5 @@ +#version 420 + uniform sampler2D s_texture; uniform vec3 lightDiffuse; @@ -8,6 +10,7 @@ uniform vec3 lightDirection; uniform int shadeType; uniform float discardAlphaValue; uniform float selection; +uniform bool selected; uniform bool lightToggle; uniform bool viewTextures; uniform bool enableCullFace; @@ -19,10 +22,12 @@ uniform float fogNear; uniform float fogFar; //uniform float fogExp; uniform vec4 fogColor; +uniform vec4 selectedColor; -varying vec2 texCoord; -varying vec3 normal; -varying vec3 mult; +out vec4 fragColor; +in vec2 texCoord; +in vec3 normal; +in vec3 mult; //texture animation uniform bool textureAnimToggle; @@ -44,6 +49,7 @@ void main() } vec4 color = texture2D(s_texture, texCoord2); + if (color.a < discardAlphaValue) discard; if(!viewTextures) @@ -65,7 +71,7 @@ void main() float depth = gl_FragCoord.z / gl_FragCoord.w; float fogAmount = smoothstep(fogNear, fogFar, depth); color = mix(color, fogColor, fogAmount); - } - - gl_FragData[0] = mix(color, vec4(1,0,0,1), min(1.0,selection)); + } + + fragColor = selected ? selectedColor : mix(color, vec4(1,0,0,1), min(1.0,selection)); } \ No newline at end of file diff --git a/imgui.ini b/imgui.ini index 576318b4..c8220e6b 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,23 +1,23 @@ [Window][BrowEditDock] -Pos=0,74 -Size=1920,968 +Pos=0,66 +Size=1920,976 Collapsed=0 [Window][Undo stack] -Pos=1749,74 -Size=171,968 +Pos=1749,66 +Size=171,976 Collapsed=0 DockId=0x00000024,0 [Window][Objects] -Pos=0,74 -Size=249,688 +Pos=0,66 +Size=249,696 Collapsed=0 DockId=0x00000001,0 [Window][Properties] -Pos=1230,74 -Size=517,688 +Pos=1230,66 +Size=517,696 Collapsed=0 DockId=0x0000000C,1 @@ -25,7 +25,7 @@ DockId=0x0000000C,1 Pos=374,66 Size=1232,974 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][Dear ImGui Metrics/Debugger] ViewportPos=664,264 @@ -40,7 +40,7 @@ Collapsed=0 [Window][Toolbar] Pos=0,26 -Size=1920,48 +Size=1920,40 Collapsed=0 [Window][Statusbar] @@ -68,7 +68,7 @@ Collapsed=0 Pos=257,66 Size=1349,1115 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\prontera.rsw##1] Pos=1322,106 @@ -79,13 +79,13 @@ Collapsed=0 Pos=257,66 Size=1349,974 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\prontera.rsw#0] Pos=251,74 Size=977,688 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][Object Picker] Pos=0,764 @@ -139,7 +139,7 @@ Collapsed=0 Pos=376,66 Size=1213,586 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\prontera.rsw#1] Pos=978,74 @@ -163,31 +163,31 @@ DockId=0x00000010,0 Pos=369,74 Size=1190,700 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\guild_vs4.rsw#0] Pos=0,74 Size=1589,968 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\06guild_r.rsw#0] Pos=369,74 Size=1237,678 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\1@4cdn.rsw#0] Pos=376,74 Size=1117,706 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\1@4drk.rsw#0] Pos=371,66 Size=1235,756 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\1@4igd.rsw#0] Pos=1182,66 @@ -199,13 +199,13 @@ DockId=0x00000014,0 Pos=0,74 Size=2147,1305 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\guild_vs5.rsw#0] Pos=0,74 Size=1589,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][Progress] Pos=810,479 @@ -216,19 +216,19 @@ Collapsed=0 Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,9 +DockId=0x00000035,9 [Window][Help] Pos=0,74 Size=1464,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\alberta.rsw#0] Pos=0,74 Size=1545,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\guild_vs01.rsw#0] Pos=553,176 @@ -239,37 +239,37 @@ Collapsed=0 Pos=369,74 Size=1237,558 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\06guild_r.rsw#1] Pos=369,74 Size=1237,678 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\1@air2.rsw#0] Pos=369,74 Size=1237,678 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\comodo.rsw#0] Pos=251,74 Size=1254,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\prt_in.rsw#0] Pos=0,74 Size=1589,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\abbey03.rsw#0] Pos=369,74 Size=1220,685 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][Lightmap Settings] Pos=698,354 @@ -277,16 +277,16 @@ Size=524,371 Collapsed=0 [Window][data\niflheim.rsw#0] -Pos=369,74 -Size=1293,678 +Pos=0,66 +Size=1228,976 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,1 [Window][data\alb2trea.rsw#0] Pos=369,74 Size=1267,539 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][game\client\data\guild_vs1 - Copy.rsw#0] Pos=401,172 @@ -297,31 +297,31 @@ Collapsed=0 Pos=369,74 Size=1190,700 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\guild_vs2.rsw#0] Pos=0,74 Size=1589,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\1@4inq.rsw#0] Pos=369,74 Size=1190,700 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\effects_ro.rsw#0] Pos=0,74 Size=1566,631 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][out\data\prontera.rsw#0] Pos=376,74 Size=1213,695 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\guild_vs3.rsw#0] Pos=756,74 @@ -330,8 +330,8 @@ Collapsed=0 DockId=0x0000001C,0 [Window][Height Edit] -Pos=1302,47 -Size=517,968 +Pos=1230,66 +Size=517,976 Collapsed=0 DockId=0x00000003,0 @@ -339,79 +339,79 @@ DockId=0x00000003,0 Pos=0,74 Size=1507,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\wall_colour.rsw#0] Pos=0,74 Size=1401,743 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\guild_vs1 - Copy.rsw#0] Pos=268,74 Size=1239,783 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\aldebaran.rsw#0] Pos=0,74 Size=1507,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\cmd_fild04.rsw#0] Pos=376,74 Size=1117,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\cmd_fild05.rsw#0] Pos=376,74 Size=1117,597 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\cmd_fild03.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\cmd_fild02.rsw#0] Pos=376,74 Size=1117,597 Collapsed=0 -DockId=0x00000019,4 +DockId=0x00000035,4 [Window][data\abyss_01.rsw#0] Pos=376,74 Size=1117,706 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\iz_int01.rsw#0] Pos=376,74 Size=1117,706 Collapsed=0 -DockId=0x00000019,3 +DockId=0x00000035,3 [Window][data\veins.rsw#0] Pos=0,74 Size=1720,657 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\veins.rsw#1] Pos=376,74 Size=1117,706 Collapsed=0 -DockId=0x00000019,5 +DockId=0x00000035,5 [Window][data\amicit01.rsw#0] Pos=268,74 Size=1225,620 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\geffen.rsw#1] Pos=1103,74 @@ -429,71 +429,71 @@ DockId=0x00000018,0 Pos=0,74 Size=1493,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\bl_ice.rsw#0] Pos=0,74 Size=765,484 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\grademk.rsw#0] Pos=251,74 Size=977,688 Collapsed=0 -DockId=0x00000019,3 +DockId=0x00000035,3 [Window][noel02.rsw#0] Pos=268,74 Size=1225,620 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\endless_eve.rsw#0] Pos=268,74 Size=1148,746 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\noel02.rsw#0] Pos=251,74 Size=977,688 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\d_mond01.rsw#0] Pos=268,74 Size=1225,620 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\d_mond02.rsw#0] Pos=268,74 Size=1225,620 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\ba_maison.rsw#0] Pos=268,74 Size=1225,620 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\ma_scene01.rsw#0] Pos=268,74 Size=1148,746 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\1@alice_mad.rsw#0] Pos=0,74 Size=1545,631 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][Texture Brush Options] -Pos=1302,47 -Size=517,968 +Pos=1230,66 +Size=517,976 Collapsed=0 DockId=0x00000012,0 @@ -501,7 +501,7 @@ DockId=0x00000012,0 Pos=0,74 Size=1507,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][Export Map] Pos=348,200 @@ -517,16 +517,16 @@ Collapsed=0 Pos=1509,833 Size=411,209 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\lookout.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][Texture Picker] -Pos=72,792 +Pos=0,819 Size=1228,223 Collapsed=0 DockId=0x0000001E,0 @@ -535,53 +535,53 @@ DockId=0x0000001E,0 Pos=268,74 Size=1277,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\1@dth1.rsw#0] Pos=0,74 Size=1545,631 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\wolfvill.rsw#0] Pos=268,74 Size=1277,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\2@alice_mad.rsw#0] Pos=0,74 Size=1545,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\jawaii.rsw#0] Pos=0,74 Size=1545,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\fay_vilg00.rsw#0] Pos=0,74 Size=1545,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\prt_vilg01.rsw#0] Pos=0,74 Size=1670,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][data\prt_vilg02.rsw#0] Pos=0,74 Size=1545,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][Gat Edit] -Pos=1302,47 -Size=517,968 +Pos=1230,66 +Size=517,976 Collapsed=0 DockId=0x00000021,0 @@ -589,13 +589,13 @@ DockId=0x00000021,0 Pos=0,74 Size=1566,636 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\dae_paysq.rsw#0] Pos=0,74 Size=1507,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][Hotkey Test] Pos=822,235 @@ -608,8 +608,8 @@ Size=721,583 Collapsed=0 [Window][Object Edit Tools] -Pos=1230,74 -Size=517,688 +Pos=1230,66 +Size=517,696 Collapsed=0 DockId=0x0000000C,0 @@ -617,7 +617,7 @@ DockId=0x0000000C,0 Pos=0,74 Size=1401,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][NewMapPopup] Pos=810,461 @@ -628,11 +628,11 @@ Collapsed=0 Pos=0,74 Size=1507,631 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][Wall Editing] -Pos=1403,74 -Size=517,782 +Pos=1230,66 +Size=517,976 Collapsed=0 DockId=0x00000025,0 @@ -640,10 +640,10 @@ DockId=0x00000025,0 Pos=0,74 Size=1507,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][HotkeyPopup] -Pos=663,442 +Pos=664,442 Size=400,260 Collapsed=0 @@ -651,55 +651,55 @@ Collapsed=0 Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\gef_fild03.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,2 +DockId=0x00000035,2 [Window][data\gef_fild01.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,3 +DockId=0x00000035,3 [Window][data\gef_fild04.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,4 +DockId=0x00000035,4 [Window][data\gef_fild05.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,5 +DockId=0x00000035,5 [Window][data\gef_fild06.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,6 +DockId=0x00000035,6 [Window][data\gef_fild07.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,7 +DockId=0x00000035,7 [Window][data\gef_fild08.rsw#0] Pos=268,74 Size=1239,597 Collapsed=0 -DockId=0x00000019,8 +DockId=0x00000035,8 [Window][data\gef_fild00.rsw#0] Pos=0,74 Size=1507,968 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\wall_colour.rsw#1] Pos=560,272 @@ -710,7 +710,7 @@ Collapsed=0 Pos=0,74 Size=2147,1305 Collapsed=0 -DockId=0x00000019,3 +DockId=0x00000035,3 [Window][Color Edit Window] Pos=1403,74 @@ -724,7 +724,7 @@ Size=229,92 Collapsed=0 [Window][Cinematic Mode] -Pos=-27,683 +Pos=0,733 Size=1395,309 Collapsed=0 DockId=0x00000027,0 @@ -736,7 +736,7 @@ Size=773,1141 Collapsed=0 [Window][Cinematic Mode Properties] -Pos=1370,683 +Pos=1397,733 Size=350,309 Collapsed=0 DockId=0x00000028,0 @@ -745,7 +745,7 @@ DockId=0x00000028,0 Pos=0,74 Size=1401,968 Collapsed=0 -DockId=0x00000019,0 +DockId=0x00000035,0 [Window][RecordVideo] Pos=913,304 @@ -798,32 +798,25 @@ Size=41,36 Collapsed=0 [Window][ModelEditorProperties] -ViewportPos=2712,352 -ViewportId=0xF9BAB730 -Pos=1284,60 +Pos=1384,170 Size=455,612 Collapsed=0 DockId=0x00000031,0 [Window][ModelEditorTimeline] -ViewportPos=2712,352 -ViewportId=0xF9BAB730 -Pos=8,674 +Pos=108,784 Size=1413,286 Collapsed=0 DockId=0x00000032,0 [Window][ModelEditorNodes] -ViewportPos=2712,352 -ViewportId=0xF9BAB730 -Pos=8,60 +Pos=108,170 Size=290,612 Collapsed=0 DockId=0x0000001D,0 [Window][ModelEditor] -ViewportPos=2712,352 -ViewportId=0xF9BAB730 +Pos=100,110 Size=1747,968 Collapsed=0 @@ -834,9 +827,7 @@ Collapsed=0 DockId=0x943392F8,0 [Window][ModelEditorTimelineProperties] -ViewportPos=2712,352 -ViewportId=0xF9BAB730 -Pos=1423,674 +Pos=1523,784 Size=316,286 Collapsed=0 DockId=0x00000033,0 @@ -848,7 +839,7 @@ Size=691,1434 Collapsed=0 [Window][QuitConfirm] -Pos=778,449 +Pos=785,449 Size=572,110 Collapsed=0 @@ -872,7 +863,7 @@ DockId=0x00000030,0 Pos=251,74 Size=977,688 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 [Window][data\model\ilusion\goldberg_s_01.rsm2] Pos=302,134 @@ -884,7 +875,60 @@ DockId=0x00000030,1 Pos=251,74 Size=977,688 Collapsed=0 -DockId=0x00000019,1 +DockId=0x00000035,1 + +[Window][Water Edit] +Pos=1230,66 +Size=517,976 +Collapsed=0 +DockId=0x00000038,0 + +[Window][Shadow Edit Window] +Pos=1230,66 +Size=517,976 +Collapsed=0 +DockId=0x00000036,0 + +[Window][data\morocc.rsw#0] +Pos=0,66 +Size=1228,976 +Collapsed=0 +DockId=0x00000035,0 + +[Window][data\1@vrsn.rsw#0] +Pos=0,66 +Size=1228,976 +Collapsed=0 +DockId=0x00000035,0 + +[Window][data\2@mir.rsw#0] +Pos=251,66 +Size=977,696 +Collapsed=0 +DockId=0x00000035,0 + +[Window][data\prt_fild08.rsw#0] +Pos=60,60 +Size=360,300 +Collapsed=0 + +[Window][data\1@bamn.rsw#0] +Pos=251,66 +Size=1617,972 +Collapsed=0 +DockId=0x00000035,0 + +[Window][data\model\ilusion\chair_y_02.rsm] +Pos=468,145 +Size=982,612 +Collapsed=0 +DockId=0x00000030,0 + +[Window][data\model\abyss\coin_j_01.rsm] +Pos=400,170 +Size=982,612 +Collapsed=0 +DockId=0x00000030,0 [Table][0xD0F0C6E3,2] Column 0 Weight=1.0000 @@ -923,7 +967,7 @@ DockNode ID=0x00000009 Pos=829,358 Size=714,621 S DockNode ID=0x0000002A Parent=0x0000002C SizeRef=472,621 HiddenTabBar=1 DockNode ID=0x0000002B Parent=0x0000002C SizeRef=240,621 HiddenTabBar=1 Selected=0x0F5F7960 DockNode ID=0x0000002D Parent=0x00000009 SizeRef=714,147 HiddenTabBar=1 Selected=0x493A0740 -DockSpace ID=0x6CE547E3 Window=0x4B8D8AF2 Pos=112,209 Size=1920,968 Split=X +DockSpace ID=0x6CE547E3 Window=0x4B8D8AF2 Pos=190,279 Size=1920,976 Split=X DockNode ID=0x00000023 Parent=0x6CE547E3 SizeRef=1899,1305 Split=Y DockNode ID=0x00000005 Parent=0x00000023 SizeRef=1920,688 Split=Y DockNode ID=0x0000001F Parent=0x00000005 SizeRef=1920,657 Split=X @@ -936,7 +980,11 @@ DockSpace ID=0x6CE547E3 Window=0x4B8D8AF2 Pos=112, DockNode ID=0x00000017 Parent=0x0000000A SizeRef=765,620 Split=X Selected=0xAAABD1F1 DockNode ID=0x00000007 Parent=0x00000017 SizeRef=1181,687 Split=X Selected=0x91F763DA DockNode ID=0x0000001B Parent=0x00000007 SizeRef=754,968 Split=Y Selected=0x44412C7A - DockNode ID=0x00000019 Parent=0x0000001B SizeRef=1507,743 CentralNode=1 Selected=0xF9BAB730 + DockNode ID=0x00000019 Parent=0x0000001B SizeRef=1507,743 Split=X Selected=0xB7FCA82D + DockNode ID=0x00000034 Parent=0x00000019 SizeRef=1228,976 Split=X Selected=0xB7FCA82D + DockNode ID=0x00000035 Parent=0x00000034 SizeRef=1228,976 CentralNode=1 Selected=0xBE94C61B + DockNode ID=0x00000038 Parent=0x00000034 SizeRef=517,976 Selected=0x85A6B17E + DockNode ID=0x00000036 Parent=0x00000019 SizeRef=517,976 Selected=0x832C5D4C DockNode ID=0x0000001E Parent=0x0000001B SizeRef=1507,223 Selected=0x5AC25EAE DockNode ID=0x0000001C Parent=0x00000007 SizeRef=751,968 Selected=0x066872F3 DockNode ID=0x00000008 Parent=0x00000017 SizeRef=517,687 Split=Y Selected=0xC89E3217 @@ -963,11 +1011,11 @@ DockSpace ID=0x6CE547E3 Window=0x4B8D8AF2 Pos=112, DockNode ID=0x00000006 Parent=0x00000023 SizeRef=1920,278 Selected=0x05200481 DockNode ID=0x00000024 Parent=0x6CE547E3 SizeRef=171,1305 Selected=0x816F6440 DockSpace ID=0x943392F8 Pos=746,448 Size=1093,663 CentralNode=1 -DockSpace ID=0xFFC4C7D1 Window=0xF9BAB730 Pos=2720,412 Size=1731,900 Split=Y Selected=0x6AC46EDD +DockSpace ID=0xFFC4C7D1 Window=0xF9BAB730 Pos=298,383 Size=1731,900 Split=Y Selected=0x6AC46EDD DockNode ID=0x0000002E Parent=0xFFC4C7D1 SizeRef=1731,612 Split=X DockNode ID=0x0000001D Parent=0x0000002E SizeRef=290,900 Selected=0xF0CFC56F DockNode ID=0x00000029 Parent=0x0000002E SizeRef=1439,900 Split=X Selected=0x6AC46EDD - DockNode ID=0x00000030 Parent=0x00000029 SizeRef=982,612 CentralNode=1 Selected=0x6AC46EDD + DockNode ID=0x00000030 Parent=0x00000029 SizeRef=982,612 CentralNode=1 Selected=0xC9F6FCB3 DockNode ID=0x00000031 Parent=0x00000029 SizeRef=455,612 Selected=0x3AB8A81E DockNode ID=0x0000002F Parent=0xFFC4C7D1 SizeRef=1731,286 Split=X Selected=0xF83015A6 DockNode ID=0x00000032 Parent=0x0000002F SizeRef=1413,286 Selected=0x21E2845C