mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
fix(editor): undo now covers texture painting, fix stale buffer bug
- Extend undo/redo to snapshot alpha maps and texture layers alongside heights — texture painting operations are now fully undoable - Bracket paint mode with beginStroke/endStroke like sculpt mode - Fix stale static char buffer in quest objective loop (showed wrong objective's description when editing multiple objectives) - Zero-initialize all quest UI text buffers for null termination safety - Fix unused variable warnings in terrain_editor.cpp
This commit is contained in:
parent
617228559a
commit
4e2f704124
5 changed files with 44 additions and 22 deletions
|
|
@ -400,12 +400,12 @@ void EditorApp::processEvents() {
|
|||
}
|
||||
} else {
|
||||
painting_ = true;
|
||||
if (mode_ == EditorMode::Sculpt)
|
||||
if (mode_ == EditorMode::Sculpt || mode_ == EditorMode::Paint)
|
||||
terrainEditor_.beginStroke();
|
||||
}
|
||||
} else if (event.type == SDL_MOUSEBUTTONUP) {
|
||||
painting_ = false;
|
||||
if (mode_ == EditorMode::Sculpt)
|
||||
if (mode_ == EditorMode::Sculpt || mode_ == EditorMode::Paint)
|
||||
terrainEditor_.endStroke();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,37 @@
|
|||
namespace wowee {
|
||||
namespace editor {
|
||||
|
||||
ChunkSnapshot EditorHistory::captureChunk(const pipeline::ADTTerrain& terrain, int idx) {
|
||||
ChunkSnapshot snap;
|
||||
snap.chunkIndex = idx;
|
||||
snap.heights = terrain.chunks[idx].heightMap.heights;
|
||||
snap.alphaMap = terrain.chunks[idx].alphaMap;
|
||||
snap.layers = terrain.chunks[idx].layers;
|
||||
return snap;
|
||||
}
|
||||
|
||||
void EditorHistory::restoreChunk(pipeline::ADTTerrain& terrain, const ChunkSnapshot& snap) {
|
||||
terrain.chunks[snap.chunkIndex].heightMap.heights = snap.heights;
|
||||
terrain.chunks[snap.chunkIndex].alphaMap = snap.alphaMap;
|
||||
terrain.chunks[snap.chunkIndex].layers = snap.layers;
|
||||
}
|
||||
|
||||
bool EditorHistory::snapshotChanged(const ChunkSnapshot& a, const ChunkSnapshot& b) {
|
||||
if (a.heights != b.heights) return true;
|
||||
if (a.alphaMap != b.alphaMap) return true;
|
||||
if (a.layers.size() != b.layers.size()) return true;
|
||||
for (size_t i = 0; i < a.layers.size(); i++) {
|
||||
if (a.layers[i].textureId != b.layers[i].textureId) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorHistory::beginEdit(const pipeline::ADTTerrain& terrain,
|
||||
const std::vector<int>& affectedChunks) {
|
||||
pending_ = {};
|
||||
pending_.before.reserve(affectedChunks.size());
|
||||
for (int idx : affectedChunks) {
|
||||
ChunkSnapshot snap;
|
||||
snap.chunkIndex = idx;
|
||||
snap.heights = terrain.chunks[idx].heightMap.heights;
|
||||
pending_.before.push_back(snap);
|
||||
pending_.before.push_back(captureChunk(terrain, idx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -19,17 +41,13 @@ void EditorHistory::endEdit(const pipeline::ADTTerrain& terrain) {
|
|||
pending_.after.reserve(pending_.before.size());
|
||||
lastAffected_.clear();
|
||||
for (const auto& snap : pending_.before) {
|
||||
ChunkSnapshot after;
|
||||
after.chunkIndex = snap.chunkIndex;
|
||||
after.heights = terrain.chunks[snap.chunkIndex].heightMap.heights;
|
||||
pending_.after.push_back(after);
|
||||
pending_.after.push_back(captureChunk(terrain, snap.chunkIndex));
|
||||
lastAffected_.push_back(snap.chunkIndex);
|
||||
}
|
||||
|
||||
// Only push if something actually changed
|
||||
bool changed = false;
|
||||
for (size_t i = 0; i < pending_.before.size(); i++) {
|
||||
if (pending_.before[i].heights != pending_.after[i].heights) {
|
||||
if (snapshotChanged(pending_.before[i], pending_.after[i])) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -51,7 +69,7 @@ void EditorHistory::undo(pipeline::ADTTerrain& terrain) {
|
|||
|
||||
lastAffected_.clear();
|
||||
for (const auto& snap : cmd.before) {
|
||||
terrain.chunks[snap.chunkIndex].heightMap.heights = snap.heights;
|
||||
restoreChunk(terrain, snap);
|
||||
lastAffected_.push_back(snap.chunkIndex);
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +84,7 @@ void EditorHistory::redo(pipeline::ADTTerrain& terrain) {
|
|||
|
||||
lastAffected_.clear();
|
||||
for (const auto& snap : cmd.after) {
|
||||
terrain.chunks[snap.chunkIndex].heightMap.heights = snap.heights;
|
||||
restoreChunk(terrain, snap);
|
||||
lastAffected_.push_back(snap.chunkIndex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ namespace editor {
|
|||
struct ChunkSnapshot {
|
||||
int chunkIndex;
|
||||
std::array<float, 145> heights;
|
||||
std::vector<uint8_t> alphaMap;
|
||||
std::vector<pipeline::TextureLayer> layers;
|
||||
};
|
||||
|
||||
struct EditCommand {
|
||||
|
|
@ -37,6 +39,10 @@ public:
|
|||
const std::vector<int>& lastAffectedChunks() const { return lastAffected_; }
|
||||
|
||||
private:
|
||||
static ChunkSnapshot captureChunk(const pipeline::ADTTerrain& terrain, int idx);
|
||||
static void restoreChunk(pipeline::ADTTerrain& terrain, const ChunkSnapshot& snap);
|
||||
static bool snapshotChanged(const ChunkSnapshot& a, const ChunkSnapshot& b);
|
||||
|
||||
std::vector<EditCommand> undoStack_;
|
||||
std::vector<EditCommand> redoStack_;
|
||||
EditCommand pending_;
|
||||
|
|
|
|||
|
|
@ -1706,12 +1706,12 @@ void EditorUI::renderQuestPanel(EditorApp& app) {
|
|||
auto& tmpl = qe.getTemplate();
|
||||
|
||||
if (ImGui::CollapsingHeader("New Quest", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
static char titleBuf[128] = "New Quest";
|
||||
char titleBuf[128] = {};
|
||||
std::strncpy(titleBuf, tmpl.title.c_str(), sizeof(titleBuf) - 1);
|
||||
if (ImGui::InputText("Title##q", titleBuf, sizeof(titleBuf)))
|
||||
tmpl.title = titleBuf;
|
||||
|
||||
static char descBuf[512] = "";
|
||||
char descBuf[512] = {};
|
||||
std::strncpy(descBuf, tmpl.description.c_str(), sizeof(descBuf) - 1);
|
||||
if (ImGui::InputTextMultiline("Description##q", descBuf, sizeof(descBuf), ImVec2(-1, 60)))
|
||||
tmpl.description = descBuf;
|
||||
|
|
@ -1756,7 +1756,7 @@ void EditorUI::renderQuestPanel(EditorApp& app) {
|
|||
int ti = static_cast<int>(obj.type);
|
||||
ImGui::Combo("Type", &ti, types, 6);
|
||||
obj.type = static_cast<QuestObjectiveType>(ti);
|
||||
static char objDesc[128];
|
||||
char objDesc[128] = {};
|
||||
std::strncpy(objDesc, obj.description.c_str(), sizeof(objDesc) - 1);
|
||||
if (ImGui::InputText("Desc", objDesc, sizeof(objDesc))) obj.description = objDesc;
|
||||
int cnt = obj.targetCount;
|
||||
|
|
@ -1786,7 +1786,7 @@ void EditorUI::renderQuestPanel(EditorApp& app) {
|
|||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
static char completeBuf[256] = "";
|
||||
char completeBuf[256] = {};
|
||||
std::strncpy(completeBuf, tmpl.completionText.c_str(), sizeof(completeBuf) - 1);
|
||||
if (ImGui::InputTextMultiline("Completion Text##q", completeBuf, sizeof(completeBuf), ImVec2(-1, 40)))
|
||||
tmpl.completionText = completeBuf;
|
||||
|
|
@ -1816,7 +1816,7 @@ void EditorUI::renderQuestPanel(EditorApp& app) {
|
|||
if (selectedQuest >= 0 && selectedQuest < static_cast<int>(qe.questCount())) {
|
||||
auto* sq = qe.getQuest(selectedQuest);
|
||||
ImGui::TextColored(ImVec4(1, 0.8f, 0.3f, 1), "Editing: [%u] %s", sq->id, sq->title.c_str());
|
||||
static char etBuf[128];
|
||||
char etBuf[128] = {};
|
||||
std::strncpy(etBuf, sq->title.c_str(), sizeof(etBuf) - 1);
|
||||
if (ImGui::InputText("Title##edit", etBuf, sizeof(etBuf))) sq->title = etBuf;
|
||||
int elv = sq->requiredLevel;
|
||||
|
|
|
|||
|
|
@ -1445,7 +1445,7 @@ void TerrainEditor::applyErode(float dt) {
|
|||
if (influence <= 0.0f) continue;
|
||||
|
||||
float h = chunk.heightMap.heights[v];
|
||||
int row = v / 17, col = v % 17;
|
||||
int col = v % 17;
|
||||
|
||||
// Find lowest neighbor (same chunk)
|
||||
float lowestH = h;
|
||||
|
|
@ -1505,8 +1505,6 @@ void TerrainEditor::applyNoise(float frequency, float amplitude, int octaves, ui
|
|||
for (int ci = 0; ci < 256; ci++) {
|
||||
auto& chunk = terrain_->chunks[ci];
|
||||
if (!chunk.hasHeightMap()) continue;
|
||||
int cx = ci % 16, cy = ci / 16;
|
||||
|
||||
for (int v = 0; v < 145; v++) {
|
||||
glm::vec3 wpos = chunkVertexWorldPos(ci, v);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue