"""Shared constants, numpy dtypes, and enums for SimVX Graphics."""
import logging
from dataclasses import dataclass
from enum import IntFlag
from importlib.resources import files
from pathlib import Path
from typing import Any, NamedTuple
import numpy as np
log = logging.getLogger(__name__)
__all__ = [
"Feature",
"MeshHandle",
"Viewport",
"VERTEX_DTYPE",
"TRANSFORM_DTYPE",
"MATERIAL_DTYPE",
"INDIRECT_DRAW_DTYPE",
"LIGHT_DTYPE",
"MAX_TEXTURES",
"MAX_LIGHTS",
"MAX_OBJECTS",
"SKINNED_VERTEX_DTYPE",
"FRAMES_IN_FLIGHT",
"ALPHA_OPAQUE",
"ALPHA_BLEND",
"ALPHA_CUTOFF",
"SHADER_DIR",
"UI_VERTEX_STRIDE",
]
# GLSL/SPIR-V shaders ship as a real subpackage so they are present in built
# wheels (uv_build only packages files under src/). ``importlib.resources.files``
# returns a real ``pathlib.Path`` for installed subpackages, which is what
# ``compile_shader`` (glslc subprocess) and the shader cache require.
SHADER_DIR: Path = Path(str(files("simvx.graphics.shaders")))
# UI/2D vertex stride: pos(vec2) + uv(vec2) + colour(vec4) = 32 bytes
UI_VERTEX_STRIDE = 32
# Alpha mode constants (match GLSL #defines)
ALPHA_OPAQUE: int = 0
ALPHA_BLEND: int = 1
ALPHA_CUTOFF: int = 2
# Limits
MAX_TEXTURES = 4096
MAX_LIGHTS = 1024
MAX_OBJECTS = 65536
FRAMES_IN_FLIGHT = 2
[docs]
class MeshHandle(NamedTuple):
"""Opaque handle to a registered GPU mesh."""
id: int
vertex_count: int
index_count: int
bounding_radius: float
[docs]
@dataclass
class Viewport:
"""Viewport configuration for rendering."""
x: int
y: int
width: int
height: int
camera_view: np.ndarray # 4x4 view matrix
camera_proj: np.ndarray # 4x4 projection matrix
render_target: Any | None = None # None = main swapchain
[docs]
class Feature(IntFlag):
"""Material feature bitmask — matches shader #defines."""
NONE = 0
HAS_ALBEDO = 1 << 0
HAS_NORMAL = 1 << 1
HAS_METALLIC_ROUGHNESS = 1 << 2
HAS_EMISSIVE = 1 << 3
HAS_AO = 1 << 4
HAS_EMISSIVE_COLOR = 1 << 5
# Vertex format: position(vec3) + normal(vec3) + uv(vec2) = 32 bytes
VERTEX_DTYPE = np.dtype(
[
("position", np.float32, 3),
("normal", np.float32, 3),
("uv", np.float32, 2),
]
)
# GPU-aligned structured dtypes (match common.glsl layouts)
TRANSFORM_DTYPE = np.dtype(
[
("model", np.float32, (4, 4)), # mat4 (64 bytes)
("normal_mat", np.float32, (4, 4)), # mat4 (64 bytes)
("material_index", np.uint32), # uint (4 bytes)
("_pad", np.uint32, 3), # padding to 16-byte alignment (12 bytes)
]
) # Total: 144 bytes
MATERIAL_DTYPE = np.dtype(
[
("albedo", np.float32, 4), # vec4
("metallic", np.float32),
("roughness", np.float32),
("albedo_tex", np.int32), # bindless texture index (-1 = none)
("normal_tex", np.int32),
("metallic_roughness_tex", np.int32),
("emissive_tex", np.int32),
("ao_tex", np.int32),
("features", np.uint32), # Feature bitmask
("emissive_colour", np.float32, 4), # vec4 (rgb=colour, a=intensity)
("alpha_mode", np.uint32), # 0=OPAQUE, 1=ALPHA_BLEND, 2=ALPHA_CUTOFF
("alpha_cutoff", np.float32), # cutoff threshold (used when alpha_mode==2)
("double_sided", np.uint32), # 1=disable backface culling
("_pad", np.uint32, 1), # padding to 16-byte alignment
]
)
INDIRECT_DRAW_DTYPE = np.dtype(
[
("index_count", np.uint32),
("instance_count", np.uint32),
("first_index", np.uint32),
("vertex_offset", np.int32),
("first_instance", np.uint32),
]
)
LIGHT_DTYPE = np.dtype(
[
("position", np.float32, 4), # vec4 (w = type: 0=dir, 1=point, 2=spot)
("direction", np.float32, 4), # vec4
("colour", np.float32, 4), # vec4 (w = intensity)
("params", np.float32, 4), # vec4 (range, inner_cone, outer_cone, shadow_flag)
]
)
# Skinned vertex: standard + joints(uvec4) + weights(vec4) = 48 bytes
SKINNED_VERTEX_DTYPE = np.dtype(
[
("position", np.float32, 3),
("normal", np.float32, 3),
("uv", np.float32, 2),
("joints", np.uint16, 4), # 4 bone indices (8 bytes)
("weights", np.float32, 4), # 4 bone weights (16 bytes)
]
)
# Vulkan handle type aliases — the `vulkan` CFFI bindings return opaque ffi.CData pointers.
# These aliases document intent without introducing runtime dependencies on internal CFFI types.
# Private (underscore prefix) — backend-internal annotations, not part of the public surface.
_VkInstance = Any
_VkDevice = Any
_VkPhysicalDevice = Any
_VkQueue = Any
_VkSurfaceKHR = Any
_VkRenderPass = Any
_VkPipeline = Any
_VkPipelineLayout = Any
_VkCommandBuffer = Any
_VkFramebuffer = Any
_VkShaderModule = Any
_VkImage = Any
_VkImageView = Any
_VkDeviceMemory = Any
_VkDescriptorPool = Any
_VkDescriptorSet = Any
_VkDescriptorSetLayout = Any
_VkSampler = Any
_VkDebugUtilsMessengerEXT = Any