You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
8.7 KiB
283 lines
8.7 KiB
/* |
|
* libTangerine, a small, modern openGL renderer specializing in flat shaded, |
|
* solid color models using pallete textures. See README for build instructions |
|
* and look in the examples folder for... examples |
|
*/ |
|
|
|
/* |
|
* === TODO: === |
|
* - try to improve the setup interface for examples |
|
* see if we can remove some boilerplate with more helpers, or |
|
* re-organizing |
|
* - add orbit function to camera, see orbitPositionZ0 in example |
|
* maybe implement with quaternion, so we can set arbitrary orbit axis |
|
* - update camera interal state and rotations to use quaternions |
|
* - add scene abstrastion for RenderState |
|
* - add an example of dynamically switching shaders for an entity |
|
* - fix debug load times (either by using cgltf, or hiding tinygltf.h) |
|
* - RenderGroups and Entities need to come into and out of existence during |
|
* gameplay. So, we need to extend MemoryArena to be a pool allocator |
|
* instead of an allocate only linear allocator |
|
* - resizable arrays for entities and asset system (^ see above) |
|
* - add libTangerine namespace? |
|
* - make a test case for overflowing default array sizes, rg->assets |
|
* rg_info->groups, render_group->enitities, rg->textures |
|
* - test for video memory leaking since we're not actually deleting GLBuffers |
|
* anywhere |
|
* - look for glm::mat4 in structs, and replace with pointers (easier debugging) |
|
* - defaults include for various #defines |
|
* - make separate shaders for per vertex, and per pixel/fragment lighting |
|
* see red book chapter 7 |
|
* - add a bloom/blur render to texture shader for light sources? |
|
* https://learnopengl.com/Advanced-Lighting/Bloom |
|
* |
|
* === TODONE: === |
|
* - don't allocate Asset structure on asset arena |
|
* - store on RenderState as reference |
|
* - store asset arena to asset structure |
|
* - condense get_X_ByPath functions with assetLoad functions |
|
* - move to asset interface |
|
* - load diffuse texture automatically when loading a model |
|
* - move entity structure and functions to new file? |
|
* - load diffuse texture into OpenGL, and store GLTexture structure onto |
|
* GLContext |
|
* - need a cache algorithm starting in initEntity() |
|
* - check for GLTexture by path hash |
|
* - load texture into gl if not cached |
|
* - pass result GLTexture to loadGLMesh() |
|
* - update loadScene function with textured models, and test texture loading |
|
* - work on cleaner interface for initEntity and loadScene... |
|
* - add a LOGF macro for printf style logging |
|
* - replace instances of printf |
|
* - rename data structures to be in the new format, eg) UpperCaseStyleNames |
|
* - rename instances of 'model_xform' that refer to a mesh node to something |
|
* like node_xform. model_xform should be reserved for the entity node |
|
* - move default shaders out of git-lfs |
|
* - full lighting model |
|
* - add buffer backed storage for light arrays in GLSL |
|
* - remove hard-coded values in full_lighting.frag |
|
* - test buffer backed lights, probably need to pad any scalars/vec3s |
|
* - add point light type with tweakable attenuation parameters |
|
* - test complex entities |
|
* - need a separate GLBufferToAttribMapping for each mesh on an entity |
|
* - maybe fixed now with MeshBufferType enum and getMeshData() |
|
* - allow entities to have an empty diffuse texture (see initEntity()) |
|
* - use dynamic shader parsing to set 'sampler_id' for shaders with textures |
|
* - add ambient light to LightsBuffer structure |
|
* - remember to update offsets in initLights() |
|
* - use rg_arena for store GLMeshes, see initGLMesh() |
|
* - merge back into libTangerine |
|
* - merge render_group_fix branch back into master |
|
*/ |
|
|
|
|
|
#pragma once |
|
|
|
#include <SDL2/SDL.h> |
|
|
|
#include "asset.h" |
|
#include "camera.h" |
|
#include "entity.h" |
|
#include "dumbLog.h" |
|
#include "GLDebug.h" |
|
#include "shader.h" |
|
#include "types.h" |
|
#include "util.h" |
|
|
|
|
|
struct SDLHandles |
|
{ |
|
SDL_Window* window; |
|
SDL_GLContext sdl_gl_ctx; |
|
SDL_DisplayMode display_mode; |
|
}; |
|
|
|
// TODO: node/tree structure for entities |
|
struct Node; |
|
|
|
struct RenderGroup |
|
{ |
|
ShaderProgram* shader; |
|
u32 num_entities; |
|
u32 max_entities; |
|
Entity* entities; |
|
char* name; |
|
}; |
|
|
|
#if 0 |
|
struct Scene |
|
{ |
|
MemoryArena* rg_arena; |
|
u32 num_render_groups; |
|
u32 max_render_groups; |
|
RenderGroup* render_groups; |
|
|
|
u32 num_point_lights; |
|
u32 max_point_lights; |
|
PointLight* p_lights; |
|
|
|
u32 num_d_lights; |
|
u32 max_d_lights; |
|
DirectionalLight* d_lights; |
|
|
|
u32 num_spot_lights; |
|
u32 max_spot_lights; |
|
SpotLight* s_lights; |
|
|
|
Node root_node; |
|
|
|
Camera cam; |
|
}; |
|
#endif |
|
|
|
struct GLClearColor |
|
{ |
|
GLfloat R; |
|
GLfloat G; |
|
GLfloat B; |
|
GLfloat A; |
|
}; |
|
|
|
// NOTE: structure to match the layout of the 'lights' uniform in a shader |
|
// all the pointers are pointers into the address space of 'buffer'. the vec4 |
|
// pointers are required to start on 16 byte boundaries as per layout std140, |
|
// so there may be some padding added between the 'header', and the start of |
|
// the arrays |
|
// NOTE: this is also very fragile. Since c/c++ doesn't support reflection, we |
|
// need to manually update 'initLights()' if we ever update this structure. |
|
// And remember to update the 'padding' if the number of 'header' attributes |
|
// change |
|
struct LightsBuffer |
|
{ |
|
u32 buf_size; |
|
u32* max_p_lights; |
|
u32* active_p_lights; |
|
u32* max_d_lights; |
|
u32* active_d_lights; |
|
|
|
vec4* ambient_color; |
|
|
|
vec4* pl_positions; |
|
vec4* pl_colors; |
|
uvec4* pl_intensities; |
|
|
|
vec4* dl_directions; |
|
vec4* dl_colors; |
|
uvec4* dl_intensities; |
|
|
|
void* buffer; |
|
}; |
|
|
|
struct RenderState |
|
{ |
|
bool running; |
|
GLClearColor clear_col; |
|
SDLHandles handles; |
|
GLContext* gl_ctx; |
|
Assets assets; |
|
|
|
MemoryArena* rg_arena; |
|
u32 num_render_groups; |
|
u32 max_render_groups; |
|
RenderGroup* render_groups; |
|
|
|
// TODO: should we have a 'scene' abstraction here? |
|
// could have render groups, lights, camera |
|
// could match up with gltf scene graph where everyting is part of a node |
|
LightsBuffer* lights_buf; |
|
Camera* camera; |
|
}; |
|
|
|
|
|
#define DEFAULT_WIDTH 1280 |
|
#define DEFAULT_HEIGHT 720 |
|
#define DEFAULT_MODEL_COUNT 256 |
|
#define DEFAULT_TEXTURE_COUNT 64 |
|
#define DEFAULT_SHADER_COUNT 64 |
|
#define DEFAULT_UBO_COUNT 32 |
|
#define DEFAULT_RENDER_GROUP_COUNT 256 |
|
#define DEFAULT_CLEAR_COLOR { 0.2, 0.2, 0.2, 1 } |
|
#define DEFAULT_AMBIENT_COLOR { 0.1, 0.1, 0.1, 1 } |
|
#define DEFAULT_MAX_LIGHTS 32 // NOTE: needs to match NUM_LIGHTS in shaders |
|
RenderState* initRenderState(const char* window_title = "tangerine", |
|
uvec2 window_dims = uvec2(DEFAULT_WIDTH, DEFAULT_HEIGHT), |
|
GLClearColor clear_col = DEFAULT_CLEAR_COLOR, |
|
vec4 ambient_color = DEFAULT_AMBIENT_COLOR, |
|
u32 max_models = DEFAULT_MODEL_COUNT, |
|
u32 max_textures = DEFAULT_TEXTURE_COUNT, |
|
u32 max_shaders = DEFAULT_SHADER_COUNT, |
|
u32 max_render_groups = DEFAULT_RENDER_GROUP_COUNT, |
|
u32 max_ubos = DEFAULT_UBO_COUNT, |
|
u32 max_lights = DEFAULT_MAX_LIGHTS); |
|
|
|
void freeRenderState(RenderState*& rs); |
|
|
|
#define DEFAULT_ENTITY_COUNT 256 |
|
void initRenderGroup(RenderGroup* rg, |
|
MemoryArena* arena, |
|
ShaderProgram* shader, |
|
u32 num_entities = DEFAULT_ENTITY_COUNT, |
|
const char* name = ""); |
|
|
|
void freeRenderGroup(RenderGroup* rg, MemoryArena* arena); |
|
|
|
RenderGroup* getFreeRenderGroup(RenderState* rs); |
|
|
|
RenderGroup* getRenderGroupByName(RenderState* rs, const char* name); |
|
|
|
Entity* getFreeEntity(RenderGroup* rg); |
|
|
|
// NOTE: callback function signature to use with renDoRenderLoop() |
|
typedef void (*frame_callback_fn) (RenderState*); |
|
|
|
// NOTE: There are 2 callbacks to use here, cb_func_pre is called before |
|
// the call to renRenderFrame(), cb_fun_post is called after |
|
// NOTE: if you use cb_func_pre, you will have to use SDL_PollEvent() manually |
|
// and at minimum set rs->running = false on SDL_QUIT event |
|
void doRenderLoop(RenderState* rs, |
|
uint framerate = 60, |
|
frame_callback_fn cb_func_pre = nullptr, |
|
frame_callback_fn cb_func_post = nullptr); |
|
|
|
void renderFrame(RenderState* rs, const GLClearColor& clear_col); |
|
|
|
|
|
// NOTE: automatic loading of default shaders |
|
|
|
struct ShaderInit |
|
{ |
|
const char* name; |
|
const char* vert_path; |
|
const char* frag_path; |
|
}; |
|
|
|
#define SHADER_INIT_COUNT 4 |
|
#define TEXTURE_ONLY_SHADER_INIT { "texture_only", \ |
|
"../data/texture_only.vert", \ |
|
"../data/texture_only.frag" } |
|
#define FULL_LIGHTING_SHADER_INIT { "full_lighting", \ |
|
"../data/full_lighting.vert", \ |
|
"../data/full_lighting.frag" } |
|
#define DEBUG_SHADER_INIT { "debug", \ |
|
"../data/debug.vert", \ |
|
"../data/debug.frag", } |
|
#define COLORED_VERT_SHADER_INIT { "colored_vertices", \ |
|
"../data/colored_vertices.vert", \ |
|
"../data/colored_vertices.frag", } |
|
const ShaderInit SHADER_INIT_LIST[SHADER_INIT_COUNT] |
|
{ |
|
TEXTURE_ONLY_SHADER_INIT, |
|
FULL_LIGHTING_SHADER_INIT, |
|
DEBUG_SHADER_INIT, |
|
COLORED_VERT_SHADER_INIT |
|
}; |
|
|
|
bool loadDefaultShaders(RenderState* rs, |
|
u32 num_shaders = SHADER_INIT_COUNT, |
|
const ShaderInit shaders[] = SHADER_INIT_LIST); |
|
|
|
// NOTE: only useful if the shader attribute names match the names in the |
|
// default shaders. If loading a custom shader, this may not work as expected, |
|
// and you should use getVertexAttribByName instead |
|
GLVertexAttrib* getVertexAttribByType(ShaderProgram* shader, |
|
MeshBufferType buf_type);
|
|
|