diff --git a/src/entity/component-manager.hpp b/src/entity/component-manager.hpp index 69a913d..c1e6615 100644 --- a/src/entity/component-manager.hpp +++ b/src/entity/component-manager.hpp @@ -90,6 +90,17 @@ public: * @return Pointer to the component, or `nullptr` if the specified component was not found. */ ComponentBase* getComponent(EntityID entity, ComponentType type); + + /** + * Returns the specified component of an entity. + * + * @param entity Specifies an entity. + * @tparam type Specifies the component type. + * + * @return Pointer to the component, or `nullptr` if the specified component was not found. + */ + template + T* getComponent(EntityID entity); /** * Returns the component map of the specified entity. @@ -108,6 +119,20 @@ private: std::list componentObservers; }; +template +T* ComponentManager::getComponent(EntityID entity) +{ + ComponentMap& componentMap = entityMap[entity]; + + auto it = componentMap.find(T::TYPE); + if (it == componentMap.end()) + { + return nullptr; + } + + return static_cast(it->second); +} + inline ComponentMap* ComponentManager::getComponents(EntityID entity) { return &entityMap[entity]; diff --git a/src/entity/components/terrain-patch-component.cpp b/src/entity/components/terrain-patch-component.cpp index 645c660..9902039 100644 --- a/src/entity/components/terrain-patch-component.cpp +++ b/src/entity/components/terrain-patch-component.cpp @@ -22,6 +22,7 @@ ComponentBase* TerrainPatchComponent::clone() const { TerrainPatchComponent* component = new TerrainPatchComponent(); + component->subdivisions = subdivisions; component->position = position; return component; diff --git a/src/entity/components/terrain-patch-component.hpp b/src/entity/components/terrain-patch-component.hpp index f4023be..7e387ad 100644 --- a/src/entity/components/terrain-patch-component.hpp +++ b/src/entity/components/terrain-patch-component.hpp @@ -28,6 +28,9 @@ class TerrainPatchComponent: public Component { public: virtual ComponentBase* clone() const; + + // Number of terrain mesh subdivisions (at LOD 0) + int subdivisions; // Position in integer terrain coordinates std::tuple position; diff --git a/src/entity/systems/terrain-system.cpp b/src/entity/systems/terrain-system.cpp index 6540779..70aba7f 100644 --- a/src/entity/systems/terrain-system.cpp +++ b/src/entity/systems/terrain-system.cpp @@ -27,8 +27,7 @@ TerrainSystem::TerrainSystem(ComponentManager* componentManager): { terrainCreationGroup.addGroupObserver(this); terrainGroup.addGroupObserver(this); - - patchSize = 100.0f; + patchSize = 1.0f; } TerrainSystem::~TerrainSystem() @@ -43,16 +42,23 @@ void TerrainSystem::update(float t, float dt) ModelComponent* model = std::get<0>(member->components); TerrainPatchComponent* patch = std::get<1>(member->components); TransformComponent* transform = std::get<2>(member->components); + + transform->transform.translation = Vector3(std::get<0>(patch->position), 0.0f, std::get<1>(patch->position)) * patchSize; } } +void TerrainSystem::setPatchSize(float size) +{ + patchSize = size; +} + void TerrainSystem::memberRegistered(const TerrainCreationGroup::Member* member) { TerrainPatchComponent* patch = std::get<0>(member->components); TransformComponent* transform = std::get<1>(member->components); // Generate a subdivided plane mesh - TriangleMesh* patchMesh = generatePlane(5); + TriangleMesh* patchMesh = generatePlane(patch->subdivisions); // Generate a model from the subdivided plane Model* patchModel = generateModel(patchMesh); @@ -63,7 +69,7 @@ void TerrainSystem::memberRegistered(const TerrainCreationGroup::Member* member) componentManager->addComponent(member->entity, model); // Set scale of the transform component - transform->transform.scale = Vector3(patchSize); + transform->transform.scale = Vector3(patchSize, 1.0f, patchSize); transform->transform.translation = Vector3(std::get<0>(patch->position), 0.0f, std::get<1>(patch->position)) * patchSize; } @@ -137,51 +143,6 @@ TriangleMesh* TerrainSystem::generatePlane(int subdivisions) } return new TriangleMesh(vertices, indices); - - /* - // Generate navmesh - surfaceNavmesh.create(surfaceVertices, surfaceIndices); - - // Calculate vertex normals - calculateSurfaceNormals(); - - // Create and load VAO, VBO, and IBO - glGenVertexArrays(1, &surfaceVAO); - glBindVertexArray(surfaceVAO); - glGenBuffers(1, &surfaceVBO); - glBindBuffer(GL_ARRAY_BUFFER, surfaceVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * surfaceVertexSize * surfaceVertexCount, surfaceVertexData, GL_STATIC_DRAW); - glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION); - glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 0 * sizeof(float)); - glEnableVertexAttribArray(EMERGENT_VERTEX_NORMAL); - glVertexAttribPointer(EMERGENT_VERTEX_NORMAL, 3, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 3 * sizeof(float)); - glEnableVertexAttribArray(EMERGENT_VERTEX_TEXCOORD); - glVertexAttribPointer(EMERGENT_VERTEX_TEXCOORD, 2, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 6 * sizeof(float)); - glGenBuffers(1, &surfaceIBO); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surfaceIBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * surfaceIndexCount, surfaceIndexData, GL_STATIC_DRAW); - - // Setup material - //surfaceMaterial.flags = static_cast(PhysicalMaterial::Flags::OBJECT); - - // Setup buffers - surfaceModel.setVAO(surfaceVAO); - surfaceModel.setVBO(surfaceVBO); - surfaceModel.setIBO(surfaceIBO); - - // Create model group - Model::Group* group = new Model::Group(); - group->name = "default"; - group->material = nullptr;//&surfaceMaterial; - group->indexOffset = 0; - group->triangleCount = surfaceTriangleCount; - - // Add group to the model - surfaceModel.addGroup(group); - - // Set model bounds - surfaceModel.setBounds(surfaceNavmesh.getBounds()); - */ } Model* TerrainSystem::generateModel(TriangleMesh* mesh) @@ -335,7 +296,7 @@ Model* TerrainSystem::generateModel(TriangleMesh* mesh) ShaderVariable* roughness = material->addVariable("roughness"); ShaderVariable* metalness = material->addVariable("metalness"); ShaderVariable* opacity = material->addVariable("opacity"); - albedo->setValue(Vector3(0.8f)); + albedo->setValue(Vector3(frand(0.0f, 1.0f), frand(0.0f, 1.0f), frand(0.0, 1.0f))); roughness->setValue(0.5f); metalness->setValue(0.0f); opacity->setValue(1.0f); diff --git a/src/entity/systems/terrain-system.hpp b/src/entity/systems/terrain-system.hpp index 211da3e..e1319d9 100644 --- a/src/entity/systems/terrain-system.hpp +++ b/src/entity/systems/terrain-system.hpp @@ -42,6 +42,8 @@ public: virtual void update(float t, float dt); + void setPatchSize(float size); + private: virtual void memberRegistered(const TerrainCreationGroup::Member* member); virtual void memberUnregistered(const TerrainCreationGroup::Member* member); diff --git a/src/game.cpp b/src/game.cpp index 7706826..c2f56bb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -40,6 +40,7 @@ #include "entity/component-manager.hpp" #include "entity/components/transform-component.hpp" #include "entity/components/model-component.hpp" +#include "entity/components/terrain-patch-component.hpp" #include "entity/entity-manager.hpp" #include "entity/entity-template.hpp" #include "entity/system-manager.hpp" @@ -334,6 +335,7 @@ void Game::setup() steeringSystem = new SteeringSystem(componentManager); locomotionSystem = new LocomotionSystem(componentManager); terrainSystem = new TerrainSystem(componentManager); + terrainSystem->setPatchSize(500.0f); particleSystem = new ParticleSystem(componentManager); particleSystem->resize(1000); particleSystem->setMaterial(smokeMaterial); @@ -412,8 +414,41 @@ void Game::setup() //EntityID tool0 = createInstanceOf("lens"); - - EntityID patch0 = createInstanceOf("terrain-patch"); + + int highResolutionDiameter = 3; + int mediumResolutionDiameter = highResolutionDiameter + 2; + int lowResolutionDiameter = 20; + + float lowResolutionRadius = static_cast(lowResolutionDiameter) / 2.0f; + float mediumResolutionRadius = static_cast(mediumResolutionDiameter) / 2.0f; + float highResolutionRadius = static_cast(highResolutionDiameter) / 2.0f; + + for (int i = 0; i < lowResolutionDiameter; ++i) + { + for (int j = 0; j < lowResolutionDiameter; ++j) + { + EntityID patch; + + int x = i - lowResolutionDiameter / 2; + int z = j - lowResolutionDiameter / 2; + + + if (std::abs(x) < highResolutionRadius && std::abs(z) < highResolutionRadius) + { + patch = createInstanceOf("terrain-patch-high-resolution"); + } + else if (std::abs(x) < mediumResolutionRadius && std::abs(z) < mediumResolutionRadius) + { + patch = createInstanceOf("terrain-patch-medium-resolution"); + } + else + { + patch = createInstanceOf("terrain-patch-low-resolution"); + } + + setTerrainPatchPosition(patch, {x, z}); + } + } changeState(sandboxState); } @@ -422,9 +457,6 @@ void Game::update(float t, float dt) { this->time = t; - // Dispatch scheduled events - eventDispatcher.update(t); - // Execute current state if (currentState != nullptr) { @@ -469,14 +501,14 @@ void Game::render() renderer.render(*worldScene); renderer.render(*uiScene); - // Swap window framebuffers - window->swapBuffers(); - if (screenshotQueued) { screenshot(); screenshotQueued = false; } + + // Swap window framebuffers + window->swapBuffers(); } void Game::exit() @@ -922,6 +954,11 @@ void Game::setupUI() toolIconCameraImage->setTextureBounds(normalizeTextureBounds(hudTextureAtlas.getBounds("tool-icon-camera"), hudTextureAtlasBounds)); radialMenuImage->addChild(toolIconCameraImage); + toolIconMicrochipImage = new UIImage(); + toolIconMicrochipImage->setTexture(hudSpriteSheetTexture); + toolIconMicrochipImage->setTextureBounds(normalizeTextureBounds(hudTextureAtlas.getBounds("tool-icon-microchip"), hudTextureAtlasBounds)); + radialMenuImage->addChild(toolIconMicrochipImage); + toolIconTestTubeImage = new UIImage(); toolIconTestTubeImage->setTexture(hudSpriteSheetTexture); toolIconTestTubeImage->setTextureBounds(normalizeTextureBounds(hudTextureAtlas.getBounds("tool-icon-test-tube"), hudTextureAtlasBounds)); @@ -1080,7 +1117,7 @@ void Game::setupUI() cameraGridContainer->addChild(cameraGridX0Image); cameraGridContainer->addChild(cameraGridX1Image); cameraGridContainer->addChild(cameraReticleImage); - cameraGridContainer->setVisible(true); + cameraGridContainer->setVisible(false); uiRootElement->addChild(cameraGridContainer); cameraFlashImage = new UIImage(); @@ -1859,6 +1896,9 @@ void Game::resizeUI(int w, int h) toolIconCameraImage->setDimensions(Vector2(toolIconCameraBounds.getWidth(), toolIconCameraBounds.getHeight())); toolIconCameraImage->setAnchor(Anchor::CENTER); + Rect toolIconMicrochipBounds = hudTextureAtlas.getBounds("tool-icon-microchip"); + toolIconMicrochipImage->setDimensions(Vector2(toolIconMicrochipBounds.getWidth(), toolIconMicrochipBounds.getHeight())); + toolIconMicrochipImage->setAnchor(Anchor::CENTER); Rect toolIconTestTubeBounds = hudTextureAtlas.getBounds("tool-icon-test-tube"); toolIconTestTubeImage->setDimensions(Vector2(toolIconTestTubeBounds.getWidth(), toolIconTestTubeBounds.getHeight())); @@ -1931,7 +1971,7 @@ void Game::resizeUI(int w, int h) toolIconLensImage, nullptr, toolIconForcepsImage, - nullptr, + toolIconMicrochipImage, toolIconCameraImage, nullptr }; @@ -2015,6 +2055,7 @@ void Game::screenshot() // Read pixel data from framebuffer unsigned char* pixels = new unsigned char[w * h * 3]; + glReadBuffer(GL_BACK); glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels); // Get game title in current language @@ -2056,13 +2097,12 @@ void Game::screenshot() // Play camera shutter sound // Restore camera UI visibility - cameraGridContainer->setVisible(true); + //cameraGridContainer->setVisible(true); fpsLabel->setVisible(true); // Whiteout screen immediately glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - window->swapBuffers(); } void Game::mapInput(const InputMapping& mapping) @@ -2215,7 +2255,7 @@ void Game::removeComponent(EntityID entity, ComponentType type) void Game::setTranslation(EntityID entity, const Vector3& translation) { - TransformComponent* component = static_cast(componentManager->getComponent(entity, ComponentType::TRANSFORM)); + TransformComponent* component = componentManager->getComponent(entity); if (!component) { return; @@ -2226,7 +2266,7 @@ void Game::setTranslation(EntityID entity, const Vector3& translation) void Game::setRotation(EntityID entity, const Quaternion& rotation) { - TransformComponent* component = static_cast(componentManager->getComponent(entity, ComponentType::TRANSFORM)); + TransformComponent* component = componentManager->getComponent(entity); if (!component) { return; @@ -2237,7 +2277,7 @@ void Game::setRotation(EntityID entity, const Quaternion& rotation) void Game::setScale(EntityID entity, const Vector3& scale) { - TransformComponent* component = static_cast(componentManager->getComponent(entity, ComponentType::TRANSFORM)); + TransformComponent* component = componentManager->getComponent(entity); if (!component) { return; @@ -2246,6 +2286,16 @@ void Game::setScale(EntityID entity, const Vector3& scale) component->transform.scale = scale; } +void Game::setTerrainPatchPosition(EntityID entity, const std::tuple& position) +{ + TerrainPatchComponent* component = componentManager->getComponent(entity); + if (!component) + { + return; + } + + component->position = position; +} void Game::saveScreenshot(const std::string& filename, unsigned int width, unsigned int height, unsigned char* pixels) { diff --git a/src/game.hpp b/src/game.hpp index f160a0f..578b987 100644 --- a/src/game.hpp +++ b/src/game.hpp @@ -172,6 +172,7 @@ public: void setTranslation(EntityID entity, const Vector3& translation); void setRotation(EntityID entity, const Quaternion& rotation); void setScale(EntityID entity, const Vector3& scale); + void setTerrainPatchPosition(EntityID entity, const std::tuple& position); void boxSelect(float x, float y, float w, float h); @@ -283,6 +284,7 @@ public: UIImage* toolIconForcepsImage; UIImage* toolIconSpadeImage; UIImage* toolIconCameraImage; + UIImage* toolIconMicrochipImage; UIImage* toolIconTestTubeImage; UIContainer* buttonContainer; UIImage* playButtonBGImage; diff --git a/src/graphics/lighting-render-pass.cpp b/src/graphics/lighting-render-pass.cpp index 3c20c1b..2a1c7f5 100755 --- a/src/graphics/lighting-render-pass.cpp +++ b/src/graphics/lighting-render-pass.cpp @@ -81,6 +81,9 @@ bool LightingRenderPass::load(const RenderContext* renderContext) spotlightCutoffsParam.connect(shader->getInput("spotlightCutoffs")); spotlightExponentsParam.connect(shader->getInput("spotlightExponents")); + clipNearParam.connect(shader->getInput("clipNear")); + clipFarParam.connect(shader->getInput("clipFar")); + #if defined(DEBUG) wireframeLineWidthParam.connect(shader->getInput("wireframeLineWidth")); #endif @@ -228,6 +231,8 @@ void LightingRenderPass::render(RenderContext* renderContext) cameraPositionParam.setValue(cameraPosition); shadowMapParam.setValue(shadowMap); timeParam.setValue(time); + clipNearParam.setValue(camera.getClipNear()); + clipFarParam.setValue(camera.getClipFar()); std::uint32_t permutation = 0xDEADBEEF; bool blending = false; @@ -284,6 +289,9 @@ void LightingRenderPass::render(RenderContext* renderContext) spotlightExponentsParam.upload(); } + clipNearParam.upload(); + clipFarParam.upload(); + #if defined(DEBUG) wireframeLineWidthParam.upload(); #endif diff --git a/src/graphics/lighting-render-pass.hpp b/src/graphics/lighting-render-pass.hpp index 1fbf12a..32f0e07 100755 --- a/src/graphics/lighting-render-pass.hpp +++ b/src/graphics/lighting-render-pass.hpp @@ -82,6 +82,8 @@ private: ShaderVector3 spotlightDirectionsParam; ShaderFloat spotlightCutoffsParam; ShaderFloat spotlightExponentsParam; + ShaderFloat clipNearParam; + ShaderFloat clipFarParam; #if defined(DEBUG) ShaderFloat wireframeLineWidthParam; diff --git a/src/resources/entity-template-loader.cpp b/src/resources/entity-template-loader.cpp index 92488f3..6ff7b20 100644 --- a/src/resources/entity-template-loader.cpp +++ b/src/resources/entity-template-loader.cpp @@ -80,12 +80,14 @@ static ComponentBase* loadModelComponent(ResourceManager* resourceManager, const static ComponentBase* loadTerrainPatchComponent(const std::vector& parameters) { - if (parameters.size() != 3) + if (parameters.size() != 4) { throw std::runtime_error("loadTerrainPatchComponent(): Invalid parameter count."); } + int subdivisions; std::tuple position; + float size; std::stringstream stream; for (std::size_t i = 1; i < parameters.size(); ++i) { @@ -93,10 +95,12 @@ static ComponentBase* loadTerrainPatchComponent(const std::vector& if (i < parameters.size() - 1) stream << ' '; } + stream >> subdivisions; stream >> std::get<0>(position); stream >> std::get<1>(position); TerrainPatchComponent* component = new TerrainPatchComponent(); + component->subdivisions = subdivisions; component->position = position; return component; diff --git a/src/states/sandbox-state.cpp b/src/states/sandbox-state.cpp index 9384017..36f3e86 100755 --- a/src/states/sandbox-state.cpp +++ b/src/states/sandbox-state.cpp @@ -67,13 +67,13 @@ void SandboxState::enter() game->orbitCam->setTargetAzimuth(azimuth); game->freeCam->setTranslation(Vector3(-5, 5.0f, -5.0f)); - game->cameraRig = game->freeCam; - game->mouse->setRelativeMode(true); + //game->cameraRig = game->freeCam; + //game->mouse->setRelativeMode(true); toolIndex = 0; game->selectTool(toolIndex); - game->currentTool->setActive(false); - //game->mouse->warp(game->window, game->w / 2, game->h / 2); + //game->currentTool->setActive(false); + game->mouse->warp(game->window, game->w / 2, game->h / 2); zoom = 0.5f; noPick = false; @@ -153,7 +153,7 @@ void SandboxState::execute() zoom = std::max(0.0f, std::min(1.0f, zoom)); float minFocalDistance = 5.0f; - float maxFocalDistance = 70.0f; + float maxFocalDistance = 200.0f; float logMinFocalDistance = std::log(minFocalDistance); float logMaxFocalDistance = std::log(maxFocalDistance); float logFocalDistance = lerp(logMinFocalDistance, logMaxFocalDistance, 1.0f - zoom); @@ -167,9 +167,9 @@ void SandboxState::execute() float fov = std::exp(logFOV); float minClipNear = 1.0f; - float maxClipNear = 10.0f; - float minClipFar = 80.0f; - float maxClipFar = 350.0f; + float maxClipNear = 5.0f; + float minClipFar = 100.0f; + float maxClipFar = 5000.0f; float logMinClipNear = std::log(minClipNear); float logMaxClipNear = std::log(maxClipNear); float logMinClipFar = std::log(minClipFar); @@ -179,15 +179,8 @@ void SandboxState::execute() float clipNear = std::exp(logClipNear); float clipFar = std::exp(logClipFar); - float nearElevation = glm::radians(40.0f); - float farElevation = glm::radians(80.0f); - float logNearElevation = std::log(nearElevation); - float logFarElevation = std::log(farElevation); - float logElevation = lerp(logNearElevation, logFarElevation, 1.0f - zoom); - float elevation = std::exp(logElevation); - - float minMovementSpeed = 2.5f * game->timestep; - float maxMovementSpeed = 40.0f * game->timestep; + float minMovementSpeed = 3.5f * game->timestep; + float maxMovementSpeed = 100.0f * game->timestep; float logMinMovementSpeed = std::log(minMovementSpeed); float logMaxMovementSpeed = std::log(maxMovementSpeed); float logMovementSpeed = lerp(logMinMovementSpeed, logMaxMovementSpeed, 1.0f - zoom); @@ -217,12 +210,23 @@ void SandboxState::execute() float logLabelDistance = lerp(logNearLabelDistance, logFarLabelDistance, 1.0f - zoom); float labelDistance = std::exp(logLabelDistance); + if (game->adjustCameraControl.isActive() && !game->adjustCameraControl.wasActive()) + { + savedMousePosition = game->mouse->getCurrentPosition(); + game->mouse->setRelativeMode(true); + } + if (!game->radialMenuContainer->isVisible() && !menuClosed) { // Picking Vector3 pick; std::tuple mousePosition = game->mouse->getCurrentPosition(); + if (game->adjustCameraControl.isActive() || game->adjustCameraControl.wasActive()) + { + mousePosition = savedMousePosition; + } + std::get<1>(mousePosition) = game->h - std::get<1>(mousePosition); Vector4 viewport(0.0f, 0.0f, game->w, game->h); Vector3 mouseNear = game->cameraRig->getCamera()->unproject(Vector3(std::get<0>(mousePosition), std::get<1>(mousePosition), 0.0f), viewport); @@ -250,26 +254,8 @@ void SandboxState::execute() } game->currentTool->update(game->timestep); } - - if (game->adjustCameraControl.isActive() || game->dragCameraControl.isActive()) - { - noPick = true; - } - else - { - noPick = false; - } - - - - if (game->adjustCameraControl.isActive() && !game->adjustCameraControl.wasActive()) - { - Vector3 focalPoint = pick; - game->orbitCam->setTargetFocalPoint(focalPoint); - savedMousePosition = game->mouse->getCurrentPosition(); - game->mouse->setRelativeMode(true); - } - else if (game->dragCameraControl.isActive()) + + if (game->dragCameraControl.isActive()) { if (!game->dragCameraControl.wasActive()) { @@ -308,7 +294,7 @@ void SandboxState::execute() if (!game->adjustCameraControl.isActive() && game->adjustCameraControl.wasActive()) { game->mouse->setRelativeMode(false); - game->mouse->warp(game->window, game->w / 2, game->h / 2); + game->mouse->warp(game->window, std::get<0>(savedMousePosition), std::get<1>(savedMousePosition)); noPick = false; } } @@ -377,7 +363,7 @@ void SandboxState::handleEvent(const MouseMovedEvent& event) float rotation = glm::radians(22.5f) * rotationFactor * game->timestep; - float minElevation = glm::radians(-80.0f); + float minElevation = glm::radians(4.0f); float maxElevation = glm::radians(80.0f); float elevation = game->orbitCam->getTargetElevation() + elevationFactor * 0.25f * game->timestep; elevation = std::min(maxElevation, std::max(minElevation, elevation));