Compare commits
No commits in common. 'cc33b5d481b3438d9000c2aa1f165523410d89a8' and 'b6e68eccecd38403e6fbfde7f228bed8b75771db' have entirely different histories.
cc33b5d481
...
b6e68eccec
28 changed files with 224 additions and 676 deletions
@ -1,127 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Riyyi |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: MIT |
|
||||||
*/ |
|
||||||
|
|
||||||
#include "glm/ext/matrix_float2x2.hpp" |
|
||||||
#include "glm/ext/matrix_float3x3.hpp" |
|
||||||
#include "glm/ext/matrix_float4x4.hpp" |
|
||||||
#include "glm/ext/vector_float2.hpp" |
|
||||||
#include "glm/ext/vector_float3.hpp" |
|
||||||
#include "glm/ext/vector_float4.hpp" |
|
||||||
#include "ruc/json/json.h" |
|
||||||
|
|
||||||
#include "inferno/component/serialize.h" |
|
||||||
|
|
||||||
namespace glm { |
|
||||||
|
|
||||||
void toJson(ruc::Json& json, const vec2& value) |
|
||||||
{ |
|
||||||
json = ruc::Json { |
|
||||||
{ value.x, value.y }, |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
void fromJson(const ruc::Json& json, vec2& value) |
|
||||||
{ |
|
||||||
VERIFY(json.type() == ruc::Json::Type::Array); |
|
||||||
|
|
||||||
auto& values = json.asArray(); |
|
||||||
VERIFY(values.size() == 2, "glm::vec2 expected 2 values, got: {}", values.size()); |
|
||||||
|
|
||||||
value.x = values.at(0).get<float>(); |
|
||||||
value.y = values.at(1).get<float>(); |
|
||||||
} |
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
void toJson(ruc::Json& json, const vec3& value) |
|
||||||
{ |
|
||||||
json = ruc::Json { |
|
||||||
{ value.x, value.y, value.z }, |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
void fromJson(const ruc::Json& json, vec3& value) |
|
||||||
{ |
|
||||||
VERIFY(json.type() == ruc::Json::Type::Array); |
|
||||||
|
|
||||||
auto& values = json.asArray(); |
|
||||||
VERIFY(values.size() == 3, "glm::vec3 expected 3 values, got: {}", values.size()); |
|
||||||
|
|
||||||
value.x = values.at(0).get<float>(); |
|
||||||
value.y = values.at(1).get<float>(); |
|
||||||
value.z = values.at(2).get<float>(); |
|
||||||
} |
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
void toJson(ruc::Json& json, const vec4& value) |
|
||||||
{ |
|
||||||
json = ruc::Json { |
|
||||||
{ value.r, value.g, value.b, value.a }, |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
void fromJson(const ruc::Json& json, vec4& value) |
|
||||||
{ |
|
||||||
VERIFY(json.type() == ruc::Json::Type::Array); |
|
||||||
|
|
||||||
auto& values = json.asArray(); |
|
||||||
VERIFY(values.size() == 4, "glm::vec4 expected 4 values, got: {}", values.size()); |
|
||||||
|
|
||||||
value.r = values.at(0).get<float>(); |
|
||||||
value.g = values.at(1).get<float>(); |
|
||||||
value.b = values.at(2).get<float>(); |
|
||||||
value.a = values.at(3).get<float>(); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace glm
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
void ruc::format::Formatter<glm::vec2>::format(Builder& builder, glm::vec2 value) const |
|
||||||
{ |
|
||||||
return Formatter<std::vector<float>>::format(builder, { value.x, value.y }); |
|
||||||
} |
|
||||||
|
|
||||||
void ruc::format::Formatter<glm::vec3>::format(Builder& builder, glm::vec3 value) const |
|
||||||
{ |
|
||||||
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z }); |
|
||||||
} |
|
||||||
|
|
||||||
void ruc::format::Formatter<glm::vec4>::format(Builder& builder, glm::vec4 value) const |
|
||||||
{ |
|
||||||
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z, value.w }); |
|
||||||
} |
|
||||||
|
|
||||||
void ruc::format::Formatter<glm::mat2>::format(Builder& builder, glm::mat2 value) const |
|
||||||
{ |
|
||||||
builder.putString("mat2 "); |
|
||||||
Formatter<glm::vec2>::format(builder, value[0]); |
|
||||||
builder.putString("\n "); |
|
||||||
return Formatter<glm::vec2>::format(builder, value[1]); |
|
||||||
} |
|
||||||
|
|
||||||
void ruc::format::Formatter<glm::mat3>::format(Builder& builder, glm::mat3 value) const |
|
||||||
{ |
|
||||||
builder.putString("mat3 "); |
|
||||||
Formatter<glm::vec3>::format(builder, value[0]); |
|
||||||
builder.putString("\n "); |
|
||||||
Formatter<glm::vec3>::format(builder, value[1]); |
|
||||||
builder.putString("\n "); |
|
||||||
return Formatter<glm::vec3>::format(builder, value[2]); |
|
||||||
} |
|
||||||
|
|
||||||
void ruc::format::Formatter<glm::mat4>::format(Builder& builder, glm::mat4 value) const |
|
||||||
{ |
|
||||||
builder.putString("mat4 "); |
|
||||||
Formatter<glm::vec4>::format(builder, value[0]); |
|
||||||
builder.putString("\n "); |
|
||||||
Formatter<glm::vec4>::format(builder, value[1]); |
|
||||||
builder.putString("\n "); |
|
||||||
Formatter<glm::vec4>::format(builder, value[2]); |
|
||||||
builder.putString("\n "); |
|
||||||
return Formatter<glm::vec4>::format(builder, value[3]); |
|
||||||
} |
|
@ -1,58 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Riyyi |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: MIT |
|
||||||
*/ |
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include "glm/ext/matrix_float2x2.hpp" |
|
||||||
#include "glm/ext/matrix_float3x3.hpp" |
|
||||||
#include "glm/ext/matrix_float4x4.hpp" |
|
||||||
#include "glm/ext/vector_float2.hpp" |
|
||||||
#include "glm/ext/vector_float3.hpp" |
|
||||||
#include "glm/ext/vector_float4.hpp" |
|
||||||
#include "ruc/json/json.h" |
|
||||||
|
|
||||||
namespace glm { |
|
||||||
|
|
||||||
void toJson(ruc::Json& json, const vec2& value); |
|
||||||
void fromJson(const ruc::Json& json, vec2& value); |
|
||||||
|
|
||||||
void toJson(ruc::Json& json, const vec3& value); |
|
||||||
void fromJson(const ruc::Json& json, vec3& value); |
|
||||||
|
|
||||||
void toJson(ruc::Json& json, const vec4& value); |
|
||||||
void fromJson(const ruc::Json& json, vec4& value); |
|
||||||
|
|
||||||
} // namespace glm
|
|
||||||
|
|
||||||
template<> |
|
||||||
struct ruc::format::Formatter<glm::vec2> : Formatter<std::vector<float>> { |
|
||||||
void format(Builder& builder, glm::vec2 value) const; |
|
||||||
}; |
|
||||||
|
|
||||||
template<> |
|
||||||
struct ruc::format::Formatter<glm::vec3> : Formatter<std::vector<float>> { |
|
||||||
void format(Builder& builder, glm::vec3 value) const; |
|
||||||
}; |
|
||||||
|
|
||||||
template<> |
|
||||||
struct ruc::format::Formatter<glm::vec4> : Formatter<std::vector<float>> { |
|
||||||
void format(Builder& builder, glm::vec4 value) const; |
|
||||||
}; |
|
||||||
|
|
||||||
template<> |
|
||||||
struct ruc::format::Formatter<glm::mat2> : Formatter<glm::vec2> { |
|
||||||
void format(Builder& builder, glm::mat2 value) const; |
|
||||||
}; |
|
||||||
|
|
||||||
template<> |
|
||||||
struct ruc::format::Formatter<glm::mat3> : Formatter<glm::vec3> { |
|
||||||
void format(Builder& builder, glm::mat3 value) const; |
|
||||||
}; |
|
||||||
|
|
||||||
template<> |
|
||||||
struct ruc::format::Formatter<glm::mat4> : Formatter<glm::vec4> { |
|
||||||
void format(Builder& builder, glm::mat4 value) const; |
|
||||||
}; |
|
@ -1,195 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Riyyi |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: MIT |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <cstdint> // int32_t, uint8_t, uintt32_t |
|
||||||
|
|
||||||
#include "glad/glad.h" |
|
||||||
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2 |
|
||||||
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3 |
|
||||||
#include "glm/ext/vector_float4.hpp" // glm::vec4 |
|
||||||
|
|
||||||
#include "inferno/render/buffer.h" |
|
||||||
#include "inferno/render/shader-storage-buffer.h" |
|
||||||
|
|
||||||
namespace Inferno { |
|
||||||
|
|
||||||
ShaderStorageBuffer::ShaderStorageBuffer(s) |
|
||||||
{ |
|
||||||
// Get maximum uniformbuffer bindings the GPU supports
|
|
||||||
int32_t maxBindingPoints = 0; |
|
||||||
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxBindingPoints); |
|
||||||
m_maxBindingPoints = static_cast<uint8_t>(maxBindingPoints); |
|
||||||
} |
|
||||||
|
|
||||||
ShaderStorageBuffer::~ShaderStorageBuffer() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/56512216#answer-56513136
|
|
||||||
void ShaderStorageBuffer::setLayout(std::string_view blockName, uint8_t bindingPoint, uint32_t shaderID) |
|
||||||
{ |
|
||||||
VERIFY(bindingPoint < m_maxBindingPoints, |
|
||||||
"shader storage buffer exceeded binding points: {}/{}", bindingPoint, m_maxBindingPoints); |
|
||||||
|
|
||||||
if (!exists(blockName)) { |
|
||||||
m_blocks[blockName.data()] = {}; |
|
||||||
} |
|
||||||
|
|
||||||
BufferBlock& block = m_blocks[blockName.data()]; |
|
||||||
block.bindingPoint = bindingPoint; |
|
||||||
block.memberOffsets.clear(); |
|
||||||
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id); |
|
||||||
|
|
||||||
// Get the shader block index
|
|
||||||
uint32_t resourceIndex = glGetProgramResourceIndex(shaderID, GL_SHADER_STORAGE_BLOCK, blockName.data()); |
|
||||||
VERIFY(resourceIndex != GL_INVALID_INDEX, "block doesnt exist in shader: {}::{}", blockName, shaderID); |
|
||||||
|
|
||||||
// Get the amount of member variables
|
|
||||||
uint32_t prop = GL_NUM_ACTIVE_VARIABLES; |
|
||||||
int32_t memberCount; |
|
||||||
glGetProgramResourceiv(shaderID, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &prop, 1, nullptr, &memberCount); |
|
||||||
|
|
||||||
// Get the indices of the members
|
|
||||||
prop = GL_ACTIVE_VARIABLES; |
|
||||||
std::vector<int32_t> members(memberCount); |
|
||||||
glGetProgramResourceiv(shaderID, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &prop, (int32_t)members.size(), nullptr, members.data()); |
|
||||||
|
|
||||||
// Reserve memory for the names of the members
|
|
||||||
int32_t memberNameSize; |
|
||||||
glGetProgramInterfaceiv(shaderID, GL_BUFFER_VARIABLE, GL_MAX_NAME_LENGTH, &memberNameSize); |
|
||||||
std::vector<char> memberNameBuffer(memberNameSize); |
|
||||||
|
|
||||||
int32_t lastOffset = 0; |
|
||||||
int32_t lastType = 0; |
|
||||||
for (int32_t i = 0; i < memberCount; i++) { |
|
||||||
|
|
||||||
// Get name of buffer variable
|
|
||||||
int32_t stringLength; |
|
||||||
glGetProgramResourceName(shaderID, GL_BUFFER_VARIABLE, members[i], memberNameSize, &stringLength, memberNameBuffer.data()); |
|
||||||
std::string memberName = std::string(memberNameBuffer.begin(), memberNameBuffer.begin() + stringLength); |
|
||||||
|
|
||||||
// Get the other data needed for computing
|
|
||||||
|
|
||||||
uint32_t props[7] = { |
|
||||||
GL_OFFSET, // 0
|
|
||||||
GL_TYPE, // 1
|
|
||||||
GL_ARRAY_SIZE, // 2
|
|
||||||
GL_ARRAY_STRIDE, // 3
|
|
||||||
GL_MATRIX_STRIDE, // 4
|
|
||||||
GL_TOP_LEVEL_ARRAY_SIZE, // 5
|
|
||||||
GL_TOP_LEVEL_ARRAY_STRIDE, // 6
|
|
||||||
}; |
|
||||||
int32_t params[7]; |
|
||||||
glGetProgramResourceiv(shaderID, GL_BUFFER_VARIABLE, members[i], 7, props, 7, nullptr, params); |
|
||||||
|
|
||||||
// ruc::error("{}", memberName);
|
|
||||||
// ruc::error("\n Offset: {}, type: {:#x}, arraySize: {}, arrayStride: {},\n matrixStride: {}, top level size: {}, top level stride: {}\n",
|
|
||||||
// params[0], params[1], params[2], params[3], params[4], params[5], params[6]);
|
|
||||||
|
|
||||||
// Array of structs
|
|
||||||
if (params[5] != 1 && params[6 != 0]) { |
|
||||||
size_t bracketOpen = memberName.find_first_of('['); |
|
||||||
size_t bracketClose = memberName.find_first_of(']'); |
|
||||||
std::string memberNameBegin = memberName.substr(0, bracketOpen); // name: myArray[0].member -> myArray
|
|
||||||
std::string memberNameMember = memberName.substr(bracketClose + 1); // name: myArray[0].member -> .member
|
|
||||||
for (int32_t j = 0; j < params[5]; ++j) { |
|
||||||
lastOffset = params[0] + (j * params[6]); // calc offset
|
|
||||||
lastType = params[1]; |
|
||||||
|
|
||||||
// Only add the member variant the first time its encountered
|
|
||||||
if (j == 0 && block.memberOffsets.find(memberNameBegin) == block.memberOffsets.end()) { |
|
||||||
block.memberOffsets.emplace(memberNameBegin, lastOffset); // name: myArray
|
|
||||||
} |
|
||||||
|
|
||||||
// Only add the index variant the first time its encountered
|
|
||||||
std::string memberNameIndex = memberNameBegin + "[" + std::to_string(j) + "]"; // name: myArray -> myArray[i]
|
|
||||||
if (block.memberOffsets.find(memberNameIndex) == block.memberOffsets.end()) { |
|
||||||
block.memberOffsets.emplace(memberNameIndex, lastOffset); |
|
||||||
} |
|
||||||
|
|
||||||
block.memberOffsets.emplace(memberNameIndex + memberNameMember, // name: myArray -> myArray[i].member
|
|
||||||
lastOffset); |
|
||||||
} |
|
||||||
} |
|
||||||
// Array of primitives
|
|
||||||
else if (params[2] != 1 && params[3] != 0) { |
|
||||||
std::string memberNameBegin = memberName.substr(0, memberName.find_first_of('[')); // name: myArray[0] -> myArray
|
|
||||||
for (int32_t j = 0; j < params[2]; ++j) { |
|
||||||
lastOffset = params[0] + (j * params[3]); // calc offset
|
|
||||||
lastType = params[1]; |
|
||||||
|
|
||||||
// Only add the member variant the first time its encountered
|
|
||||||
if (j == 0) { |
|
||||||
block.memberOffsets.emplace(memberNameBegin, lastOffset); // name: myArray
|
|
||||||
} |
|
||||||
|
|
||||||
block.memberOffsets.emplace(memberNameBegin + "[" + std::to_string(j) + "]", // name: myArray -> myArray[i]
|
|
||||||
lastOffset); |
|
||||||
} |
|
||||||
} |
|
||||||
// Matrix case
|
|
||||||
else if (params[4] != 0) { |
|
||||||
lastType = params[1]; |
|
||||||
lastOffset = params[0]; |
|
||||||
block.memberOffsets.emplace(memberName, params[0]); |
|
||||||
} |
|
||||||
else { |
|
||||||
lastType = params[1]; |
|
||||||
lastOffset = params[0]; |
|
||||||
block.memberOffsets.emplace(memberName, params[0]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
block.size = lastOffset + BufferElement::getGLTypeSize(lastType); |
|
||||||
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
|
||||||
|
|
||||||
// Results
|
|
||||||
// for (auto [k, v] : block.memberOffsets) {
|
|
||||||
// ruc::error("{}:{}", k, v);
|
|
||||||
// }
|
|
||||||
} |
|
||||||
|
|
||||||
void ShaderStorageBuffer::create(std::string_view blockName) |
|
||||||
{ |
|
||||||
VERIFY(exists(blockName), "shader storage buffer block doesnt exist"); |
|
||||||
|
|
||||||
BufferBlock& block = m_blocks[blockName.data()]; |
|
||||||
|
|
||||||
if (block.id != 0) { |
|
||||||
glDeleteBuffers(1, &block.id); |
|
||||||
} |
|
||||||
|
|
||||||
// Allocate buffer
|
|
||||||
block.id = UINT_MAX; |
|
||||||
glGenBuffers(1, &block.id); |
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id); |
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, block.size, NULL, GL_DYNAMIC_DRAW); |
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
|
||||||
|
|
||||||
// Bind buffer to binding point
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, block.bindingPoint, block.id); |
|
||||||
} |
|
||||||
|
|
||||||
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, bool value) |
|
||||||
{ |
|
||||||
setValue(blockName, member, static_cast<uint32_t>(value), sizeof(uint32_t)); |
|
||||||
} |
|
||||||
|
|
||||||
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, glm::mat2 value) |
|
||||||
{ |
|
||||||
setValue(blockName, member, static_cast<glm::mat4>(value), sizeof(glm::vec4) * 2); |
|
||||||
} |
|
||||||
|
|
||||||
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, glm::mat3 value) |
|
||||||
{ |
|
||||||
setValue(blockName, member, static_cast<glm::mat4>(value), sizeof(glm::vec4) * 3); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace Inferno
|
|
@ -1,63 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Riyyi |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: MIT |
|
||||||
*/ |
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <cstddef> // size_t |
|
||||||
#include <cstdint> // uint8_t, uint32_t |
|
||||||
#include <string_view> |
|
||||||
#include <unordered_map> |
|
||||||
|
|
||||||
#include "glad/glad.h" |
|
||||||
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2 |
|
||||||
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3 |
|
||||||
#include "ruc/singleton.h" |
|
||||||
|
|
||||||
#define CHECK_SET_CALL(blockName, member) \ |
|
||||||
VERIFY(exists(blockName), "shader storage buffer block doesnt exist: {}", blockName); \
|
|
||||||
const BufferBlock& block = m_blocks[blockName.data()]; \
|
|
||||||
VERIFY(block.memberOffsets.find(member.data()) != block.memberOffsets.end(), \
|
|
||||||
"shader storage buffer member doesnt exist: {}", member); |
|
||||||
|
|
||||||
namespace Inferno { |
|
||||||
|
|
||||||
struct BufferBlock { |
|
||||||
uint32_t id { 0 }; |
|
||||||
uint32_t size { 0 }; |
|
||||||
uint8_t bindingPoint { 0 }; |
|
||||||
std::unordered_map<std::string, uint32_t> memberOffsets {}; |
|
||||||
}; |
|
||||||
|
|
||||||
class ShaderStorageBuffer final : public ruc::Singleton<ShaderStorageBuffer> { // Shader Storage Buffer Object, SSBO
|
|
||||||
public: |
|
||||||
ShaderStorageBuffer(s); |
|
||||||
virtual ~ShaderStorageBuffer(); |
|
||||||
|
|
||||||
void setLayout(std::string_view blockName, uint8_t bindingPoint, uint32_t shaderID); |
|
||||||
void create(std::string_view blockName); |
|
||||||
|
|
||||||
bool exists(std::string_view blockName) const { return m_blocks.find(blockName.data()) != m_blocks.end(); } |
|
||||||
|
|
||||||
template<typename T> // Capture value by reference, instead of decaying to pointer
|
|
||||||
void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0) |
|
||||||
{ |
|
||||||
CHECK_SET_CALL(blockName, member); |
|
||||||
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id); |
|
||||||
glBufferSubData(GL_SHADER_STORAGE_BUFFER, block.memberOffsets.at(member.data()), (size) ? size : sizeof(T), &value); |
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
|
||||||
} |
|
||||||
// Exceptions:
|
|
||||||
void setValue(std::string_view blockName, std::string_view member, bool value); |
|
||||||
void setValue(std::string_view blockName, std::string_view member, glm::mat2 value); |
|
||||||
void setValue(std::string_view blockName, std::string_view member, glm::mat3 value); |
|
||||||
|
|
||||||
private: |
|
||||||
uint8_t m_maxBindingPoints { 0 }; |
|
||||||
std::unordered_map<std::string, BufferBlock> m_blocks; |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace Inferno
|
|
@ -1,24 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Riyyi |
|
||||||
* |
|
||||||
* SPDX-License-Identifier: MIT |
|
||||||
*/ |
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include "glm/ext/vector_float3.hpp" // glm::vec3 |
|
||||||
|
|
||||||
namespace Inferno { |
|
||||||
|
|
||||||
// Shader storage block layouts, using std430 memory layout rules
|
|
||||||
|
|
||||||
#define MAX_DIRECTIONAL_LIGHTS 4 |
|
||||||
struct alignas(16) DirectionalLightBlock { |
|
||||||
alignas(16) glm::vec3 direction { 0 }; |
|
||||||
|
|
||||||
alignas(16) glm::vec3 ambient { 0 }; |
|
||||||
alignas(16) glm::vec3 diffuse { 0 }; |
|
||||||
alignas(16) glm::vec3 specular { 0 }; |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace Inferno
|
|
Loading…
Reference in new issue