19inline constexpr uint32_t k_max_physical_materials = 256;
21inline constexpr uint8_t k_default_material = 0;
23inline constexpr uint8_t k_entry_transparent = 1u << 0;
41 uint8_t material = k_default_material;
50 std::array<uint8_t, 5> reserved {};
53 constexpr auto operator==(
const PaletteEntry&)
const noexcept ->
bool =
default;
56static_assert(
sizeof(PaletteEntry) == 16,
"a palette entry must be sixteen bytes - the shader indexes it that way");
60 std::array<PaletteEntry, k_palette_size> entries {};
62 float max_emissive = 1.0f;
64 uint32_t revision = 0;
68inline auto defaultPalette() ->
const Palette& {
69 static const Palette palette = [] {
71 for (uint32_t i = 1; i < k_palette_size; ++i) {
72 out.entries[i].albedo_r = 160;
73 out.entries[i].albedo_g = 160;
74 out.entries[i].albedo_b = 160;
75 out.entries[i].roughness = 200;
83inline auto emissiveIntensity(
const Palette& palette, uint8_t index)
noexcept ->
float {
84 return static_cast<float>(palette.entries[index].emissive) / 255.0f * palette.max_emissive;
87inline constexpr uint8_t k_material_indestructible = 1u << 0;
92inline constexpr uint8_t k_material_flammable = 1u << 2;
101 physics::Hardness
hardness = physics::material_defaults::k_hardness;
102 physics::FracturePattern fracture_pattern = physics::material_defaults::k_fracture_pattern;
106 float toughness = physics::material_defaults::k_toughness;
110 float static_friction = physics::material_defaults::k_static_friction;
111 float dynamic_friction = physics::material_defaults::k_dynamic_friction;
112 float restitution = physics::material_defaults::k_restitution;
114 float spin_friction = physics::material_defaults::k_spin_friction;
116 float ignition_energy = 0.0f;
117 float burn_rate = 0.0f;
121 constexpr auto isIndestructible() const noexcept ->
bool {
122 return (flags & k_material_indestructible) != 0;
126 constexpr auto breakableBy(physics::Hardness max_hardness)
const noexcept ->
bool {
127 return not isIndestructible() && physics::canBreak(max_hardness,
hardness);
131 constexpr auto collides() const noexcept ->
bool {
132 return (flags & k_material_passable) == 0;
136 constexpr auto isFlammable() const noexcept ->
bool {
137 return (flags & k_material_flammable) != 0;
141static_assert(
sizeof(
PhysicalMaterial) <= 64,
"a physical material must fit in one cache line");
144 std::vector<PhysicalMaterial> materials;
151 const uint8_t material = palette.entries[palette_index].material;
152 return material < library.materials.size() ? material : k_default_material;
156inline auto densityTable(
const Palette& palette,
const MaterialLibrary& library) -> std::array<uint32_t, k_palette_size> {
157 std::array<uint32_t, k_palette_size> out {};
158 for (uint32_t i = 0; i < k_palette_size; ++i) {
159 out[i] = library.materials[
resolveMaterialIndex(palette, library,
static_cast<uint8_t
>(i))].density;
165inline auto massPerVoxel(
const PhysicalMaterial& material,
float voxel_size = k_voxel_size)
noexcept ->
float {
166 return static_cast<float>(material.density) * voxel_size * voxel_size * voxel_size;
185 constexpr auto operator==(
const TableProblem&)
const noexcept ->
bool =
default;
189inline auto validateLibrary(
const MaterialLibrary& library) -> std::vector<TableProblem> {
190 std::vector<TableProblem> out;
191 if (library.materials.empty()) {
192 out.push_back({TableIssue::library_empty, 0});
195 if (library.materials.size() > k_max_physical_materials) {
200 const auto negative = [](
float value) {
return !(value >= 0.0f); };
202 for (uint32_t i = 0; i < library.materials.size(); ++i) {
204 if (m.density == 0) {
205 out.push_back({TableIssue::zero_density, i});
207 if (negative(m.toughness) || negative(m.structural_strength) || negative(m.static_friction) || negative(m.dynamic_friction) ||
208 negative(m.rolling_friction) || negative(m.spin_friction) || negative(m.restitution) || m.restitution > 1.0f ||
209 negative(m.ignition_energy) || negative(m.burn_rate) || negative(m.fuel)) {
210 out.push_back({TableIssue::out_of_range, i});
217inline auto validatePalette(
const Palette& palette,
const MaterialLibrary& library) -> std::vector<TableProblem> {
218 std::vector<TableProblem> out;
219 if (!(palette.entries[k_empty_palette_index] ==
PaletteEntry {})) {
220 out.push_back({TableIssue::reserved_slot_used, k_empty_palette_index});
222 if (library.materials.empty()) {
223 out.push_back({TableIssue::library_empty, 0});
226 for (uint32_t i = 1; i < k_palette_size; ++i) {
227 if (palette.entries[i].material >= library.materials.size()) {
228 out.push_back({TableIssue::unknown_material, i});
How a material breaks: how the energy of a hit is spent and how coarse its cracks are.
Tiers of how hard a material is to break.
The values a material has when nothing sets them.
constexpr float k_structural_strength
weak bricks
Definition material_defaults.hpp:32
constexpr float k_density
between wood at 600 and stone at 2600
Definition material_defaults.hpp:26
constexpr float k_rolling_friction
A ball rolling on a hard floor loses a few percent of its speed per metre.
Definition material_defaults.hpp:22
auto resolveMaterialIndex(const Palette &palette, const MaterialLibrary &library, uint8_t palette_index) noexcept -> uint32_t
The library must not be empty.
Definition palette.hpp:149
constexpr uint8_t k_material_passable
"Passable" so the zero default is solid
Definition palette.hpp:90
TableIssue
Definition palette.hpp:169
@ library_too_large
index is the count
Definition palette.hpp:172
Definition fracture_profile.hpp:49
Definition palette.hpp:143
16 bytes and the offsets are a shader contract
Definition palette.hpp:26
uint8_t reflectivity
Separate from metallic since a wet non metal reflects and a dirty metal barely does.
Definition palette.hpp:36
uint8_t emissive
Scaled by Palette::max_emissive.
Definition palette.hpp:39
uint8_t transforms_to
0 burns away and only read for flammable materials
Definition palette.hpp:46
uint8_t roughness
0-255 for 0-1
Definition palette.hpp:32
Entry 0 is the empty voxel and must stay all zero.
Definition palette.hpp:59
Definition palette.hpp:94
physics::Hardness hardness
Damage that breaks only softer tiers never breaks this material.
Definition palette.hpp:101
uint16_t density
kg/m³ never zero and integer so MassMoments stays exact
Definition palette.hpp:96
float toughness
kJ/m³ it takes to break per m3
Definition palette.hpp:106
index is a material index a palette index or a count
Definition palette.hpp:180