Skybox and sun
This commit is contained in:
@@ -16,6 +16,8 @@ set(EDITSCENE_SOURCES
|
||||
systems/SceneSerializer.cpp
|
||||
systems/PhysicsSystem.cpp
|
||||
systems/BuoyancySystem.cpp
|
||||
systems/EditorSunSystem.cpp
|
||||
systems/EditorSkyboxSystem.cpp
|
||||
systems/LightSystem.cpp
|
||||
systems/CameraSystem.cpp
|
||||
systems/LodSystem.cpp
|
||||
@@ -84,6 +86,8 @@ set(EDITSCENE_SOURCES
|
||||
components/BuoyancyInfoModule.cpp
|
||||
components/WaterPhysicsModule.cpp
|
||||
components/WaterPlaneModule.cpp
|
||||
components/SunModule.cpp
|
||||
components/SkyboxModule.cpp
|
||||
camera/EditorCamera.cpp
|
||||
gizmo/Gizmo.cpp
|
||||
physics/physics.cpp
|
||||
@@ -100,6 +104,8 @@ set(EDITSCENE_HEADERS
|
||||
components/BuoyancyInfo.hpp
|
||||
components/WaterPhysics.hpp
|
||||
components/WaterPlane.hpp
|
||||
components/Sun.hpp
|
||||
components/Skybox.hpp
|
||||
components/Light.hpp
|
||||
components/Camera.hpp
|
||||
components/Lod.hpp
|
||||
@@ -132,6 +138,8 @@ set(EDITSCENE_HEADERS
|
||||
systems/SceneSerializer.hpp
|
||||
systems/PhysicsSystem.hpp
|
||||
systems/BuoyancySystem.hpp
|
||||
systems/EditorSunSystem.hpp
|
||||
systems/EditorSkyboxSystem.hpp
|
||||
systems/LightSystem.hpp
|
||||
systems/CameraSystem.hpp
|
||||
systems/LodSystem.hpp
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "systems/EditorUISystem.hpp"
|
||||
#include "systems/PhysicsSystem.hpp"
|
||||
#include "systems/BuoyancySystem.hpp"
|
||||
#include "systems/EditorSunSystem.hpp"
|
||||
#include "systems/EditorSkyboxSystem.hpp"
|
||||
#include "systems/LightSystem.hpp"
|
||||
#include "systems/CameraSystem.hpp"
|
||||
#include "systems/LodSystem.hpp"
|
||||
@@ -30,6 +32,8 @@
|
||||
#include "components/InWater.hpp"
|
||||
#include "components/WaterPhysics.hpp"
|
||||
#include "components/WaterPlane.hpp"
|
||||
#include "components/Sun.hpp"
|
||||
#include "components/Skybox.hpp"
|
||||
#include "components/Light.hpp"
|
||||
#include "components/Camera.hpp"
|
||||
#include "components/Lod.hpp"
|
||||
@@ -231,6 +235,10 @@ void EditorApp::setup()
|
||||
m_world, m_physicsSystem->getPhysicsWrapper());
|
||||
m_buoyancySystem->initialize();
|
||||
|
||||
m_sunSystem = std::make_unique<EditorSunSystem>(m_world, m_sceneMgr);
|
||||
m_skyboxSystem =
|
||||
std::make_unique<EditorSkyboxSystem>(m_world, m_sceneMgr);
|
||||
|
||||
// Apply debug setting if it was set before system creation
|
||||
if (m_debugBuoyancy) {
|
||||
m_buoyancySystem->setDebugEnabled(true);
|
||||
@@ -500,6 +508,10 @@ void EditorApp::setupECS()
|
||||
m_world.component<PlayerControllerComponent>();
|
||||
m_world.component<InWater>();
|
||||
|
||||
// Register environment components
|
||||
m_world.component<SunComponent>();
|
||||
m_world.component<SkyboxComponent>();
|
||||
|
||||
// Register CellGrid/Town components
|
||||
CellGridModule::registerComponents(m_world);
|
||||
}
|
||||
@@ -682,6 +694,17 @@ bool EditorApp::frameRenderingQueued(const Ogre::FrameEvent &evt)
|
||||
}
|
||||
|
||||
/* --- Rendering support systems --- */
|
||||
if (m_sunSystem) {
|
||||
m_sunSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
if (m_skyboxSystem) {
|
||||
Ogre::Camera *cam = nullptr;
|
||||
if (m_sceneMgr->hasCamera("PlayerCamera"))
|
||||
cam = m_sceneMgr->getCamera("PlayerCamera");
|
||||
if (!cam && m_camera)
|
||||
cam = m_camera->getCamera();
|
||||
m_skyboxSystem->update(cam);
|
||||
}
|
||||
if (m_lightSystem) {
|
||||
m_lightSystem->update();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class RoomLayoutSystem;
|
||||
class StartupMenuSystem;
|
||||
class PlayerControllerSystem;
|
||||
class BuoyancySystem;
|
||||
class EditorSunSystem;
|
||||
class EditorSkyboxSystem;
|
||||
class EditorApp;
|
||||
|
||||
/**
|
||||
@@ -196,6 +198,8 @@ private:
|
||||
std::unique_ptr<ImGuiRenderListener> m_imguiListener;
|
||||
std::unique_ptr<EditorPhysicsSystem> m_physicsSystem;
|
||||
std::unique_ptr<BuoyancySystem> m_buoyancySystem;
|
||||
std::unique_ptr<EditorSunSystem> m_sunSystem;
|
||||
std::unique_ptr<EditorSkyboxSystem> m_skyboxSystem;
|
||||
std::unique_ptr<EditorLightSystem> m_lightSystem;
|
||||
std::unique_ptr<EditorCameraSystem> m_cameraSystem;
|
||||
std::unique_ptr<EditorLodSystem> m_lodSystem;
|
||||
|
||||
58
src/features/editScene/components/Skybox.hpp
Normal file
58
src/features/editScene/components/Skybox.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef EDITSCENE_SKYBOX_HPP
|
||||
#define EDITSCENE_SKYBOX_HPP
|
||||
#pragma once
|
||||
|
||||
#include <Ogre.h>
|
||||
|
||||
/**
|
||||
* Skybox component - procedural sky rendered as a large cube
|
||||
* with a fragment shader that creates dynamic day/night/sunset
|
||||
* sky gradients.
|
||||
*
|
||||
* Designed to work alongside SunComponent on the same entity.
|
||||
* If no SunComponent is present, uses default noon lighting.
|
||||
*/
|
||||
struct SkyboxComponent {
|
||||
// Enable/disable skybox
|
||||
bool enabled = true;
|
||||
|
||||
// Size of the skybox cube (default 500)
|
||||
float size = 500.0f;
|
||||
|
||||
// Day sky colors
|
||||
Ogre::ColourValue dayTopColor = Ogre::ColourValue(0.2f, 0.5f, 1.0f);
|
||||
Ogre::ColourValue dayBottomColor = Ogre::ColourValue(0.6f, 0.8f, 1.0f);
|
||||
|
||||
// Night sky colors
|
||||
Ogre::ColourValue nightTopColor = Ogre::ColourValue(0.0f, 0.0f, 0.05f);
|
||||
Ogre::ColourValue nightBottomColor = Ogre::ColourValue(0.05f, 0.05f, 0.15f);
|
||||
|
||||
// Horizon glow colors
|
||||
Ogre::ColourValue sunriseColor = Ogre::ColourValue(1.0f, 0.5f, 0.2f);
|
||||
Ogre::ColourValue sunsetColor = Ogre::ColourValue(1.0f, 0.3f, 0.1f);
|
||||
|
||||
// Angular size of sun/moon discs in the sky shader (0.01 - 0.2)
|
||||
float sunSize = 0.05f;
|
||||
float moonSize = 0.03f;
|
||||
|
||||
// Enable simple stars at night
|
||||
bool starsEnabled = true;
|
||||
|
||||
// Cloud coverage (0.0 = clear, 1.0 = overcast)
|
||||
// Not yet implemented in shader but reserved for future
|
||||
float cloudiness = 0.0f;
|
||||
|
||||
// Runtime objects (managed by EditorSkyboxSystem)
|
||||
Ogre::SceneNode *sceneNode = nullptr;
|
||||
Ogre::ManualObject *manualObject = nullptr;
|
||||
|
||||
// Dirty flag - triggers rebuild
|
||||
bool dirty = true;
|
||||
|
||||
void markDirty()
|
||||
{
|
||||
dirty = true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_SKYBOX_HPP
|
||||
24
src/features/editScene/components/SkyboxModule.cpp
Normal file
24
src/features/editScene/components/SkyboxModule.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "Skybox.hpp"
|
||||
#include "Transform.hpp"
|
||||
#include "EditorMarker.hpp"
|
||||
#include "EntityName.hpp"
|
||||
#include "../ui/ComponentRegistration.hpp"
|
||||
#include "../ui/SkyboxEditor.hpp"
|
||||
|
||||
REGISTER_COMPONENT_GROUP("Skybox", "Environment", SkyboxComponent, SkyboxEditor)
|
||||
{
|
||||
registry.registerComponent<SkyboxComponent>(
|
||||
"Skybox", "Environment", std::make_unique<SkyboxEditor>(),
|
||||
// Adder
|
||||
[](flecs::entity e) {
|
||||
if (!e.has<SkyboxComponent>()) {
|
||||
e.set<SkyboxComponent>({});
|
||||
}
|
||||
},
|
||||
// Remover
|
||||
[](flecs::entity e) {
|
||||
if (e.has<SkyboxComponent>()) {
|
||||
e.remove<SkyboxComponent>();
|
||||
}
|
||||
});
|
||||
}
|
||||
70
src/features/editScene/components/Sun.hpp
Normal file
70
src/features/editScene/components/Sun.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef EDITSCENE_SUN_HPP
|
||||
#define EDITSCENE_SUN_HPP
|
||||
#pragma once
|
||||
|
||||
#include <Ogre.h>
|
||||
|
||||
/**
|
||||
* Sun component - manages a directional light that rotates
|
||||
* based on in-game time, with sun/moon visualization.
|
||||
*
|
||||
* Designed to work alongside SkyboxComponent on the same entity.
|
||||
*/
|
||||
struct SunComponent {
|
||||
// Enable/disable sun system
|
||||
bool enabled = true;
|
||||
|
||||
// Time of day in hours (0.0 - 24.0)
|
||||
float timeOfDay = 12.0f;
|
||||
|
||||
// Game time speed: game-hours per real-second
|
||||
// 0.01 = 1 game hour per 100 real seconds (slow)
|
||||
// 0.1 = 1 game hour per 10 real seconds
|
||||
// 1.0 = 1 game hour per 1 real second (fast)
|
||||
float timeSpeed = 0.05f;
|
||||
|
||||
// Sun color when at zenith (day)
|
||||
Ogre::ColourValue sunColor = Ogre::ColourValue(1.0f, 0.95f, 0.8f);
|
||||
|
||||
// Moon color when sun is below horizon (night)
|
||||
Ogre::ColourValue moonColor = Ogre::ColourValue(0.3f, 0.3f, 0.5f);
|
||||
|
||||
// Ambient light colors
|
||||
Ogre::ColourValue ambientDay = Ogre::ColourValue(0.3f, 0.3f, 0.3f);
|
||||
Ogre::ColourValue ambientNight = Ogre::ColourValue(0.05f, 0.05f, 0.15f);
|
||||
Ogre::ColourValue ambientSunrise = Ogre::ColourValue(0.3f, 0.2f, 0.15f);
|
||||
Ogre::ColourValue ambientSunset = Ogre::ColourValue(0.25f, 0.15f, 0.1f);
|
||||
|
||||
// Sun / moon visualization spheres
|
||||
bool showSunSphere = true;
|
||||
bool showMoonSphere = true;
|
||||
float sunSphereSize = 5.0f;
|
||||
float moonSphereSize = 3.0f;
|
||||
|
||||
// Orbit tilt (degrees) - tilts the sun path north/south
|
||||
float orbitTilt = 15.0f;
|
||||
|
||||
// Light intensity multiplier
|
||||
float intensity = 1.0f;
|
||||
|
||||
// Cast shadows
|
||||
bool castShadows = true;
|
||||
|
||||
// Runtime objects (managed by EditorSunSystem)
|
||||
Ogre::Light *light = nullptr;
|
||||
Ogre::SceneNode *lightNode = nullptr;
|
||||
Ogre::SceneNode *sunSphereNode = nullptr;
|
||||
Ogre::SceneNode *moonSphereNode = nullptr;
|
||||
Ogre::ManualObject *sunSphere = nullptr;
|
||||
Ogre::ManualObject *moonSphere = nullptr;
|
||||
|
||||
// Dirty flag - triggers rebuild
|
||||
bool dirty = true;
|
||||
|
||||
void markDirty()
|
||||
{
|
||||
dirty = true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_SUN_HPP
|
||||
24
src/features/editScene/components/SunModule.cpp
Normal file
24
src/features/editScene/components/SunModule.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "Sun.hpp"
|
||||
#include "Transform.hpp"
|
||||
#include "EditorMarker.hpp"
|
||||
#include "EntityName.hpp"
|
||||
#include "../ui/ComponentRegistration.hpp"
|
||||
#include "../ui/SunEditor.hpp"
|
||||
|
||||
REGISTER_COMPONENT_GROUP("Sun", "Environment", SunComponent, SunEditor)
|
||||
{
|
||||
registry.registerComponent<SunComponent>(
|
||||
"Sun", "Environment", std::make_unique<SunEditor>(),
|
||||
// Adder
|
||||
[](flecs::entity e) {
|
||||
if (!e.has<SunComponent>()) {
|
||||
e.set<SunComponent>({});
|
||||
}
|
||||
},
|
||||
// Remover
|
||||
[](flecs::entity e) {
|
||||
if (e.has<SunComponent>()) {
|
||||
e.remove<SunComponent>();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1574,11 +1574,10 @@ public:
|
||||
MyCollector collector(&physics_system, surface_point,
|
||||
JPH::Vec3::sAxisY(), dt);
|
||||
// Apply buoyancy to all bodies that intersect with the water
|
||||
// Create a symmetrical box around the surface point:
|
||||
// 1000 units in X/Z, 1.0 unit above and below in Y
|
||||
// This detects bodies slightly above and well below water surface
|
||||
JPH::AABox water_box(-JPH::Vec3(1000, 1.0f, 1000),
|
||||
JPH::Vec3(1000, 1000, 1000));
|
||||
// Detects bodies up to 0.1 units above the surface point
|
||||
// and up to 1000 units below (deep underwater)
|
||||
JPH::AABox water_box(-JPH::Vec3(1000, 1000, 1000),
|
||||
JPH::Vec3(1000, 0.1f, 1000));
|
||||
water_box.Translate(JPH::Vec3(surface_point));
|
||||
physics_system.GetBroadPhaseQuery().CollideAABox(
|
||||
water_box, collector,
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
OGRE_NATIVE_GLSL_VERSION_DIRECTIVE
|
||||
#include <OgreUnifiedShader.h>
|
||||
|
||||
OGRE_UNIFORMS(
|
||||
uniform vec3 uDayTop;
|
||||
uniform vec3 uDayBottom;
|
||||
uniform vec3 uNightTop;
|
||||
uniform vec3 uNightBottom;
|
||||
uniform vec3 uSunriseColor;
|
||||
uniform vec3 uSunsetColor;
|
||||
uniform vec3 uSunDir;
|
||||
uniform float uSunElev;
|
||||
uniform float uSunSize;
|
||||
uniform float uMoonSize;
|
||||
uniform float uStarsEnabled;
|
||||
)
|
||||
|
||||
IN(vec3 vWorldPos, TEXCOORD0)
|
||||
|
||||
// Simple pseudo-random function for stars
|
||||
float hash(vec2 p)
|
||||
{
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
|
||||
}
|
||||
|
||||
MAIN_DECLARATION
|
||||
{
|
||||
vec3 dir = normalize(vWorldPos);
|
||||
float y = dir.y;
|
||||
|
||||
// Sky gradient factor based on elevation
|
||||
float gradT = clamp(y * 0.5 + 0.5, 0.0, 1.0);
|
||||
|
||||
// Day / night interpolation based on sun elevation
|
||||
// uSunElev: -1.0 = midnight, 0.0 = horizon, 1.0 = noon
|
||||
float dayFactor = smoothstep(-0.15, 0.25, uSunElev);
|
||||
float nightFactor = 1.0 - smoothstep(-0.25, 0.15, uSunElev);
|
||||
|
||||
vec3 daySky = mix(uDayBottom, uDayTop, gradT);
|
||||
vec3 nightSky = mix(uNightBottom, uNightTop, gradT);
|
||||
|
||||
vec3 skyColor = mix(nightSky, daySky, dayFactor);
|
||||
|
||||
// Horizon glow for sunrise / sunset
|
||||
float horizon = 1.0 - abs(y);
|
||||
horizon = horizon * horizon;
|
||||
|
||||
// Sunrise when sun is rising (uSunElev near 0, morning)
|
||||
// Sunset when sun is setting (uSunElev near 0, evening)
|
||||
// We approximate by checking if sun is near horizon
|
||||
float nearHorizon = 1.0 - smoothstep(0.0, 0.3, abs(uSunElev));
|
||||
vec3 glowColor = mix(uSunriseColor, uSunsetColor,
|
||||
smoothstep(-0.1, 0.1, uSunDir.x));
|
||||
skyColor += glowColor * nearHorizon * horizon * 0.8;
|
||||
|
||||
// Sun disc
|
||||
vec3 sunPos = -uSunDir;
|
||||
float sunDot = max(0.0, dot(dir, sunPos));
|
||||
float sunDisc = pow(sunDot, 1.0 / uSunSize);
|
||||
skyColor += vec3(1.0, 0.95, 0.8) * sunDisc * dayFactor;
|
||||
|
||||
// Moon disc (opposite to sun)
|
||||
vec3 moonPos = uSunDir;
|
||||
float moonDot = max(0.0, dot(dir, moonPos));
|
||||
float moonDisc = pow(moonDot, 1.0 / uMoonSize);
|
||||
skyColor += vec3(0.85, 0.85, 0.95) * moonDisc * nightFactor;
|
||||
|
||||
// Simple stars
|
||||
if (uStarsEnabled > 0.5) {
|
||||
float starNoise = hash(floor(dir.xz * 80.0));
|
||||
float star = smoothstep(0.995, 1.0, starNoise);
|
||||
// Only show stars at night and above horizon
|
||||
float starMask = nightFactor * smoothstep(-0.2, 0.1, y);
|
||||
skyColor += vec3(1.0, 1.0, 1.0) * star * starMask * 0.8;
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(skyColor, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
material Skybox/Dynamic
|
||||
{
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
lighting off
|
||||
depth_write off
|
||||
depth_check off
|
||||
cull_hardware none
|
||||
|
||||
vertex_program_ref SkyboxVP
|
||||
{
|
||||
}
|
||||
|
||||
fragment_program_ref SkyboxFP
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
vertex_program SkyboxVP glsl glsles glslang hlsl
|
||||
{
|
||||
source skybox.vert
|
||||
default_params
|
||||
{
|
||||
param_named_auto worldViewProj worldviewproj_matrix
|
||||
}
|
||||
}
|
||||
|
||||
fragment_program SkyboxFP glsl glsles glslang hlsl
|
||||
{
|
||||
source skybox.frag
|
||||
default_params
|
||||
{
|
||||
param_named uDayTop float3 0.2 0.5 1.0
|
||||
param_named uDayBottom float3 0.6 0.8 1.0
|
||||
param_named uNightTop float3 0.0 0.0 0.05
|
||||
param_named uNightBottom float3 0.05 0.05 0.15
|
||||
param_named uSunriseColor float3 1.0 0.5 0.2
|
||||
param_named uSunsetColor float3 1.0 0.3 0.1
|
||||
param_named uSunDir float3 0.0 -1.0 0.0
|
||||
param_named uSunElev float 1.0
|
||||
param_named uSunSize float 0.05
|
||||
param_named uMoonSize float 0.03
|
||||
param_named uStarsEnabled float 1.0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
OGRE_NATIVE_GLSL_VERSION_DIRECTIVE
|
||||
#include <OgreUnifiedShader.h>
|
||||
|
||||
OGRE_UNIFORMS(
|
||||
uniform mat4 worldViewProj;
|
||||
)
|
||||
|
||||
OUT(vec3 vWorldPos, TEXCOORD0)
|
||||
|
||||
MAIN_PARAMETERS
|
||||
IN(vec4 vertex, POSITION)
|
||||
MAIN_DECLARATION
|
||||
{
|
||||
gl_Position = worldViewProj * vertex;
|
||||
vWorldPos = vertex.xyz;
|
||||
}
|
||||
@@ -110,11 +110,16 @@ void BuoyancySystem::update(float deltaTime)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark entity as in water
|
||||
if (!entity.has<InWater>()) {
|
||||
entity.add<InWater>();
|
||||
// Only mark as InWater if body center is below surface
|
||||
// (for swim animation logic; buoyancy still applied to
|
||||
// bodies partially submerged via broadphase)
|
||||
Ogre::Vector3 bodyPos = m_physics->getPosition(bodyID);
|
||||
if (bodyPos.y < waterPhysics->waterSurfaceY) {
|
||||
if (!entity.has<InWater>()) {
|
||||
entity.add<InWater>();
|
||||
}
|
||||
m_entitiesInWater.insert(entity.id());
|
||||
}
|
||||
m_entitiesInWater.insert(entity.id());
|
||||
|
||||
// Debug logging for buoyancy application
|
||||
if (m_debugEnabled) {
|
||||
|
||||
228
src/features/editScene/systems/EditorSkyboxSystem.cpp
Normal file
228
src/features/editScene/systems/EditorSkyboxSystem.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
#include "EditorSkyboxSystem.hpp"
|
||||
#include "../components/Skybox.hpp"
|
||||
#include "../components/Sun.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
#include <OgreManualObject.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <OgrePass.h>
|
||||
#include <OgreGpuProgramParams.h>
|
||||
|
||||
EditorSkyboxSystem::EditorSkyboxSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr)
|
||||
: m_world(world)
|
||||
, m_sceneMgr(sceneMgr)
|
||||
, m_query(world.query<SkyboxComponent>())
|
||||
{
|
||||
}
|
||||
|
||||
EditorSkyboxSystem::~EditorSkyboxSystem() = default;
|
||||
|
||||
void EditorSkyboxSystem::update(Ogre::Camera *camera)
|
||||
{
|
||||
m_query.each([&](flecs::entity entity, SkyboxComponent &skybox) {
|
||||
if (!skybox.enabled) {
|
||||
if (skybox.sceneNode) {
|
||||
skybox.sceneNode->setVisible(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (skybox.dirty || !skybox.manualObject) {
|
||||
rebuildSkybox(entity, skybox);
|
||||
skybox.dirty = false;
|
||||
}
|
||||
|
||||
if (!skybox.sceneNode || !camera)
|
||||
return;
|
||||
|
||||
// Follow camera position
|
||||
skybox.sceneNode->setPosition(camera->getDerivedPosition());
|
||||
|
||||
// Get sun data from same entity or use defaults
|
||||
float sunElev = 1.0f;
|
||||
Ogre::Vector3 sunDir(0.0f, -1.0f, 0.0f);
|
||||
|
||||
if (entity.has<SunComponent>()) {
|
||||
const SunComponent &sun = entity.get<SunComponent>();
|
||||
{
|
||||
float sunAngle = (sun.timeOfDay - 6.0f) / 24.0f * 2.0f *
|
||||
M_PI;
|
||||
sunElev = std::sin(sunAngle);
|
||||
float tiltRad = sun.orbitTilt * M_PI / 180.0f;
|
||||
sunDir.x = -std::cos(sunAngle);
|
||||
sunDir.y = -sunElev;
|
||||
sunDir.z = -std::sin(sunAngle) * std::sin(tiltRad);
|
||||
sunDir.normalise();
|
||||
}
|
||||
}
|
||||
|
||||
updateShaderParams(skybox, sunElev, sunDir);
|
||||
});
|
||||
}
|
||||
|
||||
void EditorSkyboxSystem::rebuildSkybox(flecs::entity entity,
|
||||
SkyboxComponent &skybox)
|
||||
{
|
||||
cleanupSkybox(skybox);
|
||||
|
||||
Ogre::String baseName = "Skybox_" +
|
||||
Ogre::StringConverter::toString(entity.id());
|
||||
|
||||
// Create scene node at origin (will follow camera)
|
||||
skybox.sceneNode =
|
||||
m_sceneMgr->getRootSceneNode()->createChildSceneNode(
|
||||
baseName + "Node");
|
||||
|
||||
// Create manual object cube
|
||||
skybox.manualObject =
|
||||
m_sceneMgr->createManualObject(baseName + "Mesh");
|
||||
createCube(skybox.manualObject, skybox.size);
|
||||
|
||||
// Get material instance
|
||||
Ogre::MaterialPtr material =
|
||||
Ogre::MaterialManager::getSingleton()
|
||||
.getByName("Skybox/Dynamic",
|
||||
Ogre::ResourceGroupManager::
|
||||
DEFAULT_RESOURCE_GROUP_NAME);
|
||||
|
||||
if (material) {
|
||||
skybox.manualObject->setMaterialName(0, "Skybox/Dynamic");
|
||||
}
|
||||
|
||||
skybox.manualObject->setRenderQueueGroup(
|
||||
Ogre::RENDER_QUEUE_SKIES_EARLY);
|
||||
|
||||
skybox.sceneNode->attachObject(skybox.manualObject);
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"SkyboxSystem: Created skybox for entity " +
|
||||
Ogre::StringConverter::toString(entity.id()) +
|
||||
", size=" + Ogre::StringConverter::toString(skybox.size));
|
||||
}
|
||||
|
||||
void EditorSkyboxSystem::cleanupSkybox(SkyboxComponent &skybox)
|
||||
{
|
||||
if (skybox.manualObject) {
|
||||
if (skybox.sceneNode) {
|
||||
skybox.sceneNode->detachObject(skybox.manualObject);
|
||||
}
|
||||
m_sceneMgr->destroyManualObject(skybox.manualObject);
|
||||
skybox.manualObject = nullptr;
|
||||
}
|
||||
if (skybox.sceneNode) {
|
||||
m_sceneMgr->destroySceneNode(skybox.sceneNode);
|
||||
skybox.sceneNode = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSkyboxSystem::createCube(Ogre::ManualObject *obj, float size)
|
||||
{
|
||||
float h = size * 0.5f;
|
||||
|
||||
obj->begin("Skybox/Dynamic",
|
||||
Ogre::RenderOperation::OT_TRIANGLE_LIST);
|
||||
|
||||
// Front face (+Z)
|
||||
obj->position(-h, -h, h);
|
||||
obj->position(h, -h, h);
|
||||
obj->position(h, h, h);
|
||||
obj->position(-h, h, h);
|
||||
obj->triangle(0, 2, 1);
|
||||
obj->triangle(0, 3, 2);
|
||||
|
||||
// Back face (-Z)
|
||||
obj->position(h, -h, -h);
|
||||
obj->position(-h, -h, -h);
|
||||
obj->position(-h, h, -h);
|
||||
obj->position(h, h, -h);
|
||||
obj->triangle(4, 6, 5);
|
||||
obj->triangle(4, 7, 6);
|
||||
|
||||
// Left face (-X)
|
||||
obj->position(-h, -h, -h);
|
||||
obj->position(-h, -h, h);
|
||||
obj->position(-h, h, h);
|
||||
obj->position(-h, h, -h);
|
||||
obj->triangle(8, 10, 9);
|
||||
obj->triangle(8, 11, 10);
|
||||
|
||||
// Right face (+X)
|
||||
obj->position(h, -h, h);
|
||||
obj->position(h, -h, -h);
|
||||
obj->position(h, h, -h);
|
||||
obj->position(h, h, h);
|
||||
obj->triangle(12, 14, 13);
|
||||
obj->triangle(12, 15, 14);
|
||||
|
||||
// Top face (+Y)
|
||||
obj->position(-h, h, h);
|
||||
obj->position(h, h, h);
|
||||
obj->position(h, h, -h);
|
||||
obj->position(-h, h, -h);
|
||||
obj->triangle(16, 18, 17);
|
||||
obj->triangle(16, 19, 18);
|
||||
|
||||
// Bottom face (-Y)
|
||||
obj->position(-h, -h, -h);
|
||||
obj->position(h, -h, -h);
|
||||
obj->position(h, -h, h);
|
||||
obj->position(-h, -h, h);
|
||||
obj->triangle(20, 22, 21);
|
||||
obj->triangle(20, 23, 22);
|
||||
|
||||
obj->end();
|
||||
}
|
||||
|
||||
void EditorSkyboxSystem::updateShaderParams(SkyboxComponent &skybox,
|
||||
float sunElev,
|
||||
const Ogre::Vector3 &sunDir)
|
||||
{
|
||||
if (!skybox.manualObject)
|
||||
return;
|
||||
|
||||
Ogre::MaterialPtr material =
|
||||
Ogre::MaterialManager::getSingleton()
|
||||
.getByName("Skybox/Dynamic",
|
||||
Ogre::ResourceGroupManager::
|
||||
DEFAULT_RESOURCE_GROUP_NAME);
|
||||
if (!material)
|
||||
return;
|
||||
|
||||
Ogre::Pass *pass = material->getTechnique(0)->getPass(0);
|
||||
Ogre::GpuProgramParametersSharedPtr fpParams =
|
||||
pass->getFragmentProgramParameters();
|
||||
if (!fpParams)
|
||||
return;
|
||||
|
||||
fpParams->setNamedConstant("uDayTop",
|
||||
Ogre::Vector3(skybox.dayTopColor.r,
|
||||
skybox.dayTopColor.g,
|
||||
skybox.dayTopColor.b));
|
||||
fpParams->setNamedConstant("uDayBottom",
|
||||
Ogre::Vector3(skybox.dayBottomColor.r,
|
||||
skybox.dayBottomColor.g,
|
||||
skybox.dayBottomColor.b));
|
||||
fpParams->setNamedConstant("uNightTop",
|
||||
Ogre::Vector3(skybox.nightTopColor.r,
|
||||
skybox.nightTopColor.g,
|
||||
skybox.nightTopColor.b));
|
||||
fpParams->setNamedConstant("uNightBottom",
|
||||
Ogre::Vector3(skybox.nightBottomColor.r,
|
||||
skybox.nightBottomColor.g,
|
||||
skybox.nightBottomColor.b));
|
||||
fpParams->setNamedConstant("uSunriseColor",
|
||||
Ogre::Vector3(skybox.sunriseColor.r,
|
||||
skybox.sunriseColor.g,
|
||||
skybox.sunriseColor.b));
|
||||
fpParams->setNamedConstant("uSunsetColor",
|
||||
Ogre::Vector3(skybox.sunsetColor.r,
|
||||
skybox.sunsetColor.g,
|
||||
skybox.sunsetColor.b));
|
||||
fpParams->setNamedConstant("uSunDir", sunDir);
|
||||
fpParams->setNamedConstant("uSunElev", sunElev);
|
||||
fpParams->setNamedConstant("uSunSize", skybox.sunSize);
|
||||
fpParams->setNamedConstant("uMoonSize", skybox.moonSize);
|
||||
fpParams->setNamedConstant("uStarsEnabled",
|
||||
skybox.starsEnabled ? 1.0f : 0.0f);
|
||||
}
|
||||
33
src/features/editScene/systems/EditorSkyboxSystem.hpp
Normal file
33
src/features/editScene/systems/EditorSkyboxSystem.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef EDITSCENE_EDITOR_SKYBOX_SYSTEM_HPP
|
||||
#define EDITSCENE_EDITOR_SKYBOX_SYSTEM_HPP
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
#include <Ogre.h>
|
||||
|
||||
/**
|
||||
* Skybox system - creates and updates a procedural skybox cube
|
||||
* that follows the camera and renders dynamic sky colors.
|
||||
*/
|
||||
class EditorSkyboxSystem {
|
||||
public:
|
||||
EditorSkyboxSystem(flecs::world &world, Ogre::SceneManager *sceneMgr);
|
||||
~EditorSkyboxSystem();
|
||||
|
||||
// Update skybox position and shader parameters
|
||||
void update(Ogre::Camera *camera);
|
||||
|
||||
private:
|
||||
void rebuildSkybox(flecs::entity entity,
|
||||
struct SkyboxComponent &skybox);
|
||||
void cleanupSkybox(SkyboxComponent &skybox);
|
||||
void createCube(Ogre::ManualObject *obj, float size);
|
||||
void updateShaderParams(SkyboxComponent &skybox,
|
||||
float sunElev, const Ogre::Vector3 &sunDir);
|
||||
|
||||
flecs::world &m_world;
|
||||
Ogre::SceneManager *m_sceneMgr;
|
||||
flecs::query<struct SkyboxComponent> m_query;
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_EDITOR_SKYBOX_SYSTEM_HPP
|
||||
314
src/features/editScene/systems/EditorSunSystem.cpp
Normal file
314
src/features/editScene/systems/EditorSunSystem.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
#include "EditorSunSystem.hpp"
|
||||
#include "../components/Sun.hpp"
|
||||
#include "../components/Transform.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
#include <OgreManualObject.h>
|
||||
#include <cmath>
|
||||
|
||||
EditorSunSystem::EditorSunSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr)
|
||||
: m_world(world)
|
||||
, m_sceneMgr(sceneMgr)
|
||||
, m_query(world.query<SunComponent, TransformComponent>())
|
||||
{
|
||||
}
|
||||
|
||||
EditorSunSystem::~EditorSunSystem() = default;
|
||||
|
||||
void EditorSunSystem::update(float deltaTime)
|
||||
{
|
||||
m_query.each([&](flecs::entity entity, SunComponent &sun,
|
||||
TransformComponent &transform) {
|
||||
if (!sun.enabled) {
|
||||
if (sun.light) {
|
||||
cleanupSun(sun);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Rebuild if dirty or first time
|
||||
if (sun.dirty || !sun.light) {
|
||||
rebuildSun(entity, sun, transform);
|
||||
sun.dirty = false;
|
||||
}
|
||||
|
||||
// Advance time
|
||||
sun.timeOfDay += deltaTime * sun.timeSpeed;
|
||||
if (sun.timeOfDay >= 24.0f)
|
||||
sun.timeOfDay -= 24.0f;
|
||||
if (sun.timeOfDay < 0.0f)
|
||||
sun.timeOfDay += 24.0f;
|
||||
|
||||
// Compute sun angle:
|
||||
// 6:00 = 0 rad (horizon, east)
|
||||
// 12:00 = PI/2 rad (zenith)
|
||||
// 18:00 = PI rad (horizon, west)
|
||||
// 24:00 = 3*PI/2 rad (nadir)
|
||||
float sunAngle = (sun.timeOfDay - 6.0f) / 24.0f * 2.0f * M_PI;
|
||||
float sunElev = std::sin(sunAngle);
|
||||
|
||||
// Light direction (points TOWARD scene from sun)
|
||||
float tiltRad = sun.orbitTilt * M_PI / 180.0f;
|
||||
Ogre::Vector3 lightDir;
|
||||
lightDir.x = -std::cos(sunAngle);
|
||||
lightDir.y = -sunElev;
|
||||
lightDir.z = -std::sin(sunAngle) * std::sin(tiltRad);
|
||||
lightDir.normalise();
|
||||
|
||||
// Update light direction by orienting the light node
|
||||
if (sun.lightNode) {
|
||||
Ogre::Vector3 defaultDir(0, -1, 0);
|
||||
Ogre::Quaternion rot = defaultDir.getRotationTo(lightDir);
|
||||
sun.lightNode->setOrientation(rot);
|
||||
}
|
||||
|
||||
// Determine if sun is above horizon
|
||||
bool isDay = sunElev > -0.1f;
|
||||
|
||||
// Interpolate light color
|
||||
Ogre::ColourValue lightColor;
|
||||
float intensity = sun.intensity;
|
||||
if (isDay) {
|
||||
float t = std::clamp((sunElev + 0.1f) / 0.3f, 0.0f, 1.0f);
|
||||
lightColor = Ogre::ColourValue::White * (1.0f - t) +
|
||||
sun.sunColor * t;
|
||||
// Dim at horizon
|
||||
intensity *= std::clamp((sunElev + 0.1f) / 0.2f, 0.0f, 1.0f);
|
||||
} else {
|
||||
lightColor = sun.moonColor;
|
||||
intensity *= 0.3f;
|
||||
}
|
||||
|
||||
if (sun.light) {
|
||||
sun.light->setDiffuseColour(lightColor * intensity);
|
||||
sun.light->setSpecularColour(lightColor * intensity * 0.5f);
|
||||
}
|
||||
|
||||
// Update ambient light
|
||||
Ogre::ColourValue ambient;
|
||||
if (sunElev > 0.2f) {
|
||||
// Day
|
||||
ambient = sun.ambientDay;
|
||||
} else if (sunElev < -0.2f) {
|
||||
// Night
|
||||
ambient = sun.ambientNight;
|
||||
} else if (sun.timeOfDay < 12.0f) {
|
||||
// Sunrise transition
|
||||
float t = std::clamp((sunElev + 0.2f) / 0.4f, 0.0f, 1.0f);
|
||||
ambient = sun.ambientSunrise * (1.0f - t) +
|
||||
sun.ambientDay * t;
|
||||
} else {
|
||||
// Sunset transition
|
||||
float t = std::clamp((sunElev + 0.2f) / 0.4f, 0.0f, 1.0f);
|
||||
ambient = sun.ambientSunset * (1.0f - t) +
|
||||
sun.ambientDay * t;
|
||||
}
|
||||
m_sceneMgr->setAmbientLight(ambient);
|
||||
|
||||
// Update sphere positions
|
||||
float orbitRadius = 200.0f;
|
||||
Ogre::Vector3 sunPos = -lightDir * orbitRadius;
|
||||
Ogre::Vector3 moonPos = lightDir * orbitRadius;
|
||||
|
||||
if (sun.sunSphereNode) {
|
||||
sun.sunSphereNode->setPosition(sunPos);
|
||||
sun.sunSphereNode->setVisible(
|
||||
sun.showSunSphere && sunElev > -0.2f);
|
||||
}
|
||||
if (sun.moonSphereNode) {
|
||||
sun.moonSphereNode->setPosition(moonPos);
|
||||
sun.moonSphereNode->setVisible(
|
||||
sun.showMoonSphere && sunElev < 0.2f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EditorSunSystem::rebuildSun(flecs::entity entity, SunComponent &sun,
|
||||
TransformComponent &transform)
|
||||
{
|
||||
cleanupSun(sun);
|
||||
|
||||
// Create or get scene node from transform
|
||||
if (!transform.node) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"SunSystem: Entity has no transform node, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create directional light
|
||||
Ogre::String lightName = "SunLight_" +
|
||||
Ogre::StringConverter::toString(entity.id());
|
||||
sun.light = m_sceneMgr->createLight(lightName);
|
||||
sun.light->setType(Ogre::Light::LT_DIRECTIONAL);
|
||||
sun.light->setDiffuseColour(sun.sunColor * sun.intensity);
|
||||
sun.light->setSpecularColour(
|
||||
Ogre::ColourValue(0.4f, 0.4f, 0.4f) * sun.intensity);
|
||||
sun.light->setCastShadows(sun.castShadows);
|
||||
|
||||
// Create a child node for the light (separate from entity node
|
||||
// so we can orbit it independently)
|
||||
sun.lightNode = transform.node->createChildSceneNode(
|
||||
lightName + "Node");
|
||||
sun.lightNode->attachObject(sun.light);
|
||||
|
||||
// Create sun sphere
|
||||
if (sun.showSunSphere) {
|
||||
Ogre::String sunName = "SunSphere_" +
|
||||
Ogre::StringConverter::toString(
|
||||
entity.id());
|
||||
sun.sunSphere = m_sceneMgr->createManualObject(sunName);
|
||||
createSphere(sun.sunSphere, sun.sunSphereSize,
|
||||
Ogre::ColourValue(1.0f, 0.95f, 0.8f));
|
||||
sun.sunSphereNode =
|
||||
transform.node->createChildSceneNode(sunName + "Node");
|
||||
sun.sunSphereNode->attachObject(sun.sunSphere);
|
||||
}
|
||||
|
||||
// Create moon sphere
|
||||
if (sun.showMoonSphere) {
|
||||
Ogre::String moonName = "MoonSphere_" +
|
||||
Ogre::StringConverter::toString(
|
||||
entity.id());
|
||||
sun.moonSphere = m_sceneMgr->createManualObject(moonName);
|
||||
createSphere(sun.moonSphere, sun.moonSphereSize,
|
||||
Ogre::ColourValue(0.8f, 0.8f, 0.9f));
|
||||
sun.moonSphereNode =
|
||||
transform.node->createChildSceneNode(moonName + "Node");
|
||||
sun.moonSphereNode->attachObject(sun.moonSphere);
|
||||
}
|
||||
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"SunSystem: Created sun for entity " +
|
||||
Ogre::StringConverter::toString(entity.id()));
|
||||
}
|
||||
|
||||
void EditorSunSystem::cleanupSun(SunComponent &sun)
|
||||
{
|
||||
if (sun.sunSphere) {
|
||||
if (sun.sunSphereNode) {
|
||||
sun.sunSphereNode->detachObject(sun.sunSphere);
|
||||
}
|
||||
m_sceneMgr->destroyManualObject(sun.sunSphere);
|
||||
sun.sunSphere = nullptr;
|
||||
}
|
||||
if (sun.sunSphereNode) {
|
||||
if (sun.sunSphereNode->getParentSceneNode()) {
|
||||
sun.sunSphereNode->getParentSceneNode()->removeChild(
|
||||
sun.sunSphereNode);
|
||||
}
|
||||
m_sceneMgr->destroySceneNode(sun.sunSphereNode);
|
||||
sun.sunSphereNode = nullptr;
|
||||
}
|
||||
|
||||
if (sun.moonSphere) {
|
||||
if (sun.moonSphereNode) {
|
||||
sun.moonSphereNode->detachObject(sun.moonSphere);
|
||||
}
|
||||
m_sceneMgr->destroyManualObject(sun.moonSphere);
|
||||
sun.moonSphere = nullptr;
|
||||
}
|
||||
if (sun.moonSphereNode) {
|
||||
if (sun.moonSphereNode->getParentSceneNode()) {
|
||||
sun.moonSphereNode->getParentSceneNode()->removeChild(
|
||||
sun.moonSphereNode);
|
||||
}
|
||||
m_sceneMgr->destroySceneNode(sun.moonSphereNode);
|
||||
sun.moonSphereNode = nullptr;
|
||||
}
|
||||
|
||||
if (sun.light) {
|
||||
if (sun.lightNode) {
|
||||
sun.lightNode->detachObject(sun.light);
|
||||
}
|
||||
m_sceneMgr->destroyLight(sun.light);
|
||||
sun.light = nullptr;
|
||||
}
|
||||
if (sun.lightNode) {
|
||||
if (sun.lightNode->getParentSceneNode()) {
|
||||
sun.lightNode->getParentSceneNode()->removeChild(
|
||||
sun.lightNode);
|
||||
}
|
||||
m_sceneMgr->destroySceneNode(sun.lightNode);
|
||||
sun.lightNode = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSunSystem::createSphere(Ogre::ManualObject *obj, float radius,
|
||||
const Ogre::ColourValue &color)
|
||||
{
|
||||
// Simple icosphere approximation (octahedron + one subdivision)
|
||||
// 8 faces, subdivided once = 32 faces
|
||||
obj->begin("BaseWhiteNoLighting",
|
||||
Ogre::RenderOperation::OT_TRIANGLE_LIST);
|
||||
|
||||
struct Vertex {
|
||||
Ogre::Vector3 p;
|
||||
};
|
||||
std::vector<Vertex> verts;
|
||||
std::vector<int> indices;
|
||||
|
||||
// Octahedron vertices
|
||||
verts.push_back({ Ogre::Vector3(0, 1, 0) * radius });
|
||||
verts.push_back({ Ogre::Vector3(0, -1, 0) * radius });
|
||||
verts.push_back({ Ogre::Vector3(-1, 0, 0) * radius });
|
||||
verts.push_back({ Ogre::Vector3(1, 0, 0) * radius });
|
||||
verts.push_back({ Ogre::Vector3(0, 0, 1) * radius });
|
||||
verts.push_back({ Ogre::Vector3(0, 0, -1) * radius });
|
||||
|
||||
// Octahedron faces
|
||||
int faces[] = { 0, 4, 3, 0, 3, 5, 0, 5, 2, 0, 2, 4,
|
||||
1, 3, 4, 1, 5, 3, 1, 2, 5, 1, 4, 2 };
|
||||
|
||||
for (int i = 0; i < 24; i += 3) {
|
||||
indices.push_back(faces[i]);
|
||||
indices.push_back(faces[i + 1]);
|
||||
indices.push_back(faces[i + 2]);
|
||||
}
|
||||
|
||||
// Subdivide once
|
||||
std::vector<int> newIndices;
|
||||
for (size_t i = 0; i < indices.size(); i += 3) {
|
||||
Ogre::Vector3 a = verts[indices[i]].p;
|
||||
Ogre::Vector3 b = verts[indices[i + 1]].p;
|
||||
Ogre::Vector3 c = verts[indices[i + 2]].p;
|
||||
|
||||
Ogre::Vector3 ab = (a + b).normalisedCopy() * radius;
|
||||
Ogre::Vector3 bc = (b + c).normalisedCopy() * radius;
|
||||
Ogre::Vector3 ca = (c + a).normalisedCopy() * radius;
|
||||
|
||||
int ia = indices[i];
|
||||
int ib = indices[i + 1];
|
||||
int ic = indices[i + 2];
|
||||
int iab = (int)verts.size();
|
||||
verts.push_back({ ab });
|
||||
int ibc = (int)verts.size();
|
||||
verts.push_back({ bc });
|
||||
int ica = (int)verts.size();
|
||||
verts.push_back({ ca });
|
||||
|
||||
newIndices.push_back(ia);
|
||||
newIndices.push_back(iab);
|
||||
newIndices.push_back(ica);
|
||||
newIndices.push_back(iab);
|
||||
newIndices.push_back(ib);
|
||||
newIndices.push_back(ibc);
|
||||
newIndices.push_back(ica);
|
||||
newIndices.push_back(ibc);
|
||||
newIndices.push_back(ic);
|
||||
newIndices.push_back(iab);
|
||||
newIndices.push_back(ibc);
|
||||
newIndices.push_back(ica);
|
||||
}
|
||||
indices = newIndices;
|
||||
|
||||
// Write vertices
|
||||
for (const auto &v : verts) {
|
||||
obj->position(v.p);
|
||||
obj->colour(color);
|
||||
}
|
||||
for (int idx : indices) {
|
||||
obj->index(idx);
|
||||
}
|
||||
|
||||
obj->end();
|
||||
}
|
||||
32
src/features/editScene/systems/EditorSunSystem.hpp
Normal file
32
src/features/editScene/systems/EditorSunSystem.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef EDITSCENE_EDITOR_SUN_SYSTEM_HPP
|
||||
#define EDITSCENE_EDITOR_SUN_SYSTEM_HPP
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
#include <Ogre.h>
|
||||
|
||||
/**
|
||||
* Sun system - manages directional light and sun/moon spheres
|
||||
* based on in-game time.
|
||||
*/
|
||||
class EditorSunSystem {
|
||||
public:
|
||||
EditorSunSystem(flecs::world &world, Ogre::SceneManager *sceneMgr);
|
||||
~EditorSunSystem();
|
||||
|
||||
// Update sun position, light, and colors
|
||||
void update(float deltaTime);
|
||||
|
||||
private:
|
||||
void rebuildSun(flecs::entity entity, struct SunComponent &sun,
|
||||
struct TransformComponent &transform);
|
||||
void cleanupSun(SunComponent &sun);
|
||||
void createSphere(Ogre::ManualObject *obj, float radius,
|
||||
const Ogre::ColourValue &color);
|
||||
|
||||
flecs::world &m_world;
|
||||
Ogre::SceneManager *m_sceneMgr;
|
||||
flecs::query<struct SunComponent, struct TransformComponent> m_query;
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_EDITOR_SUN_SYSTEM_HPP
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "../components/RigidBody.hpp"
|
||||
#include "../components/BuoyancyInfo.hpp"
|
||||
#include "../components/WaterPhysics.hpp"
|
||||
#include "../components/Sun.hpp"
|
||||
#include "../components/Skybox.hpp"
|
||||
#include "../components/Light.hpp"
|
||||
#include "../components/Camera.hpp"
|
||||
#include "../components/Lod.hpp"
|
||||
@@ -619,6 +621,24 @@ void EditorUISystem::renderComponentList(flecs::entity entity)
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render Sun if present
|
||||
if (entity.has<SunComponent>()) {
|
||||
auto &sun = entity.get_mut<SunComponent>();
|
||||
if (m_componentRegistry.render<SunComponent>(entity, sun)) {
|
||||
sun.markDirty();
|
||||
}
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render Skybox if present
|
||||
if (entity.has<SkyboxComponent>()) {
|
||||
auto &sky = entity.get_mut<SkyboxComponent>();
|
||||
if (m_componentRegistry.render<SkyboxComponent>(entity, sky)) {
|
||||
sky.markDirty();
|
||||
}
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render LOD Settings if present
|
||||
if (entity.has<LodSettingsComponent>()) {
|
||||
auto &lodSettings = entity.get_mut<LodSettingsComponent>();
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "../components/GeneratedPhysicsTag.hpp"
|
||||
#include "../components/BuoyancyInfo.hpp"
|
||||
#include "../components/WaterPhysics.hpp"
|
||||
#include "../components/Sun.hpp"
|
||||
#include "../components/Skybox.hpp"
|
||||
#include "EditorUISystem.hpp"
|
||||
#include <random>
|
||||
#include <fstream>
|
||||
@@ -259,6 +261,14 @@ nlohmann::json SceneSerializer::serializeEntity(flecs::entity entity)
|
||||
json["waterPhysics"] = serializeWaterPhysics(entity);
|
||||
}
|
||||
|
||||
if (entity.has<SunComponent>()) {
|
||||
json["sun"] = serializeSun(entity);
|
||||
}
|
||||
|
||||
if (entity.has<SkyboxComponent>()) {
|
||||
json["skybox"] = serializeSkybox(entity);
|
||||
}
|
||||
|
||||
// Serialize children
|
||||
json["children"] = nlohmann::json::array();
|
||||
entity.children([&](flecs::entity child) {
|
||||
@@ -420,6 +430,14 @@ void SceneSerializer::deserializeEntity(const nlohmann::json &json,
|
||||
deserializeWaterPhysics(entity, json["waterPhysics"]);
|
||||
}
|
||||
|
||||
if (json.contains("sun")) {
|
||||
deserializeSun(entity, json["sun"]);
|
||||
}
|
||||
|
||||
if (json.contains("skybox")) {
|
||||
deserializeSkybox(entity, json["skybox"]);
|
||||
}
|
||||
|
||||
// Add to UI system if provided
|
||||
if (uiSystem) {
|
||||
uiSystem->addEntity(entity);
|
||||
@@ -2331,3 +2349,172 @@ void SceneSerializer::deserializeWaterPhysics(flecs::entity entity,
|
||||
|
||||
entity.set<WaterPhysics>(water);
|
||||
}
|
||||
|
||||
|
||||
nlohmann::json SceneSerializer::serializeSun(flecs::entity entity)
|
||||
{
|
||||
const SunComponent &sun = entity.get<SunComponent>();
|
||||
nlohmann::json json;
|
||||
|
||||
json["enabled"] = sun.enabled;
|
||||
json["timeOfDay"] = sun.timeOfDay;
|
||||
json["timeSpeed"] = sun.timeSpeed;
|
||||
json["sunColor"] = { sun.sunColor.r, sun.sunColor.g,
|
||||
sun.sunColor.b };
|
||||
json["moonColor"] = { sun.moonColor.r, sun.moonColor.g,
|
||||
sun.moonColor.b };
|
||||
json["ambientDay"] = { sun.ambientDay.r, sun.ambientDay.g,
|
||||
sun.ambientDay.b };
|
||||
json["ambientNight"] = { sun.ambientNight.r, sun.ambientNight.g,
|
||||
sun.ambientNight.b };
|
||||
json["ambientSunrise"] = { sun.ambientSunrise.r, sun.ambientSunrise.g,
|
||||
sun.ambientSunrise.b };
|
||||
json["ambientSunset"] = { sun.ambientSunset.r, sun.ambientSunset.g,
|
||||
sun.ambientSunset.b };
|
||||
json["showSunSphere"] = sun.showSunSphere;
|
||||
json["showMoonSphere"] = sun.showMoonSphere;
|
||||
json["sunSphereSize"] = sun.sunSphereSize;
|
||||
json["moonSphereSize"] = sun.moonSphereSize;
|
||||
json["orbitTilt"] = sun.orbitTilt;
|
||||
json["intensity"] = sun.intensity;
|
||||
json["castShadows"] = sun.castShadows;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
nlohmann::json SceneSerializer::serializeSkybox(flecs::entity entity)
|
||||
{
|
||||
const SkyboxComponent &sky = entity.get<SkyboxComponent>();
|
||||
nlohmann::json json;
|
||||
|
||||
json["enabled"] = sky.enabled;
|
||||
json["size"] = sky.size;
|
||||
json["dayTopColor"] = { sky.dayTopColor.r, sky.dayTopColor.g,
|
||||
sky.dayTopColor.b };
|
||||
json["dayBottomColor"] = { sky.dayBottomColor.r, sky.dayBottomColor.g,
|
||||
sky.dayBottomColor.b };
|
||||
json["nightTopColor"] = { sky.nightTopColor.r, sky.nightTopColor.g,
|
||||
sky.nightTopColor.b };
|
||||
json["nightBottomColor"] = { sky.nightBottomColor.r,
|
||||
sky.nightBottomColor.g,
|
||||
sky.nightBottomColor.b };
|
||||
json["sunriseColor"] = { sky.sunriseColor.r, sky.sunriseColor.g,
|
||||
sky.sunriseColor.b };
|
||||
json["sunsetColor"] = { sky.sunsetColor.r, sky.sunsetColor.g,
|
||||
sky.sunsetColor.b };
|
||||
json["sunSize"] = sky.sunSize;
|
||||
json["moonSize"] = sky.moonSize;
|
||||
json["starsEnabled"] = sky.starsEnabled;
|
||||
json["cloudiness"] = sky.cloudiness;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeSun(flecs::entity entity,
|
||||
const nlohmann::json &json)
|
||||
{
|
||||
SunComponent sun;
|
||||
|
||||
sun.enabled = json.value("enabled", true);
|
||||
sun.timeOfDay = json.value("timeOfDay", 12.0f);
|
||||
sun.timeSpeed = json.value("timeSpeed", 0.05f);
|
||||
if (json.contains("sunColor") && json["sunColor"].is_array() &&
|
||||
json["sunColor"].size() >= 3) {
|
||||
sun.sunColor = Ogre::ColourValue(json["sunColor"][0],
|
||||
json["sunColor"][1],
|
||||
json["sunColor"][2]);
|
||||
}
|
||||
if (json.contains("moonColor") && json["moonColor"].is_array() &&
|
||||
json["moonColor"].size() >= 3) {
|
||||
sun.moonColor = Ogre::ColourValue(json["moonColor"][0],
|
||||
json["moonColor"][1],
|
||||
json["moonColor"][2]);
|
||||
}
|
||||
if (json.contains("ambientDay") && json["ambientDay"].is_array() &&
|
||||
json["ambientDay"].size() >= 3) {
|
||||
sun.ambientDay = Ogre::ColourValue(json["ambientDay"][0],
|
||||
json["ambientDay"][1],
|
||||
json["ambientDay"][2]);
|
||||
}
|
||||
if (json.contains("ambientNight") && json["ambientNight"].is_array() &&
|
||||
json["ambientNight"].size() >= 3) {
|
||||
sun.ambientNight = Ogre::ColourValue(json["ambientNight"][0],
|
||||
json["ambientNight"][1],
|
||||
json["ambientNight"][2]);
|
||||
}
|
||||
if (json.contains("ambientSunrise") &&
|
||||
json["ambientSunrise"].is_array() &&
|
||||
json["ambientSunrise"].size() >= 3) {
|
||||
sun.ambientSunrise = Ogre::ColourValue(
|
||||
json["ambientSunrise"][0], json["ambientSunrise"][1],
|
||||
json["ambientSunrise"][2]);
|
||||
}
|
||||
if (json.contains("ambientSunset") && json["ambientSunset"].is_array() &&
|
||||
json["ambientSunset"].size() >= 3) {
|
||||
sun.ambientSunset = Ogre::ColourValue(json["ambientSunset"][0],
|
||||
json["ambientSunset"][1],
|
||||
json["ambientSunset"][2]);
|
||||
}
|
||||
sun.showSunSphere = json.value("showSunSphere", true);
|
||||
sun.showMoonSphere = json.value("showMoonSphere", true);
|
||||
sun.sunSphereSize = json.value("sunSphereSize", 5.0f);
|
||||
sun.moonSphereSize = json.value("moonSphereSize", 3.0f);
|
||||
sun.orbitTilt = json.value("orbitTilt", 15.0f);
|
||||
sun.intensity = json.value("intensity", 1.0f);
|
||||
sun.castShadows = json.value("castShadows", true);
|
||||
|
||||
entity.set<SunComponent>(sun);
|
||||
}
|
||||
|
||||
void SceneSerializer::deserializeSkybox(flecs::entity entity,
|
||||
const nlohmann::json &json)
|
||||
{
|
||||
SkyboxComponent sky;
|
||||
|
||||
sky.enabled = json.value("enabled", true);
|
||||
sky.size = json.value("size", 500.0f);
|
||||
if (json.contains("dayTopColor") && json["dayTopColor"].is_array() &&
|
||||
json["dayTopColor"].size() >= 3) {
|
||||
sky.dayTopColor = Ogre::ColourValue(json["dayTopColor"][0],
|
||||
json["dayTopColor"][1],
|
||||
json["dayTopColor"][2]);
|
||||
}
|
||||
if (json.contains("dayBottomColor") &&
|
||||
json["dayBottomColor"].is_array() &&
|
||||
json["dayBottomColor"].size() >= 3) {
|
||||
sky.dayBottomColor = Ogre::ColourValue(
|
||||
json["dayBottomColor"][0], json["dayBottomColor"][1],
|
||||
json["dayBottomColor"][2]);
|
||||
}
|
||||
if (json.contains("nightTopColor") && json["nightTopColor"].is_array() &&
|
||||
json["nightTopColor"].size() >= 3) {
|
||||
sky.nightTopColor = Ogre::ColourValue(json["nightTopColor"][0],
|
||||
json["nightTopColor"][1],
|
||||
json["nightTopColor"][2]);
|
||||
}
|
||||
if (json.contains("nightBottomColor") &&
|
||||
json["nightBottomColor"].is_array() &&
|
||||
json["nightBottomColor"].size() >= 3) {
|
||||
sky.nightBottomColor = Ogre::ColourValue(
|
||||
json["nightBottomColor"][0], json["nightBottomColor"][1],
|
||||
json["nightBottomColor"][2]);
|
||||
}
|
||||
if (json.contains("sunriseColor") && json["sunriseColor"].is_array() &&
|
||||
json["sunriseColor"].size() >= 3) {
|
||||
sky.sunriseColor = Ogre::ColourValue(json["sunriseColor"][0],
|
||||
json["sunriseColor"][1],
|
||||
json["sunriseColor"][2]);
|
||||
}
|
||||
if (json.contains("sunsetColor") && json["sunsetColor"].is_array() &&
|
||||
json["sunsetColor"].size() >= 3) {
|
||||
sky.sunsetColor = Ogre::ColourValue(json["sunsetColor"][0],
|
||||
json["sunsetColor"][1],
|
||||
json["sunsetColor"][2]);
|
||||
}
|
||||
sky.sunSize = json.value("sunSize", 0.05f);
|
||||
sky.moonSize = json.value("moonSize", 0.03f);
|
||||
sky.starsEnabled = json.value("starsEnabled", true);
|
||||
sky.cloudiness = json.value("cloudiness", 0.0f);
|
||||
|
||||
entity.set<SkyboxComponent>(sky);
|
||||
}
|
||||
|
||||
@@ -141,6 +141,12 @@ private:
|
||||
void deserializeWaterPhysics(flecs::entity entity,
|
||||
const nlohmann::json &json);
|
||||
|
||||
// Sun / Skybox serialization
|
||||
nlohmann::json serializeSun(flecs::entity entity);
|
||||
nlohmann::json serializeSkybox(flecs::entity entity);
|
||||
void deserializeSun(flecs::entity entity, const nlohmann::json &json);
|
||||
void deserializeSkybox(flecs::entity entity, const nlohmann::json &json);
|
||||
|
||||
flecs::world &m_world;
|
||||
Ogre::SceneManager *m_sceneMgr;
|
||||
std::string m_lastError;
|
||||
|
||||
127
src/features/editScene/ui/SkyboxEditor.hpp
Normal file
127
src/features/editScene/ui/SkyboxEditor.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef SKYBOX_EDITOR_HPP
|
||||
#define SKYBOX_EDITOR_HPP
|
||||
#pragma once
|
||||
|
||||
#include "ComponentEditor.hpp"
|
||||
#include "../components/Skybox.hpp"
|
||||
|
||||
/**
|
||||
* Editor for Skybox component
|
||||
*/
|
||||
class SkyboxEditor : public ComponentEditor<SkyboxComponent> {
|
||||
public:
|
||||
bool renderComponent(flecs::entity entity,
|
||||
SkyboxComponent &component) override
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
ImGui::Text("Procedural Skybox");
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Checkbox("Enabled", &component.enabled)) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Box Size", &component.size, 100.0f, 2000.0f,
|
||||
"%.0f")) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Day Colors");
|
||||
|
||||
float dayTop[3] = { component.dayTopColor.r, component.dayTopColor.g,
|
||||
component.dayTopColor.b };
|
||||
if (ImGui::ColorEdit3("Day Top", dayTop)) {
|
||||
component.dayTopColor = Ogre::ColourValue(dayTop[0], dayTop[1],
|
||||
dayTop[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float dayBot[3] = { component.dayBottomColor.r,
|
||||
component.dayBottomColor.g,
|
||||
component.dayBottomColor.b };
|
||||
if (ImGui::ColorEdit3("Day Bottom", dayBot)) {
|
||||
component.dayBottomColor = Ogre::ColourValue(
|
||||
dayBot[0], dayBot[1], dayBot[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Night Colors");
|
||||
|
||||
float nightTop[3] = { component.nightTopColor.r,
|
||||
component.nightTopColor.g,
|
||||
component.nightTopColor.b };
|
||||
if (ImGui::ColorEdit3("Night Top", nightTop)) {
|
||||
component.nightTopColor = Ogre::ColourValue(
|
||||
nightTop[0], nightTop[1], nightTop[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float nightBot[3] = { component.nightBottomColor.r,
|
||||
component.nightBottomColor.g,
|
||||
component.nightBottomColor.b };
|
||||
if (ImGui::ColorEdit3("Night Bottom", nightBot)) {
|
||||
component.nightBottomColor = Ogre::ColourValue(
|
||||
nightBot[0], nightBot[1], nightBot[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Horizon Glow");
|
||||
|
||||
float sunrise[3] = { component.sunriseColor.r,
|
||||
component.sunriseColor.g,
|
||||
component.sunriseColor.b };
|
||||
if (ImGui::ColorEdit3("Sunrise", sunrise)) {
|
||||
component.sunriseColor = Ogre::ColourValue(
|
||||
sunrise[0], sunrise[1], sunrise[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float sunset[3] = { component.sunsetColor.r,
|
||||
component.sunsetColor.g,
|
||||
component.sunsetColor.b };
|
||||
if (ImGui::ColorEdit3("Sunset", sunset)) {
|
||||
component.sunsetColor = Ogre::ColourValue(
|
||||
sunset[0], sunset[1], sunset[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Celestial Bodies");
|
||||
|
||||
if (ImGui::SliderFloat("Sun Size", &component.sunSize, 0.01f, 0.2f,
|
||||
"%.3f")) {
|
||||
changed = true;
|
||||
}
|
||||
if (ImGui::SliderFloat("Moon Size", &component.moonSize, 0.01f, 0.2f,
|
||||
"%.3f")) {
|
||||
changed = true;
|
||||
}
|
||||
if (ImGui::Checkbox("Stars Enabled", &component.starsEnabled)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushID("Skybox");
|
||||
if (ImGui::Button("Reset to Defaults")) {
|
||||
component = SkyboxComponent();
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
const char *getName() const override
|
||||
{
|
||||
return "Skybox";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SKYBOX_EDITOR_HPP
|
||||
147
src/features/editScene/ui/SunEditor.hpp
Normal file
147
src/features/editScene/ui/SunEditor.hpp
Normal file
@@ -0,0 +1,147 @@
|
||||
#ifndef SUN_EDITOR_HPP
|
||||
#define SUN_EDITOR_HPP
|
||||
#pragma once
|
||||
|
||||
#include "ComponentEditor.hpp"
|
||||
#include "../components/Sun.hpp"
|
||||
|
||||
/**
|
||||
* Editor for Sun component
|
||||
*/
|
||||
class SunEditor : public ComponentEditor<SunComponent> {
|
||||
public:
|
||||
bool renderComponent(flecs::entity entity,
|
||||
SunComponent &component) override
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
ImGui::Text("Sun / Time of Day");
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Checkbox("Enabled", &component.enabled)) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Time of Day", &component.timeOfDay, 0.0f,
|
||||
24.0f, "%.2f h")) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Time Speed",
|
||||
&component.timeSpeed, 0.0f, 2.0f,
|
||||
"%.3f h/s")) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Intensity", &component.intensity, 0.0f,
|
||||
3.0f, "%.2f")) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Orbit Tilt", &component.orbitTilt, -45.0f,
|
||||
45.0f, "%.1f deg")) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Cast Shadows", &component.castShadows)) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Colors");
|
||||
|
||||
float sunColor[3] = { component.sunColor.r, component.sunColor.g,
|
||||
component.sunColor.b };
|
||||
if (ImGui::ColorEdit3("Sun Color", sunColor)) {
|
||||
component.sunColor = Ogre::ColourValue(sunColor[0], sunColor[1],
|
||||
sunColor[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float moonColor[3] = { component.moonColor.r, component.moonColor.g,
|
||||
component.moonColor.b };
|
||||
if (ImGui::ColorEdit3("Moon Color", moonColor)) {
|
||||
component.moonColor = Ogre::ColourValue(moonColor[0], moonColor[1],
|
||||
moonColor[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float ambDay[3] = { component.ambientDay.r, component.ambientDay.g,
|
||||
component.ambientDay.b };
|
||||
if (ImGui::ColorEdit3("Ambient Day", ambDay)) {
|
||||
component.ambientDay = Ogre::ColourValue(ambDay[0], ambDay[1],
|
||||
ambDay[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float ambNight[3] = { component.ambientNight.r,
|
||||
component.ambientNight.g,
|
||||
component.ambientNight.b };
|
||||
if (ImGui::ColorEdit3("Ambient Night", ambNight)) {
|
||||
component.ambientNight = Ogre::ColourValue(ambNight[0], ambNight[1],
|
||||
ambNight[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float ambSunrise[3] = { component.ambientSunrise.r,
|
||||
component.ambientSunrise.g,
|
||||
component.ambientSunrise.b };
|
||||
if (ImGui::ColorEdit3("Ambient Sunrise", ambSunrise)) {
|
||||
component.ambientSunrise = Ogre::ColourValue(
|
||||
ambSunrise[0], ambSunrise[1], ambSunrise[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
float ambSunset[3] = { component.ambientSunset.r,
|
||||
component.ambientSunset.g,
|
||||
component.ambientSunset.b };
|
||||
if (ImGui::ColorEdit3("Ambient Sunset", ambSunset)) {
|
||||
component.ambientSunset = Ogre::ColourValue(
|
||||
ambSunset[0], ambSunset[1], ambSunset[2]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Visualization");
|
||||
|
||||
if (ImGui::Checkbox("Show Sun Sphere", &component.showSunSphere)) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
if (ImGui::Checkbox("Show Moon Sphere", &component.showMoonSphere)) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
if (ImGui::SliderFloat("Sun Sphere Size", &component.sunSphereSize,
|
||||
0.5f, 20.0f, "%.1f")) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
if (ImGui::SliderFloat("Moon Sphere Size", &component.moonSphereSize,
|
||||
0.5f, 20.0f, "%.1f")) {
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushID("Sun");
|
||||
if (ImGui::Button("Reset to Defaults")) {
|
||||
component = SunComponent();
|
||||
changed = true;
|
||||
component.markDirty();
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
const char *getName() const override
|
||||
{
|
||||
return "Sun";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SUN_EDITOR_HPP
|
||||
Reference in New Issue
Block a user