Beco: Difference between revisions
imported>Leoetlino m (lowercase title) |
(→Getting data for a given coordinate: replace pseudocode with actual C++ source code (from the decomp project)) |
||
(8 intermediate revisions by one other user not shown) | |||
Line 12: | Line 12: | ||
| 0x0 || u32 || Magic (0x00112233) | | 0x0 || u32 || Magic (0x00112233) | ||
|- | |- | ||
| 0x4 || u32 || Number of | | 0x4 || u32 || Number of rows | ||
|- | |- | ||
| 0x8 || u32 || Divisor | | 0x8 || u32 || Divisor | ||
Line 19: | Line 19: | ||
|} | |} | ||
=== | === Offsets === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Offset !! Type !! Description | ! Offset !! Type !! Description | ||
|- | |- | ||
| 0x0 || u32[ | | 0x0 || u32[num_rows] || Offsets to row data, divided by 2 and relative to the start of the row section | ||
|} | |} | ||
=== | === Rows === | ||
==== Segment ==== | ==== Segment ==== | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 40: | Line 38: | ||
|} | |} | ||
This structure is repeated until the | This structure is repeated until the entire row has been covered by segments. The sum of all segment lengths is equal to the length of the map on the X axis. | ||
== Operations == | == Operations == | ||
=== Getting | === Getting data for a given coordinate === | ||
{{ | The algorithm that returns the custom data that is associated with a coordinate is very simple. It consists of determining the correct row index in the table, then iterating over segments in that row and returning the segment data when the X coordinate is within its bounds. | ||
<syntaxhighlight lang="c++"> | |||
s32 Ecosystem::getMapArea(const EcoMapInfo& info, f32 posX, f32 posZ) const { | |||
posX = sead::Mathf::clamp(posX, -5000.0f, 4999.0f); | |||
posZ = sead::Mathf::clamp(posZ, -4000.0f, 4000.0f); | |||
const auto epsilon = [](float n) { return n >= 0.0f ? 0.5f : -0.5f; }; | |||
s32 x = s32(posX + 5000.0f + epsilon(posX + 5000.0f)); | |||
s32 z = s32(posZ + 4000.0f + epsilon(posZ + 4000.0f)) / info.mHeader->divisor; | |||
s32 row = sead::Mathi::clamp(z, 0, info.mHeader->num_rows - 2); | |||
if (info.mHeader->divisor == 10) | |||
x /= 10; | |||
if (info.mRowOffsets[row] >= info.mRowOffsets[row + 1]) | |||
return -1; | |||
auto* segmentEnd = reinterpret_cast<const Segment*>(info.mRows + 2 * info.mRowOffsets[row + 1]); | |||
auto* segment = reinterpret_cast<const Segment*>(info.mRows + 2 * info.mRowOffsets[row]); | |||
s32 totalLength = 0; | |||
while (true) { | |||
totalLength += segment->length; | |||
if (x < totalLength) | |||
break; | |||
++segment; | |||
if (segment >= segmentEnd) | |||
return -1; | |||
} | |||
return segment->value; | |||
} | |||
</syntaxhighlight> | |||
Source: https://github.com/zeldaret/botw/blob/022f029db1ef03d900fb54bad0807939c9695720/src/KingSystem/Ecosystem/ecoSystem.cpp#L100 | |||
== Usage in ''Breath of the Wild'' == | |||
beco files are used in ''Breath of the Wild'' to map coordinates to arbitrary u16 data. Three beco files are used for different purposes: [[FieldMapArea.beco]], [[MapTower.beco]] and [[LoadBalancer.beco]]. | |||
[[Category:File formats]] | [[Category:File formats]] | ||
[[Category:File extensions]] | [[Category:File extensions]] |
Latest revision as of 01:22, 24 November 2021
beco is a file format that is used for storing per-coordinate data.
Structure
beco files are little endian on Switch and big endian on Wii U.
Header
Offset | Type | Description |
---|---|---|
0x0 | u32 | Magic (0x00112233) |
0x4 | u32 | Number of rows |
0x8 | u32 | Divisor |
0xc | u32 | Padding |
Offsets
Offset | Type | Description |
---|---|---|
0x0 | u32[num_rows] | Offsets to row data, divided by 2 and relative to the start of the row section |
Rows
Segment
Offset | Type | Description |
---|---|---|
0x0 | u16 | Custom data |
0x2 | u16 | Length (X axis) |
This structure is repeated until the entire row has been covered by segments. The sum of all segment lengths is equal to the length of the map on the X axis.
Operations
Getting data for a given coordinate
The algorithm that returns the custom data that is associated with a coordinate is very simple. It consists of determining the correct row index in the table, then iterating over segments in that row and returning the segment data when the X coordinate is within its bounds.
s32 Ecosystem::getMapArea(const EcoMapInfo& info, f32 posX, f32 posZ) const {
posX = sead::Mathf::clamp(posX, -5000.0f, 4999.0f);
posZ = sead::Mathf::clamp(posZ, -4000.0f, 4000.0f);
const auto epsilon = [](float n) { return n >= 0.0f ? 0.5f : -0.5f; };
s32 x = s32(posX + 5000.0f + epsilon(posX + 5000.0f));
s32 z = s32(posZ + 4000.0f + epsilon(posZ + 4000.0f)) / info.mHeader->divisor;
s32 row = sead::Mathi::clamp(z, 0, info.mHeader->num_rows - 2);
if (info.mHeader->divisor == 10)
x /= 10;
if (info.mRowOffsets[row] >= info.mRowOffsets[row + 1])
return -1;
auto* segmentEnd = reinterpret_cast<const Segment*>(info.mRows + 2 * info.mRowOffsets[row + 1]);
auto* segment = reinterpret_cast<const Segment*>(info.mRows + 2 * info.mRowOffsets[row]);
s32 totalLength = 0;
while (true) {
totalLength += segment->length;
if (x < totalLength)
break;
++segment;
if (segment >= segmentEnd)
return -1;
}
return segment->value;
}
Usage in Breath of the Wild
beco files are used in Breath of the Wild to map coordinates to arbitrary u16 data. Three beco files are used for different purposes: FieldMapArea.beco, MapTower.beco and LoadBalancer.beco.