About to start shaders
This commit is contained in:
15
src/duskgl/display/shader/CMakeLists.txt
Normal file
15
src/duskgl/display/shader/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
shadermanager.c
|
||||
shader.c
|
||||
shaderbuffer.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(entityshader)
|
14
src/duskgl/display/shader/entityshader/CMakeLists.txt
Normal file
14
src/duskgl/display/shader/entityshader/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Shaders
|
||||
glsltool(entity_vert.glsl)
|
||||
glsltool(entity_frag.glsl)
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
entityshader.c
|
||||
)
|
27
src/duskgl/display/shader/entityshader/entity.glsl
Normal file
27
src/duskgl/display/shader/entityshader/entity.glsl
Normal file
@ -0,0 +1,27 @@
|
||||
#include "../fragments/header.glsl"
|
||||
#include "../fragments/transforms.glsl"
|
||||
|
||||
#define ENTITY_TILE_OFFSET_X (MAP_TILE_WIDTH - ENTITY_WIDTH) / 2
|
||||
#define ENTITY_TILE_OFFSET_Y (MAP_TILE_HEIGHT - ENTITY_HEIGHT) / 2
|
||||
|
||||
struct Entity {
|
||||
int x;
|
||||
int y;
|
||||
int tileset;
|
||||
int tile;
|
||||
};
|
||||
|
||||
layout(std140) uniform b_Data {
|
||||
Entity entities[MAP_ENTITY_COUNT_MAX];
|
||||
int entityCount;
|
||||
};
|
||||
|
||||
vec4 entityGetCoordinates(Entity ent) {
|
||||
int vx = (ent.x * MAP_TILE_WIDTH) + ENTITY_TILE_OFFSET_X;
|
||||
int vy = (ent.y * MAP_TILE_HEIGHT) + ENTITY_TILE_OFFSET_Y;
|
||||
return vec4(vx, vy, vx + ENTITY_WIDTH, vy + ENTITY_HEIGHT);
|
||||
}
|
||||
|
||||
vec4 entityGetUVs(Entity ent) {
|
||||
return tilesetGetUVsByIndex(ent.tileset, ent.tile);
|
||||
}
|
18
src/duskgl/display/shader/entityshader/entity_frag.glsl
Normal file
18
src/duskgl/display/shader/entityshader/entity_frag.glsl
Normal file
@ -0,0 +1,18 @@
|
||||
#include "entity.glsl"
|
||||
|
||||
in vec2 v_TextureCoord;
|
||||
flat in int v_Entity;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
Entity e = entities[v_Entity];
|
||||
vec4 textureColor = tilesetGetColor(e.tileset, v_TextureCoord);
|
||||
|
||||
// We remove the pink color as transparent
|
||||
if(textureColor.r == 1.0 && textureColor.g == 0.0 && textureColor.b == 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
FragColor = textureColor;
|
||||
}
|
35
src/duskgl/display/shader/entityshader/entity_vert.glsl
Normal file
35
src/duskgl/display/shader/entityshader/entity_vert.glsl
Normal file
@ -0,0 +1,35 @@
|
||||
#include "entity.glsl"
|
||||
|
||||
// Outputs to fragment shader
|
||||
out vec2 v_TextureCoord;
|
||||
flat out int v_Entity;
|
||||
|
||||
void main() {
|
||||
int entityIndex = gl_InstanceID;
|
||||
int indiceIndex = gl_VertexID % 6;
|
||||
|
||||
Entity entity = entities[entityIndex];
|
||||
|
||||
vec4 quadPos = entityGetCoordinates(entity);
|
||||
vec4 quadUVs = entityGetUVs(entity);
|
||||
|
||||
vec2 vertex;
|
||||
vec2 uv;
|
||||
if(indiceIndex == 0 || indiceIndex == 4) {
|
||||
vertex = quadPos.xy;
|
||||
uv = quadUVs.xy;
|
||||
} else if(indiceIndex == 1) {
|
||||
vertex = quadPos.zy;
|
||||
uv = quadUVs.zy;
|
||||
} else if(indiceIndex == 2 || indiceIndex == 5) {
|
||||
vertex = quadPos.zw;
|
||||
uv = quadUVs.zw;
|
||||
} else if(indiceIndex == 3) {
|
||||
vertex = quadPos.xw;
|
||||
uv = quadUVs.xw;
|
||||
}
|
||||
|
||||
gl_Position = transforms.projection * transforms.view * vec4(vertex, 0.0, 1.0);
|
||||
v_TextureCoord = uv;
|
||||
v_Entity = entityIndex;
|
||||
}
|
32
src/duskgl/display/shader/entityshader/entityshader.c
Normal file
32
src/duskgl/display/shader/entityshader/entityshader.c
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assert.h"
|
||||
#include "assert/assertgl.h"
|
||||
#include "entityshader.h"
|
||||
#include "entity_vert.glsl.h"
|
||||
#include "entity_frag.glsl.h"
|
||||
|
||||
entityshader_t ENTITY_SHADER;
|
||||
|
||||
void entityShaderInit() {
|
||||
memset(&ENTITY_SHADER, 0, sizeof(entityshader_t));
|
||||
|
||||
shaderInit(
|
||||
&ENTITY_SHADER.shader,
|
||||
entity_vertShaderSource,
|
||||
entity_fragShaderSource
|
||||
);
|
||||
|
||||
// Uniform buffers
|
||||
|
||||
// Uniforms
|
||||
}
|
||||
|
||||
void entityShaderDispose() {
|
||||
shaderDispose(&ENTITY_SHADER.shader);
|
||||
}
|
31
src/duskgl/display/shader/entityshader/entityshader.h
Normal file
31
src/duskgl/display/shader/entityshader/entityshader.h
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "display/shader/shader.h"
|
||||
|
||||
typedef struct {
|
||||
shader_t shader;
|
||||
|
||||
// GLuint dataBlock;
|
||||
// GLuint transformsBlock;
|
||||
// GLuint tilesetsBlock;
|
||||
|
||||
// GLuint uniformTilesetTextures;
|
||||
} entityshader_t;
|
||||
|
||||
extern entityshader_t ENTITY_SHADER;
|
||||
|
||||
/**
|
||||
* Initializes the entity shader.
|
||||
*/
|
||||
void entityShaderInit();
|
||||
|
||||
/**
|
||||
* Disposes of the entity shader.
|
||||
*/
|
||||
void entityShaderDispose();
|
6
src/duskgl/display/shader/fragments/header.glsl
Normal file
6
src/duskgl/display/shader/fragments/header.glsl
Normal file
@ -0,0 +1,6 @@
|
||||
#version 330 core
|
||||
|
||||
// Copyright (c) 2025 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
25
src/duskgl/display/shader/fragments/quad.glsl
Normal file
25
src/duskgl/display/shader/fragments/quad.glsl
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2025 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
vec2 quadGetVertice(uint indiceIndex) {
|
||||
vec2 vert = vec2(0, 0);
|
||||
|
||||
if(indiceIndex == 0u || indiceIndex == 4u) {
|
||||
// vert = vec2(0, 0);
|
||||
} else if(indiceIndex == 1u) {
|
||||
vert = vec2(1, 0);
|
||||
} else if(indiceIndex == 2u || indiceIndex == 5u) {
|
||||
vert = vec2(1, 1);
|
||||
} else if(indiceIndex == 3u) {
|
||||
vert = vec2(0, 1);
|
||||
}
|
||||
|
||||
return vert;
|
||||
}
|
||||
|
||||
vec2 quadGetTextureCoordinate(uint indiceIndex) {
|
||||
vec2 vert = quadGetVertice(indiceIndex);
|
||||
return vert;
|
||||
}
|
32
src/duskgl/display/shader/fragments/transforms.glsl
Normal file
32
src/duskgl/display/shader/fragments/transforms.glsl
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2025 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "../../../../dusk/display/displaydefs.h"
|
||||
|
||||
struct Transform {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
vec2 resolution;
|
||||
};
|
||||
|
||||
layout(std140) uniform b_Transforms {
|
||||
Transform transforms;
|
||||
};
|
||||
|
||||
vec2 transformDisplayGetSize() {
|
||||
return vec2(DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
||||
}
|
||||
|
||||
float transformDisplayGetAspectRatio() {
|
||||
return (float(DISPLAY_WIDTH) / float(DISPLAY_HEIGHT));
|
||||
}
|
||||
|
||||
vec2 transformResolutionGetSize() {
|
||||
return transforms.resolution;
|
||||
}
|
||||
|
||||
float transformResolutionGetAspectRatio() {
|
||||
return (transforms.resolution.x / transforms.resolution.y);
|
||||
}
|
134
src/duskgl/display/shader/shader.c
Normal file
134
src/duskgl/display/shader/shader.c
Normal file
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "shader.h"
|
||||
#include "assert/assert.h"
|
||||
#include "assert/assertgl.h"
|
||||
|
||||
void shaderInit(
|
||||
shader_t *shader,
|
||||
const char *vertexSource,
|
||||
const char *fragmentSource
|
||||
) {
|
||||
assertNotNull(shader, "shader must not be NULL");
|
||||
assertNotNull(vertexSource, "vertexSource must not be NULL");
|
||||
assertNotNull(fragmentSource, "fragmentSource must not be NULL");
|
||||
|
||||
int32_t success;
|
||||
char infoLog[SHADER_LOG_LENGTH];
|
||||
|
||||
// Create vertex shader
|
||||
shader->vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
assertNoGLError();
|
||||
|
||||
glShaderSource(shader->vertexShader, 1, &vertexSource, NULL);
|
||||
assertNoGLError();
|
||||
|
||||
glCompileShader(shader->vertexShader);
|
||||
assertNoGLError();
|
||||
|
||||
glGetShaderiv(shader->vertexShader, GL_COMPILE_STATUS, &success);
|
||||
assertNoGLError();
|
||||
|
||||
if(!success) {
|
||||
glGetShaderInfoLog(
|
||||
shader->vertexShader, SHADER_LOG_LENGTH, NULL, infoLog
|
||||
);
|
||||
assertNoGLError();
|
||||
assertUnreachable(infoLog);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create fragment shader
|
||||
shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
assertNoGLError();
|
||||
|
||||
glShaderSource(shader->fragmentShader, 1, &fragmentSource, NULL);
|
||||
assertNoGLError();
|
||||
|
||||
glCompileShader(shader->fragmentShader);
|
||||
assertNoGLError();
|
||||
|
||||
glGetShaderiv(shader->fragmentShader, GL_COMPILE_STATUS, &success);
|
||||
assertNoGLError();
|
||||
|
||||
if(!success) {
|
||||
glGetShaderInfoLog(
|
||||
shader->fragmentShader, SHADER_LOG_LENGTH, NULL, infoLog
|
||||
);
|
||||
assertNoGLError();
|
||||
assertUnreachable(infoLog);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create shader program
|
||||
shader->shaderProgram = glCreateProgram();
|
||||
assertNoGLError();
|
||||
|
||||
glAttachShader(shader->shaderProgram, shader->vertexShader);
|
||||
assertNoGLError();
|
||||
|
||||
glAttachShader(shader->shaderProgram, shader->fragmentShader);
|
||||
assertNoGLError();
|
||||
|
||||
glLinkProgram(shader->shaderProgram);
|
||||
assertNoGLError();
|
||||
|
||||
glGetProgramiv(shader->shaderProgram, GL_LINK_STATUS, &success);
|
||||
assertNoGLError();
|
||||
|
||||
if(!success) {
|
||||
glGetProgramInfoLog(shader->shaderProgram, SHADER_LOG_LENGTH, NULL, infoLog);
|
||||
assertNoGLError();
|
||||
assertUnreachable(infoLog);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void shaderUse(const shader_t *shader) {
|
||||
assertNotNull(shader, "shader must not be NULL");
|
||||
|
||||
glUseProgram(shader->shaderProgram);
|
||||
assertNoGLError();
|
||||
}
|
||||
|
||||
GLuint shaderGetUniform(const shader_t *shader, const char_t *name) {
|
||||
assertNotNull(shader, "shader must not be NULL");
|
||||
assertNotNull(name, "name must not be NULL");
|
||||
|
||||
GLuint uniform = glGetUniformLocation(shader->shaderProgram, name);
|
||||
assertNoGLError();
|
||||
|
||||
return uniform;
|
||||
}
|
||||
|
||||
GLuint shaderGetBlock(const shader_t *shader, const char *name) {
|
||||
assertNotNull(shader, "shader must not be NULL");
|
||||
assertNotNull(name, "name must not be NULL");
|
||||
|
||||
GLuint blockIndex = glGetUniformBlockIndex(shader->shaderProgram, name);
|
||||
assertNoGLError();
|
||||
|
||||
// TODO: I really don't think this should be here at all.
|
||||
glUniformBlockBinding(shader->shaderProgram, blockIndex, blockIndex);
|
||||
assertNoGLError();
|
||||
|
||||
return blockIndex;
|
||||
}
|
||||
|
||||
void shaderDispose(shader_t *shader) {
|
||||
assertNotNull(shader, "shader must not be NULL");
|
||||
|
||||
glDeleteProgram(shader->shaderProgram);
|
||||
assertNoGLError();
|
||||
|
||||
glDeleteShader(shader->vertexShader);
|
||||
assertNoGLError();
|
||||
|
||||
glDeleteShader(shader->fragmentShader);
|
||||
assertNoGLError();
|
||||
}
|
62
src/duskgl/display/shader/shader.h
Normal file
62
src/duskgl/display/shader/shader.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskgl.h"
|
||||
|
||||
#define SHADER_LOG_LENGTH 512
|
||||
|
||||
typedef struct {
|
||||
GLuint shaderProgram;
|
||||
GLuint vertexShader;
|
||||
GLuint fragmentShader;
|
||||
} shader_t;
|
||||
|
||||
/**
|
||||
* Initializes a shader.
|
||||
*
|
||||
* @param shader The shader to initialize.
|
||||
* @param vertexSource The vertex shader source.
|
||||
* @param fragmentSource The fragment shader source.
|
||||
*/
|
||||
void shaderInit(
|
||||
shader_t *shader,
|
||||
const char_t *vertexSource,
|
||||
const char_t *fragmentSource
|
||||
);
|
||||
|
||||
/**
|
||||
* Uses a shader.
|
||||
*
|
||||
* @param shader The shader to use.
|
||||
*/
|
||||
void shaderUse(const shader_t *shader);
|
||||
|
||||
/**
|
||||
* Gets a uniform from a shader.
|
||||
*
|
||||
* @param shader The shader to get the uniform from.
|
||||
* @param name The name of the uniform.
|
||||
* @return The uniform.
|
||||
*/
|
||||
GLuint shaderGetUniform(const shader_t *shader, const char_t *name);
|
||||
|
||||
/**
|
||||
* Gets a block id from a shader.
|
||||
*
|
||||
* @param shader The shader to get the block from.
|
||||
* @param name The name of the block.
|
||||
* @return The block index/identifier.
|
||||
*/
|
||||
GLuint shaderGetBlock(const shader_t *shader, const char_t *name);
|
||||
|
||||
/**
|
||||
* Disposes of a shader.
|
||||
*
|
||||
* @param shader The shader to dispose of.
|
||||
*/
|
||||
void shaderDispose(shader_t *shader);
|
55
src/duskgl/display/shader/shaderbuffer.c
Normal file
55
src/duskgl/display/shader/shaderbuffer.c
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assert.h"
|
||||
#include "shaderbuffer.h"
|
||||
#include "assert/assertgl.h"
|
||||
|
||||
void shaderBufferInit(shaderbuffer_t *shaderBuffer, const size_t size) {
|
||||
assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL.");
|
||||
assertTrue(size > 0, "size must be greater than 0.");
|
||||
|
||||
shaderBuffer->size = size;
|
||||
|
||||
glGenBuffers(1, &shaderBuffer->id);
|
||||
assertNoGLError();
|
||||
|
||||
shaderBufferBind(shaderBuffer);
|
||||
|
||||
glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
void shaderBufferBind(shaderbuffer_t *shaderBuffer) {
|
||||
assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL.");
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, shaderBuffer->id);
|
||||
assertNoGLError();
|
||||
}
|
||||
|
||||
void shaderBufferSetData(shaderbuffer_t *shaderBuffer, const void *data) {
|
||||
assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL.");
|
||||
assertNotNull(data, "data cannot be NULL.");
|
||||
|
||||
glBufferData(GL_UNIFORM_BUFFER, shaderBuffer->size, data, GL_STATIC_DRAW);
|
||||
assertNoGLError();
|
||||
}
|
||||
|
||||
void shaderBufferBindToBlock(
|
||||
shaderbuffer_t *shaderBuffer,
|
||||
const GLuint blockIndex
|
||||
) {
|
||||
assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL.");
|
||||
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, blockIndex, shaderBuffer->id);
|
||||
assertNoGLError();
|
||||
}
|
||||
|
||||
void shaderBufferDispose(shaderbuffer_t *shaderBuffer) {
|
||||
assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL.");
|
||||
glDeleteBuffers(1, &shaderBuffer->id);
|
||||
assertNoGLError();
|
||||
}
|
61
src/duskgl/display/shader/shaderbuffer.h
Normal file
61
src/duskgl/display/shader/shaderbuffer.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskgl.h"
|
||||
|
||||
typedef struct {
|
||||
GLuint id;
|
||||
size_t size;
|
||||
} shaderbuffer_t;
|
||||
|
||||
/**
|
||||
* Initializes a shader buffer.
|
||||
*
|
||||
* @param shaderBuffer The shader buffer to initialize.
|
||||
* @param size The size of the buffer.
|
||||
*/
|
||||
void shaderBufferInit(
|
||||
shaderbuffer_t *shaderBuffer,
|
||||
const size_t size
|
||||
);
|
||||
|
||||
/**
|
||||
* Binds a shader buffer.
|
||||
*
|
||||
* @param shaderBuffer The shader buffer to bind.
|
||||
*/
|
||||
void shaderBufferBind(shaderbuffer_t *shaderBuffer);
|
||||
|
||||
/**
|
||||
* Sets the data of a shader buffer.
|
||||
*
|
||||
* @param shaderBuffer The shader buffer to set the data of.
|
||||
* @param data The data to set.
|
||||
*/
|
||||
void shaderBufferSetData(
|
||||
shaderbuffer_t *shaderBuffer,
|
||||
const void *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Binds a shader buffer to a block.
|
||||
*
|
||||
* @param shaderBuffer The shader buffer to bind.
|
||||
* @param blockIndex The block index to bind to.
|
||||
*/
|
||||
void shaderBufferBindToBlock(
|
||||
shaderbuffer_t *shaderBuffer,
|
||||
const GLuint blockIndex
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes of a shader buffer.
|
||||
*
|
||||
* @param shaderBuffer The shader buffer to dispose of.
|
||||
*/
|
||||
void shaderBufferDispose(shaderbuffer_t *shaderBuffer);
|
16
src/duskgl/display/shader/shadermanager.c
Normal file
16
src/duskgl/display/shader/shadermanager.c
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "shadermanager.h"
|
||||
|
||||
void shaderManagerInit() {
|
||||
|
||||
}
|
||||
|
||||
void shaderManagerDispose() {
|
||||
|
||||
}
|
23
src/duskgl/display/shader/shadermanager.h
Normal file
23
src/duskgl/display/shader/shadermanager.h
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskgl.h"
|
||||
|
||||
// typedef struct {
|
||||
|
||||
// } shadermanager_t;
|
||||
|
||||
/**
|
||||
* Initializes the Shader Manager
|
||||
*/
|
||||
void shaderManagerInit();
|
||||
|
||||
/**
|
||||
* Disposes of the Shader Manager
|
||||
*/
|
||||
void shaderManagerDispose();
|
Reference in New Issue
Block a user