becs/examples/example1/example1.c

206 lines
7.5 KiB
C

#define BECS_MAX_ENTITIES 100000ULL
#define BECS_MAX_COMPONENTS 4ULL
#define BECS_IMPLEMENTATION
#include "../../becs.h"
#include <stdlib.h>
#include <stdio.h>
#include "external/raylib/src/raylib.h"
#include "external/raylib/src/rlgl.h"
#include "external/raylib/src/raymath.h"
// Component structs
typedef struct {
float x, y;
} Position;
typedef struct {
float vx, vy;
} Velocity;
typedef struct {
float ax, ay;
} Acceleration;
typedef struct {
float radius;
float lifetime;
} ParticleData;
// Function to spawn a particle
void SpawnParticle(BECS_ECS *ecs, BECS_ComponentID posID, BECS_ComponentID velID, BECS_ComponentID accID, BECS_ComponentID dataID, float x, float y) {
BECS_Entity entity = BECS_EntityCreate(ecs);
if (entity == BECS_NULL_ENTITY) return;
Position *pos = (Position *)BECS_ComponentAdd(ecs, entity, posID);
pos->x = x;
pos->y = y;
Velocity *vel = (Velocity *)BECS_ComponentAdd(ecs, entity, velID);
vel->vx = GetRandomValue(-100, 100);
vel->vy = GetRandomValue(-200, -50);
Acceleration *acc = (Acceleration *)BECS_ComponentAdd(ecs, entity, accID);
acc->ax = 0.0f;
acc->ay = 100.0f; // Gravity
ParticleData *data = (ParticleData *)BECS_ComponentAdd(ecs, entity, dataID);
data->radius = 5.0f;
data->lifetime = 2.0f;
}
void LifetimeSystem(BECS_ECS *ecs, float dt, ParticleData *data, BECS_Entity *entity) {
// ParticleData *data = (ParticleData *)ecs->componentPools[3].denseArray;
// BECS_Entity *entity = (BECS_Entity *)ecs->componentPools[3].denseEntityMapping;
// for (uint32_t i = 0; i < ecs->entityCount; i++) {
uint32_t entityCount = ecs->entityCount;
for (uint32_t i = 0; i < entityCount; i++) {
data[i].lifetime -= dt;
if (data[i].lifetime <= 0.0f) {
BECS_EntityDestroy(ecs, entity[i]);
}
}
}
void PhysicsSystem(BECS_ECS *ecs, float dt, Position *pos, Velocity *vel, Acceleration *acc) {
//Position *pos = ((Position *)ecs->componentPools[0].denseArray);
//Velocity *vel = ((Velocity *)ecs->componentPools[1].denseArray);
// Acceleration *acc = ((Acceleration *)ecs->componentPools[2].denseArray);
// for (uint32_t i = 0; i < ecs->entityCount; i++) {
uint32_t entityCount = ecs->entityCount;
for (uint32_t i = 0; i < entityCount; i++) {
vel[i].vy += acc[i].ay * dt;
vel[i].vx += acc[i].ax * dt;
pos[i].y += vel[i].vy * dt;
pos[i].x += vel[i].vx * dt;
}
}
void RenderSystem(BECS_ECS *ecs, float dt, Position *pos, ParticleData *data) {
// Position *pos = ((Position *)ecs->componentPools[0].denseArray);
// ParticleData *data = ((ParticleData *)ecs->componentPools[3].denseArray);
// for (uint32_t i = 0; i < ecs->entityCount; i++) {
uint32_t entityCount = ecs->entityCount;
for (uint32_t i = 0; i < entityCount; i++) {
float alpha = data[i].lifetime / 2.0;
Color color = {255, 255, 255, (unsigned char)(alpha * 255)};
DrawCircle(pos[i].x, pos[i].y, data[i].radius, color);
}
}
// NOTE: This didn't actually improve it as much as I wanted. Gotta look for a better way to render.
void DrawCircleBatched(Vector2 *positions, float *radii, Color *colors, uint32_t count, uint32_t segments) {
rlBegin(RL_TRIANGLES);
for(uint32_t i=0 ;i<count; i++){
Vector2 center=positions[i];
float radius=radii[i];
Color color=colors[i];
rlColor4ub(color.r,color.g,color.b,color.a);
//Approximatecirclewithtriangles
for(uint32_t j=0; j<segments; j++){
float angle1=(j*2.0f*PI)/segments;
float angle2=((j+1)*2.0f*PI)/segments;
Vector2 v1={center.x+radius*cosf(angle1),center.y+radius*sinf(angle1)};
Vector2 v2={center.x+radius*cosf(angle2),center.y+radius*sinf(angle2)};
rlVertex2f(center.x,center.y);
rlVertex2f(v1.x,v1.y);
rlVertex2f(v2.x,v2.y);
}
}
rlEnd();
}
void RenderSystemBatched(BECS_ECS *ecs, float dt, Position *pos, ParticleData *data, Vector2 *posArray, float *radArray, Color *colArray) {
uint32_t batchCount = 0;
uint32_t entityCount = ecs->componentPools[0].count;//Use correct count
for(uint32_t i=0; i<entityCount; i++){
posArray[batchCount]=(Vector2){pos[i].x,pos[i].y};
radArray[batchCount]=data[i].radius;
float alpha=data[i].lifetime/2.0f;
colArray[batchCount]=(Color){255,255,255,(unsigned char)(alpha*255)};
batchCount++;
}
DrawCircleBatched(posArray, radArray, colArray, batchCount, 16);
}
int main(void) {
// Initialize ECS
size_t componentSizes[4] = {sizeof(Position), sizeof(Velocity), sizeof(Acceleration), sizeof(ParticleData)};
size_t memSize = BECS_GetMinMemoryArenaSize(componentSizes, 4);
#ifdef _WIN32
printf("%llu\n", memSize);
#elif __unix__
printf("%lu\n", memSize);
#endif
char *memory = (char *)malloc(memSize);
BECS_ECS ecs = BECS_InitECS(memory, memSize);
// Register components
BECS_ComponentID posID = BECS_ComponentRegister(&ecs, sizeof(Position), BECS_MAX_ENTITIES);
BECS_ComponentID velID = BECS_ComponentRegister(&ecs, sizeof(Velocity), BECS_MAX_ENTITIES);
BECS_ComponentID accID = BECS_ComponentRegister(&ecs, sizeof(Acceleration), BECS_MAX_ENTITIES);
BECS_ComponentID dataID = BECS_ComponentRegister(&ecs, sizeof(ParticleData), BECS_MAX_ENTITIES);
Position *posData = (Position *)BECS_ComponentGetPool(&ecs, posID);
Velocity *velData = (Velocity *)BECS_ComponentGetPool(&ecs, velID);
Acceleration *accData = (Acceleration *)BECS_ComponentGetPool(&ecs, accID);
ParticleData *dataData = (ParticleData *)BECS_ComponentGetPool(&ecs, dataID);
// TODO: This should probably be done in a query system
BECS_Entity *entityData = (BECS_Entity *)ecs.componentPools[dataID].denseEntityMapping;
InitWindow(1600, 800, "2D Particle System with BECS");
Vector2 *posArray = malloc(BECS_MAX_ENTITIES * sizeof(Vector2));
float *radArray = malloc(BECS_MAX_ENTITIES * sizeof(float));
Color *colArray = malloc(BECS_MAX_ENTITIES * sizeof(Color));
rlMatrixMode(RL_PROJECTION);
rlLoadIdentity();
rlOrtho(0,GetScreenWidth(),GetScreenHeight(),0, 0.0f, 1.0f);
rlMatrixMode(RL_MODELVIEW);
rlLoadIdentity();
rlSetBlendMode(RL_BLEND_ALPHA);
rlDisableBackfaceCulling();
rlDisableDepthTest();
rlDisableTexture();
rlDrawRenderBatchActive();
while (!WindowShouldClose()) {
float dt = GetFrameTime();
LifetimeSystem(&ecs, dt, dataData, entityData);
// Spawn particle on mouse click
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
Vector2 mousePos = GetMousePosition();
for (uint32_t i = 0; i < 100; i++) {
SpawnParticle(&ecs, posID, velID, accID, dataID, mousePos.x, mousePos.y);
}
}
PhysicsSystem(&ecs, dt, posData, velData, accData);
BeginDrawing();
ClearBackground(BLACK);
// RenderSystem(&ecs, dt, posData, dataData);
RenderSystemBatched(&ecs, dt, posData, dataData, posArray, radArray, colArray);
DrawText(TextFormat("Particles: %u", ecs.entityCount), 10, 10, 20, WHITE);
DrawText(TextFormat("Time(ms): %f", dt * 1000), 10, 30, 20, WHITE);
DrawText(TextFormat("FPS: %f", 1/dt), 10, 50, 20, WHITE);
DrawText(TextFormat("Screen Res: %d x %d", GetScreenWidth(), GetScreenHeight()), 10, 70, 20, WHITE);
EndDrawing();
}
CloseWindow();
free(memory);
free(posArray);
free(colArray);
free(radArray);
return 0;
}