diff --git a/.gitignore b/.gitignore index 4f23721..13d419a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,68 @@ -Nothing should be ignored based on the provided file changes. The only modified file is README.md, which is a source/config file and should not be added to .gitignore. \ No newline at end of file +``` +# Compiled and build artifacts +*.o +*.obj +*.exe +*.dll +*.so +*.a +*.out +build/ +dist/ +target/ + +# Dependencies +node_modules/ +venv/ +.venv/ +__pycache__/ +.mypy_cache/ +.pytest_cache/ +.gradle/ +julia-*/ +zig*/ + +# Editors and IDEs +.vscode/ +.idea/ +*.swp +*.swo +*.tmp + +# System files +.DS_Store +Thumbs.db +.env +.env.local +*.env.* + +# Logs and coverage +*.log +coverage/ +htmlcov/ +.coverage + +# Compressed files +*.zip +*.gz +*.tar +*.tgz +*.bz2 +*.xz +*.7z +*.rar +*.zst +*.lz4 +*.lzh +*.cab +*.arj +*.rpm +*.deb +*.Z +*.lz +*.lzo +*.tar.gz +*.tar.bz2 +*.tar.xz +*.tar.zst +``` \ No newline at end of file diff --git a/FarmEngine/assets/shaders/sprite.frag.glsl b/FarmEngine/assets/shaders/sprite.frag.glsl new file mode 100644 index 0000000..c408975 --- /dev/null +++ b/FarmEngine/assets/shaders/sprite.frag.glsl @@ -0,0 +1,20 @@ +#version 450 + +// Fragment shader básico para sprites 2D +layout(location = 0) in vec2 fragTexCoord; +layout(location = 1) in vec4 fragColor; + +layout(location = 0) out vec4 outColor; + +layout(binding = 1) uniform sampler2D spriteTexture; + +void main() { + vec4 texColor = texture(spriteTexture, fragTexCoord); + + // Alpha test para recortes + if (texColor.a < 0.1) { + discard; + } + + outColor = texColor * fragColor; +} diff --git a/FarmEngine/assets/shaders/sprite.vert.glsl b/FarmEngine/assets/shaders/sprite.vert.glsl new file mode 100644 index 0000000..5ebdfaf --- /dev/null +++ b/FarmEngine/assets/shaders/sprite.vert.glsl @@ -0,0 +1,21 @@ +#version 450 + +// Vertex shader básico para sprites 2D +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec2 inTexCoord; +layout(location = 2) in vec4 inColor; + +layout(location = 0) out vec2 fragTexCoord; +layout(location = 1) out vec4 fragColor; + +layout(binding = 0) uniform MVP { + mat4 model; + mat4 view; + mat4 projection; +}; + +void main() { + gl_Position = projection * view * model * vec4(inPosition, 0.0, 1.0); + fragTexCoord = inTexCoord; + fragColor = inColor; +} diff --git a/FarmEngine/assets/shaders/terrain.frag.glsl b/FarmEngine/assets/shaders/terrain.frag.glsl new file mode 100644 index 0000000..2763660 --- /dev/null +++ b/FarmEngine/assets/shaders/terrain.frag.glsl @@ -0,0 +1,68 @@ +#version 450 + +// Fragment shader para terreno 3D con PBR básico +layout(location = 0) in vec3 fragPosition; +layout(location = 1) in vec3 fragNormal; +layout(location = 2) in vec2 fragTexCoord; +layout(location = 3) in mat4 fragTBN; + +layout(location = 0) out vec4 outColor; + +layout(binding = 1) uniform sampler2D albedoMap; +layout(binding = 2) uniform sampler2D normalMap; +layout(binding = 3) uniform sampler2D roughnessMap; +layout(binding = 4) uniform sampler2D metalnessMap; + +layout(binding = 5) uniform LightData { + vec3 position; + vec3 color; + float intensity; + vec3 ambientColor; + float ambientIntensity; +}; + +// PBR helper functions +vec3 getNormalFromMap() { + vec3 tangentNormal = texture(normalMap, fragTexCoord).xyz * 2.0 - 1.0; + return normalize(fragTBN * vec4(tangentNormal, 0.0)).xyz; +} + +float calculateShadow(vec3 lightDir) { + // Simplified shadow calculation + return 1.0; +} + +void main() { + // Albedo + vec3 albedo = texture(albedoMap, fragTexCoord).rgb; + + // Normal + vec3 normal = getNormalFromMap(); + + // Material properties + float roughness = texture(roughnessMap, fragTexCoord).r; + float metalness = texture(metalnessMap, fragTexCoord).r; + + // Lighting + vec3 lightDir = normalize(position - fragPosition); + vec3 viewDir = normalize(cameraPosition - fragPosition); + vec3 halfDir = normalize(lightDir + viewDir); + + // Diffuse (Lambert) + float NdotL = max(dot(normal, lightDir), 0.0); + vec3 diffuse = albedo * NdotL; + + // Specular (Blinn-Phong simplificado) + float NdotH = max(dot(normal, halfDir), 0.0); + float specPow = pow(2.0, (1.0 - roughness) * 10.0); + vec3 specular = vec3(pow(NdotH, specPow)) * metalness; + + // Shadow + float shadow = calculateShadow(lightDir); + + // Final lighting + vec3 lighting = (diffuse + specular) * color * intensity * shadow; + lighting += albedo * ambientColor * ambientIntensity; + + outColor = vec4(lighting, 1.0); +} diff --git a/FarmEngine/assets/shaders/terrain.vert.glsl b/FarmEngine/assets/shaders/terrain.vert.glsl new file mode 100644 index 0000000..721c4b2 --- /dev/null +++ b/FarmEngine/assets/shaders/terrain.vert.glsl @@ -0,0 +1,36 @@ +#version 450 + +// Vertex shader para terreno 3D +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec2 inTexCoord; +layout(location = 3) in vec4 inTangent; + +layout(location = 0) out vec3 fragPosition; +layout(location = 1) out vec3 fragNormal; +layout(location = 2) out vec2 fragTexCoord; +layout(location = 3) out mat4 fragTBN; + +layout(binding = 0) uniform UniformBuffer { + mat4 model; + mat4 view; + mat4 projection; + vec3 cameraPosition; + float time; +}; + +void main() { + vec4 worldPos = model * vec4(inPosition, 1.0); + fragPosition = worldPos.xyz; + + // Normal mapping + vec3 normal = normalize(mat3(model) * inNormal); + vec3 tangent = normalize(mat3(model) * inTangent.xyz); + vec3 bitangent = cross(normal, tangent) * inTangent.w; + fragTBN = mat4(tangent, bitangent, normal, vec4(0, 0, 0, 1)); + + fragNormal = normal; + fragTexCoord = inTexCoord; + + gl_Position = projection * view * worldPos; +} diff --git a/FarmEngine/core/ecs/ECS.cpp b/FarmEngine/core/ecs/ECS.cpp new file mode 100644 index 0000000..7fdc8d2 --- /dev/null +++ b/FarmEngine/core/ecs/ECS.cpp @@ -0,0 +1,47 @@ +#include "ECS.h" + +namespace FarmEngine { + +ECS::ECS() { + entities.reserve(MAX_ENTITIES); +} + +ECS::~ECS() = default; + +EntityID ECS::createEntity() { + EntityID id; + + if (!availableIDs.empty()) { + id = availableIDs.back(); + availableIDs.pop_back(); + entities[id].active = true; + } else { + id = static_cast(entities.size()); + entities.emplace_back(id); + } + + return id; +} + +void ECS::destroyEntity(EntityID entity) { + if (entity >= entities.size()) return; + + entities[entity].active = false; + entities[entity].mask.reset(); + + // Limpiar componentes + for (auto& componentList : components) { + if (componentList.second && entity < componentList.second->size()) { + (*componentList.second)[entity].reset(); + } + } + + availableIDs.push_back(entity); +} + +void ECS::update(float deltaTime) { + // Actualizar sistemas basados en ECS + (void)deltaTime; +} + +} // namespace FarmEngine diff --git a/FarmEngine/core/ecs/ECS.h b/FarmEngine/core/ecs/ECS.h new file mode 100644 index 0000000..362a51e --- /dev/null +++ b/FarmEngine/core/ecs/ECS.h @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace FarmEngine { + +constexpr size_t MAX_ENTITIES = 10000; +constexpr size_t MAX_COMPONENTS = 64; + +using EntityID = uint32_t; +using ComponentMask = std::bitset; + +class Component { +public: + virtual ~Component() = default; + EntityID entityID = UINT32_MAX; +}; + +class Entity { +public: + EntityID id; + ComponentMask mask; + bool active = true; + + Entity() : id(UINT32_MAX) {} + Entity(EntityID entityId) : id(entityId) {} +}; + +class ECS { +public: + ECS(); + ~ECS(); + + EntityID createEntity(); + void destroyEntity(EntityID entity); + + template + T& addComponent(EntityID entity, Args&&... args); + + template + T* getComponent(EntityID entity); + + template + void removeComponent(EntityID entity); + + template + std::vector getEntitiesWithComponents(); + + void update(float deltaTime); + +private: + std::vector entities; + std::vector availableIDs; + std::unordered_map>> components; + std::unordered_map componentTypeToIndex; + + uint32_t nextComponentIndex = 0; + + template + uint32_t getComponentTypeIndex(); +}; + +// Template implementations +template +T& ECS::addComponent(EntityID entity, Args&&... args) { + auto index = getComponentTypeIndex(); + + if (index >= components.size()) { + components.resize(index + 1); + } + + if (!components[index]) { + components[index] = std::vector>(); + } + + while (components[index]->size() <= entity) { + components[index]->push_back(nullptr); + } + + auto component = std::make_unique(std::forward(args)...); + component->entityID = entity; + T* ptr = component.get(); + components[index][entity] = std::move(component); + + entities[entity].mask.set(index); + + return *ptr; +} + +template +T* ECS::getComponent(EntityID entity) { + auto index = getComponentTypeIndex(); + + if (index >= components.size() || !components[index]) { + return nullptr; + } + + if (entity >= components[index]->size()) { + return nullptr; + } + + return static_cast(components[index][entity].get()); +} + +template +void ECS::removeComponent(EntityID entity) { + auto index = getComponentTypeIndex(); + + if (index < components.size() && components[index] && entity < components[index]->size()) { + components[index][entity].reset(); + entities[entity].mask.reset(index); + } +} + +template +uint32_t ECS::getComponentTypeIndex() { + static uint32_t index = []() { + return nextComponentIndex++; + }(); + return index; +} + +template +std::vector ECS::getEntitiesWithComponents() { + std::vector result; + ComponentMask requiredMask; + + ((requiredMask.set(getComponentTypeIndex()), ...)); + + for (const auto& entity : entities) { + if (entity.active && (entity.mask & requiredMask) == requiredMask) { + result.push_back(entity.id); + } + } + + return result; +} + +} // namespace FarmEngine diff --git a/FarmEngine/core/memory/MemoryManager.cpp b/FarmEngine/core/memory/MemoryManager.cpp new file mode 100644 index 0000000..e1176e5 --- /dev/null +++ b/FarmEngine/core/memory/MemoryManager.cpp @@ -0,0 +1,199 @@ +#include "MemoryManager.h" +#include +#include + +namespace FarmEngine { + +MemoryManager& MemoryManager::getInstance() { + static MemoryManager instance; + return instance; +} + +MemoryManager::~MemoryManager() { + dumpLeaks(); +} + +void* MemoryManager::allocate(size_t size, MemoryTag tag) { + void* ptr = malloc(size); + + if (ptr) { + AllocationHeader header{size, tag, allocationCounter++}; + allocations.push_back(header); + totalAllocated += size; + } + + return ptr; +} + +void MemoryManager::deallocate(void* ptr) { + if (!ptr) return; + + // Buscar y remover la asignación + 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 + }); + + if (it != allocations.end()) { + totalAllocated -= it->size; + allocations.erase(it); + } + + free(ptr); +} + +void* MemoryManager::reallocate(void* ptr, size_t newSize) { + if (!ptr) return allocate(newSize); + if (newSize == 0) { + deallocate(ptr); + return nullptr; + } + + 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()) { + totalAllocated -= it->size; + it->size = newSize; + totalAllocated += newSize; + } else { + AllocationHeader header{newSize, MemoryTag::None, allocationCounter++}; + allocations.push_back(header); + totalAllocated += newSize; + } + } + + return newPtr; +} + +size_t MemoryManager::getTotalAllocated() const { + return totalAllocated; +} + +size_t MemoryManager::getAllocationsByTag(MemoryTag tag) const { + size_t count = 0; + for (const auto& alloc : allocations) { + if (alloc.tag == tag) { + count += alloc.size; + } + } + return count; +} + +size_t MemoryManager::getAllocationCount() const { + return allocations.size(); +} + +void MemoryManager::reset() { + for (auto& alloc : allocations) { + // Liberar memoria asociada (simplificado) + } + allocations.clear(); + totalAllocated = 0; + allocationCounter = 0; +} + +void MemoryManager::dumpLeaks() { + if (!allocations.empty()) { + std::cout << "[MEMORY] Possible leaks detected: " << allocations.size() + << " allocations, " << totalAllocated << " bytes\n"; + } +} + +// PoolAllocator implementation +template +PoolAllocator::PoolAllocator(size_t poolSize) + : blockSize(sizeof(T)), poolSize(poolSize) { + uint8_t* pool = new uint8_t[blockSize * poolSize]; + pools.push_back(pool); + + for (size_t i = 0; i < poolSize; ++i) { + freeList.push_back(reinterpret_cast(pool + i * blockSize)); + } +} + +template +PoolAllocator::~PoolAllocator() { + for (auto* pool : pools) { + delete[] pool; + } +} + +template +T* PoolAllocator::allocate() { + if (freeList.empty()) { + // Crear nuevo pool + uint8_t* pool = new uint8_t[blockSize * poolSize]; + pools.push_back(pool); + + for (size_t i = 0; i < poolSize; ++i) { + freeList.push_back(reinterpret_cast(pool + i * blockSize)); + } + } + + T* ptr = freeList.back(); + freeList.pop_back(); + return ptr; +} + +template +void PoolAllocator::deallocate(T* ptr) { + freeList.push_back(ptr); +} + +template +size_t PoolAllocator::getAvailableBlocks() const { + return freeList.size(); +} + +// StackAllocator implementation +template +StackAllocator::StackAllocator(size_t size) + : totalSize(size), usedOffset(0) { + buffer = new uint8_t[size]; +} + +template +StackAllocator::~StackAllocator() { + delete[] buffer; +} + +template +void* StackAllocator::allocate(size_t alignment, size_t size) { + size_t alignedOffset = (usedOffset + alignment - 1) & ~(alignment - 1); + + if (alignedOffset + size > totalSize) { + return nullptr; // Out of memory + } + + void* ptr = buffer + alignedOffset; + usedOffset = alignedOffset + size; + return ptr; +} + +template +void StackAllocator::reset() { + usedOffset = 0; +} + +template +size_t StackAllocator::getUsedMemory() const { + return usedOffset; +} + +// Explicit instantiations para tipos comunes +template class PoolAllocator; +template class PoolAllocator; +template class PoolAllocator; +template class StackAllocator; +template class StackAllocator; +template class StackAllocator; + +} // namespace FarmEngine diff --git a/FarmEngine/core/memory/MemoryManager.h b/FarmEngine/core/memory/MemoryManager.h new file mode 100644 index 0000000..44032d9 --- /dev/null +++ b/FarmEngine/core/memory/MemoryManager.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include + +namespace FarmEngine { + +// Estados de memoria para debugging +enum class MemoryTag { + None = 0, + Engine, + Renderer, + Physics, + Audio, + World, + Simulation, + UI, + Assets, + Temporary +}; + +class MemoryManager { +public: + static MemoryManager& getInstance(); + + void* allocate(size_t size, MemoryTag tag = MemoryTag::None); + void deallocate(void* ptr); + + void* reallocate(void* ptr, size_t newSize); + + // Estadísticas de memoria + size_t getTotalAllocated() const; + size_t getAllocationsByTag(MemoryTag tag) const; + size_t getAllocationCount() const; + + // Limpieza y debugging + void reset(); + void dumpLeaks(); + +private: + MemoryManager() = default; + ~MemoryManager(); + + MemoryManager(const MemoryManager&) = delete; + MemoryManager& operator=(const MemoryManager&) = delete; + + struct AllocationHeader { + size_t size; + MemoryTag tag; + uint32_t id; + }; + + std::vector allocations; + size_t totalAllocated = 0; + uint32_t allocationCounter = 0; +}; + +// Macros para tracking de memoria +#ifdef FE_DEBUG + #define FE_ALLOC(size) MemoryManager::getInstance().allocate(size, MemoryTag::Temporary) + #define FE_FREE(ptr) MemoryManager::getInstance().deallocate(ptr) +#else + #define FE_ALLOC(size) malloc(size) + #define FE_FREE(ptr) free(ptr) +#endif + +// Allocators especializados +template +class PoolAllocator { +public: + PoolAllocator(size_t poolSize = 1024); + ~PoolAllocator(); + + T* allocate(); + void deallocate(T* ptr); + + size_t getAvailableBlocks() const; + +private: + std::vector freeList; + std::vector pools; + size_t blockSize; + size_t poolSize; +}; + +template +class StackAllocator { +public: + StackAllocator(size_t size); + ~StackAllocator(); + + void* allocate(size_t alignment, size_t size); + void reset(); + + size_t getUsedMemory() const; + +private: + uint8_t* buffer; + size_t totalSize; + size_t usedOffset; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/platform/input/Input.h b/FarmEngine/platform/input/Input.h new file mode 100644 index 0000000..e24b0cd --- /dev/null +++ b/FarmEngine/platform/input/Input.h @@ -0,0 +1,233 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace FarmEngine { + +enum class KeyCode { + Unknown = -1, + Space = 32, + Apostrophe = 39, + Comma = 44, + Minus = 45, + Period = 46, + Slash = 47, + D0 = 48, + D1, D2, D3, D4, D5, D6, D7, D8, D9, + Semicolon = 59, + Equal = 61, + A = 65, B, C, D, E, F, G, H, I, J, K, L, M, + N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + LeftBracket = 91, + Backslash = 92, + RightBracket = 93, + GraveAccent = 96, + Escape = 256, + Enter, Tab, Backspace, Insert, Delete, + Right, Left, Down, Up, + PageUp, PageDown, Home, End, + CapsLock = 280, + ScrollLock, NumLock, PrintScreen, Pause, + F1 = 290, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + LeftShift = 340, LeftControl, LeftAlt, LeftSuper, + RightShift, RightControl, RightAlt, RightSuper, Menu +}; + +enum class MouseButton { + Button0 = 0, + Button1 = 1, + Button2 = 2, + Button3 = 3, + Button4 = 4, + Button5 = 5, + ButtonLast = Button5, + Left = Button0, + Right = Button1, + Middle = Button2 +}; + +enum class InputAction { + Press, + Release, + Repeat +}; + +enum class InputMode { + Normal, // Cursor visible y responde normalmente + Hidden, // Cursor oculto pero input normal + Disabled, // Cursor capturado, solo movimiento relativo + Locked // Cursor capturado en el centro +}; + +class Keyboard { +public: + static Keyboard& getInstance(); + + bool isKeyPressed(KeyCode key) const; + bool isKeyJustPressed(KeyCode key) const; + bool isKeyJustReleased(KeyCode key) const; + + void setKeyCallback(std::function callback); + + // Estado interno (llamado por Window) + void setKeyState(KeyCode key, bool pressed); + void processFrame(); + +private: + Keyboard() = default; + + std::vector currentKeys; + std::vector previousKeys; + std::vector justPressed; + std::vector justReleased; + + std::function keyCallback; +}; + +class Mouse { +public: + static Mouse& getInstance(); + + // Posición + double getX() const { return posX; } + double getY() const { return posY; } + glm::vec2 getPosition() const { return {static_cast(posX), static_cast(posY)}; } + + // Botones + bool isButtonPressed(MouseButton button) const; + bool isButtonJustPressed(MouseButton button) const; + bool isButtonJustReleased(MouseButton button) const; + + // Scroll + double getScrollX() const { return scrollX; } + double getScrollY() const { return scrollY; } + void resetScroll(); + + // Movimiento relativo (para cámaras FPS) + glm::vec2 getDelta() const { return delta; } + + // Callbacks + void setButtonCallback(std::function callback); + void setScrollCallback(std::function callback); + void setMotionCallback(std::function callback); + + // Estado interno + void setButtonState(MouseButton button, bool pressed); + void setPosition(double x, double y); + void setScroll(double x, double y); + void processFrame(); + +private: + Mouse() = default; + + double posX = 0.0, posY = 0.0; + double prevX = 0.0, prevY = 0.0; + glm::vec2 delta{0.0f, 0.0f}; + + std::vector currentButtons; + std::vector previousButtons; + std::vector justPressed; + std::vector justReleased; + + double scrollX = 0.0, scrollY = 0.0; + + std::function buttonCallback; + std::function scrollCallback; + std::function motionCallback; +}; + +class Gamepad { +public: + struct Axis { + enum Type { + LeftX, LeftY, RightX, RightY, + LeftTrigger, RightTrigger, + Count + }; + }; + + struct Button { + enum Type { + A, B, X, Y, + LeftBumper, RightBumper, + Back, Start, Guide, + LeftStick, RightStick, + DPadUp, DPadDown, DPadLeft, DPadRight, + Count + }; + }; + + static Gamepad& getInstance(); + + bool isConnected() const { return connected; } + bool isButtonPressed(Button::Type button) const; + float getAxis(Axis::Type axis) const; + + void setConnectionCallback(std::function callback); + + // Estado interno + void setConnected(bool connected); + void setButtonState(Button::Type button, bool pressed); + void setAxisState(Axis::Type axis, float value); + +private: + Gamepad() = default; + + bool connected = false; + std::vector buttons; + std::vector axes; + + std::function connectionCallback; +}; + +class InputManager { +public: + static InputManager& getInstance(); + + void initialize(); + void cleanup(); + + void update(); + + // Modos de input + void setInputMode(InputMode mode); + InputMode getInputMode() const { return currentMode; } + + // Acciones mapeadas (input mapping system) + void bindAction(const std::string& actionName, KeyCode key); + void bindAction(const std::string& actionName, MouseButton button); + bool isActionPressed(const std::string& actionName) const; + + // Ejes mapeados + void bindAxis(const std::string& axisName, KeyCode positive, KeyCode negative); + float getAxisValue(const std::string& axisName) const; + + // Vibración (gamepad) + void setVibration(float leftMotor, float rightMotor, float duration); + +private: + InputManager() = default; + ~InputManager(); + + InputMode currentMode = InputMode::Normal; + + struct ActionBinding { + std::vector keys; + std::vector buttons; + }; + + struct AxisBinding { + KeyCode positive = KeyCode::Unknown; + KeyCode negative = KeyCode::Unknown; + }; + + std::unordered_map actionBindings; + std::unordered_map axisBindings; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/renderer/2d/SpriteRenderer.h b/FarmEngine/renderer/2d/SpriteRenderer.h new file mode 100644 index 0000000..f3787a8 --- /dev/null +++ b/FarmEngine/renderer/2d/SpriteRenderer.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include +#include + +namespace FarmEngine { + +struct SpriteRenderData { + VkBuffer vertexBuffer; + VkBuffer indexBuffer; + uint32_t vertexCount; + uint32_t indexCount; +}; + +struct SpriteInstanceData { + glm::vec4 position; // x, y, width, height + glm::vec4 color; // r, g, b, a + glm::vec4 uvRect; // u, v, uWidth, vHeight + float rotation; + int32_t textureIndex; +}; + +class SpriteRenderer2D { +public: + SpriteRenderer2D(VkDevice device, VkPhysicalDevice physicalDevice); + ~SpriteRenderer2D(); + + bool initialize(uint32_t maxSprites = 10000); + void cleanup(); + + // Rendering + void beginFrame(); + void submitSprite(const SpriteInstanceData& data); + void endFrame(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout); + + // Batch management + void flush(); + void reset(); + + // Texture binding + void bindTexture(uint32_t slot, VkDescriptorSet descriptorSet); + + uint32_t getBatchCount() const { return batchCount; } + uint32_t getMaxSprites() const { return maxSprites; } + +private: + void createBuffers(); + void createPipeline(); + void createDescriptorSets(); + void updateBuffers(); + + VkDevice device; + VkPhysicalDevice physicalDevice; + + // Buffers + VkBuffer vertexBuffer = VK_NULL_HANDLE; + VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE; + VkBuffer indexBuffer = VK_NULL_HANDLE; + VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE; + VkBuffer instanceBuffer = VK_NULL_HANDLE; + VkDeviceMemory instanceBufferMemory = VK_NULL_HANDLE; + + // Pipeline + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + + // Data + std::vector spriteData; + uint32_t maxSprites; + uint32_t batchCount; + uint32_t currentIndex; + + bool initialized = false; +}; + +// Tilemap rendering +struct TileData { + uint32_t tileID; + uint32_t layer; + uint8_t flags; // Flip H, Flip V, Rotate + uint8_t padding[3]; +}; + +class TilemapRenderer2D { +public: + TilemapRenderer2D(VkDevice device, VkPhysicalDevice physicalDevice); + ~TilemapRenderer2D(); + + bool initialize(uint32_t mapWidth, uint32_t mapHeight, uint32_t tileSize); + void cleanup(); + + // Map manipulation + void setTile(uint32_t x, uint32_t y, uint32_t layer, const TileData& tile); + void setTiles(const std::vector& tiles); + + // Rendering + void render(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, + const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix); + + // Culling + void setVisibleRegion(int32_t startX, int32_t startY, + int32_t endX, int32_t endY); + + uint32_t getWidth() const { return mapWidth; } + uint32_t getHeight() const { return mapHeight; } + uint32_t getLayerCount() const { return layerCount; } + +private: + void rebuildMesh(); + void createBuffers(); + + VkDevice device; + VkPhysicalDevice physicalDevice; + + uint32_t mapWidth; + uint32_t mapHeight; + uint32_t tileSize; + uint32_t layerCount; + + std::vector> layers; + + // Buffers + VkBuffer vertexBuffer = VK_NULL_HANDLE; + VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE; + VkBuffer indexBuffer = VK_NULL_HANDLE; + VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE; + + // Visibility + int32_t visibleStartX = 0; + int32_t visibleStartY = 0; + int32_t visibleEndX = -1; + int32_t visibleEndY = -1; + + bool needsRebuild = true; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/renderer/3d/MeshRenderer.h b/FarmEngine/renderer/3d/MeshRenderer.h new file mode 100644 index 0000000..3b3c544 --- /dev/null +++ b/FarmEngine/renderer/3d/MeshRenderer.h @@ -0,0 +1,190 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace FarmEngine { + +struct Vertex3D { + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texCoord; + glm::vec4 tangent; + + static VkVertexInputBindingDescription getBindingDescription(); + static std::array getAttributeDescriptions(); +}; + +struct MeshData { + std::vector vertices; + std::vector indices; +}; + +class Mesh { +public: + Mesh(VkDevice device, VkPhysicalDevice physicalDevice); + ~Mesh(); + + bool initialize(const MeshData& data); + void cleanup(); + + void bind(VkCommandBuffer commandBuffer); + void draw(VkCommandBuffer commandBuffer, uint32_t instanceCount = 1); + + uint32_t getIndexCount() const { return static_cast(indices.size()); } + uint32_t getVertexCount() const { return static_cast(vertices.size()); } + +private: + void createVertexBuffers(const std::vector& vertices); + void createIndexBuffers(const std::vector& indices); + + VkDevice device; + VkPhysicalDevice physicalDevice; + + std::vector vertices; + std::vector indices; + + VkBuffer vertexBuffer = VK_NULL_HANDLE; + VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE; + VkBuffer indexBuffer = VK_NULL_HANDLE; + VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE; +}; + +// Terrain mesh generation +struct TerrainConfig { + uint32_t width; + uint32_t depth; + float scale; + float heightScale; + int32_t seed; + std::string heightmapPath; +}; + +class TerrainMesh { +public: + TerrainMesh(VkDevice device, VkPhysicalDevice physicalDevice); + ~TerrainMesh(); + + bool generate(const TerrainConfig& config); + void updateHeightmap(const std::vector& heights); + + Mesh* getMesh() { return mesh.get(); } + + // LOD + void setLODDistance(float distance); + void updateLOD(const glm::vec3& cameraPosition); + + uint32_t getWidth() const { return config.width; } + uint32_t getDepth() const { return config.depth; } + +private: + void generateVertices(); + void calculateNormals(); + void generateIndices(); + void generateLODMeshes(); + + VkDevice device; + VkPhysicalDevice physicalDevice; + + TerrainConfig config; + std::unique_ptr mesh; + std::vector lodMeshes; + + std::vector heightmap; + std::vector vertices; + std::vector indices; + + float lodDistance = 50.0f; + int32_t currentLOD = 0; +}; + +// Model loading (glTF/OBJ) +struct Material { + glm::vec4 baseColorFactor; + float metallicFactor; + float roughnessFactor; + uint32_t baseColorTexture; + uint32_t normalTexture; + uint32_t materialTexture; +}; + +class Model { +public: + Model(VkDevice device, VkPhysicalDevice physicalDevice); + ~Model(); + + bool loadFromFile(const std::string& path); + bool loadFromData(const void* data, size_t size); + void cleanup(); + + void render(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout); + + const std::vector>& getMeshes() const { return meshes; } + const std::vector& getMaterials() const { return materials; } + +private: + bool loadGLTF(const std::string& path); + bool loadOBJ(const std::string& path); + + VkDevice device; + VkPhysicalDevice physicalDevice; + + std::vector> meshes; + std::vector materials; + std::vector descriptorSets; +}; + +// Renderer 3D principal +class Renderer3D { +public: + static Renderer3D& getInstance(); + + bool initialize(VkDevice device, VkPhysicalDevice physicalDevice); + void cleanup(); + + // Rendering + void beginFrame(); + void submitMesh(const Mesh* mesh, const glm::mat4& transform, + const Material* material = nullptr); + void submitTerrain(const TerrainMesh* terrain); + void endFrame(VkCommandBuffer commandBuffer); + + // Camera + void setViewProjection(const glm::mat4& view, const glm::mat4& projection); + + // Stats + uint32_t getDrawCalls() const { return drawCalls; } + uint32_t getTriangleCount() const { return triangleCount; } + +private: + void createPipeline(); + void createDescriptorSets(); + void flush(); + + VkDevice device = VK_NULL_HANDLE; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; + + struct DrawCall { + const Mesh* mesh; + glm::mat4 transform; + const Material* material; + }; + + std::vector drawCalls; + std::vector terrains; + + glm::mat4 viewMatrix; + glm::mat4 projectionMatrix; + + uint32_t drawCalls; + uint32_t triangleCount; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/renderer/passes/RenderPasses.h b/FarmEngine/renderer/passes/RenderPasses.h new file mode 100644 index 0000000..afd4cf5 --- /dev/null +++ b/FarmEngine/renderer/passes/RenderPasses.h @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include +#include + +namespace FarmEngine { + +// Tipos de render passes +enum class RenderPassType { + Shadow, + GBuffer, + Lighting, + Transparent, + UI, + PostProcess +}; + +struct RenderPassConfig { + RenderPassType type; + std::string name; + uint32_t width; + uint32_t height; + std::vector attachments; + std::vector subpasses; + std::vector dependencies; +}; + +class RenderPass { +public: + RenderPass(VkDevice device); + ~RenderPass(); + + bool initialize(const RenderPassConfig& config); + VkRenderPass getHandle() const { return renderPass; } + const RenderPassConfig& getConfig() const { return config; } + +private: + VkDevice device; + VkRenderPass renderPass = VK_NULL_HANDLE; + RenderPassConfig config; +}; + +class Framebuffer { +public: + Framebuffer(VkDevice device, VkRenderPass renderPass); + ~Framebuffer(); + + bool initialize(uint32_t width, uint32_t height, + const std::vector& attachments); + + VkFramebuffer getHandle() const { return framebuffer; } + uint32_t getWidth() const { return width; } + uint32_t getHeight() const { return height; } + + void resize(uint32_t newWidth, uint32_t newHeight); + +private: + VkDevice device; + VkRenderPass renderPass; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + uint32_t width; + uint32_t height; +}; + +// Attachment helpers +class AttachmentBuilder { +public: + static VkAttachmentDescription colorAttachment( + VkFormat format, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, + VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE); + + static VkAttachmentDescription depthAttachment( + VkFormat format, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT, + VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE); + + static VkAttachmentReference colorReference(uint32_t attachment, + VkImageLayout layout); + static VkAttachmentReference depthReference(uint32_t attachment, + VkImageLayout layout); +}; + +// Render Pass Factory +class RenderPassFactory { +public: + static RenderPassConfig createShadowPass(uint32_t size); + static RenderPassConfig createGBufferPass(uint32_t width, uint32_t height); + static RenderPassConfig createLightingPass(uint32_t width, uint32_t height); + static RenderPassConfig createTransparentPass(uint32_t width, uint32_t height); + static RenderPassConfig createUIPass(uint32_t width, uint32_t height); + static RenderPassConfig createPostProcessPass(uint32_t width, uint32_t height); +}; + +// Manager de render passes +class RenderPassManager { +public: + static RenderPassManager& getInstance(); + + void initialize(VkDevice device, uint32_t screenWidth, uint32_t screenHeight); + void cleanup(); + + RenderPass* getRenderPass(RenderPassType type); + Framebuffer* getFramebuffer(RenderPassType type); + + void recreateFramebuffers(uint32_t newWidth, uint32_t newHeight); + +private: + RenderPassManager() = default; + ~RenderPassManager(); + + VkDevice device = VK_NULL_HANDLE; + uint32_t screenWidth; + uint32_t screenHeight; + + std::vector> renderPasses; + std::vector> framebuffers; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/renderer/vulkan/VulkanContext.h b/FarmEngine/renderer/vulkan/VulkanContext.h new file mode 100644 index 0000000..e79e7de --- /dev/null +++ b/FarmEngine/renderer/vulkan/VulkanContext.h @@ -0,0 +1,148 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace FarmEngine { + +struct VulkanDeviceConfig { + bool enableValidationLayers = true; + bool enableDebugUtils = true; + uint32_t desiredImageCount = 3; +}; + +class VulkanInstance { +public: + VulkanInstance(); + ~VulkanInstance(); + + bool initialize(const VulkanDeviceConfig& config); + VkInstance getInstance() const { return instance; } + +private: + bool createInstance(const VulkanDeviceConfig& config); + bool setupDebugMessenger(); + void populateValidationLayers(); + void populateRequiredExtensions(); + + VkInstance instance = VK_NULL_HANDLE; + VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + std::vector validationLayers; + std::vector requiredExtensions; +}; + +struct QueueFamilyIndices { + std::optional graphicsFamily; + std::optional presentFamily; + + bool isComplete() const { + return graphicsFamily.has_value() && presentFamily.has_value(); + } +}; + +class VulkanPhysicalDevice { +public: + VulkanPhysicalDevice(VkInstance instance, VkSurfaceKHR surface); + + bool isSuitable(); + void select(); + + VkPhysicalDevice getDevice() const { return physicalDevice; } + QueueFamilyIndices getQueueFamilies() const { return queueFamilyIndices; } + +private: + bool checkExtensionSupport(); + bool checkValidationLayerSupport(); + void queryQueueFamilies(); + + VkInstance instance; + VkSurfaceKHR surface; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + QueueFamilyIndices queueFamilyIndices; +}; + +class VulkanLogicalDevice { +public: + VulkanLogicalDevice(VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + const QueueFamilyIndices& indices); + ~VulkanLogicalDevice(); + + VkDevice getDevice() const { return device; } + VkQueue getGraphicsQueue() const { return graphicsQueue; } + VkQueue getPresentQueue() const { return presentQueue; } + +private: + void createDevice(const QueueFamilyIndices& indices); + void getQueues(const QueueFamilyIndices& indices); + + VkDevice device = VK_NULL_HANDLE; + VkQueue graphicsQueue = VK_NULL_HANDLE; + VkQueue presentQueue = VK_NULL_HANDLE; +}; + +class VulkanSwapchain { +public: + VulkanSwapchain(VkDevice device, + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkQueue presentQueue, + uint32_t imageCount); + ~VulkanSwapchain(); + + VkSwapchainKHR getSwapchain() const { return swapchain; } + const std::vector& getImages() const { return images; } + VkFormat getImageFormat() const { return imageFormat; } + VkExtent2D getExtent() const { return extent; } + +private: + VkSurfaceFormatKHR chooseSurfaceFormat(const std::vector& formats); + VkPresentModeKHR choosePresentMode(const std::vector& modes); + VkExtent2D chooseExtent(const VkSurfaceCapabilitiesKHR& capabilities); + + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + std::vector images; + VkFormat imageFormat; + VkExtent2D extent{}; +}; + +class VulkanContext { +public: + static VulkanContext& getInstance(); + + bool initialize(void* windowHandle, void* windowInstance, const VulkanDeviceConfig& config = {}); + void cleanup(); + + // Getters + VkInstance getInstance() const { return vulkanInstance.getInstance(); } + VkPhysicalDevice getPhysicalDevice() const { return physicalDevice.getDevice(); } + VkDevice getDevice() const { return logicalDevice->getDevice(); } + VkSurfaceKHR getSurface() const { return surface; } + VkQueue getGraphicsQueue() const { return logicalDevice->getGraphicsQueue(); } + VkQueue getPresentQueue() const { return logicalDevice->getPresentQueue(); } + VkSwapchainKHR getSwapchain() const { return swapchain->getSwapchain(); } + + const std::vector& getSwapchainImages() const { return swapchain->getImages(); } + VkFormat getSwapchainImageFormat() const { return swapchain->getImageFormat(); } + VkExtent2D getSwapchainExtent() const { return swapchain->getExtent(); } + +private: + VulkanContext() = default; + ~VulkanContext(); + + VulkanContext(const VulkanContext&) = delete; + VulkanContext& operator=(const VulkanContext&) = delete; + + bool createSurface(void* windowHandle, void* windowInstance); + + VulkanInstance vulkanInstance; + VkSurfaceKHR surface = VK_NULL_HANDLE; + VulkanPhysicalDevice physicalDevice{nullptr, nullptr}; + std::unique_ptr logicalDevice; + std::unique_ptr swapchain; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/simulation/animals/AnimalSystem.h b/FarmEngine/simulation/animals/AnimalSystem.h new file mode 100644 index 0000000..e67370d --- /dev/null +++ b/FarmEngine/simulation/animals/AnimalSystem.h @@ -0,0 +1,204 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace FarmEngine { + +enum class AnimalType { + Chicken, + Cow, + Sheep, + Pig, + Horse, + Duck, + Goat, + Rabbit +}; + +enum class AnimalState { + Idle, + Walking, + Eating, + Sleeping, + Producing, + Following +}; + +struct AnimalConfig { + AnimalType type; + std::string name; + float moveSpeed; + float hungerRate; + float thirstRate; + float happinessDecay; + float productionTime; // Tiempo para producir recurso + uint32_t productID; + uint32_t maxInventory; + glm::vec3 size; // Collision bounds +}; + +class Animal { +public: + Animal(AnimalType type, const glm::vec3& position, uint32_t enclosureID); + + void update(float deltaTime); + + // Estado + AnimalState getState() const { return state; } + float getHunger() const { return hunger; } // 0-100, 0 = hambriento + float getThirst() const { return thirst; } + float getHappiness() const { return happiness; } + bool isProducing() const { return canProduce; } + + // Acciones del jugador + bool feed(uint32_t foodID); + bool water(); + bool pet(); + bool collectProduct(); + + // Movimiento + void setDestination(const glm::vec3& target); + void stopMoving(); + + // Producción + uint32_t getProductCount() const { return products.size(); } + const std::vector& getProducts() const { return products; } + + // Datos + const AnimalConfig& getConfig() const; + uint32_t getEnclosureID() const { return enclosureID; } + glm::vec3 getPosition() const { return position; } + +private: + void updateState(float deltaTime); + void updateNeeds(float deltaTime); + void updateMovement(float deltaTime); + void checkProduction(); + void wander(); + + AnimalType animalType; + glm::vec3 position; + glm::vec3 destination; + uint32_t enclosureID; + + AnimalState state = AnimalState::Idle; + float hunger = 100.0f; + float thirst = 100.0f; + float happiness = 100.0f; + + std::vector products; + bool canProduce = false; + float productionTimer = 0.0f; + + float moveTimer = 0.0f; + float stateTimer = 0.0f; +}; + +class AnimalManager { +public: + static AnimalManager& getInstance(); + + void initialize(); + void cleanup(); + + // Creación + Animal* addAnimal(AnimalType type, const glm::vec3& position, uint32_t enclosureID); + void removeAnimal(uint32_t animalID); + + // Gestión por corral + std::vector getAnimalsInEnclosure(uint32_t enclosureID); + void transferAnimal(uint32_t animalID, uint32_t newEnclosureID); + + // Actualización + void update(float deltaTime); + void updateEnclosure(uint32_t enclosureID, float deltaTime); + + // Consultas + Animal* getAnimalByID(uint32_t animalID); + std::vector getAnimalsByType(AnimalType type); + std::vector getHungryAnimals(float threshold = 50.0f); + std::vector getReadyToCollect(); + + // Estadísticas + size_t getTotalAnimalCount() const { return animals.size(); } + size_t getEnclosurePopulation(uint32_t enclosureID) const; + + // Configuración + const AnimalConfig* getAnimalConfig(AnimalType type) const; + +private: + AnimalManager() = default; + ~AnimalManager(); + + std::unordered_map> animals; + std::unordered_map animalConfigs; + std::unordered_map> enclosureAnimals; + + uint32_t nextAnimalID = 1; +}; + +// IA de animales +class AnimalAI { +public: + struct BehaviorTree { + enum class Node { + Sequence, + Selector, + Action, + Condition + }; + + Node type; + std::vector> children; + std::string actionName; + }; + + static AnimalAI& getInstance(); + + void update(Animal* animal, float deltaTime); + + // Comportamientos + void findFood(Animal* animal); + void findWater(Animal* animal); + void findRestSpot(Animal* animal); + void avoidDanger(Animal* animal, const glm::vec3& threat); + void followLeader(Animal* animal, const glm::vec3& leaderPos); + +private: + AnimalAI() = default; + + glm::vec3 findNearestPoint(Animal* animal, + const std::vector& points); + bool hasLineOfSight(Animal* animal, const glm::vec3& target); +}; + +// Sistema de cría/genética simple +class AnimalBreeding { +public: + struct Genetics { + float sizeModifier; // 0.8 - 1.2 + float productionBonus; // 0.0 - 0.5 + float diseaseResistance; // 0.0 - 1.0 + float temperament; // 0.0 - 1.0 (calm to aggressive) + }; + + static AnimalBreeding& getInstance(); + + bool canBreed(Animal* animal1, Animal* animal2); + Animal* breed(Animal* parent1, Animal* parent2, const glm::vec3& position); + + const Genetics& getGenetics(uint32_t animalID) const; + +private: + AnimalBreeding() = default; + + Genetics mixGenetics(const Genetics& g1, const Genetics& g2); + + std::unordered_map animalGenetics; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/simulation/crops/CropSystem.h b/FarmEngine/simulation/crops/CropSystem.h new file mode 100644 index 0000000..d22ec6c --- /dev/null +++ b/FarmEngine/simulation/crops/CropSystem.h @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace FarmEngine { + +enum class CropType { + Wheat, + Corn, + Tomato, + Carrot, + Potato, + Pumpkin, + Sunflower, + Strawberry, + Blueberry +}; + +enum class CropGrowthStage { + Seed, + Sprout, + Growing, + Mature, + Ready +}; + +struct CropConfig { + CropType type; + std::string name; + float growthTime; // Tiempo base en segundos + int32_t stagesCount; + float waterNeed; // 0.0 - 1.0 + float temperatureMin; + float temperatureMax; + float fertilityNeed; + uint32_t seedYield; + uint32_t harvestYield; +}; + +class Crop { +public: + Crop(CropType type, const glm::vec3& position); + + void update(float deltaTime); + + // Estado + CropGrowthStage getGrowthStage() const { return growthStage; } + float getGrowthProgress() const { return growthProgress; } + bool isReadyToHarvest() const { return growthStage == CropGrowthStage::Ready; } + bool isDead() const { return dead; } + + // Acciones + bool water(); + bool fertilize(); + bool harvest(); + + // Factores ambientales + void setWaterLevel(float level) { waterLevel = level; } + void setFertility(float fertility) { soilFertility = fertility; } + void setTemperature(float temp) { temperature = temp; } + + // Datos + const CropConfig& getConfig() const; + uint32_t getYield() const { return currentYield; } + +private: + void updateGrowth(float deltaTime); + void checkConditions(); + void advanceStage(); + + CropType cropType; + glm::vec3 position; + + CropGrowthStage growthStage = CropGrowthStage::Seed; + float growthProgress = 0.0f; + float waterLevel = 0.5f; + float soilFertility = 0.5f; + float temperature = 20.0f; + + uint32_t currentYield = 0; + bool dead = false; + bool watered = false; +}; + +class CropManager { +public: + static CropManager& getInstance(); + + void initialize(); + void cleanup(); + + // Creación + Crop* plantCrop(CropType type, const glm::vec3& position, uint32_t fieldID); + + // Gestión por campo + std::vector getCropsInField(uint32_t fieldID); + void removeCropsFromField(uint32_t fieldID); + + // Actualización + void update(float deltaTime); + void updateRegion(const glm::vec3& center, float radius); + + // Consultas + Crop* getCropAtPosition(const glm::vec3& position); + std::vector getCropsByType(CropType type); + std::vector getReadyCrops(); + + // Estadísticas + size_t getTotalCropCount() const { return crops.size(); } + size_t getReadyCropCount() const; + + // Configuración + const CropConfig* getCropConfig(CropType type) const; + +private: + CropManager() = default; + ~CropManager(); + + std::unordered_map> crops; + std::unordered_map cropConfigs; + std::unordered_map> fieldCrops; // fieldID -> crop IDs + + uint32_t nextCropID = 1; +}; + +// Sistema de rotación de cultivos +class CropRotation { +public: + struct RotationPlan { + std::vector sequence; + int32_t seasonsPerCrop; + int32_t restSeasons; + }; + + static CropRotation& getInstance(); + + void setRotationPlan(uint32_t fieldID, const RotationPlan& plan); + CropType getNextCropForField(uint32_t fieldID); + + // Beneficios de rotación + float getFertilityBonus(uint32_t fieldID) const; + float getPestResistanceBonus(uint32_t fieldID) const; + +private: + CropRotation() = default; + + std::unordered_map fieldPlans; + std::unordered_map fieldHistory; // Última posición en secuencia +}; + +} // namespace FarmEngine diff --git a/FarmEngine/simulation/soil/SoilSystem.h b/FarmEngine/simulation/soil/SoilSystem.h new file mode 100644 index 0000000..70a1947 --- /dev/null +++ b/FarmEngine/simulation/soil/SoilSystem.h @@ -0,0 +1,184 @@ +#pragma once + +#include +#include +#include + +namespace FarmEngine { + +enum class SoilType { + Sandy, + Loamy, + Clay, + Silty, + Peaty, + Chalky +}; + +enum class SoilCondition { + Poor, + Average, + Good, + Excellent +}; + +struct SoilData { + SoilType type = SoilType::Loamy; + float moisture = 0.5f; // 0.0 - 1.0 + float fertility = 0.5f; // 0.0 - 1.0 + float pH = 7.0f; // 3.0 - 9.0 + float nitrogen = 0.5f; // NPK values + float phosphorus = 0.5f; + float potassium = 0.5f; + float organicMatter = 0.5f; + float temperature = 20.0f; // Celsius + uint8_t tillageState = 0; // 0 = untilled, 1 = tilled +}; + +class Soil { +public: + Soil(const glm::ivec3& position); + + void update(float deltaTime); + + // Propiedades básicas + SoilType getType() const { return data.type; } + float getMoisture() const { return data.moisture; } + float getFertility() const { return data.fertility; } + float getpH() const { return data.pH; } + bool isTilled() const { return data.tillageState > 0; } + + // Acciones + bool till(); + bool water(float amount); + bool fertilize(float nitrogen, float phosphorus, float potassium); + bool addOrganicMatter(float amount); + bool adjustPH(float amount); // Positive = more alkaline, negative = more acidic + + // Estado + SoilCondition getCondition() const; + float getQualityScore() const; // 0.0 - 1.0 + + // Factores ambientales + void setTemperature(float temp) { data.temperature = temp; } + void absorbRainfall(float amount); + void evaporate(float rate); + + // Datos completos + const SoilData& getData() const { return data; } + void setData(const SoilData& newData) { data = newData; } + +private: + void updateMoisture(float deltaTime); + void updateNutrients(float deltaTime); + void updateTemperature(float deltaTime); + void calculateCondition(); + + glm::ivec3 position; + SoilData data; + SoilCondition condition = SoilCondition::Average; +}; + +class SoilManager { +public: + static SoilManager& getInstance(); + + void initialize(); + void cleanup(); + + // Acceso a suelo + Soil* getSoil(const glm::ivec3& position); + Soil* getSoilAtWorld(const glm::vec3& worldPosition); + + // Operaciones en área + void tillArea(const glm::vec3& center, float radius); + void waterArea(const glm::vec3& center, float radius, float amount); + void fertilizeArea(const glm::vec3& center, float radius, + float n, float p, float k); + + // Actualización + void update(float deltaTime); + void updateRegion(const glm::vec3& center, float radius, float deltaTime); + + // Análisis + float getAverageFertility(const glm::vec3& center, float radius) const; + float getAverageMoisture(const glm::vec3& center, float radius) const; + SoilCondition getDominantCondition(const glm::vec3& center, float radius) const; + + // Mapa de suelo (para rendering/analysis) + std::vector getMoistureMap(int32_t width, int32_t depth, + const glm::vec3& origin, float scale) const; + std::vector getFertilityMap(int32_t width, int32_t depth, + const glm::vec3& origin, float scale) const; + +private: + SoilManager() = default; + ~SoilManager(); + + glm::ivec3 worldToGrid(const glm::vec3& worldPos) const; + glm::vec3 gridToWorld(const glm::ivec3& gridPos) const; + + std::unordered_map> soilGrid; + + // Configuración + float gridScale = 1.0f; // Tamaño de cada celda de suelo +}; + +// Sistema de erosión y degradación +class SoilErosion { +public: + static SoilErosion& getInstance(); + + void update(float deltaTime); + + // Causas de erosión + void applyWaterErosion(const glm::vec3& start, const glm::vec3& end, float intensity); + void applyWindErosion(const glm::vec3& direction, float intensity); + void applyTillageErosion(const glm::vec3& position, float intensity); + + // Prevención + void plantCoverCrop(const glm::vec3& center, float radius); + void buildTerrace(const glm::vec3& start, const glm::vec3& end); + void addMulch(const glm::vec3& center, float radius, float thickness); + +private: + SoilErosion() = default; + + void redistributeSoil(const glm::ivec3& from, const glm::ivec3& to, float amount); +}; + +// Compostaje y mejora de suelo +class CompostSystem { +public: + struct CompostPile { + std::vector ingredients; + float carbon = 0.0f; + float nitrogen = 0.0f; + float moisture = 0.0f; + float temperature = 20.0f; + float decompositionProgress = 0.0f; + bool ready = false; + }; + + static CompostSystem& getInstance(); + + uint32_t createCompostPile(const glm::vec3& position); + void addIngredient(uint32_t pileID, uint32_t ingredientID, float amount); + void turnCompost(uint32_t pileID); + void waterCompost(uint32_t pileID, float amount); + + uint32_t harvestCompost(uint32_t pileID); + + void update(float deltaTime); + +private: + CompostSystem() = default; + + void updateDecomposition(CompostPile& pile, float deltaTime); + float calculateIdealCNRatio() const; + + std::unordered_map compostPiles; + uint32_t nextPileID = 1; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/simulation/weather/WeatherSystem.h b/FarmEngine/simulation/weather/WeatherSystem.h new file mode 100644 index 0000000..a207154 --- /dev/null +++ b/FarmEngine/simulation/weather/WeatherSystem.h @@ -0,0 +1,202 @@ +#pragma once + +#include +#include +#include +#include + +namespace FarmEngine { + +enum class Season { + Spring, + Summer, + Autumn, + Winter +}; + +enum class WeatherType { + Clear, + Cloudy, + Rainy, + Stormy, + Snowy, + Foggy, + Windy +}; + +struct WeatherConfig { + float baseTemperature; // Temperatura base de la estación + float temperatureVariation; // Variación diaria + float rainProbability; // 0.0 - 1.0 + float windSpeed; // m/s + float humidity; // 0.0 - 1.0 + int32_t dayLength; // Horas de luz +}; + +class Weather { +public: + Weather(); + + void update(float deltaTime); + + // Estado actual + WeatherType getType() const { return currentWeather; } + float getTemperature() const { return temperature; } + float getHumidity() const { return humidity; } + float getWindSpeed() const { return windSpeed; } + glm::vec3 getWindDirection() const { return windDirection; } + float getRainIntensity() const { return rainIntensity; } + float getCloudCover() const { return cloudCover; } + + // Predicción (próximas horas) + WeatherType predictWeather(int32_t hoursAhead) const; + float predictTemperature(int32_t hoursAhead) const; + + // Efectos en el juego + bool isRaining() const { return currentWeather == WeatherType::Rainy || + currentWeather == WeatherType::Stormy; } + bool isSnowing() const { return currentWeather == WeatherType::Snowy; } + bool isStormy() const { return currentWeather == WeatherType::Stormy; } + float getLightModifier() const; // Modificador de luz ambiental + +private: + void updateTemperature(float deltaTime); + void updateWeatherType(float deltaTime); + void generateDailyForecast(); + + WeatherType currentWeather = WeatherType::Clear; + float temperature = 20.0f; + float humidity = 0.5f; + float windSpeed = 5.0f; + glm::vec3 windDirection{1.0f, 0.0f, 0.0f}; + float rainIntensity = 0.0f; + float cloudCover = 0.2f; + + float timeOfDay = 12.0f; // Hora actual (0-24) + int32_t currentDay = 1; + + std::vector forecast; +}; + +class SeasonSystem { +public: + static SeasonSystem& getInstance(); + + void initialize(int32_t daysPerSeason = 30); + void update(float deltaTime); + + // Estado + Season getCurrentSeason() const { return currentSeason; } + int32_t getCurrentDay() const { return currentDay; } + int32_t getDaysPerSeason() const { return daysPerSeason; } + float getSeasonProgress() const; // 0.0 - 1.0 + + // Configuración de estación + const WeatherConfig& getSeasonConfig() const; + + // Efectos de estación + float getGrowthModifier() const; // Multiplicador de crecimiento de cultivos + float getWaterEvaporationRate() const; + int32_t getDayLengthHours() const; + + // Transiciones + bool isSeasonTransition() const; // Últimos días de la estación + int32_t getDaysUntilTransition() const; + + // Forzar cambio (para debugging/eventos) + void advanceSeason(); + void setSeason(Season season); + +private: + SeasonSystem() = default; + + void updateSeasonEffects(); + WeatherConfig calculateSeasonConfig() const; + + Season currentSeason = Season::Spring; + int32_t currentDay = 1; + int32_t daysPerSeason = 30; + + WeatherConfig seasonConfig; + float growthModifier = 1.0f; + float evaporationRate = 1.0f; +}; + +// Sistema climático global +class ClimateSystem { +public: + static ClimateSystem& getInstance(); + + void initialize(); + void update(float deltaTime); + + // Clima por región + void setRegionClimate(const std::string& regionName, + float avgTemperature, + float avgRainfall); + + // Cambio climático a largo plazo + void applyClimateChange(float temperatureDelta, float rainfallDelta); + + // Eventos extremos + bool checkExtremeWeatherEvent(); + void triggerDrought(float duration); + void triggerHeatwave(float duration); + void triggerFlood(float duration); + +private: + ClimateSystem() = default; + + struct RegionClimate { + float baseTemperature; + float baseRainfall; + float currentTemperature; + float currentRainfall; + }; + + std::unordered_map regions; + + float globalTemperatureModifier = 0.0f; + float globalRainfallModifier = 0.0f; + + // Eventos activos + struct ActiveEvent { + enum class Type { Drought, Heatwave, Flood, None }; + Type type = Type::None; + float remainingDuration = 0.0f; + float intensity = 1.0f; + }; + + ActiveEvent activeEvent; +}; + +// Efectos del clima en cultivos y animales +class WeatherEffects { +public: + static WeatherEffects& getInstance(); + + void update(float deltaTime); + + // Efectos en cultivos + float getCropGrowthModifier(const glm::vec3& position) const; + float getCropDamageRisk(const glm::vec3& position) const; + bool needsIrrigation(const glm::vec3& position) const; + bool needsProtection(const glm::vec3& position) const; + + // Efectos en animales + float getAnimalComfortModifier(const glm::vec3& position) const; + bool needsShelter(const glm::vec3& position) const; + float getDiseaseRisk(const glm::vec3& position) const; + + // Efectos en suelo + float getSoilErosionRisk(const glm::vec3& position) const; + float getSoilMoistureGain(const glm::vec3& position) const; + +private: + WeatherEffects() = default; + + float calculateWindChill(float temperature, float windSpeed) const; + float calculateHeatIndex(float temperature, float humidity) const; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/tools/inspector/Inspector.h b/FarmEngine/tools/inspector/Inspector.h new file mode 100644 index 0000000..6ca78df --- /dev/null +++ b/FarmEngine/tools/inspector/Inspector.h @@ -0,0 +1,178 @@ +#pragma once + +#include +#include +#include + +namespace FarmEngine { + +struct EntityInfo { + uint32_t entityID; + std::string name; + std::string type; + bool active; +}; + +struct ComponentInfo { + std::string name; + std::string value; + bool editable; +}; + +class Inspector { +public: + static Inspector& getInstance(); + + void initialize(); + void cleanup(); + + // Selección + void selectEntity(uint32_t entityID); + void deselectEntity(); + uint32_t getSelectedEntity() const { return selectedEntity; } + + // Información + EntityInfo getEntityInfo(uint32_t entityID) const; + std::vector getComponents(uint32_t entityID) const; + + // Edición + bool editComponent(uint32_t entityID, const std::string& componentName, + const std::string& newValue); + + // Añadir/Remover componentes + bool addComponent(uint32_t entityID, const std::string& componentType); + bool removeComponent(uint32_t entityID, const std::string& componentType); + + // Callbacks para UI + using SelectionCallback = std::function; + void setSelectionCallback(SelectionCallback callback); + +private: + Inspector() = default; + ~Inspector(); + + uint32_t selectedEntity = 0; + SelectionCallback selectionCallback; +}; + +class EntityTree { +public: + static EntityTree& getInstance(); + + void initialize(); + void cleanup(); + + // Navegación + struct TreeNode { + uint32_t entityID; + std::string name; + std::vector children; + uint32_t parent = 0; + bool expanded = true; + }; + + const std::vector& getRootNodes() const { return rootNodes; } + const TreeNode* getNode(uint32_t entityID) const; + + // Modificación + void addNode(uint32_t entityID, const std::string& name, + uint32_t parentID = 0); + void removeNode(uint32_t entityID); + void reorderNode(uint32_t entityID, uint32_t newParentID, int32_t index); + + // Búsqueda + std::vector searchByName(const std::string& query) const; + std::vector searchByType(const std::string& type) const; + + // Filtros + void setFilter(const std::string& filter); + void clearFilter(); + +private: + EntityTree() = default; + + std::vector rootNodes; + std::unordered_map nodes; + std::string currentFilter; +}; + +// Herramientas de debugging +class DebugTools { +public: + static DebugTools& getInstance(); + + void initialize(); + void cleanup(); + + // FPS Counter + float getFPS() const { return fps; } + float getFrameTime() const { return frameTime; } + + // Memory stats + size_t getTotalMemoryUsage() const; + size_t getAssetMemoryUsage() const; + + // Render stats + uint32_t getDrawCalls() const { return drawCalls; } + uint32_t getTriangleCount() const { return triangleCount; } + uint32_t getEntityCount() const { return entityCount; } + + // Profiling + void beginProfile(const std::string& name); + void endProfile(const std::string& name); + std::vector> getProfileResults() const; + + // Console commands + using CommandCallback = std::function&)>; + void registerCommand(const std::string& name, CommandCallback callback, + const std::string& description = ""); + void executeCommand(const std::string& commandLine); + + // Log + void addLogMessage(const std::string& message, int32_t level = 0); + const std::vector>& getLogs() const; + + void update(float deltaTime); + +private: + DebugTools() = default; + + float fps = 0.0f; + float frameTime = 0.0f; + float frameAccumulator = 0.0f; + int32_t frameCount = 0; + + uint32_t drawCalls = 0; + uint32_t triangleCount = 0; + uint32_t entityCount = 0; + + struct ProfileEntry { + std::string name; + float startTime; + float totalTime; + int32_t callCount; + }; + + std::unordered_map profileData; + std::vector> profileResults; + + std::unordered_map commands; + std::vector> logs; + + static const size_t maxLogs = 1000; +}; + +// Widget base para herramientas +class ToolWidget { +public: + virtual ~ToolWidget() = default; + virtual void render() = 0; + virtual void update(float deltaTime) {} + virtual bool isActive() const { return active; } + virtual void setActive(bool value) { active = value; } + +protected: + bool active = true; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/world/chunks/ChunkSystem.h b/FarmEngine/world/chunks/ChunkSystem.h new file mode 100644 index 0000000..d0045e6 --- /dev/null +++ b/FarmEngine/world/chunks/ChunkSystem.h @@ -0,0 +1,140 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace FarmEngine { + +struct ChunkConfig { + int32_t chunkSize = 32; + int32_t renderDistance = 8; + float lodDistances[4] = {20.0f, 50.0f, 100.0f, 200.0f}; +}; + +class Chunk { +public: + Chunk(int32_t x, int32_t z, const ChunkConfig& config); + ~Chunk(); + + // Posición en el mundo + int32_t getChunkX() const { return chunkX; } + int32_t getChunkZ() const { return chunkZ; } + glm::vec3 getPosition() const; + + // Generación y carga + bool generate(int32_t seed); + bool loadFromDisk(const std::string& path); + bool saveToDisk(const std::string& path); + + // Datos de bloques + uint8_t getBlock(int32_t x, int32_t y, int32_t z) const; + void setBlock(int32_t x, int32_t y, int32_t z, uint8_t blockID); + + // Mesh generation + bool buildMesh(); + void rebuildMesh(); + + // Estado + bool isLoaded() const { return loaded; } + bool isModified() const { return modified; } + bool needsMeshUpdate() const { return needsMeshRebuild; } + + void setLoaded(bool value) { loaded = value; } + void setModified(bool value) { modified = value; } + +private: + int32_t chunkX; + int32_t chunkZ; + ChunkConfig config; + + std::vector blocks; // Block IDs + std::vector data; // Block data (metadata) + std::vector light; // Light values + + bool loaded = false; + bool modified = false; + bool needsMeshRebuild = true; + + // Mesh data (separada para streaming) + struct MeshData { + std::vector vertices; + std::vector indices; + bool dirty = true; + }; + + MeshData opaqueMesh; + MeshData transparentMesh; +}; + +class ChunkManager { +public: + static ChunkManager& getInstance(); + + void initialize(const ChunkConfig& config); + void cleanup(); + + // Actualización + void update(const glm::vec3& playerPosition, float deltaTime); + + // Obtener chunks + Chunk* getChunk(int32_t chunkX, int32_t chunkZ); + Chunk* getChunkAtWorldPos(const glm::vec3& worldPos); + + // Generación de chunks + void requestChunkGeneration(int32_t chunkX, int32_t chunkZ); + + // Streaming + void loadChunksAroundPlayer(const glm::vec3& playerPosition); + void unloadDistantChunks(const glm::vec3& playerPosition); + + // Bloques individuales + uint8_t getBlock(const glm::vec3& worldPos); + void setBlock(const glm::vec3& worldPos, uint8_t blockID); + + // Estadísticas + size_t getLoadedChunkCount() const { return chunks.size(); } + size_t getPendingGenerationCount() const { return pendingGeneration.size(); } + +private: + ChunkManager() = default; + ~ChunkManager(); + + glm::ivec3 worldToChunk(const glm::vec3& worldPos) const; + glm::ivec3 worldToLocal(const glm::vec3& worldPos) const; + + ChunkConfig config; + + // Chunks cargados: key = (chunkX << 16) | chunkZ + std::unordered_map> chunks; + + // Cola de generación + std::vector> pendingGeneration; + + // Chunks visibles actualmente + std::vector visibleChunks; + + int32_t lastPlayerChunkX = 0; + int32_t lastPlayerChunkZ = 0; +}; + +// Thread pool para generación de chunks +class ChunkGenerationThread { +public: + ChunkGenerationThread(); + ~ChunkGenerationThread(); + + void start(); + void stop(); + + void addTask(int32_t chunkX, int32_t chunkZ, int32_t seed); + +private: + void threadFunction(); + + // Implementación multihilo +}; + +} // namespace FarmEngine diff --git a/FarmEngine/world/terrain/TerrainGenerator.h b/FarmEngine/world/terrain/TerrainGenerator.h new file mode 100644 index 0000000..e028e6b --- /dev/null +++ b/FarmEngine/world/terrain/TerrainGenerator.h @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include +#include + +namespace FarmEngine { + +enum class TerrainType { + Plains, + Desert, + Forest, + Mountains, + Hills, + Swamp, + Snow +}; + +enum class Biome { + Farmland, + Pasture, + Orchard, + Vineyard, + Greenhouse, + Pond, + Barn, + Silo +}; + +struct TerrainConfig { + int32_t seed = 12345; + float scale = 0.01f; + float heightScale = 64.0f; + float moistureScale = 0.01f; + float temperatureScale = 0.01f; + + // Octavas de ruido + int32_t octaves = 6; + float persistence = 0.5f; + float lacunarity = 2.0f; +}; + +class NoiseGenerator { +public: + NoiseGenerator(int32_t seed); + + float noise2D(float x, float y) const; + float noise3D(float x, float y, float z) const; + + float octaveNoise2D(float x, float y, int32_t octaves, + float persistence, float lacunarity) const; + + void setSeed(int32_t seed); + +private: + std::vector permutation; + int32_t seed; + + float fade(float t) const; + float lerp(float a, float b, float t) const; + float grad(int32_t hash, float x, float y) const; +}; + +class TerrainGenerator { +public: + TerrainGenerator(const TerrainConfig& config); + + void generateHeightmap(int32_t width, int32_t depth, + std::vector& heightmap); + + void generateBiomeMap(int32_t width, int32_t depth, + const std::vector& heightmap, + std::vector& biomeMap); + + float getHeightAt(int32_t x, int32_t z) const; + Biome getBiomeAt(int32_t x, int32_t z) const; + + // Generación específica para farming + float getMoistureAt(int32_t x, int32_t z) const; + float getTemperatureAt(int32_t x, int32_t z) const; + float getFertilityAt(int32_t x, int32_t z) const; + + const TerrainConfig& getConfig() const { return config; } + +private: + TerrainType calculateTerrainType(float height, float moisture, float temperature) const; + Biome calculateBiome(TerrainType terrain, float fertility) const; + + TerrainConfig config; + std::unique_ptr heightNoise; + std::unique_ptr moistureNoise; + std::unique_ptr temperatureNoise; + std::unique_ptr detailNoise; +}; + +// Sistema de erosión térmica/hidráulica +class TerrainErosion { +public: + static void applyThermalErosion(std::vector& heightmap, + int32_t width, int32_t depth, + int32_t iterations = 10); + + static void applyHydraulicErosion(std::vector& heightmap, + std::vector& moisture, + int32_t width, int32_t depth, + int32_t iterations = 20); + + static void smoothTerrain(std::vector& heightmap, + int32_t width, int32_t depth, + float strength = 0.5f); +}; + +// Features del terreno (árboles, rocas, agua) +struct TerrainFeature { + enum class Type { + Tree, + Rock, + Bush, + Flower, + Crop, + Water, + Path + }; + + Type type; + glm::vec3 position; + float rotation; + float scale; + uint32_t variant; +}; + +class TerrainFeatureGenerator { +public: + TerrainFeatureGenerator(const TerrainConfig& config); + + void generateFeatures(int32_t chunkX, int32_t chunkZ, + const std::vector& heightmap, + const std::vector& biomeMap, + std::vector& features); + + // Features específicos para granja + void generateFarmFeatures(int32_t chunkX, int32_t chunkZ, + std::vector& features); + +private: + TerrainConfig config; + NoiseGenerator featureNoise{0}; +}; + +} // namespace FarmEngine diff --git a/FarmEngine/world/tiles/Tilemap.h b/FarmEngine/world/tiles/Tilemap.h new file mode 100644 index 0000000..dae812a --- /dev/null +++ b/FarmEngine/world/tiles/Tilemap.h @@ -0,0 +1,156 @@ +#pragma once + +#include +#include +#include +#include + +namespace FarmEngine { + +struct TileConfig { + uint32_t tileID; + std::string name; + bool walkable; + bool buildable; + float fertility; + float moistureRetention; + uint32_t textureIndex; +}; + +class TileDatabase { +public: + static TileDatabase& getInstance(); + + void initialize(); + + const TileConfig* getTile(uint32_t tileID) const; + uint32_t getTileIDByName(const std::string& name) const; + + // Tiles de granja predefinidos + uint32_t getDirtTile() const { return dirtTileID; } + uint32_t getGrassTile() const { return grassTileID; } + uint32_t getFarmlandTile() const { return farmlandTileID; } + uint32_t getWateredFarmlandTile() const { return wateredFarmlandTileID; } + uint32_t getPathTile() const { return pathTileID; } + uint32_t getStoneTile() const { return stoneTileID; } + uint32_t getWoodTile() const { return woodTileID; } + +private: + TileDatabase() = default; + + std::unordered_map tiles; + std::unordered_map nameToID; + + uint32_t dirtTileID = 1; + uint32_t grassTileID = 2; + uint32_t farmlandTileID = 3; + uint32_t wateredFarmlandTileID = 4; + uint32_t pathTileID = 5; + uint32_t stoneTileID = 6; + uint32_t woodTileID = 7; +}; + +// Tilemap para granjas 2D +struct TilemapConfig { + uint32_t width; + uint32_t height; + uint32_t tileSize; + uint32_t layerCount; +}; + +enum class TileLayer { + Ground = 0, + Objects = 1, + Crops = 2, + Decorations = 3, + Overlay = 4, + LayerCount +}; + +class Tilemap { +public: + Tilemap(const TilemapConfig& config); + ~Tilemap(); + + // Dimensiones + uint32_t getWidth() const { return config.width; } + uint32_t getHeight() const { return config.height; } + uint32_t getTileSize() const { return config.tileSize; } + + // Acceso a tiles + uint32_t getTile(uint32_t x, uint32_t y, TileLayer layer) const; + void setTile(uint32_t x, uint32_t y, TileLayer layer, uint32_t tileID); + + // Acceso por coordenadas del mundo + uint32_t getTileAtWorld(float worldX, float worldY, TileLayer layer) const; + glm::vec2 getWorldPosition(uint32_t tileX, uint32_t tileY) const; + + // Conversión de coordenadas + glm::ivec2 worldToTile(float worldX, float worldY) const; + glm::vec2 tileToWorld(uint32_t tileX, uint32_t tileY) const; + + // Propiedades de tiles + bool isWalkable(uint32_t x, uint32_t y) const; + bool isBuildable(uint32_t x, uint32_t y) const; + float getFertility(uint32_t x, uint32_t y) const; + + // Carga/Guardado + bool loadFromFile(const std::string& path); + bool saveToFile(const std::string& path) const; + + // Datos crudos + const std::vector& getLayerData(TileLayer layer) const; + +private: + TilemapConfig config; + std::vector> layers; + + TileDatabase& tileDB; +}; + +// Sistema de colisión basado en tiles +class TilemapCollision { +public: + TilemapCollision(const Tilemap* tilemap); + + bool checkCollision(float x, float y, float width, float height) const; + bool isPointWalkable(float x, float y) const; + + // Pathfinding helper + bool canMoveTo(uint32_t tileX, uint32_t tileY) const; + +private: + const Tilemap* tilemap; +}; + +// Editor de tilemaps +class TilemapEditor { +public: + struct Brush { + uint32_t tileID; + TileLayer layer; + uint32_t size; + bool continuous; + }; + + TilemapEditor(Tilemap* tilemap); + + void setBrush(const Brush& brush); + void applyBrush(uint32_t tileX, uint32_t tileY); + void floodFill(uint32_t tileX, uint32_t tileY, uint32_t targetID, uint32_t fillID); + + // Herramientas + void drawLine(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1); + void drawRectangle(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, bool filled); + void copySelection(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1); + void pasteSelection(uint32_t destX, uint32_t destY); + +private: + Tilemap* tilemap; + Brush currentBrush; + std::vector clipboard; + uint32_t clipboardWidth = 0; + uint32_t clipboardHeight = 0; +}; + +} // namespace FarmEngine