Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
Material.cpp
1/*
2Copyright (C) 2016-2021,2025 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16#include "aeongames/Material.hpp"
17#include "aeongames/ProtoBufUtils.hpp"
19#include "aeongames/ProtoBufHelpers.hpp"
21#ifdef _MSC_VER
22#pragma warning( push )
23#pragma warning( disable : PROTOBUF_WARNINGS )
24#endif
25#include "material.pb.h"
26#ifdef _MSC_VER
27#pragma warning( pop )
28#endif
29
30namespace AeonGames
31{
33 = default;
35 = default;
36
37 Material::Material ( const Material& aMaterial ) : mVariables{aMaterial.mVariables}, mSamplers{aMaterial.mSamplers} {}
39 {
40 mVariables = aMaterial.mVariables;
41 mSamplers = aMaterial.mSamplers;
42 return *this;
43 }
44
45 const std::vector<uint8_t>& Material::GetUniformBuffer() const
46 {
47 return mUniformBuffer;
48 }
49
50 size_t Material::LoadVariables ( const MaterialMsg& aMaterialMsg )
51 {
52 size_t size = 0;
53 mVariables.reserve ( aMaterialMsg.property().size() );
54 for ( auto& i : aMaterialMsg.property() )
55 {
56 switch ( i.value_case() )
57 {
58 case PropertyMsg::ValueCase::kScalarFloat:
59 size += ( size % sizeof ( float ) ) ? sizeof ( float ) - ( size % sizeof ( float ) ) : 0; // Align to float
60 mVariables.emplace_back ( i.name(), size );
61 size += sizeof ( float );
62 break;
63 case PropertyMsg::ValueCase::kScalarUint:
64 size += ( size % sizeof ( uint32_t ) ) ? sizeof ( uint32_t ) - ( size % sizeof ( uint32_t ) ) : 0; // Align to uint
65 mVariables.emplace_back ( i.name(), size );
66 size += sizeof ( uint32_t );
67 break;
68 case PropertyMsg::ValueCase::kScalarInt:
69 size += ( size % sizeof ( int32_t ) ) ? sizeof ( int32_t ) - ( size % sizeof ( int32_t ) ) : 0; // Align to int
70 mVariables.emplace_back ( i.name(), size );
71 size += sizeof ( int32_t );
72 break;
73 case PropertyMsg::ValueCase::kVector2:
74 size += ( size % ( sizeof ( float ) * 2 ) ) ? ( sizeof ( float ) * 2 ) - ( size % ( sizeof ( float ) * 2 ) ) : 0; // Align to 2 floats
75 mVariables.emplace_back ( i.name(), size );
76 size += sizeof ( float ) * 2;
77 break;
78 case PropertyMsg::ValueCase::kVector3:
79 size += ( size % ( sizeof ( float ) * 4 ) ) ? ( sizeof ( float ) * 4 ) - ( size % ( sizeof ( float ) * 4 ) ) : 0; // Align to 4 floats
80 mVariables.emplace_back ( i.name(), size );
81 size += sizeof ( float ) * 3;
82 break;
83 case PropertyMsg::ValueCase::kVector4:
84 size += ( size % ( sizeof ( float ) * 4 ) ) ? ( sizeof ( float ) * 4 ) - ( size % ( sizeof ( float ) * 4 ) ) : 0; // Align to 4 floats
85 mVariables.emplace_back ( i.name(), size );
86 size += sizeof ( float ) * 4;
87 break;
88 case PropertyMsg::ValueCase::kMatrix4X4:
89 size += ( size % ( sizeof ( float ) * 4 ) ) ? ( sizeof ( float ) * 4 ) - ( size % ( sizeof ( float ) * 4 ) ) : 0; // Align to 4 floats
90 mVariables.emplace_back ( i.name(), size );
91 size += sizeof ( float ) * 16;
92 break;
93 default:
94 break;
95 }
96 }
97 size += ( size % ( sizeof ( float ) * 4 ) ) ? ( sizeof ( float ) * 4 ) - ( size % ( sizeof ( float ) * 4 ) ) : 0; // align the final value to 4 floats
98 return size;
99 }
100
101 void Material::LoadSamplers ( const MaterialMsg& aMaterialMsg )
102 {
103 mSamplers.reserve ( aMaterialMsg.sampler().size() );
104 for ( auto& i : aMaterialMsg.sampler() )
105 {
106 std::get<1> ( mSamplers.emplace_back ( crc32i ( i.name().c_str(), i.name().size() ), ResourceId{"Texture"_crc32, GetReferenceMsgId ( i.image() ) } ) ).Store();
107 }
108 }
109
110 static size_t GetUniformValueOffset ( const Material::UniformValue& aValue, size_t& aLastOffset )
111 {
112 return std::visit ( [&aLastOffset] ( auto&& arg )
113 {
114 size_t value_size = sizeof ( std::decay_t<decltype ( arg ) > );
115 size_t size = aLastOffset;
116 aLastOffset += value_size;
117 if ( value_size <= 4 )
118 {
119 size += ( size % 4 ) ? 4 - ( size % 4 ) : 0;
120 }
121 else if ( value_size <= 8 )
122 {
123 size += ( size % 8 ) ? 8 - ( size % 8 ) : 0;
124 }
125 else
126 {
127 size += ( size % 16 ) ? 16 - ( size % 16 ) : 0;
128 }
129 return size;
130 }, aValue );
131 }
132
133 size_t Material::LoadVariables ( std::initializer_list<UniformKeyValue> aUniforms )
134 {
135 size_t size = 0;
136 mVariables.reserve ( aUniforms.size() );
137 for ( auto& i : aUniforms )
138 {
139 mVariables.emplace_back ( std::get<0> ( i ), GetUniformValueOffset ( std::get<1> ( i ), size ) );
140 }
141 size += ( size % ( 16 ) ) ? ( 16 ) - ( size % ( 16 ) ) : 0; // align the final value to 4 floats
142 return size;
143 }
144
145 void Material::LoadSamplers ( std::initializer_list<SamplerKeyValue> aSamplers )
146 {
147 mSamplers.reserve ( aSamplers.size() );
148 for ( auto& i : aSamplers )
149 {
150 std::get<1> ( mSamplers.emplace_back ( std::get<0> ( i ), std::get<1> ( i ) ) ).Store();
151 }
152 }
153
155 {
156 return std::visit ( [] ( auto&& arg )
157 {
158 return sizeof ( std::decay_t<decltype ( arg ) > );
159 }, aValue );
160 }
161
162 const void* GetUniformValuePointer ( const Material::UniformValue& aValue )
163 {
164 if ( std::holds_alternative<Vector2> ( aValue ) )
165 {
166 return std::get<Vector2> ( aValue ).GetVector();
167 }
168 else if ( std::holds_alternative<Vector3> ( aValue ) )
169 {
170 return std::get<Vector3> ( aValue ).GetVector3();
171 }
172 if ( std::holds_alternative<Vector4> ( aValue ) )
173 {
174 return std::get<Vector4> ( aValue ).GetVector4();
175 }
176 if ( std::holds_alternative<Matrix4x4> ( aValue ) )
177 {
178 return std::get<Matrix4x4> ( aValue ).GetMatrix4x4();
179 }
180 return std::visit ( [] ( const auto & value )
181 {
182 return reinterpret_cast<const void*> ( &value );
183 }, aValue );
184 }
185
186 void Material::LoadFromMemory ( const void* aBuffer, size_t aBufferSize )
187 {
188 LoadFromProtoBufObject<Material, MaterialMsg, "AEONMTL"_mgk> ( *this, aBuffer, aBufferSize );
189 }
190
191 void Material::LoadFromPBMsg ( const MaterialMsg& aMaterialMsg )
192 {
193 size_t size = LoadVariables ( aMaterialMsg );
194 if ( size )
195 {
196 mUniformBuffer.resize ( size );
197 for ( auto& i : aMaterialMsg.property() )
198 {
199 Set ( PropertyToKeyValue ( i ) );
200 }
201 }
202 LoadSamplers ( aMaterialMsg );
203 }
204
205 void Material::Set ( size_t aIndex, const UniformValue& aValue )
206 {
207 memcpy ( mUniformBuffer.data() + mVariables.at ( aIndex ).GetOffset(), GetUniformValuePointer ( aValue ), GetUniformValueSize ( aValue ) );
208 }
209
210 void Material::Set ( const UniformKeyValue& aValue )
211 {
212 auto i = std::find_if ( mVariables.begin(), mVariables.end(),
213 [&aValue] ( const UniformVariable & variable )
214 {
215 return variable.GetName() == std::get<std::string> ( aValue );
216 } );
217 if ( i != mVariables.end() )
218 {
219 size_t value_size = GetUniformValueSize ( std::get<UniformValue> ( aValue ) );
220 // Do some bounds checking
221 auto j = i + 1;
222 if ( ( ( j != mVariables.end() ) ? ( j->GetOffset() - i->GetOffset() ) : ( mUniformBuffer.size() - i->GetOffset() ) ) < value_size )
223 {
224 std::cout << LogLevel::Error << "Value type size exceeds original type size." << std::endl;
225 throw std::runtime_error ( "Value type size exceeds original type size." );
226 }
227 memcpy ( mUniformBuffer.data() + i->GetOffset(), GetUniformValuePointer ( std::get<UniformValue> ( aValue ) ), value_size );
228 }
229 }
230
231 void Material::SetSampler ( const std::string& aName, const ResourceId& aValue )
232 {
233 uint32_t name_hash = crc32i ( aName.c_str(), aName.size() );
234 auto i = std::find_if ( mSamplers.begin(), mSamplers.end(),
235 [name_hash] ( const SamplerKeyValue & aTuple )
236 {
237 return std::get<0> ( aTuple ) == name_hash;
238 } );
239 if ( i != mSamplers.end() )
240 {
241 std::get<1> ( *i ) = aValue;
242 }
243 }
244
245 const std::vector<std::tuple<uint32_t, ResourceId >> & Material::GetSamplers() const
246 {
247 return mSamplers;
248 }
249
250 ResourceId Material::GetSampler ( const std::string& aName )
251 {
252 uint32_t name_hash = crc32i ( aName.c_str(), aName.size() );
253 auto i = std::find_if ( mSamplers.begin(), mSamplers.end(),
254 [name_hash] ( const SamplerKeyValue & aTuple )
255 {
256 return std::get<0> ( aTuple ) == name_hash;
257 } );
258 if ( i != mSamplers.end() )
259 {
260 return std::get<1> ( *i );
261 }
262 return ResourceId{"Texture"_crc32, 0};
263 }
264
266 {
267 mVariables.clear();
268 mSamplers.clear();
269 mUniformBuffer.clear();
270 }
271}
Defines log severity levels and stream output for the AeonGames engine.
Provides the DLL_PROTOBUF export/import macro for protobuf wrapper classes.
DLL void SetSampler(const std::string &aName, const ResourceId &aValue)
Set a sampler binding by name.
Definition Material.cpp:231
DLL void Unload() final
Unload material data and release resources.
Definition Material.cpp:265
std::variant< uint32_t, int32_t, float, Vector2, Vector3, Vector4, Matrix4x4 > UniformValue
Variant type holding any supported uniform value.
Definition Material.hpp:41
DLL void Set(size_t aIndex, const UniformValue &aValue)
Set a uniform value by index.
Definition Material.cpp:205
DLL const std::vector< uint8_t > & GetUniformBuffer() const
Get the raw uniform buffer.
Definition Material.cpp:45
std::tuple< std::string, UniformValue > UniformKeyValue
Key-value pair mapping a uniform name to its value.
Definition Material.hpp:43
DLL void LoadFromMemory(const void *aBuffer, size_t aBufferSize) final
Load material data from a raw memory buffer.
Definition Material.cpp:186
DLL Material()
Default constructor.
DLL ResourceId GetSampler(const std::string &aName)
Get the resource id of a sampler by name.
Definition Material.cpp:250
DLL void LoadFromPBMsg(const MaterialMsg &aMaterialMsg)
Load material data from a protobuf message.
Definition Material.cpp:191
DLL ~Material() final
Destructor.
DLL const std::vector< std::tuple< uint32_t, ResourceId > > & GetSamplers() const
Get all sampler bindings.
Definition Material.cpp:245
std::tuple< uint32_t, ResourceId > SamplerKeyValue
Key-value pair mapping a sampler binding index to an image resource id.
Definition Material.hpp:45
DLL Material & operator=(const Material &aMaterial)
Assignment operator due to rule of zero/three/five.
Definition Material.cpp:38
Identifies a resource by its type and path CRC32 hashes.
<- This is here just for the literals
Definition AABB.hpp:31
uint32_t crc32i(const char *message, size_t size, uint32_t previous_crc)
Compute the CRC32 of a given message, continuing from a previous CRC value.
Definition CRC.cpp:27
DLL const void * GetUniformValuePointer(const Material::UniformValue &aValue)
Get a pointer to the raw data of a uniform value.
Definition Material.cpp:162
DLL Material::UniformKeyValue PropertyToKeyValue(const PropertyMsg &aProperty)
Convert a PropertyMsg to a Material uniform key-value pair.
DLL size_t GetUniformValueSize(const Material::UniformValue &aValue)
Get the byte size of a uniform value.
Definition Material.cpp:154
void LoadFromProtoBufObject(T &aTarget, const void *aBuffer, size_t aBufferSize)
Loads a Protocol Buffer message from a buffer and populates a target object.
@ Error
Error conditions.
Definition LogLevel.hpp:33