"""
Attribute and layout specification handling module.
This module defines data structures for specifying attributes and layout
descriptors in a graphical or geometrical context. These structures are
used to describe how data is stored, accessed, and organized for rendering
or processing purposes.
"""
from dataclasses import dataclass
from typing import List
from picogl.backend.gl.enums import GLNumeric
from picogl.gpu.buffers.vertex.aliases import VertexBufferRole
from picogl.gpu.buffers.vertex.vbo.vbo_class import VBOType
from picogl.utils.strenum import StrEnum
@dataclass
[docs]
class AttributeSpec:
"""Attribute specification."""
[docs]
name: str # semantic name ("positions", "colors", "normals", etc.)
[docs]
index: int # attribute location
[docs]
size: int # number of components (e.g., 3 for vec3)
[docs]
type: GLNumeric # GL_FLOAT, GL_INT, etc.
[docs]
vbo_type: VBOType = VBOType.VBO
[docs]
role: VertexBufferRole = VertexBufferRole.VBO
[docs]
def legacy_attribute_spec(
role: VertexBufferRole,
index: int,
*,
size: int = 3,
name: str | VertexBufferRole | None = None,
type: GLNumeric,
normalized: bool = False,
stride: int = 0,
offset: int = 0,
) -> AttributeSpec:
"""Build an AttributeSpec with aligned legacy role, vbo_type, and name."""
vbo_type = role.value if isinstance(role.value, VBOType) else VBOType(role.value)
return AttributeSpec(
name=name if name is not None else role,
index=index,
size=size,
type=type,
normalized=normalized,
stride=stride,
offset=offset,
vbo_type=vbo_type,
role=role,
)
@dataclass
[docs]
class LayoutDescriptor:
"""Layout descriptor."""
[docs]
attributes: List[AttributeSpec]
[docs]
_cache: dict[VBOType, AttributeSpec] | None = None
[docs]
def __getitem__(self, vbo_type: VBOType) -> AttributeSpec:
try:
return self.as_dict()[vbo_type]
except KeyError:
raise KeyError(f"{vbo_type} not defined in layout")
[docs]
def get_attr(self, vbo_type: VBOType) -> AttributeSpec:
try:
return self.as_dict()[vbo_type]
except KeyError:
raise KeyError(f"{vbo_type} not defined in layout")
[docs]
def has_attr(self, vbo_type: VBOType) -> bool:
return vbo_type in self.as_dict()
[docs]
def as_dict(self) -> dict[VBOType, AttributeSpec]:
if self._cache is None:
self._cache = {attr.vbo_type: attr for attr in self.attributes}
return self._cache
@property
[docs]
def attr_dict(self) -> dict[VBOType, AttributeSpec]:
"""dict"""
return self.as_dict()
[docs]
class CanonicalVertexAttrs(StrEnum):
"""Canonical Vertex Attrs"""
[docs]
POSITIONS = "positions"
[docs]
class VBOAttrs:
"""VBO Attrs"""
[docs]
ALL = [VBOType.VBO, VBOType.NBO, VBOType.CBO, VBOType.EBO]