Skip to content

Commit

Permalink
feat(rendering): add splitscreen plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
joaomanita committed Dec 5, 2023
1 parent 2460cc5 commit f96bd25
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 117 deletions.
3 changes: 3 additions & 0 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ set(CUBOS_ENGINE_SOURCE
"src/cubos/engine/renderer/pps/copy_pass.cpp"
"src/cubos/engine/renderer/pps/manager.cpp"
"src/cubos/engine/renderer/pps/pass.cpp"
"src/cubos/engine/renderer/viewport.cpp"

"src/cubos/engine/splitscreen/plugin.cpp"
)

# Create cubos engine
Expand Down
1 change: 1 addition & 0 deletions engine/include/cubos/engine/renderer/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace cubos::engine
/// ## Components
/// - @ref RenderableGrid - a grid to be rendered.
/// - @ref Camera - holds camera information.
/// - @ref Viewport - holds viewport information.
/// - @ref SpotLight - emits a spot light.
/// - @ref DirectionalLight - emits a directional light.
/// - @ref PointLight - emits a point light.
Expand Down
25 changes: 25 additions & 0 deletions engine/include/cubos/engine/renderer/viewport.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// @file
/// @brief Component @ref cubos::engine::Viewport.
/// @ingroup renderer-plugin

#pragma once

#include <glm/vec2.hpp>

#include <cubos/core/reflection/reflect.hpp>

namespace cubos::engine
{
/// @brief Component which defines parameters of a viewport, the actual screen space
/// that will be used by the camera it is attached to. Useful for having multiple camera views
/// shown on screen.
/// @note Should be used with @ref LocalToWorld.
/// @ingroup renderer-plugin
struct Viewport
{
CUBOS_REFLECT;

glm::ivec2 position{0.0F, 0.0F}; //< Top left position of the viewport in pixels
glm::ivec2 size{0.0F, 0.0F}; //< Size of the viewport in pixels
};
} // namespace cubos::engine
25 changes: 25 additions & 0 deletions engine/include/cubos/engine/splitscreen/plugin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// @dir
/// @brief @ref splitscreen-plugin plugin directory.

/// @file
/// @brief Plugin entry point.
/// @ingroup splitscreen-plugin

#pragma once

#include <cubos/engine/cubos.hpp>

namespace cubos::engine
{
/// @defgroup splitscreen-plugin Splitscreen
/// @ingroup engine
/// @brief Adds viewport to all active cameras to achieve a splitscreen layout.
///
/// ## Dependencies
/// - @ref renderer-plugin

/// @brief Plugin entry function.
/// @param cubos @b CUBOS. main class
/// @ingroup splitscreen-plugin
void splitscreenPlugin(Cubos& cubos);
} // namespace cubos::engine
18 changes: 15 additions & 3 deletions engine/samples/renderer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <cubos/engine/renderer/plugin.hpp>
#include <cubos/engine/renderer/point_light.hpp>
#include <cubos/engine/settings/settings.hpp>
#include <cubos/engine/splitscreen/plugin.hpp>
#include <cubos/engine/transform/plugin.hpp>

using namespace cubos::engine;
Expand Down Expand Up @@ -66,9 +67,19 @@ static void spawnCamerasSystem(Commands commands, Write<ActiveCameras> camera)
.add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})})
.entity();

// Add two other viewports using the same camera, which splits the screen in three.
camera->entities[1] = camera->entities[0];
camera->entities[2] = camera->entities[0];
camera->entities[1] =
commands.create()
.add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F})
.add(Position{{-3.0, 1.0F, -3.0F}})
.add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})})
.entity();

camera->entities[2] =
commands.create()
.add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F})
.add(Position{{-3.0, 1.0F, -3.0F}})
.add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})})
.entity();
}
/// [Spawn the cameras]

Expand All @@ -77,6 +88,7 @@ int main()
Cubos cubos{};

/// [Adding the plugin]
cubos.addPlugin(splitscreenPlugin);
cubos.addPlugin(rendererPlugin);
/// [Adding the plugin]

Expand Down
152 changes: 76 additions & 76 deletions engine/samples/voxels/main.cpp
Original file line number Diff line number Diff line change
@@ -1,77 +1,77 @@
#include <cubos/engine/renderer/directional_light.hpp>
#include <cubos/engine/renderer/plugin.hpp>
#include <cubos/engine/settings/settings.hpp>
#include <cubos/engine/transform/plugin.hpp>
#include <cubos/engine/voxels/plugin.hpp>

using namespace cubos::engine;

/// [Get handles to assets]
static const Asset<VoxelGrid> CarAsset = AnyAsset("059c16e7-a439-44c7-9bdc-6e069dba0c75");
static const Asset<VoxelPalette> PaletteAsset = AnyAsset("1aa5e234-28cb-4386-99b4-39386b0fc215");
/// [Get handles to assets]

static void settingsSystem(Write<Settings> settings)
{
settings->setString("assets.io.path", SAMPLE_ASSETS_FOLDER);
}

/// [Load and set palette]
static void setPaletteSystem(Read<Assets> assets, Write<Renderer> renderer)
{
// Read the palette's data and pass it to the renderer.
auto palette = assets->read(PaletteAsset);
(*renderer)->setPalette(*palette);
}
/// [Load and set palette]

static void spawnCameraSystem(Commands cmds, Write<ActiveCameras> activeCameras)
{
// Spawn the camera entity.
activeCameras->entities[0] =
cmds.create()
.add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 1000.0F})
.add(Position{{50.0F, 50.0F, 50.0F}})
.add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{-1.0F, -1.0F, -1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})})
.entity();
}

static void spawnLightSystem(Commands cmds)
{
// Spawn the sun.
cmds.create()
.add(DirectionalLight{glm::vec3(1.0F), 1.0F})
.add(Rotation{glm::quat(glm::vec3(glm::radians(45.0F), glm::radians(45.0F), 0))});
}

/// [Spawn car system]
static void spawnCarSystem(Commands cmds, Read<Assets> assets)
{
// Calculate the necessary offset to center the model on (0, 0, 0).
auto car = assets->read(CarAsset);
glm::vec3 offset = glm::vec3(car->size().x, 0.0F, car->size().z) / -2.0F;

// Create the car entity
cmds.create().add(RenderableGrid{CarAsset, offset}).add(LocalToWorld{});
}
/// [Spawn car system]

int main(int argc, char** argv)
{
Cubos cubos{argc, argv};

cubos.addPlugin(rendererPlugin);
/// [Adding the plugin]
cubos.addPlugin(voxelsPlugin);
/// [Adding the plugin]

cubos.startupSystem(settingsSystem).tagged("cubos.settings");
cubos.startupSystem(spawnCameraSystem);
cubos.startupSystem(spawnLightSystem);
/// [Adding systems]
cubos.startupSystem(setPaletteSystem).after("cubos.renderer.init");
cubos.startupSystem(spawnCarSystem).tagged("cubos.assets");
/// [Adding systems]

cubos.run();
#include <cubos/engine/renderer/directional_light.hpp>
#include <cubos/engine/renderer/plugin.hpp>
#include <cubos/engine/settings/settings.hpp>
#include <cubos/engine/transform/plugin.hpp>
#include <cubos/engine/voxels/plugin.hpp>

using namespace cubos::engine;

/// [Get handles to assets]
static const Asset<VoxelGrid> CarAsset = AnyAsset("059c16e7-a439-44c7-9bdc-6e069dba0c75");
static const Asset<VoxelPalette> PaletteAsset = AnyAsset("1aa5e234-28cb-4386-99b4-39386b0fc215");
/// [Get handles to assets]

static void settingsSystem(Write<Settings> settings)
{
settings->setString("assets.io.path", SAMPLE_ASSETS_FOLDER);
}

/// [Load and set palette]
static void setPaletteSystem(Read<Assets> assets, Write<Renderer> renderer)
{
// Read the palette's data and pass it to the renderer.
auto palette = assets->read(PaletteAsset);
(*renderer)->setPalette(*palette);
}
/// [Load and set palette]

static void spawnCameraSystem(Commands cmds, Write<ActiveCameras> activeCameras)
{
// Spawn the camera entity.
activeCameras->entities[0] =
cmds.create()
.add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 1000.0F})
.add(Position{{50.0F, 50.0F, 50.0F}})
.add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{-1.0F, -1.0F, -1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})})
.entity();
}

static void spawnLightSystem(Commands cmds)
{
// Spawn the sun.
cmds.create()
.add(DirectionalLight{glm::vec3(1.0F), 1.0F})
.add(Rotation{glm::quat(glm::vec3(glm::radians(45.0F), glm::radians(45.0F), 0))});
}

/// [Spawn car system]
static void spawnCarSystem(Commands cmds, Read<Assets> assets)
{
// Calculate the necessary offset to center the model on (0, 0, 0).
auto car = assets->read(CarAsset);
glm::vec3 offset = glm::vec3(car->size().x, 0.0F, car->size().z) / -2.0F;

// Create the car entity
cmds.create().add(RenderableGrid{CarAsset, offset}).add(LocalToWorld{});
}
/// [Spawn car system]

int main(int argc, char** argv)
{
Cubos cubos{argc, argv};

cubos.addPlugin(rendererPlugin);
/// [Adding the plugin]
cubos.addPlugin(voxelsPlugin);
/// [Adding the plugin]

cubos.startupSystem(settingsSystem).tagged("cubos.settings");
cubos.startupSystem(spawnCameraSystem);
cubos.startupSystem(spawnLightSystem);
/// [Adding systems]
cubos.startupSystem(setPaletteSystem).after("cubos.renderer.init");
cubos.startupSystem(spawnCarSystem).tagged("cubos.assets");
/// [Adding systems]

cubos.run();
}
52 changes: 14 additions & 38 deletions engine/src/cubos/engine/renderer/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <cubos/engine/renderer/point_light.hpp>
#include <cubos/engine/renderer/pps/bloom.hpp>
#include <cubos/engine/renderer/spot_light.hpp>
#include <cubos/engine/renderer/viewport.hpp>
#include <cubos/engine/settings/plugin.hpp>
#include <cubos/engine/transform/plugin.hpp>
#include <cubos/engine/window/plugin.hpp>
Expand Down Expand Up @@ -113,42 +114,8 @@ static void checkPaletteUpdateSystem(Write<Assets> assets, Write<Renderer> rende
}
}

/// @brief Splits the viewport recursively for the given cameras.
/// @param position Viewport position.
/// @param size Viewport size.
/// @param count How many cameras need to be fitted in to the given viewport.
/// @param viewport Output array where the viewports will be set.
static void splitViewport(glm::ivec2 position, glm::ivec2 size, int count, BaseRenderer::Viewport* viewports)
{
if (count == 1)
{
viewports[0].position = position;
viewports[0].size = size;
}
else if (count >= 2)
{
glm::ivec2 splitSize;
glm::ivec2 splitOffset;

// Split along the largest axis.
if (size.x > size.y)
{
splitSize = {size.x / 2, size.y};
splitOffset = {size.x / 2, 0};
}
else
{
splitSize = {size.x, size.y / 2};
splitOffset = {0, size.y / 2};
}

splitViewport(position, splitSize, count / 2, viewports);
splitViewport(position + splitOffset, splitSize, (count + 1) / 2, &viewports[count / 2]);
}
}

static void draw(Write<Renderer> renderer, Read<ActiveCameras> activeCameras, Write<RendererFrame> frame,
Query<Read<LocalToWorld>, Read<Camera>> query)
Query<Read<LocalToWorld>, Read<Camera>, OptRead<Viewport>> query)
{
Camera cameras[4]{};
glm::mat4 views[4]{};
Expand All @@ -165,17 +132,25 @@ static void draw(Write<Renderer> renderer, Read<ActiveCameras> activeCameras, Wr

if (auto components = query[activeCameras->entities[i]])
{
auto [localToWorld, camera] = *components;
auto [localToWorld, camera, viewport] = *components;
cameras[cameraCount].fovY = camera->fovY;
cameras[cameraCount].zNear = camera->zNear;
cameras[cameraCount].zFar = camera->zFar;
if (viewport)
{
viewports[i].position = viewport->position;
viewports[i].size = viewport->size;
}
else
{
viewports[i].position = {0, 0};
viewports[i].size = (*renderer)->size();
}
views[cameraCount] = glm::inverse(localToWorld->mat);
cameraCount += 1;
}
}

splitViewport({0, 0}, (*renderer)->size(), cameraCount, viewports);

if (cameraCount == 0)
{
CUBOS_WARN("No active camera set - renderer skipping frame");
Expand Down Expand Up @@ -206,6 +181,7 @@ void cubos::engine::rendererPlugin(Cubos& cubos)
cubos.addComponent<SpotLight>();
cubos.addComponent<DirectionalLight>();
cubos.addComponent<PointLight>();
cubos.addComponent<Viewport>();

cubos.startupTag("cubos.renderer.init").after("cubos.window.init");
cubos.tag("cubos.renderer.frame").after("cubos.transform.update");
Expand Down
12 changes: 12 additions & 0 deletions engine/src/cubos/engine/renderer/viewport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <cubos/core/ecs/component/reflection.hpp>
#include <cubos/core/reflection/external/glm.hpp>

#include <cubos/engine/renderer/viewport.hpp>

CUBOS_REFLECT_IMPL(cubos::engine::Viewport)
{
return core::ecs::ComponentTypeBuilder<Viewport>("cubos::engine::Viewport")
.withField("position", &Viewport::position)
.withField("size", &Viewport::size)
.build();
}
Loading

0 comments on commit f96bd25

Please sign in to comment.