glslstruct is a C++ library designed to easily represent GLSL's Uniform Buffer Objects (UBOs) and Shader Storage Buffer Objects (SSBOs) in C++.
It allows you to define structures once and retrieve their precise size and field offsets according to GLSL packing rules, such as std140 or std430, eliminating the need for manual padding and tedious calculations.
- GLSL Standard Compliance: Built-in support for the most common GLSL packing rules (
std140,std430). - User-Friendly Interface: Easy-to-use interface for defining and using structures.
- C++17 compliant compiler (GCC 10+, Clang 10+, MSVC 19.29+).
- CMake (3.30+) (optional, for building examples and testing).
-
Clone the repository:
git clone [https://github.com/MAIPA01/glslstruct.git](https://github.com/MAIPA01/glslstruct.git)
-
In your project's
CMakeLists.txt, add the library and link it:add_subdirectory(glslstruct) target_link_libraries(YourApplicationName PRIVATE glslstruct)
The following code demonstrates defining a structure and querying its metadata according to the std140 layout, which is essential for binding UBOs correctly.
#include <glslstruct/glslstruct.hpp>
#include <iostream>
#include <vector>
#include <glm/glm.hpp> // Is used for vectors and matrixes
using namespace glslstruct;
// 1. Define your C++ structure
std140_struct SceneSettings {
glsl_value<glm::mat4>("viewProjection"),
glsl_value<glm::vec3>("cameraPosition"),
glsl_value<float>("globalTime"),
glsl_value<int>("renderMode")
};
int main() {
// Total aligned size of the structure
std::cout << "Total UBO size (std140): " << SceneSettings.size()
<< " bytes." << std::endl; // Should be a multiple of 16 bytes
// Offset for a specific field using a literal string
std::cout << "Offset for 'cameraPosition': " << SceneSettings.get_offset("cameraPosition")
<< " bytes." << std::endl;
// Get data for uploading to UBO
std::vector<std::byte> data_to_upload = SceneSettings.data();
// Set variable
SceneSettings.set("cameraPosition", glm::vec3{ 1.f, 0.f, 5.f });
// Get variable
glm::vec3 cameraPosition = SceneSettings.get("cameraPosition");
// Get type
base_type_handle value_type = SceneSettings.get_type("cameraPosition");
vec_type_handle vec_value_type = static_type_cast<vec_type>(value_type);
std::cout << "Vector type: " << to_string(vec_value_type->get_type())
<< " length: " << vec_value_type->get_length() << std::endl;
return 0;
}This is how the corresponding GLSL UBO definition would look for the SceneSettings structure above:
// GLSL Side:
layout(std140, binding = 0) uniform SceneSettingsUBO
{
mat4 viewProjection;
vec3 cameraPosition;
float globalTime;
int renderMode;
};In structures there are five diffrent type handlers:
scalar_typevec_typemat_typestruct_typearray_type
all of them with the same base class base_type.
For easier and safer casting instead of using dynamic_cast there is implemented function dynamic_type_cast and static_type_cast.
Each type has implemented accept function which as a input accepts all types which match with type_visitor_concept.
#include <glslstruct/glslstruct.hpp>
#include <iostream>
#include <string>
#include <glm/glm.hpp>
using namespace glslstruct;
std140_struct SceneSettings {
glsl_value<glm::mat4>("viewProjection"),
glsl_value<glm::vec3>("cameraPosition"),
glsl_value<float>("globalTime"),
glsl_value<int>("renderMode")
};
// Visitor Definition
class zero_values_visitor {
private:
std::string _valueName;
public:
zero_values_visitor() = default;
~zero_values_visitor() = default;
void setValueName(const std::string& name) {
_valueName = name;
}
void visit(const scalar_type& type) {
switch(type.get_type()) {
case ValueType::Int:
SceneSettings.set(_valueName, 0);
break;
case ValueType::Float:
SceneSettings.set(_valueName, 0.f);
break;
}
}
void visit(const vec_type& type) {
if (type.get_type() == ValueType::Float &&
type.get_length() == 3) {
SceneSettings.set(_valueName, glm::vec3{ 0.f, 0.f, 0.f });
}
}
void visit(const mat_type& type) {
if (type.get_type() == ValueType::Float &&
type.get_cols() == 4 &&
type.get_rows() == 4) {
SceneSettings.set(_valueName, glm::mat4(0.f));
}
}
void visit(const struct_type& type) {
}
void visit(const array_type& type) {
}
}
int main() {
zero_values_visitor visitor{};
for (const auto& name : SceneSettings.get_names()) {
visitor.setValueName(name);
SceneSettings.get_type(name)->accept(visitor);
}
return 0;
}This project is licensed under the MIT License. See the LICENSE file for details.
We welcome all contributions! Whether it's reporting a bug, suggesting a new feature, or submitting a pull request, your input is valued.