mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
160 lines
5.3 KiB
C++
160 lines
5.3 KiB
C++
//
|
|
// VoxelTreeCommands.cpp
|
|
// libraries/voxels/src
|
|
//
|
|
// Created by Clement on 4/4/14.
|
|
// Copyright 2013 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include "VoxelTree.h"
|
|
|
|
#include "VoxelTreeCommands.h"
|
|
|
|
|
|
|
|
struct SendVoxelsOperationArgs {
|
|
const unsigned char* newBaseOctCode;
|
|
VoxelEditPacketSender* packetSender;
|
|
};
|
|
|
|
bool sendVoxelsOperation(OctreeElement* element, void* extraData) {
|
|
VoxelTreeElement* voxel = static_cast<VoxelTreeElement*>(element);
|
|
SendVoxelsOperationArgs* args = static_cast<SendVoxelsOperationArgs*>(extraData);
|
|
if (voxel->isColored()) {
|
|
const unsigned char* nodeOctalCode = voxel->getOctalCode();
|
|
unsigned char* codeColorBuffer = NULL;
|
|
int codeLength = 0;
|
|
int bytesInCode = 0;
|
|
int codeAndColorLength;
|
|
|
|
// If the newBase is NULL, then don't rebase
|
|
if (args->newBaseOctCode) {
|
|
codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true);
|
|
codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer);
|
|
bytesInCode = bytesRequiredForCodeLength(codeLength);
|
|
codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA;
|
|
} else {
|
|
codeLength = numberOfThreeBitSectionsInCode(nodeOctalCode);
|
|
bytesInCode = bytesRequiredForCodeLength(codeLength);
|
|
codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA;
|
|
codeColorBuffer = new unsigned char[codeAndColorLength];
|
|
memcpy(codeColorBuffer, nodeOctalCode, bytesInCode);
|
|
}
|
|
|
|
// copy the colors over
|
|
codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX];
|
|
codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX];
|
|
codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX];
|
|
args->packetSender->queueVoxelEditMessage(PacketTypeVoxelSetDestructive,
|
|
codeColorBuffer, codeAndColorLength);
|
|
|
|
delete[] codeColorBuffer;
|
|
}
|
|
return true; // keep going
|
|
}
|
|
|
|
|
|
AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) :
|
|
QUndoCommand("Add Voxel", parent),
|
|
_tree(tree),
|
|
_packetSender(packetSender),
|
|
_voxel(voxel)
|
|
{
|
|
}
|
|
|
|
void AddVoxelCommand::redo() {
|
|
if (_tree) {
|
|
_tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue);
|
|
}
|
|
if (_packetSender) {
|
|
_packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel);
|
|
}
|
|
}
|
|
|
|
void AddVoxelCommand::undo() {
|
|
if (_tree) {
|
|
_tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
|
}
|
|
if (_packetSender) {
|
|
_packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel);
|
|
}
|
|
}
|
|
|
|
DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) :
|
|
QUndoCommand("Delete Voxel", parent),
|
|
_tree(tree),
|
|
_packetSender(packetSender),
|
|
_voxel(voxel),
|
|
_oldTree(NULL)
|
|
{
|
|
_tree->lockForRead();
|
|
VoxelTreeElement* element = _tree->getEnclosingVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
|
if (element->getScale() == _voxel.s) {
|
|
if (!element->hasContent() && !element->isLeaf()) {
|
|
_oldTree = new VoxelTree();
|
|
_tree->copySubTreeIntoNewTree(element, _oldTree, false);
|
|
} else {
|
|
_voxel.red = element->getColor()[0];
|
|
_voxel.green = element->getColor()[1];
|
|
_voxel.blue = element->getColor()[2];
|
|
}
|
|
} else if (element->hasContent() && element->isLeaf()) {
|
|
_voxel.red = element->getColor()[0];
|
|
_voxel.green = element->getColor()[1];
|
|
_voxel.blue = element->getColor()[2];
|
|
} else {
|
|
_voxel.s = 0.0f;
|
|
}
|
|
_tree->unlock();
|
|
}
|
|
|
|
DeleteVoxelCommand::~DeleteVoxelCommand() {
|
|
delete _oldTree;
|
|
}
|
|
|
|
void DeleteVoxelCommand::redo() {
|
|
if (_voxel.s == 0.0f) {
|
|
return;
|
|
}
|
|
|
|
if (_tree) {
|
|
_tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
|
}
|
|
if (_packetSender) {
|
|
_packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel);
|
|
}
|
|
}
|
|
|
|
void DeleteVoxelCommand::undo() {
|
|
if (_voxel.s == 0.0f) {
|
|
return;
|
|
}
|
|
|
|
if (_oldTree) {
|
|
VoxelTreeElement* element = _oldTree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s);
|
|
if (element) {
|
|
if (_tree) {
|
|
_tree->lockForWrite();
|
|
_oldTree->copySubTreeIntoNewTree(element, _tree, false);
|
|
_tree->unlock();
|
|
}
|
|
if (_packetSender) {
|
|
SendVoxelsOperationArgs args;
|
|
args.newBaseOctCode = NULL;
|
|
args.packetSender = _packetSender;
|
|
_oldTree->recurseTreeWithOperation(sendVoxelsOperation, &args);
|
|
_packetSender->releaseQueuedMessages();
|
|
}
|
|
}
|
|
} else {
|
|
if (_tree) {
|
|
_tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue);
|
|
}
|
|
if (_packetSender) {
|
|
_packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel);
|
|
}
|
|
}
|
|
}
|