From bd57f345ed9dbed1d81683e48199626de2ea9044 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 27 Jun 2025 10:18:39 -0700 Subject: Restructure project --- include/gfx/asset.h | 99 +++++++++ include/gfx/core.h | 501 ++++++++++++++++++++++++++++++++++++++++++ include/gfx/gfx.h | 31 +++ include/gfx/renderer.h | 104 +++++++++ include/gfx/scene.h | 11 + include/gfx/scene/animation.h | 142 ++++++++++++ include/gfx/scene/camera.h | 22 ++ include/gfx/scene/light.h | 30 +++ include/gfx/scene/material.h | 25 +++ include/gfx/scene/mesh.h | 23 ++ include/gfx/scene/model.h | 12 + include/gfx/scene/node.h | 156 +++++++++++++ include/gfx/scene/object.h | 39 ++++ include/gfx/scene/scene.h | 21 ++ include/gfx/sizes.h | 95 ++++++++ include/gfx/util/geometry.h | 13 ++ include/gfx/util/ibl.h | 25 +++ include/gfx/util/shader.h | 46 ++++ include/gfx/util/skyquad.h | 22 ++ 19 files changed, 1417 insertions(+) create mode 100644 include/gfx/asset.h create mode 100644 include/gfx/core.h create mode 100644 include/gfx/gfx.h create mode 100644 include/gfx/renderer.h create mode 100644 include/gfx/scene.h create mode 100644 include/gfx/scene/animation.h create mode 100644 include/gfx/scene/camera.h create mode 100644 include/gfx/scene/light.h create mode 100644 include/gfx/scene/material.h create mode 100644 include/gfx/scene/mesh.h create mode 100644 include/gfx/scene/model.h create mode 100644 include/gfx/scene/node.h create mode 100644 include/gfx/scene/object.h create mode 100644 include/gfx/scene/scene.h create mode 100644 include/gfx/sizes.h create mode 100644 include/gfx/util/geometry.h create mode 100644 include/gfx/util/ibl.h create mode 100644 include/gfx/util/shader.h create mode 100644 include/gfx/util/skyquad.h (limited to 'include') diff --git a/include/gfx/asset.h b/include/gfx/asset.h new file mode 100644 index 0000000..caf40c1 --- /dev/null +++ b/include/gfx/asset.h @@ -0,0 +1,99 @@ +/* Asset Management */ +#pragma once + +#include + +#include + +typedef struct Gfx Gfx; +typedef struct Model Model; +typedef struct ShaderProgram ShaderProgram; +typedef struct Texture Texture; + +/// Describes where the asset comes from. +typedef enum AssetOrigin { + AssetFromMemory, + AssetFromFile, +} AssetOrigin; + +/// Describes a texture's colour space. +typedef enum TextureColourSpace { + sRGB, // The most likely default. + LinearColourSpace, +} TextureColourSpace; + +/// Describes a command to load a texture. +typedef struct LoadTextureCmd { + AssetOrigin origin; + enum { LoadTexture, LoadCubemap } type; + TextureColourSpace colour_space; + TextureFiltering filtering; + TextureWrapping wrap; + bool mipmaps; + union { + // A single texture. + struct { + union { + struct { + mstring filepath; + }; + struct { + const void* data; + size_t size_bytes; + }; + }; + } texture; + // Cubemap texture. + struct { + union { + struct { + mstring filepath_pos_x; + mstring filepath_neg_x; + mstring filepath_pos_y; + mstring filepath_neg_y; + mstring filepath_pos_z; + mstring filepath_neg_z; + } filepaths; + struct { + const void* data_pos_x; + const void* data_neg_x; + const void* data_pos_y; + const void* data_neg_y; + const void* data_pos_z; + const void* data_neg_z; + } buffers; + }; + } cubemap; + } data; +} LoadTextureCmd; + +/// Describes a command to load a model. +/// +/// |shader| is an optional shader program assigned to the loaded model objects. +/// If no shader is given, a Cook-Torrance shader based on the object's +/// characteristics (presence of normals, tangents, etc) is assigned. +typedef struct LoadModelCmd { + AssetOrigin origin; + union { + struct { + mstring filepath; + }; + struct { + const void* data; + size_t size_bytes; + }; + }; + ShaderProgram* shader; +} LoadModelCmd; + +/// Load a model. +/// +/// For animated models, this function returns a (shallow) clone of the model +/// that is safe to mutate. For static models, this returns the original model +/// in the cache. +/// +/// Currently only supports the GLTF format. +Model* gfx_load_model(Gfx*, const LoadModelCmd*); + +/// Load a texture. +const Texture* gfx_load_texture(Gfx*, const LoadTextureCmd*); diff --git a/include/gfx/core.h b/include/gfx/core.h new file mode 100644 index 0000000..44509c9 --- /dev/null +++ b/include/gfx/core.h @@ -0,0 +1,501 @@ +/// Render Backend. +/// +/// The Render Backend creates and owns graphics objects and performs low-level +/// rendering operations. +#pragma once + +#include "sizes.h" + +#include +#include +#include +#include + +#include + +#include +#include + +// Implementation objects. +typedef struct Buffer Buffer; +typedef struct FrameBuffer FrameBuffer; +typedef struct Geometry Geometry; +typedef struct GfxCore GfxCore; +typedef struct RenderBuffer RenderBuffer; +typedef struct Shader Shader; +typedef struct ShaderProgram ShaderProgram; +typedef struct Texture Texture; + +/// Data type for vertex indices. +/// Might need U32 for bigger models. +typedef uint8_t VertexIndex8; +typedef uint16_t VertexIndex16; +typedef uint16_t VertexCount; + +/// Geometry drawing modes. +typedef enum PrimitiveType { + Triangles, + TriangleFan, + TriangleStrip +} PrimitiveType; + +/// Buffer usage. +typedef enum BufferUsage { BufferStatic, BufferDynamic } BufferUsage; + +/// Buffer type. +typedef enum BufferType { + BufferUntyped, + Buffer2d, + Buffer3d, + Buffer4d, + BufferFloat, + BufferU8, + BufferU16 +} BufferType; + +/// Buffer data descriptor. +typedef struct BufferDataDesc { + union { + const void* data; + const vec2* vec2s; + const vec3* vec3s; + const float* floats; + const uint8_t* u8s; + const uint16_t* u16s; + }; + size_t count; +} BufferDataDesc; + +/// Buffer descriptor. +/// +/// 'count' is the number of elements in the array. For untyped buffers, this is +/// the size in bytes of the 'data' array. For other types, it is the number of +/// vec2s, vec3s, etc. in the corresponding array. +/// +/// The data pointers can also be null. In such a case, a buffer of the given +/// size is created with its contents uninitialized. +/// +/// TODO: Think about typed buffers (Buffer, Buffer2d, Buffer3d, BufferU8, etc). +/// Typed buffers don't work well with interleaved vertex attributes. Not sure +/// this is really worth it. +typedef struct BufferDesc { + BufferUsage usage; + BufferType type; + BufferDataDesc data; +} BufferDesc; + +/// A buffer view for vertex data (attributes or indices). +/// Either 'data' or 'buffer' must be set. +#define MAKE_BUFFER_VIEW(NAME, TYPE) \ + typedef struct NAME { \ + const TYPE* data; \ + Buffer* buffer; \ + size_t offset_bytes; \ + size_t size_bytes; \ + size_t stride_bytes; \ + } NAME; + +/// A buffer view for untyped data. +MAKE_BUFFER_VIEW(BufferView, void) + +/// A buffer view for 2D vectors. +MAKE_BUFFER_VIEW(BufferView2d, vec2) + +/// A buffer view for 3D vectors. +MAKE_BUFFER_VIEW(BufferView3d, vec3) + +/// A buffer view for 4D vectors. +MAKE_BUFFER_VIEW(BufferView4d, vec4) + +/// A buffer view for floats. +MAKE_BUFFER_VIEW(BufferViewFloat, float) + +/// A buffer view for 8-bit unsigned integers. +MAKE_BUFFER_VIEW(BufferViewU8, uint8_t) + +/// A buffer view for 16-bit unsigned integers. +MAKE_BUFFER_VIEW(BufferViewU16, uint16_t) + +/// A buffer view for 8-bit vertex indices. +MAKE_BUFFER_VIEW(BufferViewIdx8, uint16_t) + +/// A buffer view for 16-bit vertex indices. +MAKE_BUFFER_VIEW(BufferViewIdx16, uint16_t) + +/// Describes a piece of geometry. +/// +/// Buffer views may point to either already-existing GPU buffers or to data in +/// host memory. +/// +/// If the buffer views do not already point to GPU buffers, GPU buffers are +/// created for the geometry. The 'buffer_usage' field specifies the usage for +/// the created buffers. Use BufferStatic for static geometry and BufferDynamic +/// for dynamic geometry. +/// +/// Currently we support only up to 16-bit vertex indices. Might have to change +/// this to support a larger variety of 3D models. +typedef struct GeometryDesc { + BufferView2d positions2d; + BufferView3d positions3d; + BufferView3d normals; + BufferView4d tangents; + BufferView2d texcoords; + struct { + BufferViewU8 u8; + BufferViewU16 u16; + } joints; // uvec4. + struct { + BufferViewFloat floats; + BufferViewU8 u8; + BufferViewU16 u16; + } weights; // vec4 or uvec4. + BufferViewIdx8 indices8; + BufferViewIdx16 indices16; + VertexCount num_verts; + size_t num_indices; + PrimitiveType type; + BufferUsage buffer_usage; + aabb3 aabb; +} GeometryDesc; + +/// Shader compiler define. +typedef struct ShaderCompilerDefine { + sstring name; + sstring value; +} ShaderCompilerDefine; + +/// Shader types. +typedef enum { VertexShader, FragmentShader } ShaderType; + +/// Describes a shader. +typedef struct ShaderDesc { + ShaderType type; + const char* code; + ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES]; + size_t num_defines; +} ShaderDesc; + +/// Describes a shader program. +typedef struct ShaderProgramDesc { + const Shader* vertex_shader; + const Shader* fragment_shader; +} ShaderProgramDesc; + +/// Shader uniform type. +typedef enum { + UniformFloat, + UniformMat4, + UniformTexture, + UniformVec3, + UniformVec4, + UniformMat4Array +} UniformType; + +/// Shader uniform. +/// +/// For uniform arrays, the client must ensure that the array is still valid by +/// the time the uniform data is passed to the GPU. +typedef struct ShaderUniform { + sstring name; + UniformType type; + union { + const Texture* texture; + mat4 mat4; + vec3 vec3; + vec4 vec4; + float scalar; + struct { + size_t count; + union { + const mat4* values; + }; + } array; + } value; +} ShaderUniform; + +/// Texture dimension. +typedef enum { Texture2D, TextureCubeMap } TextureDimension; + +/// Texture data format. +typedef enum { + TextureDepth, + TextureRG16, + TextureRG16F, + TextureRGB8, + TextureR11G11B10F, + TextureRGBA8, + TextureSRGB8, + TextureSRGBA8 +} TextureFormat; + +/// Texture filtering. +typedef enum { NearestFiltering, LinearFiltering } TextureFiltering; + +/// Texture wrap mode. +typedef enum { Repeat, ClampToEdge } TextureWrapping; + +/// Cubemap faces. +typedef enum { + CubemapFacePosX, + CubemapFaceNegX, + CubemapFacePosY, + CubemapFaceNegY, + CubemapFacePosZ, + CubemapFaceNegZ +} CubemapFace; + +/// Texture data descriptor. +typedef struct TextureDataDesc { + union { + const void* pixels; + struct { + const void* pixels_pos_x; + const void* pixels_neg_x; + const void* pixels_pos_y; + const void* pixels_neg_y; + const void* pixels_pos_z; + const void* pixels_neg_z; + } cubemap; + }; +} TextureDataDesc; + +/// Describes a texture. +typedef struct TextureDesc { + int width; + int height; + int depth; // Not used until 3D textures are exposed. + TextureDimension dimension; + TextureFormat format; + TextureFiltering filtering; + TextureWrapping wrap; + bool mipmaps; + TextureDataDesc data; +} TextureDesc; + +/// Describes a renderbuffer. +typedef struct RenderBufferDesc { + int width; + int height; + TextureFormat texture_format; +} RenderBufferDesc; + +/// Framebuffer attachment type. +typedef enum FrameBufferAttachmentType { + FrameBufferNoAttachment, + FrameBufferTexture, + FrameBufferCubemapTexture, + FrameBufferRenderBuffer +} FrameBufferAttachmentType; + +/// Describes a framebuffer attachment. +typedef struct FrameBufferAttachment { + FrameBufferAttachmentType type; + union { + struct { + Texture* texture; + int mip_level; + } texture; + struct { + Texture* texture; + int mip_level; + CubemapFace face; + } cubemap; + RenderBuffer* renderbuffer; + }; +} FrameBufferAttachment; + +/// Describes a framebuffer. +typedef struct FrameBufferDesc { + FrameBufferAttachment colour; + FrameBufferAttachment depth; +} FrameBufferDesc; + +// ----------------------------------------------------------------------------- +// Render commands. +// ----------------------------------------------------------------------------- + +/// Start a new frame. +void gfx_start_frame(GfxCore*); + +/// End a frame. +void gfx_end_frame(GfxCore*); + +/// Set the render backend's viewport dimensions. +void gfx_set_viewport(GfxCore*, int x, int y, int width, int height); + +/// Get the render backend's viewport dimensions. +void gfx_get_viewport(GfxCore*, int* x, int* y, int* width, int* height); + +/// Clear the viewport. +void gfx_clear(GfxCore*, vec4 colour); + +/// Set blending state. +void gfx_set_blending(GfxCore*, bool enable); + +/// Set depth mask. +void gfx_set_depth_mask(GfxCore*, bool enable); + +/// Set cull mode. +void gfx_set_culling(GfxCore*, bool enable); + +/// Set polygon offset. +void gfx_set_polygon_offset(GfxCore*, float scale, float bias); + +/// Reset the polygon offset. +void gfx_reset_polygon_offset(GfxCore*); + +// ----------------------------------------------------------------------------- +// Buffers. +// ----------------------------------------------------------------------------- + +/// Create a buffer from raw data. +Buffer* gfx_make_buffer(GfxCore*, const BufferDesc*); + +/// Destroy the buffer. +void gfx_destroy_buffer(GfxCore*, Buffer**); + +/// Update the buffer's data. +void gfx_update_buffer(Buffer*, const BufferDataDesc*); + +// ----------------------------------------------------------------------------- +// Geometry. +// ----------------------------------------------------------------------------- + +/// Create geometry. +Geometry* gfx_make_geometry(GfxCore*, const GeometryDesc*); + +/// Destroy the geometry. +void gfx_destroy_geometry(GfxCore*, Geometry**); + +/// Upload new vertex data for the geometry. +/// +/// This is similar to gfx_make_geometry(), but the geometry need not be +/// entirely specified. +/// +/// Only the vertex attributes, vertex count, and index count set in the +/// descriptor are updated. Index data, primitive type, and other properties of +/// the geometry are not updated. +/// +/// New data must be given as arrays in host memory. That is, the buffer views +/// in the descriptor must point to CPU arrays, not GPU buffers. +/// +/// Note that the descriptor cannot specify a larger vertex or index count than +/// what the geometry was created with. If the geometry size or any other +/// attribute not handled by this update function needs to be changed, then a +/// new geometry must be created. +void gfx_update_geometry(Geometry*, const GeometryDesc*); + +/// Render the geometry. +void gfx_render_geometry(const Geometry*); + +/// Return the geometry's bounding box. +aabb3 gfx_get_geometry_aabb(const Geometry*); + +// ----------------------------------------------------------------------------- +// Textures. +// ----------------------------------------------------------------------------- + +/// Create a texture. +Texture* gfx_make_texture(GfxCore*, const TextureDesc*); + +/// Destroy the texture. +void gfx_destroy_texture(GfxCore*, Texture**); + +/// Update the texture. +void gfx_update_texture(Texture*, const TextureDataDesc*); + +// ----------------------------------------------------------------------------- +// Renderbuffers. +// ----------------------------------------------------------------------------- + +/// Create a renderbuffer. +RenderBuffer* gfx_make_renderbuffer(GfxCore*, const RenderBufferDesc*); + +/// Destroy the renderbuffer. +void gfx_destroy_renderbuffer(GfxCore*, RenderBuffer**); + +// ----------------------------------------------------------------------------- +// Framebuffers. +// ----------------------------------------------------------------------------- + +/// Create a framebuffer. +FrameBuffer* gfx_make_framebuffer(GfxCore*, const FrameBufferDesc*); + +/// Destroy the framebuffer. +void gfx_destroy_framebuffer(GfxCore*, FrameBuffer**); + +/// Attach a colour buffer to the framebuffer. +bool gfx_framebuffer_attach_colour(FrameBuffer*, const FrameBufferAttachment*); + +/// Attach a depth buffer to the framebuffer. +bool gfx_framebuffer_attach_depth(FrameBuffer*, const FrameBufferAttachment*); + +/// Activate the framebuffer. +/// Subsequent draw calls write to this framebuffer. +void gfx_activate_framebuffer(const FrameBuffer*); + +/// Deactivate the framebuffer. +/// Subsequent draw calls write to the default framebuffer. +void gfx_deactivate_framebuffer(const FrameBuffer*); + +/// Set the framebuffer's viewport. +/// This function should be called every time the framebuffer is activated. +void gfx_framebuffer_set_viewport( + FrameBuffer*, int x, int y, int width, int height); + +// ----------------------------------------------------------------------------- +// Shaders. +// ----------------------------------------------------------------------------- + +/// Create a shader. +Shader* gfx_make_shader(GfxCore*, const ShaderDesc*); + +/// Destroy the shader. +void gfx_destroy_shader(GfxCore*, Shader**); + +/// Create a shader program. +ShaderProgram* gfx_make_shader_program(GfxCore*, const ShaderProgramDesc*); + +/// Destroy the shader program. +void gfx_destroy_shader_program(GfxCore*, ShaderProgram**); + +/// Activate the shader program. +void gfx_activate_shader_program(const ShaderProgram*); + +/// Deactivate the shader program. +void gfx_deactivate_shader_program(const ShaderProgram*); + +/// Apply the shader program's uniform variables. +/// +/// Calls to gfx_set_XYZ_uniform save the values of the uniform variables in the +/// graphics library. By calling this function, those values are passed on to +/// the graphics driver for rendering. +/// +/// This function should be called after setting all of the uniform variables +/// and prior to issuing a draw call. +void gfx_apply_uniforms(const ShaderProgram*); + +/// Set the texture uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*); + +/// Set the matrix uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_mat4_uniform(ShaderProgram*, const char* name, const mat4*); + +/// Set the vec3 uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_vec3_uniform(ShaderProgram*, const char* name, vec3); + +/// Set the vec4 uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4); + +/// Set the float uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_float_uniform(ShaderProgram*, const char* name, float value); + +/// Set the matrix array uniform. +/// Has no effect if the shader does not contain the given uniform. +void gfx_set_mat4_array_uniform( + ShaderProgram*, const char* name, const mat4*, size_t count); diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h new file mode 100644 index 0000000..7c670a5 --- /dev/null +++ b/include/gfx/gfx.h @@ -0,0 +1,31 @@ +#pragma once + +typedef struct AssetCache AssetCache; +typedef struct GfxCore GfxCore; +typedef struct ImmRenderer ImmRenderer; +typedef struct Renderer Renderer; + +typedef struct Gfx Gfx; + +/// Create a new graphics system, +Gfx* gfx_init(void); + +/// Destroy the graphics system. +void gfx_destroy(Gfx**); + +/// Get the render backend. +GfxCore* gfx_get_core(Gfx*); + +/// Get the renderer. +Renderer* gfx_get_renderer(Gfx*); + +/// Get the immediate mode renderer. +ImmRenderer* gfx_get_imm_renderer(Gfx*); + +/// Get the asset cache. +AssetCache* gfx_get_asset_cache(Gfx*); + +/// Remove unused resources from the scene (meshes, materials). +/// TODO: need to think about the interface for scene_purge(). Maybe this +/// should be gfx_purge() and take a list of Scenes? +// void gfx_purge(Scene*); diff --git a/include/gfx/renderer.h b/include/gfx/renderer.h new file mode 100644 index 0000000..2a4ada1 --- /dev/null +++ b/include/gfx/renderer.h @@ -0,0 +1,104 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +typedef struct GfxCore GfxCore; +typedef struct Scene Scene; +typedef struct SceneCamera SceneCamera; + +typedef struct ImmRenderer ImmRenderer; +typedef struct Renderer Renderer; + +// ----------------------------------------------------------------------------- +// Main Renderer. +// ----------------------------------------------------------------------------- + +typedef enum RenderSceneMode { + RenderDefault, + RenderDebug, + RenderNormals, + RenderNormalMappedNormals, + RenderTangents +} RenderSceneMode; + +typedef struct RenderSceneParams { + RenderSceneMode mode; + const Scene* scene; + const SceneCamera* camera; +} RenderSceneParams; + +/// Render the scene. +void gfx_render_scene(Renderer*, const RenderSceneParams*); + +/// Update the scene. +void gfx_update(Scene*, const SceneCamera*, R t); + +// ----------------------------------------------------------------------------- +// Immediate Mode Renderer. +// ----------------------------------------------------------------------------- + +/// Prepare the graphics systems for immediate-mode rendering. +/// +/// Call this before issuing any immediate-mode rendering draws. +void gfx_imm_start(ImmRenderer*); + +/// End immediate mode rendering. +/// +/// Call this after issuing immediate-mode rendering draws and before swapping +/// buffers. +void gfx_imm_end(ImmRenderer*); + +/// Draw a set of triangles. +void gfx_imm_draw_triangles(ImmRenderer*, const vec3[], size_t num_triangles); + +/// Draw a triangle. +void gfx_imm_draw_triangle(ImmRenderer*, const vec3[3]); + +/// Draw a bounding box. +void gfx_imm_draw_aabb2(ImmRenderer*, aabb2); + +/// Draw a bounding box. +void gfx_imm_draw_aabb3(ImmRenderer*, aabb3); + +/// Draw a box. +/// +/// The vertices must be given in the following order: +/// +/// 7 ----- 6 +/// / /| +/// 3 ----- 2 | +/// | | | +/// | 4 ----- 5 +/// |/ |/ +/// 0 ----- 1 +void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]); + +/// Set the camera. +void gfx_imm_set_camera(ImmRenderer*, const Camera*); + +/// Load an identity model matrix. Clears the matrix stack. +void gfx_imm_load_identity(ImmRenderer* renderer); + +/// Push the given matrix to the matrix stack. +void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix); + +/// Pop the top of the matrix stack. +void gfx_imm_pop_matrix(ImmRenderer* renderer); + +/// Push a translation matrix to the matrix stack. +void gfx_imm_translate(ImmRenderer* renderer, vec3 offset); + +/// Set the model matrix. Clears the matrix stack. +void gfx_imm_set_model_matrix(ImmRenderer*, const mat4*); + +/// Set the view-projection matrix. +void gfx_imm_set_view_projection_matrix(ImmRenderer*, const mat4*); + +/// Set the render colour. +void gfx_imm_set_colour(ImmRenderer*, vec4 colour); diff --git a/include/gfx/scene.h b/include/gfx/scene.h new file mode 100644 index 0000000..abcaa70 --- /dev/null +++ b/include/gfx/scene.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/gfx/scene/animation.h b/include/gfx/scene/animation.h new file mode 100644 index 0000000..d95b895 --- /dev/null +++ b/include/gfx/scene/animation.h @@ -0,0 +1,142 @@ +#pragma once + +#include "node.h" +#include "object.h" +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct Buffer Buffer; +typedef struct SceneNode SceneNode; + +typedef struct Anima Anima; +typedef struct Joint Joint; +typedef struct Skeleton Skeleton; + +/// Index type used to store relative indices into arrays. +typedef uint16_t joint_idx; + +/// Index value denoting no index. +static const joint_idx INDEX_NONE = (joint_idx)-1; + +typedef struct Box { + vec3 vertices[8]; +} Box; + +/// Joint descriptor. +typedef struct JointDesc { + joint_idx parent; /// Parent Joint; index into Anima's joints. + mat4 inv_bind_matrix; /// Transforms the mesh into the joint's local space. + aabb3 box; /// Bounding box. +} JointDesc; + +/// Skeleton descriptor. +typedef struct SkeletonDesc { + size_t num_joints; + joint_idx joints[GFX_MAX_NUM_JOINTS]; /// Indices into Anima's joints array. +} SkeletonDesc; + +/// Animation interpolation mode. +typedef enum AnimationInterpolation { + StepInterpolation, + LinearInterpolation, + CubicSplineInterpolation +} AnimationInterpolation; + +/// The kind of transformation applied by a Channel. +typedef enum ChannelType { + RotationChannel, + ScaleChannel, + TranslationChannel, + WeightsChannel +} ChannelType; + +/// Animation keyframe descriptor. +/// +/// The arrays should have as many entries as 'num_joints' in the SkeletonDesc. +typedef struct KeyframeDesc { + R time; // Start time in [0, end animation time] + union { + vec3 translation; + quat rotation; + }; +} KeyframeDesc; + +/// Animation channel descriptor. +typedef struct ChannelDesc { + joint_idx target; /// Index into Anima's joints array. + ChannelType type; + AnimationInterpolation interpolation; + size_t num_keyframes; + KeyframeDesc keyframes[GFX_MAX_NUM_KEYFRAMES]; +} ChannelDesc; + +/// Animation descriptor. +typedef struct AnimationDesc { + // TODO: Store a name hash for faster comparisons. + sstring name; // Animation name. Required for playback. + size_t num_channels; // Number of channels. + ChannelDesc channels[GFX_MAX_NUM_CHANNELS]; +} AnimationDesc; + +/// Anima object descriptor. +/// +/// The last joint of the joints array at index 'num_joints - 1' must be the +/// root of all skeletons; specifically, the root of all joints that otherwise +/// would have no parent (a skeleton need not have its own root and can be a set +/// of disjoint node hierarchies). +typedef struct AnimaDesc { + size_t num_skeletons; + size_t num_animations; + size_t num_joints; + SkeletonDesc skeletons[GFX_MAX_NUM_SKELETONS]; + AnimationDesc animations[GFX_MAX_NUM_ANIMATIONS]; + JointDesc joints[GFX_MAX_NUM_JOINTS]; +} AnimaDesc; + +/// Animation play settings. +typedef struct AnimationPlaySettings { + const char* name; // Animation name. + bool loop; // Whether to loop the animation or just play once. + // TODO: Add animation speed. +} AnimationPlaySettings; + +/// Create an anima object. +Anima* gfx_make_anima(const AnimaDesc*); + +/// Destroy the anima. +void gfx_destroy_anima(Anima**); + +/// Play an animation (sets the current animation). +bool gfx_play_animation(Anima*, const AnimationPlaySettings*); + +/// Update the current animation. +void gfx_update_animation(Anima*, R t); + +/// Stop the current animation. +void gfx_stop_animation(Anima*); + +/// Return the anima's ith skeleton. +const Skeleton* gfx_get_anima_skeleton(const Anima* anima, size_t i); + +/// Return the number of joints in the skeleton. +size_t gfx_get_skeleton_num_joints(const Skeleton*); + +/// Return true if the skeleton's ith joint has a bounding box. +/// +/// IK joints that do not directly transform vertices have no bounding box. +bool gfx_joint_has_box(const Anima*, const Skeleton*, size_t joint); + +/// Return the bounding box of the skeleton's ith joint. +/// +/// IK joints that do not directly transform vertices have no box. +Box gfx_get_joint_box(const Anima*, const Skeleton*, size_t joint); diff --git a/include/gfx/scene/camera.h b/include/gfx/scene/camera.h new file mode 100644 index 0000000..99d83fe --- /dev/null +++ b/include/gfx/scene/camera.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +typedef struct SceneNode SceneNode; + +typedef struct SceneCamera SceneCamera; + +/// Create a new camera. +SceneCamera* gfx_make_camera(); + +/// Destroy the camera. +/// +/// The camera is conveniently removed from the scene graph and its parent scene +/// node is destroyed. +void gfx_destroy_camera(SceneCamera**); + +/// Set the scene camera's math camera. +void gfx_set_camera_camera(SceneCamera* scene_camera, Camera* camera); + +/// Get the scene camera's math camera. +Camera* gfx_get_camera_camera(SceneCamera*); diff --git a/include/gfx/scene/light.h b/include/gfx/scene/light.h new file mode 100644 index 0000000..132e344 --- /dev/null +++ b/include/gfx/scene/light.h @@ -0,0 +1,30 @@ +#pragma once + +typedef struct Texture Texture; + +typedef struct Light Light; + +/// Light type. +typedef enum LightType { EnvironmentLightType } LightType; + +/// Describes an environment light. +typedef struct EnvironmentLightDesc { + const Texture* environment_map; +} EnvironmentLightDesc; + +/// Describes a light. +typedef struct LightDesc { + LightType type; + union { + EnvironmentLightDesc environment; + } light; +} LightDesc; + +/// Create a light. +Light* gfx_make_light(const LightDesc*); + +/// Destroy the light. +/// +/// The light is conveniently removed from the scene graph and its parent scene +/// node is destroyed. +void gfx_destroy_light(Light**); diff --git a/include/gfx/scene/material.h b/include/gfx/scene/material.h new file mode 100644 index 0000000..bca664e --- /dev/null +++ b/include/gfx/scene/material.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +typedef struct Material Material; + +/// Describes a material. +/// +/// A material holds a shader program and a set of shader-specific uniform +/// variables. Two materials can share the same shader, but shader parameters +/// generally give two materials a different appearance. +typedef struct MaterialDesc { + ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL]; + int num_uniforms; +} MaterialDesc; + +/// Create a material. +Material* gfx_make_material(const MaterialDesc*); + +/// Destroy the material. +/// +/// The caller must make sure that no Mesh points to the given Material. +/// For a safe purge of unused resources, see scene_purge(). +void gfx_destroy_material(Material**); diff --git a/include/gfx/scene/mesh.h b/include/gfx/scene/mesh.h new file mode 100644 index 0000000..0d3b4d4 --- /dev/null +++ b/include/gfx/scene/mesh.h @@ -0,0 +1,23 @@ +#pragma once + +typedef struct Geometry Geometry; +typedef struct Material Material; +typedef struct ShaderProgram ShaderProgram; + +typedef struct Mesh Mesh; + +/// Describes a mesh. +typedef struct MeshDesc { + const Geometry* geometry; + const Material* material; + ShaderProgram* shader; +} MeshDesc; + +/// Create a mesh. +Mesh* gfx_make_mesh(const MeshDesc*); + +/// Destroy the mesh. +/// +/// The caller must make sure that no SceneObject points to the given Mesh. +/// For a safe purge of unused resources, see scene_purge(). +void gfx_destroy_mesh(Mesh**); diff --git a/include/gfx/scene/model.h b/include/gfx/scene/model.h new file mode 100644 index 0000000..42f85d4 --- /dev/null +++ b/include/gfx/scene/model.h @@ -0,0 +1,12 @@ +#pragma once + +typedef struct Anima Anima; +typedef struct Model Model; +typedef struct SceneNode SceneNode; + +/// Return the model's anima, or null if the model is not animated. +Anima* gfx_get_model_anima(Model*); + +/// Return the model's root node. +const SceneNode* gfx_get_model_root(const Model*); +SceneNode* gfx_get_model_root_mut(Model*); diff --git a/include/gfx/scene/node.h b/include/gfx/scene/node.h new file mode 100644 index 0000000..a2c2836 --- /dev/null +++ b/include/gfx/scene/node.h @@ -0,0 +1,156 @@ +#pragma once + +#include "animation.h" + +#include +#include + +#include + +typedef struct Anima Anima; +typedef struct Light Light; +typedef struct Model Model; +typedef struct SceneCamera SceneCamera; +typedef struct SceneObject SceneObject; + +/// Scene node type. +typedef enum NodeType { + LogicalNode, + AnimaNode, + CameraNode, + LightNode, + ModelNode, + ObjectNode, +} NodeType; + +/// A node in the scene graph. +/// +/// Scene nodes take ownership of the object they are associated with (Camera, +/// Light, SceneObject, etc), as well as of child nodes. +typedef struct SceneNode SceneNode; + +// ----------------------------------------------------------------------------- +// Constructors and destructor. +// ----------------------------------------------------------------------------- + +/// Create a new scene node. +/// +/// This node does not contain any camera, light, object, etc. and exists simply +/// as a logical and spatial construct. +SceneNode* gfx_make_node(); + +/// Create an anima node. +SceneNode* gfx_make_anima_node(Anima*); + +/// Create a new camera node. +SceneNode* gfx_make_camera_node(SceneCamera*); + +/// Create a new light node. +SceneNode* gfx_make_light_node(Light*); + +/// Create a new model node. +SceneNode* gfx_make_model_node(Model*); + +/// Create a new object node. +SceneNode* gfx_make_object_node(SceneObject*); + +/// Make the node an anima node. +void gfx_construct_anima_node(SceneNode*, Anima*); + +/// Make the node a camera node. +void gfx_construct_camera_node(SceneNode*, SceneCamera*); + +/// Make the node a light node. +void gfx_construct_light_node(SceneNode*, Light*); + +/// Make the node a model node. +void gfx_construct_model_node(SceneNode*, Model*); + +/// Make the node an object node. +void gfx_construct_object_node(SceneNode*, SceneObject*); + +/// Recursively destroy the scene node and its children. +/// +/// The scene node and its children are removed from the scene graph. +/// +/// Node resources -- cameras, lights, objects, etc. -- are also destroyed. +void gfx_destroy_node(SceneNode**); + +// ----------------------------------------------------------------------------- +// Getters. +// ----------------------------------------------------------------------------- + +/// Get the node's type. +NodeType gfx_get_node_type(const SceneNode*); + +/// Get the node's anima. +/// +/// The node must be of type AnimaNode. +const Anima* gfx_get_node_anima(const SceneNode*); +Anima* gfx_get_node_anima_mut(SceneNode*); + +/// Get the node's camera. +/// +/// The node must be of type CameraNode. +const SceneCamera* gfx_get_node_camera(const SceneNode* node); +SceneCamera* gfx_get_node_camera_mut(SceneNode* node); + +/// Get the node's light. +/// +/// The node must be of type LightNode. +const Light* gfx_get_node_light(const SceneNode*); +Light* gfx_get_node_light_mut(SceneNode*); + +/// Get the node's model. +/// +/// The node must be of type ModelNode. +const Model* gfx_get_node_model(const SceneNode*); +Model* gfx_get_node_model_mut(SceneNode*); + +/// Get the node's scene object. +/// +/// The node must be of type ObjectNode. +const SceneObject* gfx_get_node_object(const SceneNode*); +SceneObject* gfx_get_node_object_mut(SceneNode*); + +/// Get the node's parent. +const SceneNode* gfx_get_node_parent(const SceneNode*); +SceneNode* gfx_get_node_parent_mut(SceneNode*); + +/// Get the node's first child. +const SceneNode* gfx_get_node_child(const SceneNode*); +SceneNode* gfx_get_node_child_mut(SceneNode*); + +/// Get the node's immediate sibling. +const SceneNode* gfx_get_node_sibling(const SceneNode*); +SceneNode* gfx_get_node_sibling_mut(SceneNode*); + +/// Get the node's (local) transform. +mat4 gfx_get_node_transform(const SceneNode*); + +/// Get the node's global transform. +mat4 gfx_get_node_global_transform(const SceneNode*); + +// ----------------------------------------------------------------------------- +// Setters. +// ----------------------------------------------------------------------------- + +/// Set the node's parent. +/// +/// Pass in null to unwire from the existing parent, if one exists. +void gfx_set_node_parent(SceneNode*, SceneNode* parent_node); + +/// Set the node's (local) transform. +void gfx_set_node_transform(SceneNode*, const mat4* transform); + +/// Set the node's position. +void gfx_set_node_position(SceneNode*, const vec3* position); + +/// Set the node's rotation. +void gfx_set_node_rotation(SceneNode*, const quat* rotation); + +/// Set the node's rotation. +void gfx_set_node_rotation_mat(SceneNode*, const mat4* rotation); + +/// Log the node's hierarchy. +void gfx_log_node_hierarchy(const SceneNode*); diff --git a/include/gfx/scene/object.h b/include/gfx/scene/object.h new file mode 100644 index 0000000..7579d29 --- /dev/null +++ b/include/gfx/scene/object.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +#include + +typedef struct Mesh Mesh; +typedef struct SceneNode SceneNode; +typedef struct Skeleton Skeleton; + +typedef struct SceneObject SceneObject; + +typedef struct ObjectDesc { + size_t num_meshes; + Mesh* meshes[GFX_MAX_NUM_MESHES]; +} ObjectDesc; + +/// Create a new object. +SceneObject* gfx_make_object(const ObjectDesc*); + +/// Destroy the object. +/// +/// The object is conveniently removed from the scene graph and its parent scene +/// node is destroyed. +void gfx_destroy_object(SceneObject**); + +/// Set the object's skeleton. +void gfx_set_object_skeleton(SceneObject*, const Skeleton*); + +/// Get the object's skeleton. +/// Return null if the object has no skeleton. +const Skeleton* gfx_get_object_skeleton(const SceneObject*); + +/// Gets the object's bounding box. +/// +/// The object's bounding box is the bounding box of its mesh geometries. +aabb3 gfx_get_object_aabb(const SceneObject*); diff --git a/include/gfx/scene/scene.h b/include/gfx/scene/scene.h new file mode 100644 index 0000000..0d96210 --- /dev/null +++ b/include/gfx/scene/scene.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +typedef struct SceneNode SceneNode; + +typedef struct Scene Scene; + +/// Create a new scene. +Scene* gfx_make_scene(void); + +/// Destroy the scene. +/// +/// This function destroys the scene and all objects that it owns (scene +/// objects, cameras, lights, etc), but not objects that could be shared with +/// other scenes (meshes, materials, etc). +void gfx_destroy_scene(Scene**); + +/// Get the scene's root node. +SceneNode* gfx_get_scene_root(Scene*); diff --git a/include/gfx/sizes.h b/include/gfx/sizes.h new file mode 100644 index 0000000..076113c --- /dev/null +++ b/include/gfx/sizes.h @@ -0,0 +1,95 @@ +/// Size constants used throughout the library. +#pragma once + +// Scene. + +/// Maximum number of cameras per scene. +#define GFX_MAX_NUM_CAMERAS 16 + +/// Maximum number of lights. +#define GFX_MAX_NUM_LIGHTS 1024 + +/// Maximum number of materials. +#define GFX_MAX_NUM_MATERIALS 1024 + +/// Maximum number of meshes. +#define GFX_MAX_NUM_MESHES 1024 + +/// Maximum number of mesh links. +#define GFX_MAX_NUM_MESH_LINKS 1024 + +/// Maximum number of models. +#define GFX_MAX_NUM_MODELS 64 + +/// Maximum number of joints per skeleton. +#define GFX_MAX_NUM_JOINTS 96 + +/// Maximum number of keyframes per channel. +#define GFX_MAX_NUM_KEYFRAMES 32 + +/// Maximum number of channels per animation. +#define GFX_MAX_NUM_CHANNELS 128 + +/// Maximum number of skeletons. +#define GFX_MAX_NUM_SKELETONS 128 + +/// Maximum number of animations. +#define GFX_MAX_NUM_ANIMATIONS 128 + +/// Maximum number of animas. +#define GFX_MAX_NUM_ANIMAS 128 + +/// Maximum number of nodes per scene. +#define GFX_MAX_NUM_NODES 1024 + +/// Maximum number of objects per scene. +#define GFX_MAX_NUM_OBJECTS 1024 + +/// Maximum number of uniforms in a Material. +#define GFX_MAX_UNIFORMS_PER_MATERIAL 18 + +// Render. + +/// Maximum number of buffers per renderer. +#define GFX_MAX_NUM_BUFFERS 1024 + +/// Maximum number of framebuffers per renderer. +#define GFX_MAX_NUM_FRAMEBUFFERS 32 + +/// Maximum number of geometries per renderer. +#define GFX_MAX_NUM_GEOMETRIES 1024 + +/// Maximum number of renderbuffers per renderer. +#define GFX_MAX_NUM_RENDERBUFFERS (GFX_MAX_NUM_FRAMEBUFFERS * 2) + +/// Maximum number of shader programs per renderer. +#define GFX_MAX_NUM_SHADER_PROGRAMS 128 + +/// Maximum number of shaders per renderer. +#define GFX_MAX_NUM_SHADERS (GFX_MAX_NUM_SHADER_PROGRAMS * 2) + +/// Maximum number of textures per renderer. +#define GFX_MAX_NUM_TEXTURES 1024 + +/// Maximum number of uniforms in a ShaderProgram. +#define GFX_MAX_UNIFORMS_PER_SHADER (GFX_MAX_UNIFORMS_PER_MATERIAL + 8) + +/// Maximum number of compiler defines in a Shader. +#define GFX_MAX_SHADER_COMPILER_DEFINES 16 + +// Renderer. + +/// Maximum number of triangles that the immediate-mode renderer can draw in a +/// frame. +#define IMM_MAX_NUM_TRIANGLES 1024 + +/// Maximum number of matrices in the immediate-mode renderer's matrix stack. +#define IMM_MAX_NUM_MATRICES 32 + +// Asset Manager. + +#define GFX_MAX_NUM_ASSETS 1024 + +// Gfx. + +#define GFX_MAX_NUM_SCENES 4 diff --git a/include/gfx/util/geometry.h b/include/gfx/util/geometry.h new file mode 100644 index 0000000..a962291 --- /dev/null +++ b/include/gfx/util/geometry.h @@ -0,0 +1,13 @@ +/// Functions to construct geometry procedurally. +#pragma once + +#include + +#include +#include + +/// Construct a quad with positions in the range [-1, 1]^2. +Geometry* gfx_make_quad_11(GfxCore*); + +/// Construct a quad with positions in the range [0, 1]^2. +Geometry* gfx_make_quad_01(GfxCore*); diff --git a/include/gfx/util/ibl.h b/include/gfx/util/ibl.h new file mode 100644 index 0000000..6e39180 --- /dev/null +++ b/include/gfx/util/ibl.h @@ -0,0 +1,25 @@ +/// Functions for image-based lighting. +#pragma once + +typedef struct IBL IBL; + +typedef struct GfxCore GfxCore; +typedef struct Texture Texture; + +/// Create an environment map filterer for IBL. +IBL* gfx_make_ibl(GfxCore*); + +/// Destroy the environment map filterer. +void gfx_destroy_ibl(GfxCore*, IBL**); + +/// Create a BRDF integration map for IBL. +Texture* gfx_make_brdf_integration_map(IBL*, GfxCore*, int width, int height); + +/// Create an irradiance map (cubemap) from an environment map for IBL. +Texture* gfx_make_irradiance_map( + IBL*, GfxCore*, const Texture* environment_map, int width, int height); + +/// Create a prefiltered environment map (cubemap) for IBL. +Texture* gfx_make_prefiltered_environment_map( + IBL*, GfxCore*, const Texture* environment_map, int width, int height, + int* max_mip_level); diff --git a/include/gfx/util/shader.h b/include/gfx/util/shader.h new file mode 100644 index 0000000..bd058f4 --- /dev/null +++ b/include/gfx/util/shader.h @@ -0,0 +1,46 @@ +/// A variety of shaders included for convenience. +#pragma once + +#include + +typedef struct GfxCore GfxCore; +typedef struct ShaderCompilerDefine ShaderCompilerDefine; +typedef struct ShaderProgram ShaderProgram; + +/// Create a BRDF integration map shader. +ShaderProgram* gfx_make_brdf_integration_map_shader(GfxCore*); + +/// Create a Cook-Torrance shader. +ShaderProgram* gfx_make_cook_torrance_shader(GfxCore*); + +/// Create a Cook-Torrance shader with additional shader compiler defines. +/// This function can be used to create shader permutations. +ShaderProgram* gfx_make_cook_torrance_shader_perm( + GfxCore*, const ShaderCompilerDefine*, size_t num_defines); + +/// Create a 3D debugging shader. +ShaderProgram* gfx_make_debug3d_shader(GfxCore*); + +/// Create a shader for drawing in immediate mode. +ShaderProgram* gfx_make_immediate_mode_shader(GfxCore*); + +/// Create a shader for computing irradiance maps from cube maps. +ShaderProgram* gfx_make_irradiance_map_shader(GfxCore*); + +/// Create a shader for computing prefiltered environment maps from cube maps. +ShaderProgram* gfx_make_prefiltered_environment_map_shader(GfxCore*); + +/// Create a skyquad shader. +ShaderProgram* gfx_make_skyquad_shader(GfxCore*); + +/// Create a shader to view normal-mapped normals. +ShaderProgram* gfx_make_view_normal_mapped_normals_shader(GfxCore*); + +/// Create a shader to view vertex normals. +ShaderProgram* gfx_make_view_normals_shader(GfxCore*); + +/// Create a shader to view vertex tangents. +ShaderProgram* gfx_make_view_tangents_shader(GfxCore*); + +/// Create a shader to view textures. +ShaderProgram* gfx_make_view_texture_shader(GfxCore*); diff --git a/include/gfx/util/skyquad.h b/include/gfx/util/skyquad.h new file mode 100644 index 0000000..2b3fe17 --- /dev/null +++ b/include/gfx/util/skyquad.h @@ -0,0 +1,22 @@ +/// A skyquad is like a skybox but with a single quad. +#pragma once + +typedef struct GfxCore GfxCore; +typedef struct Scene Scene; +typedef struct SceneNode SceneNode; +typedef struct SceneObject SceneObject; +typedef struct Texture Texture; + +/// Create a skyquad. +SceneObject* gfx_make_skyquad(GfxCore*, const Texture*); + +/// Set up a skyquad in the scene. +/// +/// This function adds two scene nodes under the given root node: +/// - An object node to render the skyquad in the background. +/// - A light node to light up other objects with the skyquad. +/// +/// Return the light node under which objects affected by the light can be +/// rooted. +SceneNode* gfx_setup_skyquad( + GfxCore*, SceneNode* root, const Texture* environment_map); -- cgit v1.2.3