feat: refactor to move more elements to the scripting layer
CI / build-and-test (push) Successful in 2m13s

This commit is contained in:
2026-03-06 14:32:25 +13:00
parent 670f65b37b
commit 82886349ae
20 changed files with 1261 additions and 156 deletions
+4
View File
@@ -97,10 +97,14 @@ add_executable(simian
src/scripting/TextureBindings.cpp
src/scripting/MathBindings.cpp
src/scripting/ECSBindings.cpp
src/scripting/ResourceBindings.cpp
src/HotReload.cpp
src/gui/GuiManager.cpp
src/gui/LogWindow.cpp
src/log/log.c
src/ShaderManager.cpp
src/ModelManager.cpp
src/MaterialManager.cpp
)
target_include_directories(simian PUBLIC
+7 -8
View File
@@ -3,8 +3,10 @@
#include "HotReload.h"
#include "gui/GuiManager.h"
#include "raylib.h"
#include "ShaderManager.h"
#include "ModelManager.h"
#include "MaterialManager.h"
#include <entt.hpp>
#include <vector>
class Application {
public:
@@ -31,14 +33,11 @@ private:
// ECS
entt::registry registry;
std::vector<Model> models;
// Scene/rendering data
Camera3D camera;
Shader toonShader;
Vector3 lightDir;
float globalBandCount;
bool dayMode;
// Resource managers
ShaderManager shaderManager;
ModelManager modelManager;
MaterialManager materialManager;
static const int WINDOW_WIDTH = 1280;
static const int WINDOW_HEIGHT = 720;
+51 -1
View File
@@ -32,7 +32,7 @@ struct Velocity {
// Sprite component - visual representation
struct Sprite {
int modelId; // Index into models array
size_t modelId; // Index into models array
Color color; // Tint color
float outlineSize; // Outline thickness
@@ -52,3 +52,53 @@ struct Tag {
Tag() : name("") {}
Tag(const std::string& n) : name(n) {}
};
// Camera3D component - camera settings
struct Camera3DComponent {
Vector3 position;
Vector3 target;
Vector3 up;
float fovy;
int projection; // 0 = CAMERA_PERSPECTIVE, 1 = CAMERA_ORTHOGRAPHIC
Camera3DComponent()
: position{0.0f, 10.0f, 10.0f}
, target{0.0f, 0.0f, 0.0f}
, up{0.0f, 1.0f, 0.0f}
, fovy(45.0f)
, projection(0) {}
};
// Light component - directional light
struct LightComponent {
Vector3 direction;
Color color;
float intensity;
LightComponent()
: direction{0.5f, 0.7f, 0.3f}
, color(WHITE)
, intensity(1.0f) {}
};
// Material component - references shader and material managers
struct MaterialComponent {
unsigned int materialId; // ID in MaterialManager
MaterialComponent() : materialId(0) {}
MaterialComponent(unsigned int id) : materialId(id) {}
};
// RenderPass component - controls rendering order and properties
struct RenderPassComponent {
int order; // Render order (lower = earlier)
bool depthTest; // Enable depth testing
bool depthWrite; // Enable depth writing
unsigned int shaderId; // Override shader for this pass (0 = use material shader)
RenderPassComponent()
: order(0)
, depthTest(true)
, depthWrite(true)
, shaderId(0) {}
};
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include "raylib.h"
#include <unordered_map>
#include <string>
struct MaterialData
{
unsigned int shaderId;
Color albedo;
MaterialData() : shaderId(0), albedo(WHITE) {}
};
class MaterialManager
{
public:
MaterialManager();
~MaterialManager();
// Create a material with a shader ID
// Returns a unique ID for the material
unsigned int Create(unsigned int shaderId, Color albedo = WHITE);
// Remove a material by ID
void Remove(unsigned int id);
// Get material data by ID (returns nullptr if not found)
MaterialData* Get(unsigned int id);
// Update material shader
void SetShader(unsigned int id, unsigned int shaderId);
// Update material albedo
void SetAlbedo(unsigned int id, Color albedo);
// Clear all materials
void Clear();
private:
std::unordered_map<unsigned int, MaterialData> materials;
unsigned int nextId;
bool cleared;
};
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "raylib.h"
#include <unordered_map>
#include <string>
class ModelManager
{
public:
ModelManager();
~ModelManager();
// Load a model from a file
// Returns a unique ID for the model, or 0 on failure
unsigned int Load(const std::string& path);
// Load a model from a mesh
// Returns a unique ID for the model, or 0 on failure
unsigned int LoadFromMesh(Mesh mesh);
// Unload a model by ID
void Unload(unsigned int id);
// Get a model by ID (returns nullptr if not found)
Model* Get(unsigned int id);
// Unload all models
void UnloadAll();
private:
std::unordered_map<unsigned int, Model> models;
unsigned int nextId;
bool unloaded;
};
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "raylib.h"
#include <unordered_map>
#include <string>
class ShaderManager
{
public:
ShaderManager();
~ShaderManager();
// Load a shader from vertex and fragment shader files
// Returns a unique ID for the shader, or 0 on failure
unsigned int Load(const std::string& vsPath, const std::string& fsPath);
// Unload a shader by ID
void Unload(unsigned int id);
// Get a shader by ID (returns nullptr if not found)
Shader* Get(unsigned int id);
// Unload all shaders
void UnloadAll();
private:
std::unordered_map<unsigned int, Shader> shaders;
unsigned int nextId;
bool unloaded;
};
+9
View File
@@ -0,0 +1,9 @@
#pragma once
class asIScriptEngine;
class ShaderManager;
class ModelManager;
class MaterialManager;
void SetResourceManagers(ShaderManager* shaderMgr, ModelManager* modelMgr, MaterialManager* materialMgr);
void RegisterResourceBindings(asIScriptEngine *engine);
+69 -1
View File
@@ -69,6 +69,59 @@ namespace ECS {
void SetTag(uint entity, const string &in name);
bool HasTag(uint entity);
void RemoveTag(uint entity);
// Camera3D component
void AddCamera3D(uint entity, float px, float py, float pz, float tx, float ty, float tz, float fovy);
void SetCameraPosition(uint entity, float x, float y, float z);
void SetCameraTarget(uint entity, float x, float y, float z);
void SetCameraFovy(uint entity, float fovy);
bool HasCamera3D(uint entity);
void RemoveCamera3D(uint entity);
// Light component
void AddLight(uint entity, float dx, float dy, float dz, float intensity = 1.0f);
void SetLightDirection(uint entity, float x, float y, float z);
void SetLightIntensity(uint entity, float intensity);
void SetLightColor(uint entity, uint color);
bool HasLight(uint entity);
void RemoveLight(uint entity);
// Material component
void AddMaterial(uint entity, uint materialId);
void SetMaterialId(uint entity, uint materialId);
uint GetMaterialId(uint entity);
bool HasMaterial(uint entity);
void RemoveMaterial(uint entity);
// RenderPass component
void AddRenderPass(uint entity, int order, bool depthTest, bool depthWrite, uint shaderId);
void SetRenderPassOrder(uint entity, int order);
void SetRenderPassShader(uint entity, uint shaderId);
bool HasRenderPass(uint entity);
void RemoveRenderPass(uint entity);
}
// Shader resource management
namespace Shader {
uint Load(const string &in vsPath, const string &in fsPath);
void Unload(uint id);
}
// Model resource management
namespace Model {
uint Load(const string &in path);
uint LoadCube(float width, float height, float length);
uint LoadSphere(float radius, int rings, int slices);
uint LoadPlane(float width, float length, int resX, int resZ);
void Unload(uint id);
}
// Material resource management
namespace Material {
uint Create(uint shaderId, uint8 r, uint8 g, uint8 b, uint8 a);
void Remove(uint id);
void SetShader(uint id, uint shaderId);
void SetAlbedo(uint id, uint8 r, uint8 g, uint8 b, uint8 a);
}
namespace Texture {
@@ -110,4 +163,19 @@ namespace Math {
float Ceil(float value);
float Modf(float x, float y);
float Abs(float value);
}
}
// Raylib input and timing functions
float GetTime();
bool IsKeyPressed(int key);
// Raylib key constants
const int KEY_SPACE = 32;
const int KEY_ESCAPE = 256;
const int KEY_ENTER = 257;
const int KEY_TAB = 258;
const int KEY_BACKSPACE = 259;
const int KEY_RIGHT = 262;
const int KEY_LEFT = 263;
const int KEY_DOWN = 264;
const int KEY_UP = 265;
+101
View File
@@ -0,0 +1,101 @@
// Example script showing how to use the new script-driven rendering system
// Global variables to track our resources
uint g_toonShader = 0;
uint g_outlineShader = 0;
uint g_cubeModel = 0;
uint g_sphereModel = 0;
uint g_redMaterial = 0;
uint g_blueMaterial = 0;
// Entities
uint g_camera = 0;
uint g_light = 0;
uint g_cube = 0;
uint g_sphere = 0;
void Init() {
Toast::Info("Initializing script-driven rendering...");
// === Load Shaders ===
g_toonShader = Shader::Load("shaders/toon.vs", "shaders/toon.fs");
g_outlineShader = Shader::Load("shaders/outline.vs", "shaders/outline.fs");
if (g_toonShader == 0 || g_outlineShader == 0) {
Toast::Error("Failed to load shaders!");
return;
}
// === Load Models ===
g_cubeModel = Model::LoadCube(1.0, 1.0, 1.0);
g_sphereModel = Model::LoadSphere(0.5, 16, 16);
// === Create Materials ===
// Red material with toon shader
g_redMaterial = Material::Create(g_toonShader, 255, 100, 100, 255);
// Blue material with toon shader
g_blueMaterial = Material::Create(g_toonShader, 100, 100, 255, 255);
// === Set up Camera ===
g_camera = ECS::CreateEntity();
ECS::AddCamera3D(g_camera,
5.0, 5.0, 5.0, // position
0.0, 0.0, 0.0, // target
45.0); // fovy
ECS::AddTag(g_camera, "MainCamera");
// === Set up Light ===
g_light = ECS::CreateEntity();
ECS::AddLight(g_light, 0.5, 0.7, 0.3, 1.0); // direction + intensity
ECS::AddTag(g_light, "MainLight");
// === Create Cube with Outline ===
g_cube = ECS::CreateEntity();
ECS::AddTransform(g_cube, -1.5, 0.5, 0.0);
ECS::AddSprite(g_cube, g_cubeModel, 0xFFFFFFFF, 0.0);
ECS::AddMaterial(g_cube, g_redMaterial);
ECS::AddTag(g_cube, "Cube");
ECS::AddVelocity(g_cube, 0.0, 0.0, 0.0, 1.0); // rotating
// Add outline render pass (order 0 = first)
ECS::AddRenderPass(g_cube, 0, false, true, g_outlineShader); // order=0, no depth test
// === Create Sphere ===
g_sphere = ECS::CreateEntity();
ECS::AddTransform(g_sphere, 1.5, 0.5, 0.0);
ECS::AddSprite(g_sphere, g_sphereModel, 0xFFFFFFFF, 0.0);
ECS::AddMaterial(g_sphere, g_blueMaterial);
ECS::AddTag(g_sphere, "Sphere");
ECS::AddVelocity(g_sphere, 0.5, 0.0, 0.2, 0.5); // moving and rotating
// Add main render pass (order 1 = second, after outlines)
ECS::AddRenderPass(g_sphere, 1, true, true, 0); // order=1, with depth test
Toast::Success("Script-driven rendering initialized!");
}
bool lightToggle = false;
void Update(float dt) {
// Camera orbital movement
if (ECS::HasCamera3D(g_camera)) {
float angle = GetTime() * 0.3;
float radius = 7.0;
float x = Math::Cos(angle) * radius;
float z = Math::Sin(angle) * radius;
ECS::SetCameraPosition(g_camera, x, 5.0, z);
}
// Example: Toggle light direction with space
if (IsKeyPressed(KEY_SPACE)) {
lightToggle = !lightToggle;
if (lightToggle) {
ECS::SetLightDirection(g_light, -0.5, 0.7, -0.3);
Toast::Info("Light direction changed!");
} else {
ECS::SetLightDirection(g_light, 0.5, 0.7, 0.3);
Toast::Info("Light direction reset!");
}
}
}
+89 -18
View File
@@ -1,5 +1,16 @@
// ECS-based game script demo
// This demonstrates creating entities with various components
// ECS-based game script demo with script-driven rendering
// This demonstrates creating entities with various components and managing rendering
// Resource IDs
uint g_toonShader = 0;
uint g_outlineShader = 0;
uint g_cubeModel = 0;
uint g_sphereModel = 0;
uint g_defaultMaterial = 0;
// Scene entities
uint g_camera = 0;
uint g_light = 0;
// Store entity IDs for manipulation
array<uint> entities;
@@ -8,25 +19,67 @@ uint spinningCube;
float time = 0.0f;
void Init() {
Log(LOG_TRACE, "Initialization complete - ECS Demo!");
Log(LOG_TRACE, "Initialization complete - ECS Demo with Script-Driven Rendering!");
Toast::Success("ECS Script initialized successfully!");
// Create a player entity at origin
// === Load shaders ===
g_toonShader = Shader::Load("shaders/toon.vs", "shaders/toon.fs");
g_outlineShader = Shader::Load("shaders/outline.vs", "shaders/outline.fs");
if (g_toonShader == 0 || g_outlineShader == 0) {
Toast::Error("Failed to load shaders!");
return;
}
// === Load models ===
g_cubeModel = Model::LoadCube(1.0, 1.0, 1.0);
g_sphereModel = Model::LoadSphere(0.5, 16, 16);
// === Create default material ===
g_defaultMaterial = Material::Create(g_toonShader, 255, 255, 255, 255);
// === Set up camera ===
g_camera = ECS::CreateEntity();
ECS::AddCamera3D(g_camera,
5.0, 5.0, 5.0, // position
0.0, 0.0, 0.0, // target
45.0); // fovy
ECS::AddTag(g_camera, "MainCamera");
// === Set up light ===
g_light = ECS::CreateEntity();
ECS::AddLight(g_light, 0.5, 0.7, 0.3, 1.0); // direction + intensity
ECS::AddTag(g_light, "MainLight");
// === Create player entity at origin with outline ===
player = ECS::CreateEntity();
ECS::AddTransform(player, 0.0f, 0.0f, 0.0f);
ECS::AddSprite(player, 1, 0xFF0000FF, 0.0f); // Red cube, model 0
ECS::AddSprite(player, g_sphereModel, 0xFF0000FF, 0.0f); // Red sphere
// Create material for player
uint playerMat = Material::Create(g_toonShader, 255, 0, 0, 255);
ECS::AddMaterial(player, playerMat);
// Add outline pass (order=0) and main pass (order=1)
ECS::AddRenderPass(player, 0, false, true, g_outlineShader);
ECS::AddTag(player, "Player");
Log(LOG_INFO, "Created player entity: " + player);
// Create a spinning cube
// === Create a spinning cube ===
spinningCube = ECS::CreateEntity();
ECS::AddTransform(spinningCube, 2.0f, 0.0f, 0.0f);
ECS::AddSprite(spinningCube, 0, 0x00FF00FF, 0.0f); // Green cube
ECS::AddSprite(spinningCube, g_cubeModel, 0x00FF00FF, 0.0f); // Green cube
ECS::AddVelocity(spinningCube, 0.0f, 0.0f, 0.0f, 2.0f); // Angular velocity
uint greenMat = Material::Create(g_toonShader, 0, 255, 0, 255);
ECS::AddMaterial(spinningCube, greenMat);
ECS::AddRenderPass(spinningCube, 1, true, true, 0); // Main pass
ECS::AddTag(spinningCube, "Spinner");
Log(LOG_INFO, "Created spinning cube: " + spinningCube);
// Create orbiting entities
// === Create orbiting entities ===
for (int i = 0; i < 5; i++) {
uint entity = ECS::CreateEntity();
@@ -39,27 +92,36 @@ void Init() {
// Different colors for each
uint color = 0;
if (i == 0) color = 0xFFFF00FF; // Yellow
else if (i == 1) color = 0xFF00FFFF; // Magenta
else if (i == 2) color = 0x00FFFFFF; // Cyan
else if (i == 3) color = 0xFFA500FF; // Orange
else color = 0xFF69B4FF; // Pink
uint8 r = 255, g = 255, b = 255;
if (i == 0) { color = 0xFFFF00FF; r = 255; g = 255; b = 0; } // Yellow
else if (i == 1) { color = 0xFF00FFFF; r = 255; g = 0; b = 255; } // Magenta
else if (i == 2) { color = 0x00FFFFFF; r = 0; g = 255; b = 255; } // Cyan
else if (i == 3) { color = 0xFFA500FF; r = 255; g = 165; b = 0; } // Orange
else { color = 0xFF69B4FF; r = 255; g = 105; b = 180; } // Pink
ECS::AddSprite(entity, g_sphereModel, color, 0.0f);
uint mat = Material::Create(g_toonShader, r, g, b, 255);
ECS::AddMaterial(entity, mat);
ECS::AddRenderPass(entity, 1, true, true, 0);
ECS::AddSprite(entity, 1, color, 0.0f);
ECS::AddTag(entity, "Orbiter" + i);
entities.insertLast(entity);
}
// Create a moving entity
// === Create a moving entity ===
uint mover = ECS::CreateEntity();
ECS::AddTransform(mover, -3.0f, 0.5f, 0.0f);
ECS::AddSprite(mover, 0, 0xFFFFFFFF, 0.0f); // White cube
ECS::AddSprite(mover, g_cubeModel, 0xFFFFFFFF, 0.0f); // White cube
ECS::AddVelocity(mover, 1.0f, 0.0f, 0.5f, 0.0f); // Moving velocity
ECS::AddMaterial(mover, g_defaultMaterial);
ECS::AddRenderPass(mover, 1, true, true, 0);
ECS::AddTag(mover, "Mover");
entities.insertLast(mover);
Toast::Success("Created " + (entities.length() + 3) + " entities!");
Toast::Success("Created " + (entities.length() + 2) + " entities with script-driven rendering!");
}
void Shutdown() {
@@ -69,6 +131,15 @@ void Shutdown() {
void Update(float dt) {
time += dt;
// Update camera to orbit around the scene
if (ECS::HasCamera3D(g_camera)) {
float angle = time * 0.3;
float radius = 7.0;
float x = Math::Cos(angle) * radius;
float z = Math::Sin(angle) * radius;
ECS::SetCameraPosition(g_camera, x, 5.0, z);
}
// Update player position - simple back and forth motion
float playerX = Math::Sin(time) * 2.0f;
ECS::SetPosition(player, playerX, 0.0f, 0.0f);
+4 -32
View File
@@ -1,37 +1,9 @@
#version 330
uniform sampler2D texture0;
uniform vec2 textureSize;
uniform int outlineSize = 2;
out vec4 fragColor;
in vec2 fragTexCoord;
out vec4 finalColor;
uniform vec4 outlineColor; // Color of the outline
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;
}
}
fragColor = outlineColor;
}
+21
View File
@@ -0,0 +1,21 @@
#version 330
layout(location = 0) in vec3 vertexPosition;
layout(location = 2) in vec3 vertexNormal;
uniform mat4 mvp;
uniform mat4 matModel;
uniform mat4 matNormal;
uniform float outlineThickness;
void main() {
// Transform normal to world space
vec3 worldNormal = normalize(vec3(matNormal * vec4(vertexNormal, 0.0)));
// Expand vertices along normals in world space
vec3 worldPos = vec3(matModel * vec4(vertexPosition, 1.0));
vec3 expandedPos = worldPos + worldNormal * outlineThickness;
// Transform to clip space
gl_Position = mvp * vec4(vertexPosition + vertexNormal * outlineThickness, 1.0);
}
+176 -96
View File
@@ -1,7 +1,9 @@
#include "Application.h"
#include "ECSComponents.h"
#include "scripting/ECSBindings.h"
#include "scripting/ResourceBindings.h"
#include "raylib.h"
#include "rlgl.h"
#include <chrono>
#include <thread>
#include <cstring>
@@ -25,7 +27,7 @@ const char *Application::WINDOW_TITLE = "Simian";
const char *Application::SCRIPT_FILE = "scripts/game.as";
Application::Application()
: hotReload(nullptr), scriptCompilationError(false), logFile(nullptr), renderTexture{}, lightDir{0.5f, 0.7f, 0.3f}, globalBandCount(3.0f), dayMode(true)
: hotReload(nullptr), scriptCompilationError(false), logFile(nullptr), renderTexture{}
{
}
@@ -75,6 +77,10 @@ bool Application::Initialize(int argc, char *argv[])
// Set up ECS bindings with our registry
SetGlobalRegistry(&registry);
// Set up resource managers for script access
extern void SetResourceManagers(ShaderManager*, ModelManager*, MaterialManager*);
SetResourceManagers(&shaderManager, &modelManager, &materialManager);
// Initialize hot reload to watch the scripts directory so any script change
// triggers a reload.
{
@@ -94,43 +100,6 @@ bool Application::Initialize(int argc, char *argv[])
renderTexture = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT);
}
// Set up camera
camera.position = {5, 5, 5};
camera.target = {0, 0, 0};
camera.up = {0, 1, 0};
camera.fovy = 45;
camera.projection = CAMERA_PERSPECTIVE; // ADD THIS LINE!
// Load models
Model cube = LoadModelFromMesh(GenMeshCube(1, 1, 1));
Model sphere = LoadModelFromMesh(GenMeshSphere(0.5f, 16, 16));
// Load shaders (use both vertex and fragment shader files explicitly)
toonShader = LoadShader("shaders/toon.vs", "shaders/toon.fs");
if (toonShader.id == 0) {
log_warn("Failed to load toon shader (id=0). Check shader paths and GL support.");
} else {
log_info("Loaded toon shader id=%d", toonShader.id);
// Verify shader locations exist
int lightLoc = GetShaderLocation(toonShader, "lightDir");
int bandLoc = GetShaderLocation(toonShader, "bandCount");
int albedoLoc = GetShaderLocation(toonShader, "albedo");
log_info("Shader locations: lightDir=%d, bandCount=%d, albedo=%d", lightLoc, bandLoc, albedoLoc);
if (lightLoc == -1 || bandLoc == -1 || albedoLoc == -1) {
log_warn("Some shader uniforms not found - shader may not work correctly");
}
}
// Assign shader to cube material
cube.materials[0].shader = toonShader;
sphere.materials[0].shader = toonShader;
models.push_back(cube);
models.push_back(sphere);
return true;
}
@@ -174,13 +143,6 @@ void Application::Update(float deltaTime)
// Update ECS systems
UpdateSystems(deltaTime);
UpdateCamera(&camera, CAMERA_ORBITAL);
// Day/night toggle
if (IsKeyPressed(KEY_SPACE))
dayMode = !dayMode;
globalBandCount = dayMode ? 3.0f : 2.0f;
}
void Application::UpdateSystems(float deltaTime)
@@ -200,53 +162,172 @@ void Application::UpdateSystems(float deltaTime)
void Application::RenderScene()
{
BeginMode3D(camera);
DrawGrid(10, 1);
BeginShaderMode(toonShader);
// Query for active camera (first one found with Camera3DComponent)
Camera3D camera = {};
bool hasCamera = false;
// Get shader locations once
int lightLoc = GetShaderLocation(toonShader, "lightDir");
int bandLoc = GetShaderLocation(toonShader, "bandCount");
int albedoLoc = GetShaderLocation(toonShader, "albedo");
auto view = registry.view<ECSTransform, Sprite>();
view.each([&](auto &transform, auto &sprite)
{
// Validate model index
// if (sprite.modelId < 0 || sprite.modelId >= models.size()) {
// return;
// }
// Set ALL uniforms before each draw call
if (lightLoc != -1) {
SetShaderValue(toonShader, lightLoc, &lightDir, SHADER_UNIFORM_VEC3);
auto cameraView = registry.view<Camera3DComponent>();
cameraView.each([&](auto& camComp) {
if (!hasCamera) {
camera.position = camComp.position;
camera.target = camComp.target;
camera.up = camComp.up;
camera.fovy = camComp.fovy;
camera.projection = camComp.projection;
hasCamera = true;
}
if (bandLoc != -1) {
SetShaderValue(toonShader, bandLoc, &globalBandCount, SHADER_UNIFORM_FLOAT);
}
// Set color for this entity
Vector4 color = {
sprite.color.r / 255.0f,
sprite.color.g / 255.0f,
sprite.color.b / 255.0f,
sprite.color.a / 255.0f
};
if (albedoLoc != -1) {
SetShaderValue(toonShader, albedoLoc, &color, SHADER_UNIFORM_VEC4);
}
// Draw the model
Model& model = models[sprite.modelId];
DrawModelEx(model, transform.position, Vector3{0, 1, 0}, transform.rotation * RAD2DEG,
transform.scale, WHITE);
});
EndShaderMode();
// If no camera found, use a default one
if (!hasCamera) {
camera.position = {5, 5, 5};
camera.target = {0, 0, 0};
camera.up = {0, 1, 0};
camera.fovy = 45;
camera.projection = CAMERA_PERSPECTIVE;
}
// Get the first light (if any) for shader uniforms
Vector3 lightDir = {0.5f, 0.7f, 0.3f};
float lightIntensity = 1.0f;
auto lightView = registry.view<LightComponent>();
lightView.each([&](auto& light) {
lightDir = light.direction;
lightIntensity = light.intensity;
return; // Use first light only for now
});
BeginMode3D(camera);
DrawGrid(10, 1);
// Collect entities with renderables and organize by render pass
struct RenderableEntity {
entt::entity entity;
ECSTransform* transform;
Sprite* sprite;
RenderPassComponent* renderPass;
};
std::vector<RenderableEntity> renderables;
auto renderView = registry.view<ECSTransform, Sprite>();
renderView.each([&](auto entity, auto& transform, auto& sprite) {
RenderableEntity re;
re.entity = entity;
re.transform = &transform;
re.sprite = &sprite;
re.renderPass = registry.try_get<RenderPassComponent>(entity);
renderables.push_back(re);
});
// Sort by render pass order (lower = earlier)
std::sort(renderables.begin(), renderables.end(), [](const RenderableEntity& a, const RenderableEntity& b) {
int orderA = a.renderPass ? a.renderPass->order : 0;
int orderB = b.renderPass ? b.renderPass->order : 0;
return orderA < orderB;
});
// Group by render pass and render
int currentPassOrder = INT_MIN;
Shader* currentShader = nullptr;
for (const auto& re : renderables) {
int passOrder = re.renderPass ? re.renderPass->order : 0;
// If we've moved to a new render pass, update settings
if (passOrder != currentPassOrder) {
if (currentShader) {
EndShaderMode();
currentShader = nullptr;
}
// Apply render pass settings
if (re.renderPass) {
if (!re.renderPass->depthTest) {
rlDisableDepthTest();
} else {
rlEnableDepthTest();
}
// If pass has a shader override, use it
if (re.renderPass->shaderId > 0) {
currentShader = shaderManager.Get(re.renderPass->shaderId);
if (currentShader) {
BeginShaderMode(*currentShader);
// Set uniforms for this shader
int lightLoc = GetShaderLocation(*currentShader, "lightDir");
if (lightLoc != -1) {
SetShaderValue(*currentShader, lightLoc, &lightDir, SHADER_UNIFORM_VEC3);
}
}
}
}
currentPassOrder = passOrder;
}
// Get material if entity has one
MaterialComponent* matComp = registry.try_get<MaterialComponent>(re.entity);
Shader* matShader = nullptr;
Color albedo = WHITE;
if (matComp && matComp->materialId > 0) {
MaterialData* matData = materialManager.Get(matComp->materialId);
if (matData) {
albedo = matData->albedo;
if (matData->shaderId > 0 && !currentShader) {
matShader = shaderManager.Get(matData->shaderId);
if (matShader) {
BeginShaderMode(*matShader);
currentShader = matShader;
// Set uniforms
int lightLoc = GetShaderLocation(*matShader, "lightDir");
if (lightLoc != -1) {
SetShaderValue(*matShader, lightLoc, &lightDir, SHADER_UNIFORM_VEC3);
}
Vector4 color = {
albedo.r / 255.0f,
albedo.g / 255.0f,
albedo.b / 255.0f,
albedo.a / 255.0f
};
int albedoLoc = GetShaderLocation(*matShader, "albedo");
if (albedoLoc != -1) {
SetShaderValue(*matShader, albedoLoc, &color, SHADER_UNIFORM_VEC4);
}
}
}
}
}
// Render the model
if (re.sprite->modelId > 0) {
Model* model = modelManager.Get(re.sprite->modelId);
if (model) {
DrawModelEx(*model, re.transform->position, Vector3{0, 1, 0},
re.transform->rotation * RAD2DEG, re.transform->scale,
re.sprite->color);
}
}
// Clean up material shader if we started it
if (matShader && currentShader == matShader) {
EndShaderMode();
currentShader = nullptr;
}
}
// Clean up any active shader
if (currentShader) {
EndShaderMode();
}
rlEnableDepthTest(); // Ensure depth test is re-enabled
EndMode3D();
}
void Application::Draw()
@@ -294,6 +375,7 @@ void Application::Shutdown()
hotReload = nullptr;
}
scriptEngine.Shutdown();
if (enableEditor)
{
@@ -303,15 +385,13 @@ void Application::Shutdown()
// Shutdown rlImGui first while the GL context and window are still valid
rlImGuiShutdown();
// Shutdown script engine
scriptEngine.Shutdown();
// Clear ECS registry first to release all component data
registry.clear();
// Unload assets
for (auto &model : models)
{
UnloadModel(model);
}
UnloadShader(toonShader);
// Unload all resources before closing window (while GL context is still valid)
materialManager.Clear();
shaderManager.UnloadAll();
modelManager.UnloadAll();
// Clear the trace log callback before closing window to prevent logging after cleanup
SetTraceLogCallback(nullptr);
+76
View File
@@ -0,0 +1,76 @@
#include "MaterialManager.h"
#include "log/log.h"
MaterialManager::MaterialManager() : nextId(1), cleared(false)
{
}
MaterialManager::~MaterialManager()
{
// Only clear if not already done
if (!cleared) {
materials.clear();
}
}
unsigned int MaterialManager::Create(unsigned int shaderId, Color albedo)
{
unsigned int id = nextId++;
MaterialData data;
data.shaderId = shaderId;
data.albedo = albedo;
materials[id] = data;
log_info("Created material id=%u with shader=%u", id, shaderId);
return id;
}
void MaterialManager::Remove(unsigned int id)
{
auto it = materials.find(id);
if (it != materials.end())
{
materials.erase(it);
log_info("Removed material id=%u", id);
}
}
MaterialData* MaterialManager::Get(unsigned int id)
{
auto it = materials.find(id);
if (it != materials.end())
{
return &it->second;
}
return nullptr;
}
void MaterialManager::SetShader(unsigned int id, unsigned int shaderId)
{
auto it = materials.find(id);
if (it != materials.end())
{
it->second.shaderId = shaderId;
log_info("Updated material id=%u shader to %u", id, shaderId);
}
}
void MaterialManager::SetAlbedo(unsigned int id, Color albedo)
{
auto it = materials.find(id);
if (it != materials.end())
{
it->second.albedo = albedo;
}
}
void MaterialManager::Clear()
{
if (!cleared) {
materials.clear();
cleared = true;
log_info("Cleared all materials");
}
}
+79
View File
@@ -0,0 +1,79 @@
#include "ModelManager.h"
#include "log/log.h"
ModelManager::ModelManager() : nextId(1), unloaded(false)
{
}
ModelManager::~ModelManager()
{
// Only unload if not already done
if (!unloaded) {
for (auto& pair : models) {
UnloadModel(pair.second);
}
models.clear();
}
}
unsigned int ModelManager::Load(const std::string& path)
{
Model model = LoadModel(path.c_str());
if (model.meshCount == 0)
{
log_warn("Failed to load model: %s", path.c_str());
return 0;
}
unsigned int id = nextId++;
models[id] = model;
log_info("Loaded model id=%u from %s", id, path.c_str());
return id;
}
unsigned int ModelManager::LoadFromMesh(Mesh mesh)
{
Model model = LoadModelFromMesh(mesh);
unsigned int id = nextId++;
models[id] = model;
log_info("Loaded model id=%u from mesh", id);
return id;
}
void ModelManager::Unload(unsigned int id)
{
auto it = models.find(id);
if (it != models.end())
{
UnloadModel(it->second);
models.erase(it);
log_info("Unloaded model id=%u", id);
}
}
Model* ModelManager::Get(unsigned int id)
{
auto it = models.find(id);
if (it != models.end())
{
return &it->second;
}
return nullptr;
}
void ModelManager::UnloadAll()
{
if (!unloaded) {
for (auto& pair : models)
{
UnloadModel(pair.second);
}
models.clear();
unloaded = true;
log_info("Unloaded all models");
}
}
+68
View File
@@ -0,0 +1,68 @@
#include "ShaderManager.h"
#include "log/log.h"
ShaderManager::ShaderManager() : nextId(1), unloaded(false)
{
}
ShaderManager::~ShaderManager()
{
// Only unload if not already done
if (!unloaded) {
for (auto& pair : shaders) {
UnloadShader(pair.second);
}
shaders.clear();
}
}
unsigned int ShaderManager::Load(const std::string& vsPath, const std::string& fsPath)
{
Shader shader = LoadShader(vsPath.c_str(), fsPath.c_str());
if (shader.id == 0)
{
log_warn("Failed to load shader: %s / %s", vsPath.c_str(), fsPath.c_str());
return 0;
}
unsigned int id = nextId++;
shaders[id] = shader;
log_info("Loaded shader id=%u from %s / %s (raylib id=%u)", id, vsPath.c_str(), fsPath.c_str(), shader.id);
return id;
}
void ShaderManager::Unload(unsigned int id)
{
auto it = shaders.find(id);
if (it != shaders.end())
{
UnloadShader(it->second);
shaders.erase(it);
log_info("Unloaded shader id=%u", id);
}
}
Shader* ShaderManager::Get(unsigned int id)
{
auto it = shaders.find(id);
if (it != shaders.end())
{
return &it->second;
}
return nullptr;
}
void ShaderManager::UnloadAll()
{
if (!unloaded) {
for (auto& pair : shaders)
{
UnloadShader(pair.second);
}
shaders.clear();
unloaded = true;
log_info("Unloaded all shaders");
}
}
+249
View File
@@ -193,6 +193,163 @@ void AS_RemoveTag(uint32_t entity) {
g_registry->remove<Tag>((entt::entity)entity);
}
// === Camera3D Component ===
void AS_AddCamera3D(uint32_t entity, float px, float py, float pz, float tx, float ty, float tz, float fovy) {
if (!g_registry) return;
Camera3DComponent cam;
cam.position = {px, py, pz};
cam.target = {tx, ty, tz};
cam.up = {0.0f, 1.0f, 0.0f};
cam.fovy = fovy;
cam.projection = 0; // CAMERA_PERSPECTIVE
g_registry->emplace<Camera3DComponent>((entt::entity)entity, cam);
}
void AS_SetCameraPosition(uint32_t entity, float x, float y, float z) {
if (!g_registry) return;
if (auto* c = g_registry->try_get<Camera3DComponent>((entt::entity)entity)) {
c->position = {x, y, z};
}
}
void AS_SetCameraTarget(uint32_t entity, float x, float y, float z) {
if (!g_registry) return;
if (auto* c = g_registry->try_get<Camera3DComponent>((entt::entity)entity)) {
c->target = {x, y, z};
}
}
void AS_SetCameraFovy(uint32_t entity, float fovy) {
if (!g_registry) return;
if (auto* c = g_registry->try_get<Camera3DComponent>((entt::entity)entity)) {
c->fovy = fovy;
}
}
bool AS_HasCamera3D(uint32_t entity) {
if (!g_registry) return false;
return g_registry->all_of<Camera3DComponent>((entt::entity)entity);
}
void AS_RemoveCamera3D(uint32_t entity) {
if (!g_registry) return;
g_registry->remove<Camera3DComponent>((entt::entity)entity);
}
// === Light Component ===
void AS_AddLight(uint32_t entity, float dx, float dy, float dz, float intensity) {
if (!g_registry) return;
LightComponent light;
light.direction = {dx, dy, dz};
light.color = WHITE;
light.intensity = intensity;
g_registry->emplace<LightComponent>((entt::entity)entity, light);
}
void AS_SetLightDirection(uint32_t entity, float x, float y, float z) {
if (!g_registry) return;
if (auto* l = g_registry->try_get<LightComponent>((entt::entity)entity)) {
l->direction = {x, y, z};
}
}
void AS_SetLightIntensity(uint32_t entity, float intensity) {
if (!g_registry) return;
if (auto* l = g_registry->try_get<LightComponent>((entt::entity)entity)) {
l->intensity = intensity;
}
}
void AS_SetLightColor(uint32_t entity, uint32_t color) {
if (!g_registry) return;
if (auto* l = g_registry->try_get<LightComponent>((entt::entity)entity)) {
l->color.r = (color >> 24) & 0xFF;
l->color.g = (color >> 16) & 0xFF;
l->color.b = (color >> 8) & 0xFF;
l->color.a = color & 0xFF;
}
}
bool AS_HasLight(uint32_t entity) {
if (!g_registry) return false;
return g_registry->all_of<LightComponent>((entt::entity)entity);
}
void AS_RemoveLight(uint32_t entity) {
if (!g_registry) return;
g_registry->remove<LightComponent>((entt::entity)entity);
}
// === Material Component ===
void AS_AddMaterial(uint32_t entity, unsigned int materialId) {
if (!g_registry) return;
g_registry->emplace<MaterialComponent>((entt::entity)entity, materialId);
}
void AS_SetMaterialId(uint32_t entity, unsigned int materialId) {
if (!g_registry) return;
if (auto* m = g_registry->try_get<MaterialComponent>((entt::entity)entity)) {
m->materialId = materialId;
}
}
unsigned int AS_GetMaterialId(uint32_t entity) {
if (!g_registry) return 0;
if (auto* m = g_registry->try_get<MaterialComponent>((entt::entity)entity)) {
return m->materialId;
}
return 0;
}
bool AS_HasMaterial(uint32_t entity) {
if (!g_registry) return false;
return g_registry->all_of<MaterialComponent>((entt::entity)entity);
}
void AS_RemoveMaterialComponent(uint32_t entity) {
if (!g_registry) return;
g_registry->remove<MaterialComponent>((entt::entity)entity);
}
// === RenderPass Component ===
void AS_AddRenderPass(uint32_t entity, int order, bool depthTest, bool depthWrite, unsigned int shaderId) {
if (!g_registry) return;
RenderPassComponent pass;
pass.order = order;
pass.depthTest = depthTest;
pass.depthWrite = depthWrite;
pass.shaderId = shaderId;
g_registry->emplace<RenderPassComponent>((entt::entity)entity, pass);
}
void AS_SetRenderPassOrder(uint32_t entity, int order) {
if (!g_registry) return;
if (auto* p = g_registry->try_get<RenderPassComponent>((entt::entity)entity)) {
p->order = order;
}
}
void AS_SetRenderPassShader(uint32_t entity, unsigned int shaderId) {
if (!g_registry) return;
if (auto* p = g_registry->try_get<RenderPassComponent>((entt::entity)entity)) {
p->shaderId = shaderId;
}
}
bool AS_HasRenderPass(uint32_t entity) {
if (!g_registry) return false;
return g_registry->all_of<RenderPassComponent>((entt::entity)entity);
}
void AS_RemoveRenderPass(uint32_t entity) {
if (!g_registry) return;
g_registry->remove<RenderPassComponent>((entt::entity)entity);
}
// === Registration ===
void RegisterECSBindings(asIScriptEngine *engine) {
@@ -313,5 +470,97 @@ void RegisterECSBindings(asIScriptEngine *engine) {
asFUNCTION(AS_RemoveTag), asCALL_CDECL);
assert(r >= 0);
// Camera3D component
r = engine->RegisterGlobalFunction("void AddCamera3D(uint, float, float, float, float, float, float, float)",
asFUNCTION(AS_AddCamera3D), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetCameraPosition(uint, float, float, float)",
asFUNCTION(AS_SetCameraPosition), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetCameraTarget(uint, float, float, float)",
asFUNCTION(AS_SetCameraTarget), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetCameraFovy(uint, float)",
asFUNCTION(AS_SetCameraFovy), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool HasCamera3D(uint)",
asFUNCTION(AS_HasCamera3D), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void RemoveCamera3D(uint)",
asFUNCTION(AS_RemoveCamera3D), asCALL_CDECL);
assert(r >= 0);
// Light component
r = engine->RegisterGlobalFunction("void AddLight(uint, float, float, float, float = 1.0f)",
asFUNCTION(AS_AddLight), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetLightDirection(uint, float, float, float)",
asFUNCTION(AS_SetLightDirection), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetLightIntensity(uint, float)",
asFUNCTION(AS_SetLightIntensity), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetLightColor(uint, uint)",
asFUNCTION(AS_SetLightColor), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool HasLight(uint)",
asFUNCTION(AS_HasLight), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void RemoveLight(uint)",
asFUNCTION(AS_RemoveLight), asCALL_CDECL);
assert(r >= 0);
// Material component
r = engine->RegisterGlobalFunction("void AddMaterial(uint, uint)",
asFUNCTION(AS_AddMaterial), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetMaterialId(uint, uint)",
asFUNCTION(AS_SetMaterialId), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("uint GetMaterialId(uint)",
asFUNCTION(AS_GetMaterialId), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool HasMaterial(uint)",
asFUNCTION(AS_HasMaterial), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void RemoveMaterial(uint)",
asFUNCTION(AS_RemoveMaterialComponent), asCALL_CDECL);
assert(r >= 0);
// RenderPass component
r = engine->RegisterGlobalFunction("void AddRenderPass(uint, int, bool, bool, uint)",
asFUNCTION(AS_AddRenderPass), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetRenderPassOrder(uint, int)",
asFUNCTION(AS_SetRenderPassOrder), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetRenderPassShader(uint, uint)",
asFUNCTION(AS_SetRenderPassShader), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("bool HasRenderPass(uint)",
asFUNCTION(AS_HasRenderPass), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void RemoveRenderPass(uint)",
asFUNCTION(AS_RemoveRenderPass), asCALL_CDECL);
assert(r >= 0);
engine->SetDefaultNamespace("");
}
+144
View File
@@ -0,0 +1,144 @@
#include "scripting/ResourceBindings.h"
#include "ShaderManager.h"
#include "ModelManager.h"
#include "MaterialManager.h"
#include <angelscript.h>
#include <assert.h>
#include "raylib.h"
// Global resource manager pointers for script access
static ShaderManager* g_shaderManager = nullptr;
static ModelManager* g_modelManager = nullptr;
static MaterialManager* g_materialManager = nullptr;
void SetResourceManagers(ShaderManager* shaderMgr, ModelManager* modelMgr, MaterialManager* materialMgr) {
g_shaderManager = shaderMgr;
g_modelManager = modelMgr;
g_materialManager = materialMgr;
}
// === Shader Management ===
unsigned int AS_LoadShader(const std::string& vsPath, const std::string& fsPath) {
if (!g_shaderManager) return 0;
return g_shaderManager->Load(vsPath, fsPath);
}
void AS_UnloadShader(unsigned int id) {
if (!g_shaderManager) return;
g_shaderManager->Unload(id);
}
// === Model Management ===
unsigned int AS_LoadModel(const std::string& path) {
if (!g_modelManager) return 0;
return g_modelManager->Load(path);
}
unsigned int AS_LoadModelCube(float width, float height, float length) {
if (!g_modelManager) return 0;
Mesh mesh = GenMeshCube(width, height, length);
return g_modelManager->LoadFromMesh(mesh);
}
unsigned int AS_LoadModelSphere(float radius, int rings, int slices) {
if (!g_modelManager) return 0;
Mesh mesh = GenMeshSphere(radius, rings, slices);
return g_modelManager->LoadFromMesh(mesh);
}
unsigned int AS_LoadModelPlane(float width, float length, int resX, int resZ) {
if (!g_modelManager) return 0;
Mesh mesh = GenMeshPlane(width, length, resX, resZ);
return g_modelManager->LoadFromMesh(mesh);
}
void AS_UnloadModel(unsigned int id) {
if (!g_modelManager) return;
g_modelManager->Unload(id);
}
// === Material Management ===
unsigned int AS_CreateMaterial(unsigned int shaderId, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
if (!g_materialManager) return 0;
Color albedo = {r, g, b, a};
return g_materialManager->Create(shaderId, albedo);
}
void AS_RemoveMaterial(unsigned int id) {
if (!g_materialManager) return;
g_materialManager->Remove(id);
}
void AS_SetMaterialShader(unsigned int id, unsigned int shaderId) {
if (!g_materialManager) return;
g_materialManager->SetShader(id, shaderId);
}
void AS_SetMaterialAlbedo(unsigned int id, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
if (!g_materialManager) return;
Color albedo = {r, g, b, a};
g_materialManager->SetAlbedo(id, albedo);
}
void RegisterResourceBindings(asIScriptEngine *engine)
{
int r;
// === Shader namespace ===
engine->SetDefaultNamespace("Shader");
r = engine->RegisterGlobalFunction("uint Load(const string &in, const string &in)",
asFUNCTION(AS_LoadShader), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void Unload(uint)",
asFUNCTION(AS_UnloadShader), asCALL_CDECL);
assert(r >= 0);
// === Model namespace ===
engine->SetDefaultNamespace("Model");
r = engine->RegisterGlobalFunction("uint Load(const string &in)",
asFUNCTION(AS_LoadModel), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("uint LoadCube(float, float, float)",
asFUNCTION(AS_LoadModelCube), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("uint LoadSphere(float, int, int)",
asFUNCTION(AS_LoadModelSphere), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("uint LoadPlane(float, float, int, int)",
asFUNCTION(AS_LoadModelPlane), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void Unload(uint)",
asFUNCTION(AS_UnloadModel), asCALL_CDECL);
assert(r >= 0);
// === Material namespace ===
engine->SetDefaultNamespace("Material");
r = engine->RegisterGlobalFunction("uint Create(uint, uint8, uint8, uint8, uint8)",
asFUNCTION(AS_CreateMaterial), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void Remove(uint)",
asFUNCTION(AS_RemoveMaterial), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetShader(uint, uint)",
asFUNCTION(AS_SetMaterialShader), asCALL_CDECL);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void SetAlbedo(uint, uint8, uint8, uint8, uint8)",
asFUNCTION(AS_SetMaterialAlbedo), asCALL_CDECL);
assert(r >= 0);
engine->SetDefaultNamespace("");
}
+2
View File
@@ -5,6 +5,7 @@
#include "scripting/TextureBindings.h"
#include "scripting/MathBindings.h"
#include "scripting/ECSBindings.h"
#include "scripting/ResourceBindings.h"
void ScriptBindings::RegisterAll(asIScriptEngine *engine)
{
@@ -15,4 +16,5 @@ void ScriptBindings::RegisterAll(asIScriptEngine *engine)
RegisterTextureBindings(engine);
RegisterMathBindings(engine);
RegisterECSBindings(engine);
RegisterResourceBindings(engine);
}
+4
View File
@@ -15,6 +15,10 @@ add_executable(unit_tests
${CMAKE_SOURCE_DIR}/src/scripting/ImageBindings.cpp
${CMAKE_SOURCE_DIR}/src/scripting/TextureBindings.cpp
${CMAKE_SOURCE_DIR}/src/scripting/MathBindings.cpp
${CMAKE_SOURCE_DIR}/src/scripting/ResourceBindings.cpp
${CMAKE_SOURCE_DIR}/src/ShaderManager.cpp
${CMAKE_SOURCE_DIR}/src/ModelManager.cpp
${CMAKE_SOURCE_DIR}/src/MaterialManager.cpp
${CMAKE_SOURCE_DIR}/src/log/log.c
)