Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 10 additions & 15 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
*.so
*.a
*.out
build/
dist/
target/

# Dependencies
node_modules/
Expand All @@ -18,26 +15,28 @@ venv/
__pycache__/
.mypy_cache/
.pytest_cache/
target/
.gradle/
julia-*/
zig*/

# Editors and IDEs
# Logs and temp files
*.log
*.tmp
*.swp

# Editors
.vscode/
.idea/
*.swp
*.swo
*.tmp

# System files
.DS_Store
Thumbs.db

# Environment
.env
.env.local
*.env.*

# Logs and coverage
*.log
# Coverage
coverage/
htmlcov/
.coverage
Expand All @@ -61,8 +60,4 @@ htmlcov/
*.Z
*.lz
*.lzo
*.tar.gz
*.tar.bz2
*.tar.xz
*.tar.zst
```
6 changes: 5 additions & 1 deletion FarmEngine/assets/shaders/terrain.frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ layout(binding = 2) uniform sampler2D normalMap;
layout(binding = 3) uniform sampler2D roughnessMap;
layout(binding = 4) uniform sampler2D metalnessMap;

layout(binding = 0) uniform CameraData {
vec3 cameraPosition;
} cameraData;
Comment on lines +16 to +18
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Terrain ubo layout mismatch 🐞 Bug ≡ Correctness

terrain.frag.glsl binds CameraData at binding 0 with only vec3 cameraPosition, but
terrain.vert.glsl binding 0 UBO starts with three mat4 fields, so the fragment shader will read
incorrect bytes for cameraPosition and compute an invalid view direction. This will produce
incorrect lighting/specular results (and is extremely hard to debug because descriptor binding types
still appear compatible).
Agent Prompt
### Issue description
The terrain vertex and fragment shaders both use descriptor `binding = 0`, but they declare incompatible UBO layouts. The fragment shader reads `cameraPosition` from offset 0, while the vertex shader’s binding=0 buffer begins with `mat4 model/view/projection`.

### Issue Context
In Vulkan, `binding = 0` refers to the same descriptor binding across shader stages. Even if both are UBOs, differing struct layouts means the fragment stage will interpret the bytes incorrectly.

### Fix Focus Areas
- FarmEngine/assets/shaders/terrain.frag.glsl[11-23]
- FarmEngine/assets/shaders/terrain.vert.glsl[14-20]
- FarmEngine/assets/shaders/terrain.frag.glsl[49-53]

### Suggested fix
Make the fragment shader binding=0 UBO match the vertex shader layout, e.g.:
```glsl
layout(binding = 0) uniform UniformBuffer {
    mat4 model;
    mat4 view;
    mat4 projection;
    vec3 cameraPosition;
    float time;
} ubo;

// ...
vec3 viewDir = normalize(ubo.cameraPosition - fragPosition);
```
Alternatively, if you truly want a separate camera-only UBO, give it a different binding number and ensure the descriptor set layout and buffer binding are updated accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


layout(binding = 5) uniform LightData {
vec3 position;
vec3 color;
Expand Down Expand Up @@ -45,7 +49,7 @@ void main() {

// Lighting
vec3 lightDir = normalize(position - fragPosition);
vec3 viewDir = normalize(cameraPosition - fragPosition);
vec3 viewDir = normalize(cameraData.cameraPosition - fragPosition);
vec3 halfDir = normalize(lightDir + viewDir);

// Diffuse (Lambert)
Expand Down
4 changes: 4 additions & 0 deletions FarmEngine/core/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

namespace farm {

// Alias for FarmEngine namespace to maintain backward compatibility
namespace EngineNS = FarmEngine;

Comment on lines +10 to +12
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Broken namespace alias 🐞 Bug ≡ Correctness

FarmEngine/core/Engine.h introduces namespace EngineNS = FarmEngine; inside namespace farm but
FarmEngine is not declared at that point, so any translation unit that includes Engine.h first
will fail to compile. FarmEngine/core/Engine.cpp includes core/Engine.h as its first include,
making this failure immediate for the core target.
Agent Prompt
### Issue description
`Engine.h` defines `namespace EngineNS = FarmEngine;` but `FarmEngine` is not declared in that header before the alias. This breaks compilation when `Engine.h` is the first include in a translation unit (it is in `Engine.cpp`).

### Issue Context
C++ namespace aliases require the target namespace to be declared before the alias.

### Fix Focus Areas
- FarmEngine/core/Engine.h[8-16]
- FarmEngine/core/Engine.cpp[1-9]

### Suggested fix
Choose one of:
1) Add a forward declaration before the alias:
```cpp
namespace FarmEngine {}
namespace farm {
  namespace EngineNS = ::FarmEngine;
  ...
}
```
2) If you intend a global alias (not nested under `farm`), move it outside `namespace farm`:
```cpp
namespace FarmEngine {}
namespace EngineNS = FarmEngine;
namespace farm { ... }
```
Also consider using `::FarmEngine` in the alias to avoid accidental lookup issues.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


// Forward declarations
class Window;
class Renderer;
Expand Down
4 changes: 2 additions & 2 deletions FarmEngine/core/ecs/ECS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void ECS::destroyEntity(EntityID entity) {

// Limpiar componentes
for (auto& componentList : components) {
if (componentList.second && entity < componentList.second->size()) {
(*componentList.second)[entity].reset();
if (entity < componentList.size()) {
componentList[entity].reset();
}
}

Expand Down
46 changes: 32 additions & 14 deletions FarmEngine/core/ecs/ECS.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ class ECS {
private:
std::vector<Entity> entities;
std::vector<EntityID> availableIDs;
std::unordered_map<std::type_index, std::vector<std::unique_ptr<Component>>> components;
std::unordered_map<std::type_index, EntityID> componentTypeToIndex;
std::vector<std::vector<std::unique_ptr<Component>>> components;
std::unordered_map<std::type_index, uint32_t> componentTypeToIndex;

uint32_t nextComponentIndex = 0;

Expand All @@ -68,18 +68,18 @@ class ECS {
// Template implementations
template<typename T, typename... Args>
T& ECS::addComponent(EntityID entity, Args&&... args) {
if (entity >= entities.size() || !entities[entity].active) {
throw std::out_of_range("Invalid or inactive entity ID");
}
Comment on lines +71 to +73
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Missing stdexcept include 🐞 Bug ≡ Correctness

ECS.h now throws std::out_of_range and std::overflow_error in header-defined templates, but
does not include <stdexcept>, causing compilation errors when these templates are instantiated.
This is directly introduced by the new validation/overflow checks.
Agent Prompt
### Issue description
`FarmEngine/core/ecs/ECS.h` throws `std::out_of_range` and `std::overflow_error` in template implementations, but the header does not include `<stdexcept>`. This will break compilation when templates are instantiated.

### Issue Context
Because the throwing code is in the header (templates), every translation unit that instantiates these methods needs the proper declarations available via includes.

### Fix Focus Areas
- FarmEngine/core/ecs/ECS.h[1-9]
- FarmEngine/core/ecs/ECS.h[68-74]
- FarmEngine/core/ecs/ECS.h[128-144]

### Suggested fix
Add the missing include near the top:
```cpp
#include <stdexcept>
```
(Keep existing includes as-is.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


auto index = getComponentTypeIndex<T>();

if (index >= components.size()) {
components.resize(index + 1);
}

if (!components[index]) {
components[index] = std::vector<std::unique_ptr<Component>>();
}

while (components[index]->size() <= entity) {
components[index]->push_back(nullptr);
while (components[index].size() <= entity) {
components[index].push_back(nullptr);
}

auto component = std::make_unique<T>(std::forward<Args>(args)...);
Expand All @@ -94,13 +94,17 @@ T& ECS::addComponent(EntityID entity, Args&&... args) {

template<typename T>
T* ECS::getComponent(EntityID entity) {
if (entity >= entities.size() || !entities[entity].active) {
return nullptr;
}

auto index = getComponentTypeIndex<T>();

if (index >= components.size() || !components[index]) {
if (index >= components.size()) {
return nullptr;
}

if (entity >= components[index]->size()) {
if (entity >= components[index].size()) {
return nullptr;
}

Expand All @@ -109,19 +113,33 @@ T* ECS::getComponent(EntityID entity) {

template<typename T>
void ECS::removeComponent(EntityID entity) {
if (entity >= entities.size() || !entities[entity].active) {
return;
}

auto index = getComponentTypeIndex<T>();

if (index < components.size() && components[index] && entity < components[index]->size()) {
if (index < components.size() && entity < components[index].size()) {
components[index][entity].reset();
entities[entity].mask.reset(index);
}
}

template<typename T>
uint32_t ECS::getComponentTypeIndex() {
static uint32_t index = []() {
return nextComponentIndex++;
}();
auto key = std::type_index(typeid(T));

auto it = componentTypeToIndex.find(key);
if (it != componentTypeToIndex.end()) {
return it->second;
}

if (nextComponentIndex >= MAX_COMPONENTS) {
throw std::overflow_error("Maximum number of component types exceeded");
}

uint32_t index = nextComponentIndex++;
componentTypeToIndex[key] = index;
return index;
}

Expand Down
30 changes: 18 additions & 12 deletions FarmEngine/core/memory/MemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void* MemoryManager::allocate(size_t size, MemoryTag tag) {
void* ptr = malloc(size);

if (ptr) {
AllocationHeader header{size, tag, allocationCounter++};
AllocationHeader header{ptr, size, tag, allocationCounter++};
allocations.push_back(header);
totalAllocated += size;
}
Expand All @@ -28,11 +28,10 @@ void* MemoryManager::allocate(size_t size, MemoryTag tag) {
void MemoryManager::deallocate(void* ptr) {
if (!ptr) return;

// Buscar y remover la asignación
// Buscar y remover la asignación por puntero
auto it = std::find_if(allocations.begin(), allocations.end(),
[ptr](const AllocationHeader& h) {
// En una implementación real, compararíamos punteros reales
return false; // Simplificado para este ejemplo
return h.ptr == ptr;
});

if (it != allocations.end()) {
Expand All @@ -50,21 +49,28 @@ void* MemoryManager::reallocate(void* ptr, size_t newSize) {
return nullptr;
}

// Find old allocation to get old size
size_t oldSize = 0;
auto it = std::find_if(allocations.begin(), allocations.end(),
[ptr](const AllocationHeader& h) {
return h.ptr == ptr;
});

if (it != allocations.end()) {
oldSize = it->size;
}

void* newPtr = realloc(ptr, newSize);
if (newPtr) {
// Find and update allocation header
auto it = std::find_if(allocations.begin(), allocations.end(),
[ptr, newPtr](const AllocationHeader& h) {
// In real implementation, compare actual pointers
return false; // Simplified for this example
});

if (it != allocations.end()) {
// Update existing record
totalAllocated -= it->size;
it->ptr = newPtr;
it->size = newSize;
totalAllocated += newSize;
} else {
AllocationHeader header{newSize, MemoryTag::None, allocationCounter++};
// Create new record if old one wasn't found
AllocationHeader header{newPtr, newSize, MemoryTag::None, allocationCounter++};
allocations.push_back(header);
totalAllocated += newSize;
}
Expand Down
1 change: 1 addition & 0 deletions FarmEngine/core/memory/MemoryManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class MemoryManager {
MemoryManager& operator=(const MemoryManager&) = delete;

struct AllocationHeader {
void* ptr;
size_t size;
MemoryTag tag;
uint32_t id;
Expand Down
Loading