2019-09-03 14:54:40 -07:00
|
|
|
#include "voxel_tool_buffer.h"
|
2020-09-14 11:33:02 -07:00
|
|
|
#include "../storage/voxel_buffer.h"
|
2021-04-25 12:23:14 -07:00
|
|
|
#include "../util/profiling.h"
|
|
|
|
#include "funcs.h"
|
2019-09-03 14:54:40 -07:00
|
|
|
|
|
|
|
VoxelToolBuffer::VoxelToolBuffer(Ref<VoxelBuffer> vb) {
|
|
|
|
ERR_FAIL_COND(vb.is_null());
|
|
|
|
_buffer = vb;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VoxelToolBuffer::is_area_editable(const Rect3i &box) const {
|
2019-12-14 13:34:41 -08:00
|
|
|
ERR_FAIL_COND_V(_buffer.is_null(), false);
|
|
|
|
return Rect3i(Vector3i(), _buffer->get_size()).encloses(box);
|
2019-09-03 14:54:40 -07:00
|
|
|
}
|
|
|
|
|
2021-04-25 12:23:14 -07:00
|
|
|
void VoxelToolBuffer::do_sphere(Vector3 center, float radius) {
|
|
|
|
ERR_FAIL_COND(_buffer.is_null());
|
|
|
|
|
|
|
|
if (_mode != MODE_TEXTURE_PAINT) {
|
|
|
|
VoxelTool::do_sphere(center, radius);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOXEL_PROFILE_SCOPE();
|
|
|
|
|
|
|
|
Rect3i box(Vector3i(center) - Vector3i(Math::floor(radius)), Vector3i(Math::ceil(radius) * 2));
|
|
|
|
box.clip(Rect3i(Vector3i(), _buffer->get_size()));
|
|
|
|
|
|
|
|
const TextureParams &tp = _texture_params;
|
|
|
|
VoxelBuffer &buffer = **_buffer;
|
|
|
|
|
|
|
|
box.for_each_cell([&buffer, center, radius, &tp](Vector3i pos) {
|
|
|
|
const float distance = radius - pos.to_vec3().distance_to(center);
|
|
|
|
const float target_weight = tp.opacity * clamp(tp.sharpness * (distance / radius), 0.f, 1.f);
|
|
|
|
if (target_weight > 0.f) {
|
|
|
|
uint16_t indices = buffer.get_voxel(pos, VoxelBuffer::CHANNEL_INDICES);
|
|
|
|
uint16_t weights = buffer.get_voxel(pos, VoxelBuffer::CHANNEL_WEIGHTS);
|
2021-05-23 12:28:06 -07:00
|
|
|
blend_texture_packed_u16(tp.index, target_weight, indices, weights);
|
2021-04-25 12:23:14 -07:00
|
|
|
// TODO Optimization: don't write back if it didn't change?
|
|
|
|
buffer.set_voxel(indices, pos, VoxelBuffer::CHANNEL_INDICES);
|
|
|
|
buffer.set_voxel(weights, pos, VoxelBuffer::CHANNEL_WEIGHTS);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
_post_edit(box);
|
|
|
|
}
|
|
|
|
|
2020-12-30 12:09:31 -08:00
|
|
|
uint64_t VoxelToolBuffer::_get_voxel(Vector3i pos) const {
|
2019-09-03 14:54:40 -07:00
|
|
|
ERR_FAIL_COND_V(_buffer.is_null(), 0);
|
2019-12-14 13:34:41 -08:00
|
|
|
return _buffer->get_voxel(pos, _channel);
|
2019-09-03 14:54:40 -07:00
|
|
|
}
|
|
|
|
|
2020-12-30 12:09:31 -08:00
|
|
|
float VoxelToolBuffer::_get_voxel_f(Vector3i pos) const {
|
2019-09-03 14:54:40 -07:00
|
|
|
ERR_FAIL_COND_V(_buffer.is_null(), 0);
|
2019-12-14 13:34:41 -08:00
|
|
|
return _buffer->get_voxel_f(pos.x, pos.y, pos.z, _channel);
|
2019-09-03 14:54:40 -07:00
|
|
|
}
|
|
|
|
|
2020-08-06 11:54:47 -07:00
|
|
|
void VoxelToolBuffer::_set_voxel(Vector3i pos, uint64_t v) {
|
2019-09-03 14:54:40 -07:00
|
|
|
ERR_FAIL_COND(_buffer.is_null());
|
2019-12-14 13:34:41 -08:00
|
|
|
return _buffer->set_voxel(v, pos, _channel);
|
2019-09-03 14:54:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void VoxelToolBuffer::_set_voxel_f(Vector3i pos, float v) {
|
|
|
|
ERR_FAIL_COND(_buffer.is_null());
|
2019-12-14 13:34:41 -08:00
|
|
|
return _buffer->set_voxel_f(v, pos.x, pos.y, pos.z, _channel);
|
2019-09-03 14:54:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void VoxelToolBuffer::_post_edit(const Rect3i &box) {
|
|
|
|
ERR_FAIL_COND(_buffer.is_null());
|
2019-12-14 13:34:41 -08:00
|
|
|
// Nothing special to do
|
2019-09-03 14:54:40 -07:00
|
|
|
}
|
2020-08-04 15:54:40 -07:00
|
|
|
|
2020-08-10 11:03:01 -07:00
|
|
|
void VoxelToolBuffer::set_voxel_metadata(Vector3i pos, Variant meta) {
|
|
|
|
ERR_FAIL_COND(_buffer.is_null());
|
|
|
|
_buffer->set_voxel_metadata(pos, meta);
|
|
|
|
}
|
|
|
|
|
|
|
|
Variant VoxelToolBuffer::get_voxel_metadata(Vector3i pos) {
|
|
|
|
ERR_FAIL_COND_V(_buffer.is_null(), Variant());
|
|
|
|
return _buffer->get_voxel_metadata(pos);
|
|
|
|
}
|
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
void VoxelToolBuffer::paste(Vector3i p_pos, Ref<VoxelBuffer> p_voxels, uint8_t channels_mask, uint64_t mask_value) {
|
2020-08-04 15:54:40 -07:00
|
|
|
ERR_FAIL_COND(_buffer.is_null());
|
|
|
|
ERR_FAIL_COND(p_voxels.is_null());
|
|
|
|
|
|
|
|
VoxelBuffer *dst = *_buffer;
|
|
|
|
const VoxelBuffer *src = *p_voxels;
|
|
|
|
|
|
|
|
Rect3i box(p_pos, p_voxels->get_size());
|
|
|
|
const Vector3i min_noclamp = box.pos;
|
|
|
|
box.clip(Rect3i(Vector3i(), _buffer->get_size()));
|
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
if (channels_mask == 0) {
|
|
|
|
channels_mask = (1 << get_channel());
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int channel_count;
|
|
|
|
FixedArray<uint8_t, VoxelBuffer::MAX_CHANNELS> channels =
|
|
|
|
VoxelBuffer::mask_to_channels_list(channels_mask, channel_count);
|
2020-08-04 15:54:40 -07:00
|
|
|
|
|
|
|
const Vector3i box_max = box.pos + box.size;
|
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
for (unsigned int ci = 0; ci < channel_count; ++ci) {
|
|
|
|
const unsigned int channel_index = channels[ci];
|
|
|
|
|
|
|
|
for (int z = box.pos.z; z < box_max.z; ++z) {
|
|
|
|
const int bz = z - min_noclamp.z;
|
2020-08-04 15:54:40 -07:00
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
for (int x = box.pos.x; x < box_max.x; ++x) {
|
|
|
|
const int bx = x - min_noclamp.x;
|
2020-08-04 15:54:40 -07:00
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
for (int y = box.pos.y; y < box_max.y; ++y) {
|
|
|
|
const int by = y - min_noclamp.y;
|
2020-08-04 15:54:40 -07:00
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
const uint64_t v = src->get_voxel(bx, by, bz, channel_index);
|
|
|
|
if (v != mask_value) {
|
|
|
|
dst->set_voxel(v, x, y, z, channel_index);
|
2020-08-10 11:03:01 -07:00
|
|
|
|
2021-02-21 10:22:40 -08:00
|
|
|
// Overwrite previous metadata
|
|
|
|
dst->set_voxel_metadata(Vector3i(x, y, z), Variant());
|
|
|
|
}
|
2020-08-04 15:54:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-10 11:03:01 -07:00
|
|
|
|
|
|
|
_buffer->copy_voxel_metadata_in_area(p_voxels, Rect3i(Vector3i(), p_voxels->get_size()), p_pos);
|
2020-08-04 15:54:40 -07:00
|
|
|
}
|