Files
fan/src/mesh.hpp
Cristian Gora d081108ea5 Add GL error handling, resource fallbacks and GPU timing; speed up lighting
Bug fixes:
- Release static GL objects (UBOs, logo texture) before the context is
  destroyed via new Renderer::shutdown()
- Fix max point/spot light warnings never firing
- Show frame time in ms instead of seconds
- Size the viewport framebuffer in physical pixels on HiDPI displays
- Stop double-flipping OBJ UVs; add flip_uvs option to load_obj for
  models with a top-left UV origin (backpack)

Build:
- Track header dependencies (-MMD -MP) so header edits trigger rebuilds
- Create build/ automatically

Error handling:
- Add gldebug module: KHR_debug output routed to the logger in debug
  builds, object labels, and error/status string helpers
- Validate inputs and check GL errors when creating textures, meshes,
  framebuffers, uniform buffers and shaders; FrameBuffer::resize() and
  Renderer::init() now report failure

Resources:
- Add ResourceCache: shares textures and shaders by path and substitutes
  fallbacks (magenta checkerboard texture, unlit shader, cube mesh) for
  assets that fail to load; specular maps are optional
- load_obj never fails, a broken model becomes a fallback cube
- Renderer draws submeshes with broken materials using the fallback
  material instead of skipping them
- Add Texture::create_from_pixels, Shader::create_from_source and
  Mesh::create_cube
- Cache uniform locations in Shader, looked up with string_view so
  hits don't allocate; missing uniforms warn once

Performance:
- Add CpuTimer and GpuTimer (GL_TIME_ELAPSED, non-blocking readback)
  and a Performance section in the UI with averaged overlay numbers
- Sample material textures once per fragment and apply material colors
  after accumulating lights
- Pass camera position through CameraBlock instead of inverting the
  view matrix per fragment
- Compute the normal matrix on the CPU instead of per vertex
- Skip spot light work for fragments outside the outer cone
2026-10-28 21:23:41 +01:00

72 lines
1.9 KiB
C++

#ifndef FAN_MESH_HPP_
#define FAN_MESH_HPP_
#include <vector>
#include <glad/gl.h>
#include "vertex.hpp"
#include "material.hpp"
#include "utils.hpp"
namespace Fan
{
class Mesh
{
public:
// A range drawn with one material. Offset and count are in indices, or in
// vertices if the mesh has no index buffer
struct SubMesh
{
GLuint index_offset{};
GLuint index_count{};
Rc<Material> material{};
};
// Without indices the vertices are drawn in order. Without submeshes a single
// one with no material covers the whole mesh
static Rc<Mesh> create(const std::vector<Vertex>& vertices,
const std::vector<GLuint>& indices = {},
const std::vector<SubMesh>& submeshes = {});
// Unit cube centered at the origin, with normals and texture coordinates
static Rc<Mesh> create_cube();
Mesh(const std::vector<Vertex>& vertices,
const std::vector<GLuint>& indices,
const std::vector<SubMesh>& submeshes,
bool has_indices,
GLuint VBO, GLuint VAO, GLuint EBO)
: m_vertices(vertices)
, m_indices(indices)
, m_submeshes(submeshes)
, m_has_indices(has_indices)
, m_VBO(VBO)
, m_VAO(VAO)
, m_EBO(EBO) {}
~Mesh();
Mesh(const Mesh&) = delete;
Mesh& operator=(const Mesh&) = delete;
Mesh(Mesh&& other) noexcept;
Mesh& operator=(Mesh&& other) noexcept;
const std::vector<SubMesh>& get_submeshes() const;
// Geometry only: the caller binds the shader and material first
void draw() const;
void draw_submesh(GLuint index_offset, GLuint index_count) const;
private:
std::vector<Vertex> m_vertices{};
std::vector<GLuint> m_indices{};
std::vector<SubMesh> m_submeshes{};
bool m_has_indices{};
GLuint m_VBO{};
GLuint m_VAO{};
GLuint m_EBO{};
};
} // namespace Fan
#endif // FAN_MESH_HPP_