3 Commits

Author SHA1 Message Date
nick 8f7bafb43f chore: include license for entt
CI / build-and-test (push) Successful in 2m33s
2026-03-05 22:39:57 +13:00
nick fc4489d211 fix: code re-org
CI / build-and-test (push) Has been cancelled
2026-03-05 22:38:41 +13:00
nick 10f6df42c6 Remove entt submodule reference, progress on shader testing
CI / build-and-test (push) Waiting to run
2026-03-05 22:25:29 +13:00
9 changed files with 96190 additions and 45 deletions
+1
View File
@@ -128,3 +128,4 @@ cd ../.. && git add external/raylib external/angelscript && git commit -m "Updat
* Raylib: Zlib License (see https://github.com/raysan5/raylib#license)
* AngelScript: MIT License (see https://github.com/angelcode/angelscript/blob/master/license.txt)
* Simian: Not open source (yet)
* Entt: MIT License (see https://github.com/skypjack/entt/blob/main/LICENSE)
+34 -7
View File
@@ -10,15 +10,15 @@ Collapsed=0
[Window][Game Window]
Pos=8,28
Size=1264,684
Size=1264,580
Collapsed=0
DockId=0x9076BACA,0
DockId=0x00000001,0
[Window][Log Viewer]
Pos=8,28
Size=1264,684
Pos=8,610
Size=1264,102
Collapsed=0
DockId=0x9076BACA,1
DockId=0x00000002,0
[Window][##TOAST0]
Pos=1007,637
@@ -45,6 +45,33 @@ Pos=1048,375
Size=212,57
Collapsed=0
[Docking][Data]
DockSpace ID=0x9076BACA Window=0x34F970D7 Pos=8,28 Size=1264,684 CentralNode=1 Selected=0x27A02DAA
[Window][Scene (0 entities)]
Pos=60,60
Size=32,36
Collapsed=1
[Window][Comic Engine]
Pos=60,60
Size=387,337
Collapsed=0
[Window][Scene (1 entities)]
Pos=60,60
Size=71,56
Collapsed=0
[Window][Scene (2 entities)]
Pos=60,60
Size=71,82
Collapsed=0
[Window][Scene (3 entities)]
Pos=60,60
Size=71,108
Collapsed=0
[Docking][Data]
DockSpace ID=0x9076BACA Window=0x34F970D7 Pos=8,28 Size=1264,684 Split=Y Selected=0x27A02DAA
DockNode ID=0x00000001 Parent=0x9076BACA SizeRef=1264,580 CentralNode=1 Selected=0x27A02DAA
DockNode ID=0x00000002 Parent=0x9076BACA SizeRef=1264,102 Selected=0xBEDDA0C1
+2
View File
@@ -35,4 +35,6 @@ private:
void Update(float deltaTime);
void Draw();
void SpawnCube();
};
+95903
View File
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
#version 330
uniform sampler2D texture0;
uniform vec2 textureSize;
uniform int outlineSize = 2;
in vec2 fragTexCoord;
out vec4 finalColor;
void main() {
vec2 texel = 1.0 / textureSize;
float center = texture(texture0, fragTexCoord).r;
if (center < 0.5) {
discard; // Transparent, show scene underneath
return;
}
// Edge detection
bool edge = false;
for (int y = -outlineSize; y <= outlineSize; y++) {
for (int x = -outlineSize; x <= outlineSize; x++) {
vec2 offset = vec2(float(x), float(y)) * texel;
if (texture(texture0, fragTexCoord + offset).r < 0.5) {
edge = true;
break;
}
}
if (edge) break;
}
if (edge) {
finalColor = vec4(0, 0, 0, 1); // Black outline
} else {
discard;
}
}
+25
View File
@@ -0,0 +1,25 @@
#version 330
in vec3 fragNormal;
in vec3 fragPosition;
uniform vec3 lightDir;
uniform float bandCount;
uniform vec4 albedo;
out vec4 fragColor;
void main() {
// Normalize the normal and light direction
vec3 normal = normalize(fragNormal);
vec3 light = normalize(lightDir);
// Calculate the dot product for lighting
float intensity = max(dot(normal, light), 0.0);
// Quantize the intensity for toon shading
intensity = floor(intensity * bandCount) / bandCount;
// Set the fragment color
//fragColor = vec4(vec3(intensity), 1.0);
fragColor = vec4(albedo.rgb , albedo.a);
}
+17
View File
@@ -0,0 +1,17 @@
#version 330
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec3 vertexNormal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 fragNormal;
out vec3 fragPosition;
void main() {
fragPosition = vec3(model * vec4(vertexPosition, 1.0));
fragNormal = mat3(transpose(inverse(model))) * vertexNormal; // Transform normals
gl_Position = projection * view * vec4(fragPosition, 1.0);
}
+169 -38
View File
@@ -4,6 +4,7 @@
#include <thread>
#include <cstring>
#include <filesystem>
#include <entt.hpp>
#include "log/log.h"
#include "rlImGui.h"
@@ -31,6 +32,36 @@ Application::~Application()
// Shutdown();
}
/// Shader and rendering data for the demo scene
Camera3D camera;
RenderTexture2D sceneRT, maskRT;
Shader toonShader, outlineShader;
Model cube;
float globalBandCount = 3.0f;
Vector3 lightDir = {0.5f, 0.7f, 0.3f};
bool showEditor = true;
bool dayMode = true;
entt::registry ecs;
std::vector<Model> models;
struct ECS_Transform
{
Vector3 pos, scale;
float rot;
};
struct Render
{
int modelId;
float outlineSize;
Color color;
};
struct ECS_Material
{
Shader shader;
int lightLoc, bandLoc;
};
/// ======
bool Application::Initialize(int argc, char *argv[])
{
if (fopen_s(&logFile, "log.txt", "w") != 0)
@@ -55,6 +86,7 @@ bool Application::Initialize(int argc, char *argv[])
enableEditor = true;
}
}
// Initialize Raylib
InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE);
SetTargetFPS(TARGET_FPS);
@@ -87,9 +119,38 @@ bool Application::Initialize(int argc, char *argv[])
renderTexture = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT);
}
camera.position = {5, 5, 5};
camera.target = {0, 0, 0};
camera.up = {0, 1, 0};
camera.fovy = 45;
// Assets
cube = LoadModelFromMesh(GenMeshCube(1, 1, 1));
models.push_back(cube);
// Shaders (toon + outline)
toonShader = LoadShader(0, "shaders/toon.fs");
outlineShader = LoadShader(0, "shaders/outline.fs");
// Render textures
sceneRT = LoadRenderTexture(1280, 720);
maskRT = LoadRenderTexture(1280, 720);
// Cache uniform locations
cube.materials[0].shader = toonShader;
return true;
}
void Application::SpawnCube()
{
auto e = ecs.create();
ecs.emplace<ECS_Transform>(
e,
Vector3{static_cast<float>(rand() % 3 - 1), 0.0f, static_cast<float>(rand() % 3 - 1)}, // Position
Vector3{1.0f, 1.0f, 1.0f}, // Scale
0.0f // Rotation
);
ecs.emplace<Render>(e, 0, 2.0f, YELLOW);
}
void Application::Run()
{
scriptEngine.CallScriptFunction(scriptEngine.GetInitFunction());
@@ -116,62 +177,125 @@ void Application::Update(float deltaTime)
{
log_warn("Script compilation failed - keeping previous version");
Toast::Warning("Script compilation failed - check console for details.");
} else {
}
else
{
Toast::Success("Script reloaded successfully.");
//Should call init function again or things don't work
// Should call init function again or things don't work
scriptEngine.CallScriptFunction(scriptEngine.GetInitFunction());
}
}
// Call script Update function
scriptEngine.CallScriptFunction(scriptEngine.GetUpdateFunction(), deltaTime);
UpdateCamera(&camera, CAMERA_ORBITAL);
// Day/night toggle
if (IsKeyPressed(KEY_SPACE))
dayMode = !dayMode;
globalBandCount = dayMode ? 3.0f : 2.0f;
// F1 editor toggle
if (IsKeyPressed(KEY_F1))
showEditor = !showEditor;
if (IsKeyPressed(KEY_F2))
SpawnCube();
}
void Application::Draw()
{
int screenWidth = GetScreenWidth();
int screenHeight = GetScreenHeight();
// Fallback to default values if screen dimensions are invalid
if (screenWidth <= 0 || screenHeight <= 0)
{
log_warn("Invalid screen dimensions: %d x %d. Using default values.", screenWidth, screenHeight);
screenWidth = 800;
screenHeight = 600;
}
ImGuiIO &io = ImGui::GetIO();
io.DisplaySize = ImVec2((float)screenWidth, (float)screenHeight); // Set DisplaySize
BeginTextureMode(renderTexture);
ClearBackground(SKYBLUE);
BeginMode3D(camera);
DrawGrid(10, 1);
DrawLine3D(Vector3{0, 0, 0}, Vector3{lightDir.x * 5.0f, lightDir.y * 5.0f, lightDir.z * 5.0f}, RED);
BeginShaderMode(toonShader);
SetShaderValue(toonShader, GetShaderLocation(toonShader, "lightDir"), &lightDir, SHADER_UNIFORM_VEC3);
SetShaderValue(toonShader, GetShaderLocation(toonShader, "bandCount"), &globalBandCount, SHADER_UNIFORM_FLOAT);
auto view = ecs.view<ECS_Transform, Render>();
view.each([&](const auto &t, const auto &r)
{
Vector4 color = {r.color.r / 255.0f, r.color.g / 255.0f, r.color.b / 255.0f, r.color.a / 255.0f};
SetShaderValue(toonShader, GetShaderLocation(toonShader, "albedo"), &color, SHADER_UNIFORM_VEC4);
DrawModel(models[r.modelId], t.pos, 1.0f, WHITE); // Use WHITE since color is handled by the shader
});
EndShaderMode();
EndMode3D();
// Call script Draw function
scriptEngine.CallScriptFunction(scriptEngine.GetDrawFunction());
// 2. Silhouette mask
// BeginTextureMode(maskRT);
// ClearBackground(WHITE);
// BeginMode3D(camera);
// for (auto e : ecs.view<ECS_Transform, Render>())
// {
// auto &t = ecs.get<ECS_Transform>(e);
// DrawModel(models[ecs.get<Render>(e).modelId], t.pos, 1.0f, BLACK);
// }
// EndMode3D();
// EndTextureMode();
// // 3. Outline postprocess
// BeginShaderMode(outlineShader);
// Rectangle src = {0, 0, (float)maskRT.texture.width, (float)-maskRT.texture.height};
// DrawTextureRec(maskRT.texture, src, {0, 0}, WHITE);
EndShaderMode();
EndTextureMode();
if (enableEditor)
{
int screenWidth = GetScreenWidth();
int screenHeight = GetScreenHeight();
// Fallback to default values if screen dimensions are invalid
if (screenWidth <= 0 || screenHeight <= 0)
{
log_warn("Invalid screen dimensions: %d x %d. Using default values.", screenWidth, screenHeight);
screenWidth = 800;
screenHeight = 600;
}
ImGuiIO &io = ImGui::GetIO();
io.DisplaySize = ImVec2((float)screenWidth, (float)screenHeight); // Set DisplaySize
BeginTextureMode(renderTexture);
ClearBackground(RAYWHITE);
// Call script Draw function
scriptEngine.CallScriptFunction(scriptEngine.GetDrawFunction());
EndTextureMode();
BeginDrawing();
ClearBackground(RAYWHITE);
guiManager.Render(renderTexture); // Render the GUI
EndDrawing();
}
else
{
BeginDrawing();
ClearBackground(RAYWHITE);
// rlImGuiBegin();
// ImGui::Begin("Comic Engine");
// std::string fpsText = "FPS: " + std::to_string(GetFPS());
// ImGui::Text(fpsText.c_str());
// if (ImGui::Button("Spawn Cube"))
// SpawnCube();
// ImGui::Checkbox("Day Mode", &dayMode);
// ImGui::SliderFloat("Band Count", &globalBandCount, 1.0f, 5.0f);
// ImGui::ColorEdit3("Light Dir", &lightDir.x);
// ImGui::Text("F1: Toggle editor");
// ImGui::End();
// Show script error status in top left if there's an error, otherwise show normal message
if (scriptCompilationError)
{
DrawText("SCRIPT ERROR - Check console for details", 10, 10, 16, RED);
}
// Call script Draw function
scriptEngine.CallScriptFunction(scriptEngine.GetDrawFunction());
// // Scene hierarchy
// std::string sceneTitle = "Scene (" + std::to_string(ecs.view<ECS_Transform>().size()) + " entities)";
// ImGui::Begin(sceneTitle.c_str());
// for (auto e : ecs.view<ECS_Transform>())
// {
// if (ImGui::Button(std::string("Cube " + std::to_string((int)e)).c_str()))
// {
// ecs.get<ECS_Transform>(e).pos.x += 1.0f;
// }
// }
// ImGui::End();
// rlImGuiEnd();
EndDrawing();
}
@@ -197,6 +321,13 @@ void Application::Shutdown()
// Shutdown script engine
scriptEngine.Shutdown();
// Unload assets
UnloadModel(cube);
UnloadShader(toonShader);
UnloadShader(outlineShader);
UnloadRenderTexture(sceneRT);
UnloadRenderTexture(maskRT);
// Clear the trace log callback before closing window to prevent logging after cleanup
SetTraceLogCallback(nullptr);
CloseWindow();
+2
View File
@@ -33,6 +33,8 @@ void GuiManager::Render(RenderTexture2D &renderTexture)
RenderErrorBanner();
RenderNotifications();
logWindow.Render(showLogWindow); // Render the LogWindow
rlImGuiEnd();
ImGui::UpdatePlatformWindows();