Skip to content
Snippets Groups Projects
Commit 48b2f463 authored by Joseph Walton-Rivers's avatar Joseph Walton-Rivers
Browse files

split the demo gamescene into its own file

parent ab953fbc
No related branches found
No related tags found
No related merge requests found
# Executable
add_executable(FgglDemo main.cpp)
add_executable(FgglDemo
main.cpp
GameScene.cpp
)
target_link_libraries(FgglDemo fggl)
#target_include_directories(FgglDemo PUBLIC ${PROJECT_BINARY_DIR})
......
/*
* ${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);
}
\ No newline at end of file
/*
* ${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.
//
#ifndef FGGL_DEMO_GAMESCENE_H
#define FGGL_DEMO_GAMESCENE_H
#include <fggl/app.hpp>
#include <fggl/gui/gui.hpp>
#include <fggl/data/heightmap.h>
#include <fggl/data/procedural.hpp>
#include <fggl/gfx/camera.hpp>
#include <fggl/input/input.hpp>
#include <fggl/input/camera_input.h>
#include <fggl/util/service.h>
#include <fggl/util/chrono.hpp>
#include <PerlinNoise.hpp>
enum camera_type { cam_free, cam_arcball };
class GameScene : public fggl::AppState {
public:
explicit GameScene(fggl::App& app) : fggl::AppState(app), m_world(nullptr), m_sceneTime(nullptr), m_inputs(nullptr) { };
//~GameScene() override = default;
void activate() override {
auto& locator = fggl::util::ServiceLocator::instance();
m_inputs = locator.providePtr<fggl::input::Input>();
// setup the world using the global type registry
// FIXME: type registry probably doesn't need to be application-global - will make savegame/mod support complicated
m_world = std::make_unique<fggl::ecs3::World>( *m_owner.registry() );
m_sceneTime = std::make_unique<fggl::util::Timer>();
m_sceneTime->frequency( glfwGetTimerFrequency() );
m_sceneTime->setup( glfwGetTimerValue() );
setup();
}
void setup();
void update() override;
void render(fggl::gfx::Graphics& gfx) override;
private:
std::unique_ptr<fggl::ecs3::World> m_world;
std::unique_ptr<fggl::util::Timer> m_sceneTime;
std::shared_ptr<fggl::input::Input> m_inputs;
fggl::gui::Panel m_canvas;
};
#endif //FGGL_DEMO_GAMESCENE_H
#include <filesystem>
#include <iostream>
#include <memory>
#include <utility>
#include <fggl/app.hpp>
#include <fggl/scenes/menu.hpp>
#include <fggl/gfx/atlas.hpp>
#include <fggl/gfx/window.hpp>
#include <fggl/gfx/camera.hpp>
#include "fggl/gfx/ogl/renderer.hpp"
#include "fggl/gfx/ogl/compat.hpp"
#include "fggl/gfx/compat.hpp"
#include "fggl/gui/containers.hpp"
#include "fggl/gfx/ogl/compat.hpp"
#include <fggl/data/heightmap.h>
#include <fggl/data/procedural.hpp>
#include <fggl/data/storage.hpp>
#include <fggl/util/chrono.hpp>
#include <fggl/util/service.h>
#include <fggl/ecs3/types.hpp>
#include <fggl/ecs3/ecs.hpp>
#include <fggl/input/camera_input.h>
#include <fggl/debug/debug.h>
// FIXME: imgui and perlinNoise shouldn't form part of our public API >.<
#include <imgui.h>
#include <PerlinNoise.hpp>
constexpr bool showNormals = false;
#include "fggl/scenes/menu.hpp"
#include "GameScene.h"
// prototype of resource discovery
void discover(const std::filesystem::path& base) {
std::vector< std::filesystem::path > contentPacks;
for ( auto& item : std::filesystem::directory_iterator(base) ) {
for ( const auto& item : std::filesystem::directory_iterator(base) ) {
// content pack detection
if ( std::filesystem::is_directory( item ) ) {
......@@ -58,287 +41,10 @@ void discover(const std::filesystem::path& base) {
}
enum camera_type { cam_free, cam_arcball };
camera_type cam_mode = cam_free;
//TODO proper input system
using InputManager = std::shared_ptr<fggl::input::Input>;
void process_camera(fggl::ecs3::World& ecs, const InputManager& 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 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 );
}
class GameScene : public fggl::AppState {
public:
explicit GameScene(fggl::App& app) : fggl::AppState(app), m_world(nullptr), m_sceneTime(nullptr), m_inputs(nullptr) { };
//~GameScene() override = default;
void activate() override {
auto& locator = fggl::util::ServiceLocator::instance();
m_inputs = locator.providePtr<fggl::input::Input>();
// setup the world using the global type registry
// FIXME: type registry probably doesn't need to be application-global - will make savegame/mod support complicated
m_world = std::make_unique<fggl::ecs3::World>( *m_owner.registry() );
m_sceneTime = std::make_unique<fggl::util::Timer>();
m_sceneTime->frequency( glfwGetTimerFrequency() );
m_sceneTime->setup( glfwGetTimerValue() );
setup();
}
void 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 deactivate() override {
}
void update() override {
process_camera(*m_world, m_inputs);
// JWR - this doesn't really seem like it belongs in the game scene...
if ( m_inputs->keyboard.pressed(glfwGetKeyScancode(GLFW_KEY_F10)) ) {
auto dbgui = fggl::util::ServiceLocator::instance().providePtr<fggl::debug::DebugUI>();
dbgui->visible( !dbgui->visible() );
}
}
void render(fggl::gfx::Graphics& gfx) override {
// 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);
}
// entity inspector
void debugInspector() {
auto types = m_world->types();
ImGui::Begin("Entities");
auto entityItr = m_world->all();
for (auto& entity : entityItr) {
std::string label = "entity-" + std::to_string(entity);
if ( ImGui::TreeNode(label.c_str()) ){
auto entComp = m_world->getComponents(entity);
for ( auto comp : entComp ){
auto meta = types.meta(comp);
ImGui::Text("%s (%d) - %lu bytes", meta->name(), comp, meta->size());
}
ImGui::TreePop();
}
}
ImGui::End();
};
private:
std::unique_ptr<fggl::ecs3::World> m_world;
std::unique_ptr<fggl::util::Timer> m_sceneTime;
InputManager m_inputs;
fggl::gui::Panel m_canvas;
};
void gamepadDebug(bool* visible) {
auto inputs = fggl::util::ServiceLocator::instance().providePtr<fggl::input::Input>();
auto &gamepads = inputs->gamepads;
ImGui::Begin("GamePad", visible);
for (int i = 0; i < 16; i++) {
std::string title = gamepads.name(i);
bool present = gamepads.present(i);
if (ImGui::TreeNode(title.c_str())) {
ImGui::Text("present: %s", present ? "yes" : "no");
if (present) {
if (ImGui::TreeNode("buttons##2")) {
for (auto &btn: fggl::input::GamepadButtonsMicrosoft) {
ImGui::Text("%s: %i %i %i", btn.name,
gamepads.button(i, btn.id),
gamepads.buttonPressed(i, btn.id),
gamepads.buttonReleased(i, btn.id)
);
}
ImGui::TreePop();
}
if (ImGui::TreeNode("axes##2")) {
for (auto &axis: fggl::input::GamepadAxes) {
ImGui::Text("%s: %f %f", axis.name,
gamepads.axis(i, axis.id),
gamepads.axisDelta(i, axis.id)
);
}
ImGui::TreePop();
}
}
ImGui::TreePop();
ImGui::Separator();
}
}
ImGui::End();
static void test_atlas_api() {
// atlas testing
std::vector< fggl::gfx::ImageAtlas<char>::SubImage > images;
auto *atlas = fggl::gfx::ImageAtlas<char>::pack(images);
}
int main(int argc, const char* argv[]) {
......@@ -365,18 +71,15 @@ int main(int argc, const char* argv[]) {
//app.use<fggl::ecs3::ecsTypes>();
app.use<fggl::gfx::SceneUtils>();
// atlas testing
std::vector< fggl::gfx::ImageAtlas<char>::SubImage > images;
auto *atlas = fggl::gfx::ImageAtlas<char>::pack(images);
test_atlas_api();
// and now our states
// Add a basic main menu
auto *menu = app.add_state<fggl::scenes::BasicMenu>("menu");
menu->add("start", [&app]() { app.change_state("game"); });
menu->add("options", [&app]() { app.change_state("game"); });
menu->add("quit", [&app]() { app.running(false); });
// game state
// the game state itself
app.add_state<GameScene>("game");
return app.run(argc, argv);
......
#ifndef FGGL_DATA_PROCEDURAL_HPP
#define FGGL_DATA_PROCEDURAL_HPP
#include "model.hpp"
......@@ -37,3 +39,5 @@ namespace fggl::data {
return make_point(mesh, OFFSET_NONE);
}
}
#endif
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment