Skip to main content

CameraWidget Class

ECS-driven ImGui camera editor for viewport-bound cameras. More...

Declaration

class helios::imgui::widgets::CameraWidget { ... }

Base class

classImGuiWidget

Abstract base class for ImGui widgets rendered in debug overlays. More...

Private Member Typedefs Index

usingGameWorld = helios::engine::runtime::world::GameWorld
usingGameObjectHandle = helios::engine::runtime::world::types::GameObjectHandle
usingViewportHandle = helios::engine::rendering::viewport::types::ViewportHandle
usingViewportCameraBindingComponent = helios::engine::scene::components::CameraBindingComponent< ViewportHandle >
usingPerspectiveCameraComponent = helios::engine::scene::components::PerspectiveCameraComponent< GameObjectHandle >
usingPosition3DComponent = helios::engine::spatial::components::Position3DComponent< GameObjectHandle, Local >
usingYawPitchRollComponent = helios::engine::spatial::components::YawPitchRollComponent< GameObjectHandle >

Public Constructors Index

CameraWidget (GameWorld &gameWorld) noexcept

Creates the widget bound to a runtime GameWorld. More...

Public Member Functions Index

voiddraw () override

Renders the camera editor UI and writes changes into ECS components. More...

Private Member Functions Index

std::stringmakeViewportCameraLabel (const ViewportHandle viewportHandle, const GameObjectHandle cameraHandle)
voidrefreshViewportCameraEntries ()
voidselectViewportCameraIndex (const int index)
template <typename TEntity>
CameraSnapshotcaptureSnapshot (const TEntity &entity) const noexcept
template <typename TEntity>
voidsyncFromEntity (TEntity &entity) noexcept
template <typename TEntity>
boolwriteProjectionToEntity (TEntity &entity)
template <typename TEntity>
boolwriteYawPitchRollToEntity (TEntity &entity)

Private Member Attributes Index

GameWorld *gameWorld_ = nullptr
GameObjectHandlecameraHandle_ {}
std::vector< ViewportCameraEntry >viewportCameraEntries_ {}
intselectedViewportCameraIndex_ = -1
helios::math::vec3ftempPosition_ {0.0f, 0.0f, 1.0f}
helios::math::vec3ftempRotation_ {0.0f, 0.0f, 0.0f}

First-person control state in radians. More...

floattempFovDegrees_ = 90.0f
floattempAspectRatio_ = 16.0f / 9.0f
floattempZNear_ = 0.1f
floattempZFar_ = 1000.0f
boolsyncedFromEntity_ = false
CameraSnapshotresetSnapshot_ {}

Description

ECS-driven ImGui camera editor for viewport-bound cameras.

The widget discovers all viewport entities that expose CameraBindingComponent<ViewportHandle>, lets the user pick one camera, and edits its transform/projection ECS components at runtime.

Definition at line 44 of file CameraWidget.ixx.

Private Member Typedefs

GameObjectHandle

using helios::imgui::widgets::CameraWidget::GameObjectHandle = helios::engine::runtime::world::types::GameObjectHandle

Definition at line 47 of file CameraWidget.ixx.

47 using GameObjectHandle = helios::engine::runtime::world::types::GameObjectHandle;

GameWorld

using helios::imgui::widgets::CameraWidget::GameWorld = helios::engine::runtime::world::GameWorld

Definition at line 46 of file CameraWidget.ixx.

46 using GameWorld = helios::engine::runtime::world::GameWorld;

PerspectiveCameraComponent

using helios::imgui::widgets::CameraWidget::PerspectiveCameraComponent = helios::engine::scene::components::PerspectiveCameraComponent<GameObjectHandle>

Definition at line 53 of file CameraWidget.ixx.

54 helios::engine::scene::components::PerspectiveCameraComponent<GameObjectHandle>;

Position3DComponent

using helios::imgui::widgets::CameraWidget::Position3DComponent = helios::engine::spatial::components::Position3DComponent<GameObjectHandle, Local>

Definition at line 56 of file CameraWidget.ixx.

57 helios::engine::spatial::components::Position3DComponent<GameObjectHandle, Local>;

ViewportCameraBindingComponent

using helios::imgui::widgets::CameraWidget::ViewportCameraBindingComponent = helios::engine::scene::components::CameraBindingComponent<ViewportHandle>

Definition at line 50 of file CameraWidget.ixx.

51 helios::engine::scene::components::CameraBindingComponent<ViewportHandle>;

ViewportHandle

using helios::imgui::widgets::CameraWidget::ViewportHandle = helios::engine::rendering::viewport::types::ViewportHandle

Definition at line 48 of file CameraWidget.ixx.

48 using ViewportHandle = helios::engine::rendering::viewport::types::ViewportHandle;

YawPitchRollComponent

using helios::imgui::widgets::CameraWidget::YawPitchRollComponent = helios::engine::spatial::components::YawPitchRollComponent<GameObjectHandle>

Definition at line 59 of file CameraWidget.ixx.

60 helios::engine::spatial::components::YawPitchRollComponent<GameObjectHandle>;

Public Constructors

CameraWidget()

helios::imgui::widgets::CameraWidget::CameraWidget (GameWorld & gameWorld)
inline explicit noexcept

Creates the widget bound to a runtime GameWorld.

Parameters
gameWorld

World used for viewport/camera discovery and component edits.

Definition at line 338 of file CameraWidget.ixx.

338 explicit CameraWidget(GameWorld& gameWorld) noexcept
339 : gameWorld_(&gameWorld) {}

Public Member Functions

draw()

void helios::imgui::widgets::CameraWidget::draw ()
inline virtual

Renders the camera editor UI and writes changes into ECS components.

The UI provides:

  • viewport/camera selection via CameraBindingComponent<ViewportHandle>
  • editing for Position3DComponent
  • first-person-style yaw/pitch/roll editing for YawPitchRollComponent
  • editing for PerspectiveCameraComponent
  • reset to the snapshot captured when the current selection became active

Definition at line 351 of file CameraWidget.ixx.

351 void draw() override {
352 ImGui::SetNextWindowSize(ImVec2(380, 520), ImGuiCond_FirstUseEver);
353
354 if (!ImGui::Begin("Camera ECS", nullptr, ImGuiWindowFlags_NoCollapse)) {
355 ImGui::End();
356 return;
357 }
358
359 if (!gameWorld_) {
360 ImGui::TextDisabled("GameWorld missing.");
361 ImGui::End();
362 return;
363 }
364
365 refreshViewportCameraEntries();
366
367 if (viewportCameraEntries_.empty()) {
368 ImGui::TextDisabled("No viewport has CameraBindingComponent.");
369 ImGui::End();
370 return;
371 }
372
373 const char* selectedLabel = "<none>";
374 if (selectedViewportCameraIndex_ >= 0
375 && selectedViewportCameraIndex_ < static_cast<int>(viewportCameraEntries_.size())) {
376 selectedLabel = viewportCameraEntries_[selectedViewportCameraIndex_].label.c_str();
377 }
378
379 if (ImGui::BeginCombo("Viewport / Camera", selectedLabel)) {
380 for (int i = 0; i < static_cast<int>(viewportCameraEntries_.size()); ++i) {
381 const bool isSelected = selectedViewportCameraIndex_ == i;
382
383 if (ImGui::Selectable(viewportCameraEntries_[i].label.c_str(), isSelected)) {
384 selectViewportCameraIndex(i);
385 }
386
387 if (isSelected) {
388 ImGui::SetItemDefaultFocus();
389 }
390 }
391
392 ImGui::EndCombo();
393 }
394
395 auto cameraEntityOptional = gameWorld_->find(cameraHandle_);
396 if (!cameraEntityOptional) {
397 ImGui::TextDisabled("Camera entity not found or stale handle.");
398 ImGui::End();
399 return;
400 }
401
402 auto& cameraEntity = *cameraEntityOptional;
403
404 if (!syncedFromEntity_) {
405 syncFromEntity(cameraEntity);
406 resetSnapshot_ = captureSnapshot(cameraEntity);
407 syncedFromEntity_ = true;
408 }
409
410 bool positionChanged = false;
411 bool rotationChanged = false;
412 bool projectionChanged = false;
413
414 bool missingPosition = false;
415 bool missingRotation = false;
416 bool missingCamera = false;
417
418 ImGui::SeparatorText("Spatial Components");
419
420 ImGui::Text("Position3DComponent");
421 positionChanged |= ImGui::DragFloat(
422 "X##Pos",
423 &tempPosition_[0],
424 0.1f,
425 -10000.0f,
426 10000.0f,
427 "%.3f"
428 );
429
430 positionChanged |= ImGui::DragFloat(
431 "Y##Pos",
432 &tempPosition_[1],
433 0.1f,
434 -10000.0f,
435 10000.0f,
436 "%.3f"
437 );
438
439 positionChanged |= ImGui::DragFloat(
440 "Z##Pos",
441 &tempPosition_[2],
442 0.1f,
443 -10000.0f,
444 10000.0f,
445 "%.3f"
446 );
447
448 ImGui::Spacing();
449 ImGui::Text("YawPitchRollComponent (first-person yaw/pitch/roll)");
450
451 const auto pi = static_cast<float>(std::numbers::pi);
452 const auto halfPi = pi * 0.5f;
453
454 rotationChanged |= ImGui::SliderFloat(
455 "Pitch##Rot",
456 &tempRotation_[1],
457 -halfPi + 0.001f,
458 halfPi - 0.001f,
459 "%.3f rad"
460 );
461
462 rotationChanged |= ImGui::SliderFloat(
463 "Yaw##Rot",
464 &tempRotation_[0],
465 -pi,
466 pi,
467 "%.3f rad"
468 );
469
474 rotationChanged |= ImGui::SliderFloat(
475 "Roll##Rot",
476 &tempRotation_[2],
477 -pi,
478 pi,
479 "%.3f rad"
480 );
481
482 ImGui::SeparatorText("PerspectiveCameraComponent");
483
484 projectionChanged |= ImGui::SliderFloat(
485 "FOV Y",
486 &tempFovDegrees_,
487 10.0f,
488 170.0f,
489 "%.1f deg"
490 );
491
492 projectionChanged |= ImGui::DragFloat(
493 "Aspect",
494 &tempAspectRatio_,
495 0.01f,
496 0.1f,
497 8.0f,
498 "%.3f"
499 );
500
501 projectionChanged |= ImGui::DragFloat(
502 "Near",
503 &tempZNear_,
504 0.001f,
505 0.001f,
506 1000.0f,
507 "%.4f"
508 );
509
510 projectionChanged |= ImGui::DragFloat(
511 "Far",
512 &tempZFar_,
513 1.0f,
514 0.01f,
515 1000000.0f,
516 "%.2f"
517 );
518
519 if (positionChanged) {
520 auto* position = cameraEntity.get<Position3DComponent>();
521 if (position) {
522 position->setValue(tempPosition_);
523 } else {
524 missingPosition = true;
525 }
526 }
527
528 if (rotationChanged) {
529 missingRotation = !writeYawPitchRollToEntity(cameraEntity);
530 }
531
532 if (projectionChanged) {
533 missingCamera = !writeProjectionToEntity(cameraEntity);
534 }
535
536 ImGui::Spacing();
537 ImGui::BeginDisabled(!resetSnapshot_.valid);
538
539 if (ImGui::Button("Reset selected camera")) {
540 if (resetSnapshot_.hasPosition) {
541 auto* position = cameraEntity.get<Position3DComponent>();
542 if (position) {
543 position->setValue(resetSnapshot_.position);
544 tempPosition_ = resetSnapshot_.position;
545 } else {
546 missingPosition = true;
547 }
548 }
549
550 if (resetSnapshot_.hasRotation) {
551 tempRotation_ = resetSnapshot_.rotation;
552 missingRotation = !writeYawPitchRollToEntity(cameraEntity);
553 }
554
555 if (resetSnapshot_.hasPerspective) {
556 auto* perspective = cameraEntity.get<PerspectiveCameraComponent>();
557 if (perspective) {
558 perspective->setPerspective(
559 helios::math::radians(resetSnapshot_.fovYDegrees),
560 resetSnapshot_.aspectRatio,
561 resetSnapshot_.zNear,
562 resetSnapshot_.zFar
563 );
564
565 tempFovDegrees_ = resetSnapshot_.fovYDegrees;
566 tempAspectRatio_ = resetSnapshot_.aspectRatio;
567 tempZNear_ = resetSnapshot_.zNear;
568 tempZFar_ = resetSnapshot_.zFar;
569 } else {
570 missingCamera = true;
571 }
572 }
573 }
574
575 ImGui::EndDisabled();
576
577 if (missingPosition || missingRotation || missingCamera) {
578 ImGui::Separator();
579 ImGui::TextColored(
580 ImVec4(1.0f, 0.75f, 0.2f, 1.0f),
581 "Missing component(s): values could not be written."
582 );
583
584 if (missingPosition) {
585 ImGui::TextDisabled("- Position3DComponent");
586 }
587
588 if (missingRotation) {
589 ImGui::TextDisabled("- YawPitchRollComponent");
590 }
591
592 if (missingCamera) {
593 ImGui::TextDisabled("- PerspectiveCameraComponent");
594 }
595 }
596
597 ImGui::Separator();
598 ImGui::TextDisabled(
599 "Handle: entityId=%u versionId=%u",
600 cameraHandle_.entityId,
601 cameraHandle_.versionId
602 );
603
604 ImGui::End();
605 }

Private Member Functions

captureSnapshot()

template <typename TEntity>
CameraSnapshot helios::imgui::widgets::CameraWidget::captureSnapshot (const TEntity & entity)
inline noexcept

Definition at line 237 of file CameraWidget.ixx.

237 [[nodiscard]] CameraSnapshot captureSnapshot(const TEntity& entity) const noexcept {
238 CameraSnapshot snapshot{};
239 snapshot.valid = true;
240
241 if (const auto* position = entity.template get<Position3DComponent>()) {
242 snapshot.hasPosition = true;
243 snapshot.position = position->value();
244 }
245
246 if (const auto* yawPitchRoll = entity.template get<YawPitchRollComponent>()) {
247 snapshot.hasRotation = true;
248 snapshot.rotation = helios::math::vec3f{
249 yawPitchRoll->yaw,
250 yawPitchRoll->pitch,
251 yawPitchRoll->roll
252 };
253 }
254
255 if (const auto* camera = entity.template get<PerspectiveCameraComponent>()) {
256 snapshot.hasPerspective = true;
257 snapshot.fovYDegrees = helios::math::degrees(camera->fovY());
258 snapshot.aspectRatio = camera->aspectRatio();
259 snapshot.zNear = camera->zNear();
260 snapshot.zFar = camera->zFar();
261 }
262
263 return snapshot;
264 }

makeViewportCameraLabel()

std::string helios::imgui::widgets::CameraWidget::makeViewportCameraLabel (const ViewportHandle viewportHandle, const GameObjectHandle cameraHandle)
inline

Definition at line 117 of file CameraWidget.ixx.

117 [[nodiscard]] std::string makeViewportCameraLabel(
118 const ViewportHandle viewportHandle,
119 const GameObjectHandle cameraHandle
120 ) {
121 auto viewportEntity = gameWorld_->find(viewportHandle);
122 auto cameraEntity = gameWorld_->find(cameraHandle);
123
124 auto* viewportDebugNameCmp = viewportEntity
125 ? viewportEntity->get<DebugNameComponent<ViewportHandle>>()
126 : nullptr;
127
128 auto* cameraDebugNameCmp = cameraEntity
129 ? cameraEntity->get<DebugNameComponent<GameObjectHandle>>()
130 : nullptr;
131
132 return (viewportDebugNameCmp
133 ? viewportDebugNameCmp->value
134 : "Viewport " + std::to_string(viewportHandle.entityId))
135 + " -> "
136 + (cameraDebugNameCmp
137 ? cameraDebugNameCmp->value
138 : "Camera " + std::to_string(cameraHandle.entityId));
139 }

refreshViewportCameraEntries()

void helios::imgui::widgets::CameraWidget::refreshViewportCameraEntries ()
inline

Definition at line 141 of file CameraWidget.ixx.

141 void refreshViewportCameraEntries() {
142 const auto previousCameraHandle = cameraHandle_;
143 ViewportHandle previousViewportHandle{};
144 bool hasPreviousViewport = false;
145
146 if (selectedViewportCameraIndex_ >= 0
147 && selectedViewportCameraIndex_ < static_cast<int>(viewportCameraEntries_.size())) {
148 previousViewportHandle = viewportCameraEntries_[selectedViewportCameraIndex_].viewportHandle;
149 hasPreviousViewport = true;
150 }
151
152 viewportCameraEntries_.clear();
153
154 if (!gameWorld_) {
155 selectedViewportCameraIndex_ = -1;
156 cameraHandle_ = {};
157 syncedFromEntity_ = false;
158 return;
159 }
160
161 for (auto [viewportEntity, cameraBinding] :
162 gameWorld_->view<ViewportHandle, ViewportCameraBindingComponent>()) {
163
164 const auto viewportHandle = viewportEntity.handle();
165 const auto boundCameraHandle = cameraBinding->targetHandle();
166
167 viewportCameraEntries_.push_back(ViewportCameraEntry{
168 viewportHandle,
169 boundCameraHandle,
170 makeViewportCameraLabel(viewportHandle, boundCameraHandle)
171 });
172 }
173
174 if (viewportCameraEntries_.empty()) {
175 selectedViewportCameraIndex_ = -1;
176 cameraHandle_ = {};
177 syncedFromEntity_ = false;
178 return;
179 }
180
181 int matchingIndex = -1;
182
183 if (hasPreviousViewport) {
184 for (int i = 0; i < static_cast<int>(viewportCameraEntries_.size()); ++i) {
185 if (viewportCameraEntries_[i].viewportHandle == previousViewportHandle) {
186 matchingIndex = i;
187 break;
188 }
189 }
190 }
191
192 if (matchingIndex < 0) {
193 for (int i = 0; i < static_cast<int>(viewportCameraEntries_.size()); ++i) {
194 if (viewportCameraEntries_[i].cameraHandle == previousCameraHandle) {
195 matchingIndex = i;
196 break;
197 }
198 }
199 }
200
201 if (matchingIndex < 0) {
202 matchingIndex = 0;
203 }
204
205 if (selectedViewportCameraIndex_ != matchingIndex) {
206 selectedViewportCameraIndex_ = matchingIndex;
207 cameraHandle_ = viewportCameraEntries_[selectedViewportCameraIndex_].cameraHandle;
208
213 syncedFromEntity_ = false;
214 }
215 }

selectViewportCameraIndex()

void helios::imgui::widgets::CameraWidget::selectViewportCameraIndex (const int index)
inline

Definition at line 217 of file CameraWidget.ixx.

217 void selectViewportCameraIndex(const int index) {
218 if (index < 0 || index >= static_cast<int>(viewportCameraEntries_.size())) {
219 return;
220 }
221
222 if (selectedViewportCameraIndex_ == index) {
223 return;
224 }
225
226 selectedViewportCameraIndex_ = index;
227 cameraHandle_ = viewportCameraEntries_[selectedViewportCameraIndex_].cameraHandle;
228
233 syncedFromEntity_ = false;
234 }

syncFromEntity()

template <typename TEntity>
void helios::imgui::widgets::CameraWidget::syncFromEntity (TEntity & entity)
inline noexcept

Definition at line 267 of file CameraWidget.ixx.

267 void syncFromEntity(TEntity& entity) noexcept {
268 if (auto* position = entity.template get<Position3DComponent>()) {
269 tempPosition_ = position->value();
270 }
271
272 if (auto* yawPitchRoll = entity.template get<YawPitchRollComponent>()) {
273 tempRotation_ = helios::math::vec3f{
274 yawPitchRoll->yaw,
275 yawPitchRoll->pitch,
276 yawPitchRoll->roll
277 };
278 }
279
280 if (auto* camera = entity.template get<PerspectiveCameraComponent>()) {
281 tempFovDegrees_ = helios::math::degrees(camera->fovY());
282 tempAspectRatio_ = camera->aspectRatio();
283 tempZNear_ = camera->zNear();
284 tempZFar_ = camera->zFar();
285 }
286 }

writeProjectionToEntity()

template <typename TEntity>
bool helios::imgui::widgets::CameraWidget::writeProjectionToEntity (TEntity & entity)
inline

Definition at line 289 of file CameraWidget.ixx.

289 bool writeProjectionToEntity(TEntity& entity) {
290 if (tempZNear_ <= 0.0f) {
291 tempZNear_ = 0.001f;
292 }
293
294 if (tempZFar_ <= tempZNear_) {
295 tempZFar_ = tempZNear_ + 0.01f;
296 }
297
298 if (tempAspectRatio_ <= 0.0f) {
299 tempAspectRatio_ = 1.0f;
300 }
301
302 auto* camera = entity.template get<PerspectiveCameraComponent>();
303 if (!camera) {
304 return false;
305 }
306
307 camera->setPerspective(
308 helios::math::radians(tempFovDegrees_),
309 tempAspectRatio_,
310 tempZNear_,
311 tempZFar_
312 );
313
314 return true;
315 }

writeYawPitchRollToEntity()

template <typename TEntity>
bool helios::imgui::widgets::CameraWidget::writeYawPitchRollToEntity (TEntity & entity)
inline

Definition at line 318 of file CameraWidget.ixx.

318 bool writeYawPitchRollToEntity(TEntity& entity) {
319 auto* yawPitchRoll = entity.template get<YawPitchRollComponent>();
320 if (!yawPitchRoll) {
321 return false;
322 }
323
324 yawPitchRoll->yaw = tempRotation_[0];
325 yawPitchRoll->pitch = tempRotation_[1];
326 yawPitchRoll->roll = tempRotation_[2];
327
328 return true;
329 }

Private Member Attributes

cameraHandle_

GameObjectHandle helios::imgui::widgets::CameraWidget::cameraHandle_ {}

Definition at line 93 of file CameraWidget.ixx.

93 GameObjectHandle cameraHandle_{};

gameWorld_

GameWorld* helios::imgui::widgets::CameraWidget::gameWorld_ = nullptr

Definition at line 92 of file CameraWidget.ixx.

92 GameWorld* gameWorld_ = nullptr;

resetSnapshot_

CameraSnapshot helios::imgui::widgets::CameraWidget::resetSnapshot_ {}

Definition at line 115 of file CameraWidget.ixx.

115 CameraSnapshot resetSnapshot_{};

selectedViewportCameraIndex_

int helios::imgui::widgets::CameraWidget::selectedViewportCameraIndex_ = -1

Definition at line 95 of file CameraWidget.ixx.

95 int selectedViewportCameraIndex_ = -1;

syncedFromEntity_

bool helios::imgui::widgets::CameraWidget::syncedFromEntity_ = false

Definition at line 114 of file CameraWidget.ixx.

114 bool syncedFromEntity_ = false;

tempAspectRatio_

float helios::imgui::widgets::CameraWidget::tempAspectRatio_ = 16.0f / 9.0f

Definition at line 110 of file CameraWidget.ixx.

110 float tempAspectRatio_ = 16.0f / 9.0f;

tempFovDegrees_

float helios::imgui::widgets::CameraWidget::tempFovDegrees_ = 90.0f

Definition at line 109 of file CameraWidget.ixx.

109 float tempFovDegrees_ = 90.0f;

tempPosition_

helios::math::vec3f helios::imgui::widgets::CameraWidget::tempPosition_ {0.0f, 0.0f, 1.0f}

Definition at line 97 of file CameraWidget.ixx.

97 helios::math::vec3f tempPosition_{0.0f, 0.0f, 1.0f};

tempRotation_

helios::math::vec3f helios::imgui::widgets::CameraWidget::tempRotation_ {0.0f, 0.0f, 0.0f}

First-person control state in radians.

Stored as:

  • x: yaw
  • y: pitch
  • z: roll

Definition at line 107 of file CameraWidget.ixx.

107 helios::math::vec3f tempRotation_{0.0f, 0.0f, 0.0f};

tempZFar_

float helios::imgui::widgets::CameraWidget::tempZFar_ = 1000.0f

Definition at line 112 of file CameraWidget.ixx.

112 float tempZFar_ = 1000.0f;

tempZNear_

float helios::imgui::widgets::CameraWidget::tempZNear_ = 0.1f

Definition at line 111 of file CameraWidget.ixx.

111 float tempZNear_ = 0.1f;

viewportCameraEntries_

std::vector<ViewportCameraEntry> helios::imgui::widgets::CameraWidget::viewportCameraEntries_ {}

Definition at line 94 of file CameraWidget.ixx.

94 std::vector<ViewportCameraEntry> viewportCameraEntries_{};

The documentation for this class was generated from the following file:


Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.