Source code for simvx.graphics._types

"""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