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 335 of file CameraWidget.ixx.

335 explicit CameraWidget(GameWorld& gameWorld) noexcept
336 : 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 348 of file CameraWidget.ixx.

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

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 entity.setTrackedValue(camera, helios::math::vec4f{
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 entity.setTrackedValue(yawPitchRoll, tempRotation_);
325 return true;
326 }

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.