Files
EVEngine/src/modules/editor/EditorVolumeTarget.cpp
T

129 lines
4.0 KiB
C++

#include "editor/EditorVolumeTarget.h"
#ifdef EVENGINE_HAS_VOXEL
#include "voxel/VoxelWorld.h"
#endif
#include <utility>
namespace eve::editor {
void EditVolume::include(int x, int y, int z) {
if (empty()) {
minX = maxX = x;
minY = maxY = y;
minZ = maxZ = z;
return;
}
if (x < minX) minX = x;
if (x > maxX) maxX = x;
if (y < minY) minY = y;
if (y > maxY) maxY = y;
if (z < minZ) minZ = z;
if (z > maxZ) maxZ = z;
}
void EditVolume::include(const EditVolume& other) {
if (other.empty()) return;
include(other.minX, other.minY, other.minZ);
include(other.maxX, other.maxY, other.maxZ);
}
EditRegion EditVolume::xzRegion() const {
EditRegion region;
if (!empty()) {
region.include(minX, minZ);
region.include(maxX, maxZ);
}
return region;
}
#ifdef EVENGINE_HAS_VOXEL
VoxelWorldTarget::VoxelWorldTarget(std::string id, voxel::VoxelWorld* world)
: id_(std::move(id)), world_(world) {}
unsigned long long VoxelWorldTarget::revision() const { return world_ ? world_->getRevision() : 0; }
TargetDescriptor VoxelWorldTarget::describe() const {
TargetDescriptor descriptor;
descriptor.id = TargetId(id_);
descriptor.type = "voxel-world";
descriptor.revision = revision();
descriptor.capabilities = {IIntVolumeTarget::editorCapabilityId()};
return descriptor;
}
void* VoxelWorldTarget::queryCapability(const CapabilityId& capability) {
if (capability == IIntVolumeTarget::editorCapabilityId()) return static_cast<IIntVolumeTarget*>(this);
return nullptr;
}
int VoxelWorldTarget::readInt3(int x, int y, int z) const {
return world_ ? static_cast<int>(world_->getVoxel(x, y, z)) : 0;
}
bool VoxelWorldTarget::writeInt3(int x, int y, int z, int value) {
if (!world_ || value < 0 || value > 255 || readInt3(x, y, z) == value) return false;
world_->setVoxel(x, y, z, static_cast<uint8_t>(value));
dirty_.include(x, y, z);
return true;
}
#endif
IntVolumeEditCommand::IntVolumeEditCommand(std::string name, IEditableTarget* target)
: name_(std::move(name)), target_(target) {}
bool IntVolumeEditCommand::record(int x, int y, int z, int after) {
auto* volume = target_ ? target_->query<IIntVolumeTarget>() : nullptr;
if (!volume) return false;
for (auto& change : changes_) {
if (change.x == x && change.y == y && change.z == z) {
change.after = after;
return true;
}
}
const int before = volume->readInt3(x, y, z);
if (before == after) return false;
changes_.push_back({x, y, z, before, after});
dirty_.include(x, y, z);
return true;
}
bool IntVolumeEditCommand::apply() {
auto* volume = target_ ? target_->query<IIntVolumeTarget>() : nullptr;
if (!volume) return false;
for (const auto& change : changes_) volume->writeInt3(change.x, change.y, change.z, change.after);
return !changes_.empty();
}
void IntVolumeEditCommand::revert() {
auto* volume = target_ ? target_->query<IIntVolumeTarget>() : nullptr;
if (!volume) return;
for (auto it = changes_.rbegin(); it != changes_.rend(); ++it)
volume->writeInt3(it->x, it->y, it->z, it->before);
}
std::unique_ptr<IEditCommand> IntVolumeEditCommand::clone() const {
return std::make_unique<IntVolumeEditCommand>(*this);
}
bool IntVolumeEditCommand::mergeWith(const IEditCommand& laterBase) {
const auto* later = dynamic_cast<const IntVolumeEditCommand*>(&laterBase);
if (!later || later->target_ != target_) return false;
for (const auto& incoming : later->changes_) {
bool merged = false;
for (auto& current : changes_) {
if (current.x == incoming.x && current.y == incoming.y && current.z == incoming.z) {
current.after = incoming.after;
merged = true;
break;
}
}
if (!merged) changes_.push_back(incoming);
}
dirty_.include(later->dirty_);
return true;
}
} // namespace eve::editor