Instances are now serialized with little-endian
This commit is contained in:
parent
d9c2d227ac
commit
a75de1eee2
@ -1,6 +1,9 @@
|
||||
Instance block format
|
||||
=======================
|
||||
|
||||
!!! warn
|
||||
This document is about an old version of the format. You may check the most recent version.
|
||||
|
||||
This page describes the binary format used by the module to save instances to files or databases.
|
||||
|
||||
Specification
|
68
doc/source/specs/instances_format_v1.md
Normal file
68
doc/source/specs/instances_format_v1.md
Normal file
@ -0,0 +1,68 @@
|
||||
Instance block format
|
||||
=======================
|
||||
|
||||
This page describes the binary format used by the module to save instances to files or databases.
|
||||
|
||||
Changes from version 0
|
||||
-------------------------
|
||||
|
||||
- Data is now little-endian instead of big-endian.
|
||||
- No other changes were made, so version 0 is easily convertible.
|
||||
|
||||
|
||||
Specification
|
||||
---------------
|
||||
|
||||
### Compressed container
|
||||
|
||||
A block is usually serialized as compressed data.
|
||||
See [Compressed container format](#compressed-container) for specification.
|
||||
|
||||
|
||||
### Binary data
|
||||
|
||||
This data is little-endian.
|
||||
|
||||
In pseudo-code:
|
||||
|
||||
```cpp
|
||||
// Root structure
|
||||
struct InstanceBlockData {
|
||||
// Version tag in case more stuff is added in the future
|
||||
uint8_t version = 1;
|
||||
// There can be up to 256 different layers in one block
|
||||
uint8_t layer_count;
|
||||
// To compress positions we need to know their range.
|
||||
// It's local to the block so we know it starts from zero.
|
||||
float position_range;
|
||||
LayerData layers[layer_count];
|
||||
// Magic number to signal the end of the data block
|
||||
uint32_t control_end = 0x900df00d;
|
||||
};
|
||||
|
||||
struct LayerData {
|
||||
uint16_t id; // Identifies the type of instances (rocks, grass, pebbles, bushes etc)
|
||||
uint16_t count;
|
||||
// To be able to compress scale we must know its range
|
||||
float scale_min;
|
||||
float scale_max;
|
||||
// This tells which format instances of this layer use. For now I always use the same format,
|
||||
// But maybe some types of instances will need more, or less data?
|
||||
uint8_t format = 0;
|
||||
InstanceData data[count];
|
||||
};
|
||||
|
||||
struct InstanceData {
|
||||
// Position is lossy-compressed based on the size of the block
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
// Scale is uniform and is lossy-compressed to 256 values
|
||||
uint8_t scale;
|
||||
// Rotation is a compressed quaternion
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t z;
|
||||
uint8_t w;
|
||||
};
|
||||
```
|
@ -8,7 +8,12 @@ namespace zylann::voxel {
|
||||
|
||||
namespace {
|
||||
const uint32_t TRAILING_MAGIC = 0x900df00d;
|
||||
}
|
||||
enum FormatVersion {
|
||||
INSTANCE_BLOCK_FORMAT_VERSION_0 = 0,
|
||||
// Now using little-endian.
|
||||
INSTANCE_BLOCK_FORMAT_VERSION_1 = 1
|
||||
};
|
||||
} //namespace
|
||||
|
||||
const float InstanceBlockData::POSITION_RANGE_MINIMUM = 0.01f;
|
||||
|
||||
@ -50,18 +55,17 @@ struct CompressedQuaternion4b {
|
||||
};
|
||||
|
||||
bool serialize_instance_block_data(const InstanceBlockData &src, std::vector<uint8_t> &dst) {
|
||||
const uint8_t version = 0;
|
||||
const uint8_t instance_format = InstanceBlockData::FORMAT_SIMPLE_11B_V1;
|
||||
|
||||
// TODO Apparently big-endian is dead
|
||||
// I chose it originally to match "network byte order",
|
||||
// but as I read comments about it there seem to be no reason to continue using it. Needs a version increment.
|
||||
zylann::MemoryWriter w(dst, zylann::ENDIANESS_BIG_ENDIAN);
|
||||
zylann::MemoryWriter w(dst, zylann::ENDIANESS_LITTLE_ENDIAN);
|
||||
|
||||
ERR_FAIL_COND_V(src.position_range < 0.f, false);
|
||||
const float position_range = math::max(src.position_range, InstanceBlockData::POSITION_RANGE_MINIMUM);
|
||||
|
||||
w.store_8(version);
|
||||
w.store_8(INSTANCE_BLOCK_FORMAT_VERSION_1);
|
||||
w.store_8(src.layers.size());
|
||||
w.store_float(position_range);
|
||||
|
||||
@ -114,13 +118,17 @@ bool serialize_instance_block_data(const InstanceBlockData &src, std::vector<uin
|
||||
}
|
||||
|
||||
bool deserialize_instance_block_data(InstanceBlockData &dst, Span<const uint8_t> src) {
|
||||
const uint8_t expected_version = 0;
|
||||
const uint8_t expected_version = INSTANCE_BLOCK_FORMAT_VERSION_1;
|
||||
const uint8_t expected_instance_format = InstanceBlockData::FORMAT_SIMPLE_11B_V1;
|
||||
|
||||
zylann::MemoryReader r(src, zylann::ENDIANESS_BIG_ENDIAN);
|
||||
zylann::MemoryReader r(src, zylann::ENDIANESS_LITTLE_ENDIAN);
|
||||
|
||||
const uint8_t version = r.get_8();
|
||||
ERR_FAIL_COND_V(version != expected_version, false);
|
||||
if (version == INSTANCE_BLOCK_FORMAT_VERSION_0) {
|
||||
r.endianess = zylann::ENDIANESS_BIG_ENDIAN;
|
||||
} else {
|
||||
ERR_FAIL_COND_V(version != expected_version, false);
|
||||
}
|
||||
|
||||
const uint8_t layers_count = r.get_8();
|
||||
dst.layers.resize(layers_count);
|
||||
|
Loading…
x
Reference in New Issue
Block a user