πΏ Mesh Loading
Fase: 5 β TransiΓ§Γ£o Dimensional
Namespace: Caffeine::Assets
Arquivo: src/assets/MeshLoader.hpp
Status: π
Planejado
RFs: RF5.2, RF5.3
VisΓ£o Geral
Carregamento de malhas 3D nos formatos .obj e .gltf, convertendo para o formato interno .caf (Mesh). Shaders HLSL (Windows Direct3D) / GLSL (Linux/macOS OpenGL via SDL_GPU).
API Planejada
namespace Caffeine::Assets {
// ============================================================================
// @brief Formato de vΓ©rtice 3D (48 bytes β SIMD-aligned a 32 bytes com padding).
//
// offset 0: Vec3 position (12 bytes)
// offset 12: Vec3 normal (12 bytes)
// offset 24: Vec2 texcoord ( 8 bytes)
// offset 32: Vec4 tangent (16 bytes) β para normal mapping
// TOTAL: 48 bytes (align 16)
// ============================================================================
struct Vertex3D {
Vec3 position;
Vec3 normal;
Vec2 texcoord;
Vec4 tangent; // xyz = tangent, w = bitangent sign
};
// ============================================================================
// @brief Sub-mesh β parte de uma mesh com material prΓ³prio.
// ============================================================================
struct SubMesh {
u32 indexOffset; // primeiro Γndice no index buffer
u32 indexCount;
u32 materialIndex;
FixedString<64> name;
};
// ============================================================================
// @brief Mesh 3D carregada.
// ============================================================================
struct Mesh3D {
std::vector<Vertex3D> vertices;
std::vector<u32> indices;
std::vector<SubMesh> subMeshes;
Rect3D bounds; // AABB para frustum culling
u32 lodCount = 1; // LODs futuros
// GPU buffers (criados apΓ³s upload)
RHI::Buffer* vertexBuffer = nullptr;
RHI::Buffer* indexBuffer = nullptr;
};
// ============================================================================
// @brief Material 3D.
// ============================================================================
struct Material3D {
FixedString<64> name;
RHI::Texture* albedoTexture = nullptr;
RHI::Texture* normalTexture = nullptr;
RHI::Texture* roughnessTexture = nullptr;
Color albedoColor = Color::WHITE;
f32 roughness = 0.5f;
f32 metallic = 0.0f;
RHI::Shader* shader = nullptr;
};
// ============================================================================
// @brief Loader de meshes .obj e .gltf.
//
// Fluxo:
// 1. Carregar .obj/.gltf β Mesh3D (vertices, indices)
// 2. Converter para .caf (AssetType::Mesh) via Asset Pipeline (Fase 6)
// 3. Em runtime: BlobLoader carrega .caf β upload GPU
// ============================================================================
class MeshLoader {
public:
explicit MeshLoader(RHI::RenderDevice* device,
AssetManager* assets);
// Carregamento assΓncrono (preferido em runtime)
AssetHandle<Mesh3D> loadAsync(const char* cafPath);
// Carregamento sΓncrono (para ferramentas, nΓ£o para runtime)
Mesh3D* loadOBJ(const char* objPath);
Mesh3D* loadGLTF(const char* gltfPath);
// Upload da mesh para GPU (chama apΓ³s loadOBJ/loadGLTF)
void uploadToGPU(Mesh3D* mesh);
private:
RHI::RenderDevice* m_device;
AssetManager* m_assets;
};
} // namespace Caffeine::Assets
// ============================================================================
// @brief Sistema de renderizaΓ§Γ£o de meshes 3D.
// ============================================================================
namespace Caffeine::Render {
class MeshSystem : public ECS::ISystem {
public:
void update(ECS::World& world, f64 dt) override;
i32 priority() const override { return 900; } // antes do render flush
const char* name() const override { return "MeshSystem"; }
private:
void submitMesh(const Assets::Mesh3D& mesh,
const Math::Mat4& worldMatrix,
RHI::CommandBuffer* cmd);
};
} // namespace Caffeine::Render
Shader System (RF5.3)
namespace Caffeine::Render {
// ============================================================================
// @brief CompilaΓ§Γ£o e gerenciamento de shaders.
//
// Plataforma:
// - Windows: HLSL β compilado com dxc β SPIR-V via SDL_GPU
// - Linux/macOS: GLSL β compilado com glslc β SPIR-V via SDL_GPU
// ============================================================================
class ShaderSystem {
public:
RHI::Shader* loadVertex(const char* path);
RHI::Shader* loadFragment(const char* path);
RHI::Pipeline* createPipeline(RHI::Shader* vert,
RHI::Shader* frag,
const RHI::PipelineDesc& desc);
// Hot-reload de shaders (dev mode)
void reloadShader(const char* path);
void pollChanges();
};
} // namespace Caffeine::Render
Componente ECS para Mesh
namespace Caffeine::Components {
struct MeshRenderer {
FixedString<128> meshPath;
Assets::AssetHandle<Assets::Mesh3D> mesh;
Assets::Material3D* material = nullptr;
bool castShadows = true;
bool receiveShadows = true;
};
} // namespace Caffeine::Components
Exemplos de Uso
// ββ Carregar mesh βββββββββββββββββββββββββββββββββββββββββββββ
Caffeine::Assets::MeshLoader meshLoader(&device, &assets);
auto meshHandle = meshLoader.loadAsync("meshes/player.caf");
// ββ Criar entidade 3D βββββββββββββββββββββββββββββββββββββββββ
Entity player3D = world.create("Player3D");
world.add<Position3D>(player3D, {0, 0, 0});
world.add<Rotation3D>(player3D);
world.add<Scale3D>(player3D, {1, 1, 1});
world.add<MeshRenderer>(player3D, { .meshPath = "meshes/player.caf" });
// ββ Shader customizado ββββββββββββββββββββββββββββββββββββββββ
auto* shaderSys = world.getSystem<ShaderSystem>();
auto* vert = shaderSys->loadVertex("shaders/pbr.vert.spv");
auto* frag = shaderSys->loadFragment("shaders/pbr.frag.spv");
auto* pipeline = shaderSys->createPipeline(vert, frag, {});
// Assign ao material da mesh
CritΓ©rio de AceitaΓ§Γ£o
DependΓͺncias
ReferΓͺncias
πΏ Mesh Loading
VisΓ£o Geral
Carregamento de malhas 3D nos formatos
.obje.gltf, convertendo para o formato interno.caf(Mesh). Shaders HLSL (Windows Direct3D) / GLSL (Linux/macOS OpenGL via SDL_GPU).API Planejada
Shader System (RF5.3)
Componente ECS para Mesh
Exemplos de Uso
CritΓ©rio de AceitaΓ§Γ£o
DependΓͺncias
ReferΓͺncias
docs/architecture_specs.mdβ Β§15 Math Librarydocs/fase3/rhi.mdβ Buffer/Shader creation