feat: implemented default shader
This commit is contained in:
parent
fdc92c8c20
commit
a0be00407f
20
resources/default_shader.fs
Normal file
20
resources/default_shader.fs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec2 fragTexCoord; // texture coordinate
|
||||||
|
in vec3 fragNormal; // normal direction
|
||||||
|
|
||||||
|
uniform sampler2D texture0;
|
||||||
|
uniform vec4 colDiffuse;
|
||||||
|
|
||||||
|
out vec4 finalColor;
|
||||||
|
|
||||||
|
uniform vec3 lightDirection; // direction of light
|
||||||
|
uniform vec4 ambient;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||||
|
vec3 light_dot = vec3(pow(dot(fragNormal, lightDirection)-0.2, 3.0));
|
||||||
|
finalColor = texelColor * colDiffuse * vec4(light_dot, 1.0);
|
||||||
|
finalColor += texelColor * (ambient/10.0) * colDiffuse;
|
||||||
|
finalColor = pow(finalColor, vec4(vec3(0.6), 1.0));
|
||||||
|
}
|
25
resources/default_shader.vs
Normal file
25
resources/default_shader.vs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// Input vertex attributes
|
||||||
|
in vec3 vertexPosition;
|
||||||
|
in vec2 vertexTexCoord;
|
||||||
|
in vec3 vertexNormal;
|
||||||
|
in vec4 vertexColor;
|
||||||
|
|
||||||
|
// Input uniform values
|
||||||
|
uniform mat4 mvp;
|
||||||
|
uniform mat4 matModel;
|
||||||
|
|
||||||
|
// Output vertex attributes (to fragment shader)
|
||||||
|
out vec2 fragTexCoord;
|
||||||
|
out vec3 fragNormal;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Send vertex attributes to fragment shader
|
||||||
|
fragTexCoord = vertexTexCoord;
|
||||||
|
fragNormal = normalize(vec3(matModel * vec4(vertexNormal, 1.0)));
|
||||||
|
|
||||||
|
// Calculate final vertex position
|
||||||
|
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 496 B |
|
@ -25,6 +25,7 @@ impl_Renderable_for(MeshRenderEntity,
|
||||||
SceneNode *CreateMeshRenderEntity(char const *resource_path) {
|
SceneNode *CreateMeshRenderEntity(char const *resource_path) {
|
||||||
MeshRenderEntity *self = new(MeshRenderEntity);
|
MeshRenderEntity *self = new(MeshRenderEntity);
|
||||||
GetModelResource(resource_path, &self->model);
|
GetModelResource(resource_path, &self->model);
|
||||||
|
GetShaderResource("default_shader", &self->shader);
|
||||||
return CreateSceneNode(MeshRenderEntity_as_SceneNodeEntity(self));
|
return CreateSceneNode(MeshRenderEntity_as_SceneNodeEntity(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,15 +37,24 @@ void MeshRenderEntityEnterTree(MeshRenderEntity *self) {
|
||||||
SceneNodeEntity parent_entity = self->node->parent->entity;
|
SceneNodeEntity parent_entity = self->node->parent->entity;
|
||||||
self->transform = TC_CAST(parent_entity, Transformable);
|
self->transform = TC_CAST(parent_entity, Transformable);
|
||||||
LoadResource(self->model.handle);
|
LoadResource(self->model.handle);
|
||||||
|
LoadResource(self->shader.handle);
|
||||||
|
Vector3 light_direction = Vector3Normalize((Vector3){1.f, 1.f, 0.f});
|
||||||
|
SetShaderValue(*self->shader.resource, GetShaderLocation(*self->shader.resource, "lightDirection"), &light_direction, SHADER_UNIFORM_VEC3);
|
||||||
|
SetShaderValue(*self->shader.resource, GetShaderLocation(*self->shader.resource, "ambient"), &BLACK, SHADER_UNIFORM_VEC4);
|
||||||
|
for(size_t i = 0; i < self->model.resource->materialCount; ++i)
|
||||||
|
self->model.resource->materials[i].shader = *self->shader.resource;
|
||||||
AddRenderable(MeshRenderEntity_as_Renderable(self));
|
AddRenderable(MeshRenderEntity_as_Renderable(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderEntityExitTree(MeshRenderEntity *self) {
|
void MeshRenderEntityExitTree(MeshRenderEntity *self) {
|
||||||
ReleaseResource(self->model.handle);
|
ReleaseResource(self->model.handle);
|
||||||
|
ReleaseResource(self->shader.handle);
|
||||||
RemoveRenderable(MeshRenderEntity_as_Renderable(self));
|
RemoveRenderable(MeshRenderEntity_as_Renderable(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderEntityDraw(MeshRenderEntity *self) {
|
void MeshRenderEntityDraw(MeshRenderEntity *self) {
|
||||||
self->model.resource->transform = TransformGetMatrix(self->transform.tc->get_global_transform(self->transform.data));
|
self->model.resource->transform = TransformGetMatrix(self->transform.tc->get_global_transform(self->transform.data));
|
||||||
DrawModel(*self->model.resource, (Vector3){0.f, 0.f, 0.f}, 1.f, WHITE);
|
BeginShaderMode(*self->shader.resource);
|
||||||
|
DrawModel(*self->model.resource, Vector3Zero(), 1.0f, WHITE);
|
||||||
|
EndShaderMode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ typedef struct MeshRenderEntity {
|
||||||
SceneNode *node;
|
SceneNode *node;
|
||||||
Transformable transform;
|
Transformable transform;
|
||||||
ModelResource model;
|
ModelResource model;
|
||||||
|
ShaderResource shader;
|
||||||
} MeshRenderEntity;
|
} MeshRenderEntity;
|
||||||
|
|
||||||
extern SceneNode *CreateMeshRenderEntity(char const *resource_path);
|
extern SceneNode *CreateMeshRenderEntity(char const *resource_path);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
char const *RESOURCE_DIRECTORY = "resources";
|
char const *RESOURCE_DIRECTORY = "resources";
|
||||||
|
|
||||||
typedef enum ResourceType {
|
typedef enum ResourceType {
|
||||||
RESOURCE_MODEL, RESOURCE_TEXTURE,
|
RESOURCE_MODEL, RESOURCE_TEXTURE, RESOURCE_SHADER,
|
||||||
RESOURCE_MAX
|
RESOURCE_MAX
|
||||||
} ResourceType;
|
} ResourceType;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ typedef struct ResourceContainer {
|
||||||
union {
|
union {
|
||||||
Model model;
|
Model model;
|
||||||
Texture texture;
|
Texture texture;
|
||||||
|
Shader shader;
|
||||||
};
|
};
|
||||||
} ResourceContainer;
|
} ResourceContainer;
|
||||||
|
|
||||||
|
@ -31,9 +32,11 @@ static void Internal_LoadModelResource(ResourceContainer *resource);
|
||||||
static void Internal_UnloadModelResource(ResourceContainer *resource);
|
static void Internal_UnloadModelResource(ResourceContainer *resource);
|
||||||
static void Internal_LoadTextureResource(ResourceContainer *resource);
|
static void Internal_LoadTextureResource(ResourceContainer *resource);
|
||||||
static void Internal_UnloadTextureResource(ResourceContainer *resource);
|
static void Internal_UnloadTextureResource(ResourceContainer *resource);
|
||||||
|
static void Internal_LoadShaderResource(ResourceContainer *resource);
|
||||||
|
static void Internal_UnloadShaderResource(ResourceContainer *resource);
|
||||||
|
|
||||||
LoadResourceFn g_load_functions[] = {Internal_LoadModelResource, Internal_LoadTextureResource};
|
LoadResourceFn g_load_functions[] = {Internal_LoadModelResource, Internal_LoadTextureResource, Internal_LoadShaderResource};
|
||||||
UnloadResourceFn g_unload_functions[] = {Internal_UnloadModelResource, Internal_UnloadTextureResource};
|
UnloadResourceFn g_unload_functions[] = {Internal_UnloadModelResource, Internal_UnloadTextureResource, Internal_UnloadShaderResource};
|
||||||
|
|
||||||
static HashMap g_resource_map;
|
static HashMap g_resource_map;
|
||||||
static FilePathList g_resource_files;
|
static FilePathList g_resource_files;
|
||||||
|
@ -52,6 +55,9 @@ static ResourceType ResourceGetTypeFromPath(char const *path) {
|
||||||
// Model files
|
// Model files
|
||||||
if(IsFileExtension(path, ".glb")) return RESOURCE_MODEL;
|
if(IsFileExtension(path, ".glb")) return RESOURCE_MODEL;
|
||||||
if(IsFileExtension(path, ".gltf")) return RESOURCE_MODEL;
|
if(IsFileExtension(path, ".gltf")) return RESOURCE_MODEL;
|
||||||
|
// Shader files
|
||||||
|
if(IsFileExtension(path, ".fg")) return RESOURCE_SHADER;
|
||||||
|
if(IsFileExtension(path, ".vs")) return RESOURCE_SHADER;
|
||||||
return RESOURCE_MAX;
|
return RESOURCE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,13 +91,23 @@ void Internal_IndexResourceDirectory() {
|
||||||
.is_loaded = false,
|
.is_loaded = false,
|
||||||
.use_counter = 0,
|
.use_counter = 0,
|
||||||
.path = g_resource_files.paths[i],
|
.path = g_resource_files.paths[i],
|
||||||
.name = GetFileName(g_resource_files.paths[i]),
|
.name = GetFileNameWithoutExt(g_resource_files.paths[i]),
|
||||||
.type = ResourceGetTypeFromPath(g_resource_files.paths[i])
|
.type = ResourceGetTypeFromPath(g_resource_files.paths[i])
|
||||||
};
|
};
|
||||||
// only index resources that the engine knows how to load
|
// only index resources that the engine knows how to load
|
||||||
if(placeholder.type != RESOURCE_MAX) {
|
if(placeholder.type == RESOURCE_SHADER) { // shaders are made up of two files, so their paths are treated differently
|
||||||
|
// if the shader has already been added, don't accidentally add it twice.
|
||||||
|
ResourceContainer *found_container = hash_map_get_as(ResourceContainer, &g_resource_map, &placeholder.name);
|
||||||
|
if(found_container == NULL) {
|
||||||
|
placeholder.path = GetDirectoryPath(placeholder.path);
|
||||||
LOG_INFO("Internal_IndexResourceDirectory: Indexing %s as %s", placeholder.path, placeholder.name);
|
LOG_INFO("Internal_IndexResourceDirectory: Indexing %s as %s", placeholder.path, placeholder.name);
|
||||||
hash_map_insert(&g_resource_map, &placeholder.name, &placeholder);
|
hash_map_insert(&g_resource_map, &placeholder.name, &placeholder);
|
||||||
|
LOG_INFO("hash: %zu", strhash(placeholder.name));
|
||||||
|
}
|
||||||
|
} else if(placeholder.type != RESOURCE_MAX) { // regular resources
|
||||||
|
LOG_INFO("Internal_IndexResourceDirectory: Indexing %s as %s", placeholder.path, placeholder.name);
|
||||||
|
hash_map_insert(&g_resource_map, &placeholder.name, &placeholder);
|
||||||
|
LOG_INFO("hash: %zu", strhash(placeholder.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +120,7 @@ void InitializeResourceSubsystem() {
|
||||||
void CleanResourceSubsystem() {
|
void CleanResourceSubsystem() {
|
||||||
List resources = hash_map_values(&g_resource_map);
|
List resources = hash_map_values(&g_resource_map);
|
||||||
list_foreach(ResourceContainer *,resource, &resources)
|
list_foreach(ResourceContainer *,resource, &resources)
|
||||||
|
if(resource->is_loaded)
|
||||||
g_unload_functions[resource->type](resource);
|
g_unload_functions[resource->type](resource);
|
||||||
hash_map_empty(&g_resource_map);
|
hash_map_empty(&g_resource_map);
|
||||||
UnloadDirectoryFiles(g_resource_files);
|
UnloadDirectoryFiles(g_resource_files);
|
||||||
|
@ -128,7 +145,7 @@ bool GetTextureResource(char const *path, TextureResource *out) {
|
||||||
*out = ResourceEmpty(Texture);
|
*out = ResourceEmpty(Texture);
|
||||||
// assert some assumptions about the found resource
|
// assert some assumptions about the found resource
|
||||||
ASSERT_RETURN(container != NULL, false, "GetTextureResource: Resource %s not in index.", path);
|
ASSERT_RETURN(container != NULL, false, "GetTextureResource: Resource %s not in index.", path);
|
||||||
ASSERT_RETURN(container->type != RESOURCE_TEXTURE, false, "GetTextureResource: Resource %s is not a Texture.", path);
|
ASSERT_RETURN(container->type == RESOURCE_TEXTURE, false, "GetTextureResource: Resource %s is not a Texture.", path);
|
||||||
*out = (TextureResource) {
|
*out = (TextureResource) {
|
||||||
.handle = container,
|
.handle = container,
|
||||||
.resource = &container->texture
|
.resource = &container->texture
|
||||||
|
@ -136,6 +153,18 @@ bool GetTextureResource(char const *path, TextureResource *out) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetShaderResource(char const *path, ShaderResource *out) {
|
||||||
|
ResourceContainer *container = hash_map_get_as(ResourceContainer, &g_resource_map, &path);
|
||||||
|
*out = ResourceEmpty(Shader);
|
||||||
|
ASSERT_RETURN(container != NULL, false, "GetShaderResource: Resource %s not in index.", path);
|
||||||
|
ASSERT_RETURN(container->type == RESOURCE_SHADER, false, "GetShaderResource: Resource %s is not a Shader.", path);
|
||||||
|
*out = (ShaderResource) {
|
||||||
|
.handle = container,
|
||||||
|
.resource = &container->shader
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsResourceLoaded(ResourceHandle handle) {
|
bool IsResourceLoaded(ResourceHandle handle) {
|
||||||
return handle->is_loaded;
|
return handle->is_loaded;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +186,7 @@ void ReleaseResource(ResourceHandle handle) {
|
||||||
|
|
||||||
static
|
static
|
||||||
void Internal_LoadModelResource(ResourceContainer *resource) {
|
void Internal_LoadModelResource(ResourceContainer *resource) {
|
||||||
|
LOG_INFO("Loading model from: %s", resource->path);
|
||||||
resource->model = LoadModel(resource->path);
|
resource->model = LoadModel(resource->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,3 +206,16 @@ void Internal_UnloadTextureResource(ResourceContainer *resource) {
|
||||||
UnloadTexture(resource->texture);
|
UnloadTexture(resource->texture);
|
||||||
resource->texture = (Texture){0};
|
resource->texture = (Texture){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void Internal_LoadShaderResource(ResourceContainer *resource) {
|
||||||
|
resource->shader = LoadShader(TextFormat("%s/%s.vs", resource->path, resource->name), TextFormat("%s/%s.fs", resource->path, resource->name));
|
||||||
|
ASSERT_RETURN(IsShaderReady(resource->shader),, "Internal_LoadShaderResource: Shader failed to load.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void Internal_UnloadShaderResource(ResourceContainer *resource) {
|
||||||
|
UnloadShader(resource->shader);
|
||||||
|
resource->shader = (Shader){0};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ typedef struct ResourceContainer* ResourceHandle;
|
||||||
|
|
||||||
ResourceType(Model);
|
ResourceType(Model);
|
||||||
ResourceType(Texture);
|
ResourceType(Texture);
|
||||||
|
ResourceType(Shader);
|
||||||
|
|
||||||
//! Allocate and initialize memory required to operate resource subsystem
|
//! Allocate and initialize memory required to operate resource subsystem
|
||||||
extern void InitializeResourceSubsystem();
|
extern void InitializeResourceSubsystem();
|
||||||
|
@ -20,6 +21,8 @@ extern void CleanResourceSubsystem();
|
||||||
extern bool GetModelResource(char const *path, ModelResource *out);
|
extern bool GetModelResource(char const *path, ModelResource *out);
|
||||||
//! Get indexed texture from resources.
|
//! Get indexed texture from resources.
|
||||||
extern bool GetTextureResource(char const *path, TextureResource *out);
|
extern bool GetTextureResource(char const *path, TextureResource *out);
|
||||||
|
//! Get indexed shader from resources.
|
||||||
|
extern bool GetShaderResource(char const *path, ShaderResource *out);
|
||||||
|
|
||||||
//! Check if a resource is loaded or not.
|
//! Check if a resource is loaded or not.
|
||||||
extern bool IsResourceLoaded(ResourceHandle handle);
|
extern bool IsResourceLoaded(ResourceHandle handle);
|
||||||
|
|
28
src/main.c
28
src/main.c
|
@ -9,22 +9,30 @@
|
||||||
#include "utils/debug.h"
|
#include "utils/debug.h"
|
||||||
|
|
||||||
Scene *CreateInitialScene() {
|
Scene *CreateInitialScene() {
|
||||||
|
Transformable transformable;
|
||||||
|
Transform transform;
|
||||||
SceneNode *root = CreateTransformNode();
|
SceneNode *root = CreateTransformNode();
|
||||||
|
// create a model with a camera attached as a child of the root of the scene
|
||||||
SceneNode *model_parent = CreateTransformNode();
|
SceneNode *model_parent = CreateTransformNode();
|
||||||
SceneNodeAddChild(root, model_parent);
|
SceneNodeAddChild(root, model_parent);
|
||||||
|
// create the rest of the scene with a mesh and a functionality node
|
||||||
SceneNode *camera_parent = CreateTransformNode();
|
SceneNodeAddChild(model_parent, CreateMeshRenderEntity("spacefighter"));
|
||||||
SceneNodeAddChild(model_parent, camera_parent);
|
SceneNodeAddChild(model_parent, CreateTestObject());
|
||||||
// set camera parent location
|
transformable = TC_CAST(model_parent->entity, Transformable);
|
||||||
Transformable transformable = TC_CAST(camera_parent->entity, Transformable);
|
transform = transformable.tc->get_global_transform(transformable.data);
|
||||||
Transform transform = transformable.tc->get_transform(transformable.data);
|
transform.translation.y += 10;
|
||||||
transform.translation = (Vector3){0.f, 3.f, -10.f};
|
transformable.tc->set_global_transform(transformable.data, transform);
|
||||||
|
// create a camera attached to it's own transform node
|
||||||
|
SceneNode *camera_parent = CreateTransformNode(); // the parent
|
||||||
|
SceneNodeAddChild(model_parent, camera_parent); // attached to the model parent
|
||||||
|
// set camera parent offset
|
||||||
|
transformable = TC_CAST(camera_parent->entity, Transformable);
|
||||||
|
transform = transformable.tc->get_transform(transformable.data);
|
||||||
|
transform.translation = (Vector3){-3.f, 3.f, -10.f};
|
||||||
transform.rotation = QuaternionFromEuler(7.5f * DEG2RAD, 0.f, 0.f);
|
transform.rotation = QuaternionFromEuler(7.5f * DEG2RAD, 0.f, 0.f);
|
||||||
transformable.tc->set_transform(transformable.data, transform);
|
transformable.tc->set_transform(transformable.data, transform);
|
||||||
|
// create the camera and attach it to the dedicated transform node
|
||||||
SceneNodeAddChild(camera_parent, CreateCameraNode());
|
SceneNodeAddChild(camera_parent, CreateCameraNode());
|
||||||
SceneNodeAddChild(model_parent, CreateMeshRenderEntity("spacefighter.glb"));
|
|
||||||
SceneNodeAddChild(model_parent, CreateTestObject());
|
|
||||||
return CreateScene(root);
|
return CreateScene(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c4ec92fa82ab0bbee24f5c60ce36455a37d3696d
|
Subproject commit af50174b71853f3ca887fc0e064e88258c412f2c
|
Loading…
Reference in a new issue