Rendering Engine 0.2.17
Modular Graphics Rendering Engine | v0.2.17
Loading...
Searching...
No Matches
material_types_tests.cpp
Go to the documentation of this file.
1// This file is part of the Rendering Engine project.
2// Author: Alexander Obzherin <alexanderobzherin@gmail.com>
3// Copyright (c) 2026 Alexander Obzherin
4// Distributed under the terms of the zlib License. See LICENSE.md for details.
5
6#include "material_types.hpp"
8#include <algorithm>
9#include <cstring>
10
11using namespace rendering_engine;
13
14namespace
15{
17
18PackedMaterialData MakeMaterial()
19{
20 // Gaps and sentinel bytes make writes outside a parameter observable.
21 return {std::vector<std::uint8_t>(96, 0xA5), {
22 {"Scalar", 4, sizeof(float), Type::Float},
23 {"Pair", 16, sizeof(glm::vec2), Type::Vec2},
24 {"Triple", 32, sizeof(glm::vec3), Type::Vec3},
25 {"Color", 64, sizeof(glm::vec4), Type::Vec4}
26 }};
27}
28
29template<typename T>
30T ReadValue(const PackedMaterialData& material, std::size_t offset)
31{
32 T value{};
33 std::memcpy(&value, material.buffer.data() + offset, sizeof(T));
34 return value;
35}
36
37void ExpectUnchangedOutside(const PackedMaterialData& material,
38 const std::vector<std::uint8_t>& before,
39 std::size_t offset, std::size_t size)
40{
41 ASSERT_EQ(material.buffer.size(), before.size());
42 for (std::size_t i = 0; i < before.size(); ++i)
43 {
44 if (i < offset || i >= offset + size)
45 {
46 EXPECT_EQ(material.buffer[i], before[i]) << "byte " << i;
47 }
48 }
49}
50
51void ExpectLayout(const std::vector<MaterialParameterLayoutEntry>& actual,
52 const std::vector<MaterialParameterLayoutEntry>& expected)
53{
54 ASSERT_EQ(actual.size(), expected.size());
55 for (const auto& entry : expected)
56 {
57 SCOPED_TRACE(entry.name);
58 // Names and metadata form the contract; vector ordering need not.
59 const auto found = std::find_if(actual.begin(), actual.end(),
60 [&](const MaterialParameterLayoutEntry& candidate) { return candidate.name == entry.name; });
61 ASSERT_NE(found, actual.end());
62 EXPECT_EQ(found->type, entry.type);
63 EXPECT_EQ(found->offset, entry.offset);
64 EXPECT_EQ(found->size, entry.size);
65 }
66}
67}
68
69TEST(PackedMaterialData, FloatWritesOnlyItsLayoutSlot)
70{
71 auto material = MakeMaterial();
72 const auto before = material.buffer;
73 material.SetMaterialFloat("Scalar", 1.25f);
74 EXPECT_FLOAT_EQ(ReadValue<float>(material, 4), 1.25f);
75 ExpectUnchangedOutside(material, before, 4, sizeof(float));
76}
77
78TEST(PackedMaterialData, Vec2WritesOnlyItsLayoutSlot)
79{
80 auto material = MakeMaterial();
81 const auto before = material.buffer;
82 material.SetMaterialVec2("Pair", glm::vec2(1.25f, -2.5f));
83 ExpectNear(ReadValue<glm::vec2>(material, 16), glm::vec2(1.25f, -2.5f));
84 ExpectUnchangedOutside(material, before, 16, sizeof(glm::vec2));
85}
86
87TEST(PackedMaterialData, Vec3WritesOnlyItsLayoutSlot)
88{
89 auto material = MakeMaterial();
90 const auto before = material.buffer;
91 material.SetMaterialVec3("Triple", glm::vec3(1.25f, -2.5f, 3.75f));
92 ExpectNear(ReadValue<glm::vec3>(material, 32), glm::vec3(1.25f, -2.5f, 3.75f));
93 ExpectUnchangedOutside(material, before, 32, sizeof(glm::vec3));
94}
95
96TEST(PackedMaterialData, Vec4WritesOnlyItsLayoutSlot)
97{
98 auto material = MakeMaterial();
99 const auto before = material.buffer;
100 material.SetMaterialVec4("Color", glm::vec4(1.25f, -2.5f, 3.75f, 0.5f));
101 ExpectNear(ReadValue<glm::vec4>(material, 64), glm::vec4(1.25f, -2.5f, 3.75f, 0.5f));
102 ExpectUnchangedOutside(material, before, 64, sizeof(glm::vec4));
103}
104
105TEST(PackedMaterialData, UnknownNamesAndWrongTypesLeaveBufferUnchanged)
106{
107 auto material = MakeMaterial();
108 const auto before = material.buffer;
109 material.SetMaterialFloat("Missing", 1);
110 EXPECT_EQ(material.buffer, before);
111 material.SetMaterialVec2("Missing", glm::vec2(2));
112 EXPECT_EQ(material.buffer, before);
113 material.SetMaterialVec3("Missing", glm::vec3(3));
114 EXPECT_EQ(material.buffer, before);
115 material.SetMaterialVec4("Missing", glm::vec4(4));
116 EXPECT_EQ(material.buffer, before);
117 material.SetMaterialFloat("Color", 1);
118 EXPECT_EQ(material.buffer, before);
119 material.SetMaterialVec2("Triple", glm::vec2(2));
120 EXPECT_EQ(material.buffer, before);
121 material.SetMaterialVec3("Pair", glm::vec3(3));
122 EXPECT_EQ(material.buffer, before);
123 material.SetMaterialVec4("Scalar", glm::vec4(4));
124 EXPECT_EQ(material.buffer, before);
125}
126
127TEST(MaterialLayouts, Font2DProtectsShaderPackingContract)
128{
129 ExpectLayout(Font2DLayout, {
130 {"FontColor", 0, 16, Type::Vec4},
131 {"OutlineColor", 16, 16, Type::Vec4},
132 {"OutlineThicknessPx", 32, 4, Type::Float},
133 {"InvAtlasSizeWidth", 36, 4, Type::Float},
134 {"InvAtlasSizeHeight", 40, 4, Type::Float}
135 });
136}
137
138TEST(MaterialLayouts, Rectangle2DProtectsShaderPackingContract)
139{
140 ExpectLayout(Rectangle2DLayout, {{"Color", 0, 16, Type::Vec4}});
141}
TEST(PackedMaterialData, FloatWritesOnlyItsLayoutSlot)
void ExpectNear(const glm::vec< N, T, Q > &actual, const glm::vec< N, T, Q > &expected, float tolerance=1e-5f)
static const std::vector< MaterialParameterLayoutEntry > Font2DLayout
static const std::vector< MaterialParameterLayoutEntry > Rectangle2DLayout
Describes the layout of a single packed parameter inside a uniform buffer.
Contains the raw buffer data and layout metadata of packed material parameters.
void SetMaterialVec2(const std::string &name, const glm::vec2 &value)
void SetMaterialFloat(const std::string &name, float value)
void SetMaterialVec3(const std::string &name, const glm::vec3 &value)
void SetMaterialVec4(const std::string &name, const glm::vec4 &value)