Skip to content
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6393a21
Initial plan
Copilot Oct 23, 2025
e3bbc26
Remove deprecated concat_idents feature flag
Copilot Oct 23, 2025
82ef186
Implement GLSL attribute parser with FFI bindings
Copilot Oct 23, 2025
a21a221
Add C++ wrapper for GLSL attribute parser FFI
Copilot Oct 23, 2025
304c484
Add comprehensive documentation for GLSL attribute parser
Copilot Oct 23, 2025
d099cea
Fix C++ code formatting with clang-format
Copilot Oct 23, 2025
7293390
Revert accidental formatting change in all_events.cpp
Copilot Oct 23, 2025
1710d2f
update
yorkie Oct 23, 2025
8a6189e
Refactor to use JSON serialization for GLSL attributes FFI
Copilot Oct 23, 2025
2408daa
update
yorkie Oct 23, 2025
5712fc9
Merge branch 'main' of github.com:M-CreativeLab/jsar-runtime into cop…
yorkie Oct 24, 2025
7e3a373
fix
yorkie Oct 24, 2025
1aef9bf
fix
yorkie Oct 24, 2025
a8a3c7b
Filter out inactive/unreferenced attributes from parser results
Copilot Oct 24, 2025
de2c8f7
Add uniform parsing support and rename to GLSLShaderAnalyzer
Copilot Oct 25, 2025
fa70daa
Use GL type enums, add size and active fields
Copilot Oct 25, 2025
9a4ebbb
Add combined Parse() method to parse attributes and uniforms in singl…
Copilot Oct 25, 2025
70ad563
Implement structured uniform support with array and nested struct exp…
Copilot Oct 25, 2025
bb091fc
Add support for gl_InstanceID/gl_VertexID as active attributes
Copilot Oct 25, 2025
0713c17
fix
yorkie Oct 27, 2025
a120c94
Add comprehensive tests for preprocessor and array size handling
Copilot Oct 27, 2025
1c26a6e
Add test for conditional compilation with #ifdef directives
Copilot Oct 27, 2025
5774f55
update
yorkie Oct 27, 2025
617df18
Fix single-element array notation and add variable expansion tracking
Copilot Oct 27, 2025
9ee327a
Fix stack overflow in variable alias tracking
Copilot Oct 27, 2025
5870ccd
update
yorkie Oct 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/jsbindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ euclid = { workspace = true }
lazy_static = "1.4.0"
log = "0.4.21"
once_cell = "1.17.1"
serde = { workspace = true }
serde_json = { workspace = true }
surfman = "0.9.2"
taffy = { workspace = true, features = ["default"] }
gl = { version = "0.14.0" }
Expand Down
235 changes: 235 additions & 0 deletions crates/jsbindings/bindings.webgl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <iostream>
#include <concepts>
#include <vector>
#include <string>
#include <optional>
#include <rapidjson/document.h>
#include "./holocron_webgl.autogen.hpp"

namespace crates::webgl
Expand All @@ -24,4 +28,235 @@ namespace crates::webgl
return std::string(patched);
}
};

/**
* Represents a GLSL vertex attribute.
*/
struct GLSLAttribute
{
std::string name; ///< Attribute name (e.g., "position", "normal")
uint32_t type; ///< GL type constant (e.g., 0x8B51 for GL_FLOAT_VEC3)
int32_t size; ///< Size (number of elements, 1 for non-arrays)
int32_t location; ///< Attribute location (0-based index)
bool active; ///< Whether the attribute is active (referenced in shader)
};

/**
* Represents a GLSL uniform variable.
*/
struct GLSLUniform
{
std::string name; ///< Uniform name (e.g., "modelViewMatrix", "lightColor")
uint32_t type; ///< GL type constant (e.g., 0x8B5C for GL_FLOAT_MAT4)
int32_t size; ///< Size (number of elements, 1 for non-arrays)
bool active; ///< Whether the uniform is active (referenced in shader)
};

/**
* GLSLShaderAnalyzer parses GLSL shader source code to extract variable information.
*
* This class provides a convenient C++ interface to parse GLSL shaders and
* extract all attribute and uniform declarations, including their names, types, and locations.
*
* Features:
* - Supports both GLSL 100 ES (attribute) and GLSL 300 ES (in) qualifiers
* - Handles explicit layout(location = N) qualifiers
* - Auto-assigns locations based on declaration order when not explicitly specified
* - Marks inactive (unreferenced) attributes and uniforms with active=false
* - Compatible with WebGL 1.0 and WebGL 2.0 shaders
*
* Example usage:
* @code
* std::string vertexShader = R"(
* #version 300 es
* in vec3 position;
* in vec3 normal;
* uniform mat4 mvpMatrix;
* void main() {
* gl_Position = mvpMatrix * vec4(position, 1.0);
* }
* )";
*
* // Recommended: Parse both attributes and uniforms in a single call
* std::vector<GLSLAttribute> attributes;
* std::vector<GLSLUniform> uniforms;
* GLSLShaderAnalyzer::Parse(vertexShader, attributes, uniforms);
*
* // Or parse individually (deprecated, less efficient)
* auto attributes = GLSLShaderAnalyzer::ParseAttributes(vertexShader);
* auto uniforms = GLSLShaderAnalyzer::ParseUniforms(vertexShader);
* @endcode
*/
class GLSLShaderAnalyzer
{
public:
/**
* Parse GLSL shader source and extract both attributes and uniforms in a single pass.
* This is more efficient than calling ParseAttributes() and ParseUniforms() separately.
*
* @param source The GLSL shader source code as a string.
* @param attributes Output vector to receive attribute metadata.
* @param uniforms Output vector to receive uniform metadata.
* @param include_builtin_attributes Whether to include gl_InstanceID/gl_VertexID as active attributes if used in shader.
* @returns true if parsing succeeded, false otherwise.
*/
static inline bool Parse(const std::string &source,
std::vector<GLSLAttribute> &attributes,
std::vector<GLSLUniform> &uniforms,
bool include_builtin_attributes = false)
{
auto json_str = holocron::webgl::parseGLSLShader(source.c_str(), include_builtin_attributes);

rapidjson::Document doc;
doc.Parse(std::string(json_str).c_str());

if (!doc.IsObject() || !doc.HasMember("attributes") || !doc.HasMember("uniforms"))
{
return false;
}

// Parse attributes
const auto &attrs = doc["attributes"];
if (attrs.IsArray())
{
attributes.clear();
attributes.reserve(attrs.Size());
for (rapidjson::SizeType i = 0; i < attrs.Size(); i++)
{
const auto &attr = attrs[i];
if (attr.IsObject() && attr.HasMember("name") && attr.HasMember("type") &&
attr.HasMember("size") && attr.HasMember("location") && attr.HasMember("active"))
{
attributes.push_back(GLSLAttribute{
attr["name"].GetString(),
attr["type"].GetUint(),
attr["size"].GetInt(),
attr["location"].GetInt(),
attr["active"].GetBool()});
}
}
}

// Parse uniforms
const auto &unifs = doc["uniforms"];
if (unifs.IsArray())
{
uniforms.clear();
uniforms.reserve(unifs.Size());
for (rapidjson::SizeType i = 0; i < unifs.Size(); i++)
{
const auto &uniform = unifs[i];
if (uniform.IsObject() && uniform.HasMember("name") && uniform.HasMember("type") &&
uniform.HasMember("size") && uniform.HasMember("active"))
{
uniforms.push_back(GLSLUniform{
uniform["name"].GetString(),
uniform["type"].GetUint(),
uniform["size"].GetInt(),
uniform["active"].GetBool()});
}
}
}

return true;
}

/**
* Parse GLSL vertex shader source and extract all attribute declarations.
* @deprecated Use Parse() instead to get both attributes and uniforms in a single call.
*
* @param source The GLSL vertex shader source code as a string.
* @param include_builtin_attributes Whether to include gl_InstanceID/gl_VertexID as active attributes if used in shader.
* @returns A vector of GLSLAttribute structs containing attribute metadata.
*/
static inline std::vector<GLSLAttribute> ParseAttributes(const std::string &source, bool include_builtin_attributes = false)
{
auto json_str = holocron::webgl::parseGLSLAttributes(source.c_str(), include_builtin_attributes);
std::vector<GLSLAttribute> attributes;

rapidjson::Document doc;
doc.Parse(std::string(json_str).c_str());

if (!doc.IsArray())
{
return attributes;
}

attributes.reserve(doc.Size());
for (rapidjson::SizeType i = 0; i < doc.Size(); i++)
{
const auto &attr = doc[i];
if (attr.IsObject() && attr.HasMember("name") && attr.HasMember("type") &&
attr.HasMember("size") && attr.HasMember("location") && attr.HasMember("active"))
{
attributes.push_back(GLSLAttribute{
attr["name"].GetString(),
attr["type"].GetUint(),
attr["size"].GetInt(),
attr["location"].GetInt(),
attr["active"].GetBool()});
}
}

return attributes;
}

/**
* Parse GLSL shader source and extract all uniform declarations.
* @deprecated Use Parse() instead to get both attributes and uniforms in a single call.
*
* @param source The GLSL shader source code as a string.
* @returns A vector of GLSLUniform structs containing uniform metadata.
*/
static inline std::vector<GLSLUniform> ParseUniforms(const std::string &source)
{
auto json_str = holocron::webgl::parseGLSLUniforms(source.c_str());
std::vector<GLSLUniform> uniforms;

rapidjson::Document doc;
doc.Parse(std::string(json_str).c_str());

if (!doc.IsArray())
{
return uniforms;
}

uniforms.reserve(doc.Size());
for (rapidjson::SizeType i = 0; i < doc.Size(); i++)
{
const auto &uniform = doc[i];
if (uniform.IsObject() && uniform.HasMember("name") && uniform.HasMember("type") &&
uniform.HasMember("size") && uniform.HasMember("active"))
{
uniforms.push_back(GLSLUniform{
uniform["name"].GetString(),
uniform["type"].GetUint(),
uniform["size"].GetInt(),
uniform["active"].GetBool()});
}
}

return uniforms;
}

/**
* Get the location of a specific attribute by name.
*
* @param source The GLSL vertex shader source code as a string.
* @param name The name of the attribute to look up.
* @returns An optional containing the attribute location if found, or std::nullopt if not found.
*/
static inline std::optional<int32_t> GetAttribLocation(const std::string &source, const std::string &name)
{
auto attributes = ParseAttributes(source);
for (const auto &attr : attributes)
{
if (attr.name == name)
{
return attr.location;
}
}
return std::nullopt;
}
};
}
1 change: 0 additions & 1 deletion crates/jsbindings/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![allow(unused_variables)]
#![allow(clippy::uninlined_format_args)]
#![allow(deprecated)]
#![feature(concat_idents)]

extern crate ctor;
extern crate jsar_jsbinding_macro;
Expand Down
Loading