/* * ${license.title} * Copyright (C) 2022 ${license.owner} * ${license.mailto} * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // // Created by webpigeon on 22/04/22. // #include "GameScene.h" camera_type cam_mode = cam_free; static void placeObject(fggl::ecs3::World& world, fggl::ecs::entity_t parent, fggl::ecs::entity_t prototype, glm::vec3 targetPos) { auto obj = world.copy(prototype); auto result = world.get<fggl::math::Transform>(obj); int xPos = (int)targetPos.x; int zPos = (int)targetPos.z * -1; // figure out the floor height auto heightMap = world.get<fggl::data::HeightMap>(parent); targetPos.y = heightMap->getValue(xPos, zPos); // TODO should really be the gradient at the required point result->origin( targetPos ); } static void process_camera(fggl::ecs3::World& ecs, const std::shared_ptr<fggl::input::Input>& input) { auto cameras = ecs.findMatching<fggl::gfx::Camera>(); fggl::ecs3::entity_t cam = cameras[0]; auto camTransform = ecs.get<fggl::math::Transform>(cam); auto camComp = ecs.get<fggl::gfx::Camera>(cam); const glm::vec3 dir = ( camTransform->origin() - camComp->target ); const glm::vec3 forward = glm::normalize( dir ); // scroll wheel glm::vec3 motion(0.0f); float delta = input->mouse.axis( fggl::input::MouseAxis::SCROLL_Y ); if ( (glm::length( dir ) < 25.0f && delta < 0.0f) || (glm::length( dir ) > 2.5f && delta > 0.0f) ) motion -= (forward * delta); camTransform->origin( camTransform->origin() + motion ); if ( cam_mode == cam_arcball || input->mouse.down( fggl::input::MouseButton::MIDDLE ) ) { fggl::input::process_arcball(ecs, *input, cam); } else if ( cam_mode == cam_free ) { fggl::input::process_freecam(ecs, *input, cam); } fggl::input::process_edgescroll( ecs, *input, cam ); } void GameScene::setup() { m_canvas.size( fggl::math::vec2(0,0), fggl::math::vec2(100, 100)); auto types = m_world->types(); // create camera using strings { auto prototype = m_world->create(false); m_world->add(prototype, types.find(fggl::math::Transform::name)); m_world->add(prototype, types.find(fggl::gfx::Camera::name)); m_world->add(prototype, types.find(fggl::input::FreeCamKeys::name)); auto camTf = m_world->get<fggl::math::Transform>(prototype); if ( camTf != nullptr) { camTf->origin(glm::vec3(10.0f, 3.0f, 10.0f)); } auto cameraKeys = m_world->get<fggl::input::FreeCamKeys>(prototype); if ( cameraKeys != nullptr ) { cameraKeys->forward = glfwGetKeyScancode(GLFW_KEY_W); cameraKeys->backward = glfwGetKeyScancode(GLFW_KEY_S); cameraKeys->left = glfwGetKeyScancode(GLFW_KEY_A); cameraKeys->right = glfwGetKeyScancode(GLFW_KEY_D); cameraKeys->rotate_cw = glfwGetKeyScancode(GLFW_KEY_Q); cameraKeys->rotate_ccw = glfwGetKeyScancode(GLFW_KEY_E); } } fggl::ecs3::entity_t terrain; { terrain = m_world->create(false); m_world->add(terrain, types.find(fggl::math::Transform::name)); auto camTf = m_world->get<fggl::math::Transform>(terrain); camTf->origin( glm::vec3(0.0f, 0.0f, 0.0f) ); //auto terrainData = m_world.get<fggl::data::HeightMap>(terrain); fggl::data::HeightMap terrainData{}; terrainData.clear(); const siv::PerlinNoise::seed_type seed = 123456u; const siv::PerlinNoise perlin{ seed }; for (int y = 0; y < 255; ++y) { for (int x = 0; x < 255; ++x) { const double noise = perlin.octave2D_11( (x * 0.01), (y * 0.01) , 4) * 10.f; terrainData.heightValues[x * 255 +y] = (float)noise; } } m_world->set<fggl::data::HeightMap>(terrain, &terrainData); } // create foundation object fggl::ecs3::entity_t foundation; { foundation = m_world->create(true); m_world->add(foundation, types.find(fggl::math::Transform::name)); // plot rendering fggl::data::Mesh mesh; fggl::data::make_cube(mesh); mesh.removeDups(); // add mesh as a component constexpr char shader[] = "phong"; fggl::data::StaticMesh staticMesh{mesh, shader}; m_world->set<fggl::data::StaticMesh>(foundation, &staticMesh); } // create building prototype fggl::ecs3::entity_t bunker; { bunker = m_world->create(true); m_world->add(bunker, types.find(fggl::math::Transform::name)); // mesh int nSections = 2; constexpr float HALF_PI = M_PI / 2.0f; constexpr char shader[] = "phong"; fggl::data::Mesh mesh; for (int j=-(nSections/2); j<=nSections/2; j++) { const auto shapeOffset = glm::vec3( 0.0f, 0.5f, (float)j * 1.0f ); const auto cubeMat = glm::translate( fggl::math::mat4( 1.0f ) , shapeOffset ); const auto leftSlope = fggl::math::modelMatrix( glm::vec3(-1.0f, 0.0f, 0.0f) + shapeOffset, glm::vec3( 0.0f, -HALF_PI, 0.0f) ); const auto rightSlope = fggl::math::modelMatrix( glm::vec3( 1.0f, 0.0f, 0.0f) + shapeOffset, glm::vec3( 0.0f, HALF_PI, 0.0f) ); fggl::data::make_cube( mesh, cubeMat ); fggl::data::make_slope( mesh, leftSlope ); fggl::data::make_slope( mesh, rightSlope ); } mesh.removeDups(); fggl::data::StaticMesh staticMesh{mesh, shader}; m_world->set<fggl::data::StaticMesh>(bunker, &staticMesh); } for (int i=0; i<3; ++i) { glm::vec3 location(i * 6.5f + 1.0f, 0.0f, -7.0f); placeObject(*m_world, terrain, foundation, location); } int nCubes = 3; for ( int i=0; i<nCubes; i++ ) { glm::vec3 location; location.x = i * 6.f + 1.0f; location.z = -5.0f + 1.0f; placeObject(*m_world, terrain, bunker, location); } } void GameScene::update() { process_camera(*m_world, m_inputs); } void GameScene::render(fggl::gfx::Graphics &gfx) { // render the 3D scene if ( m_world != nullptr ) { gfx.drawScene( *m_world ); } const fggl::math::vec2 panelSize { 250.0F, 250.0F }; const auto canvasY = gfx.canvasBounds().bottom - panelSize.y; m_canvas.size( {0.0F, canvasY}, panelSize); // now the 2D scene fggl::gfx::Paint paint; m_canvas.render(paint); gfx.draw2D(paint); }