diff --git a/harfang/engine/component.cpp b/harfang/engine/component.cpp index 2ca1279..fde520f 100644 --- a/harfang/engine/component.cpp +++ b/harfang/engine/component.cpp @@ -321,6 +321,21 @@ void Scene::SetCameraZNear(ComponentRef ref, float v) { warn("Invalid camera component"); } +void Scene::SetCameraCenterOffset(ComponentRef ref, const Vec2 & offset) { + if (auto *c = GetComponent_(cameras, ref)) + c->center_offset = offset; + else + warn("Invalid camera component"); +} + +Vec2 Scene::GetCameraCenterOffset(ComponentRef ref) const { + if (const auto *c = GetComponent_(cameras, ref)) + return c->center_offset; + + warn("Invalid camera component"); + return {}; +} + bool Camera::IsValid() const { return scene_ref && scene_ref->scene ? scene_ref->scene->IsValidCameraRef(ref) : false; } float Camera::GetZNear() const { @@ -488,6 +503,13 @@ void Camera::SetSize(float v) { warn("Orphaned camera component"); } +void Camera::SetCenterOffset(const Vec2 & offset) { + if (scene_ref && scene_ref->scene) + scene_ref->scene->SetCameraCenterOffset(ref, offset); + else + warn("Orphaned camera component"); +} + Camera Scene::CreateCamera(const float znear, const float zfar, const float fov) { return {scene_ref, cameras.add_ref({{znear, zfar}, fov, false})}; } Camera Scene::CreateOrthographicCamera(const float znear, const float zfar, const float size) { diff --git a/harfang/engine/node.h b/harfang/engine/node.h index 8c50d45..7c1150a 100644 --- a/harfang/engine/node.h +++ b/harfang/engine/node.h @@ -92,6 +92,8 @@ struct Camera { // 16B on 64 bit void SetIsOrthographic(bool v); float GetSize() const; void SetSize(float v); + void SetCenterOffset(const Vec2 & offset); + Vec2 GetCenterOffset() const; intrusive_shared_ptr_st scene_ref; ComponentRef ref; diff --git a/harfang/engine/render_pipeline.cpp b/harfang/engine/render_pipeline.cpp index 59980cc..d32c35b 100644 --- a/harfang/engine/render_pipeline.cpp +++ b/harfang/engine/render_pipeline.cpp @@ -72,10 +72,10 @@ ViewState ComputeOrthographicViewState(const Mat4 &world, float size, float znea return {frustum, proj, view}; } -ViewState ComputePerspectiveViewState(const Mat4 &world, float fov, float znear, float zfar, const Vec2 &aspect_ratio, const Vec2 &offset) { +ViewState ComputePerspectiveViewState(const Mat4 &world, float fov, float znear, float zfar, const Vec2 &aspect_ratio, const Vec2 &offset, const Vec2 & center_offset) { const bgfx::Caps *caps = bgfx::getCaps(); const auto view = InverseFast(world); - const auto proj = ComputePerspectiveProjectionMatrix(znear, zfar, FovToZoomFactor(fov), aspect_ratio, offset); + const auto proj = ComputePerspectiveProjectionMatrix(znear, zfar, FovToZoomFactor(fov), aspect_ratio, offset, center_offset); const auto frustum = MakeFrustum(proj, world); return {frustum, proj, view}; } diff --git a/harfang/engine/render_pipeline.h b/harfang/engine/render_pipeline.h index 7fef660..aa77d96 100644 --- a/harfang/engine/render_pipeline.h +++ b/harfang/engine/render_pipeline.h @@ -59,7 +59,7 @@ struct ViewState { }; ViewState ComputeOrthographicViewState(const Mat4 &world, float size, float znear, float zfar, const Vec2 &aspect_ratio, const Vec2 &offset = {}); -ViewState ComputePerspectiveViewState(const Mat4 &world, float fov, float znear, float zfar, const Vec2 &aspect_ratio, const Vec2 &offset = {}); +ViewState ComputePerspectiveViewState(const Mat4 &world, float fov, float znear, float zfar, const Vec2 &aspect_ratio, const Vec2 &offset = {}, const Vec2 ¢er_offset = {}); Mat4 ComputeBillboardMat4(const Vec3 &pos, const ViewState &view_state, const Vec3 &scale = {1, 1, 1}); diff --git a/harfang/engine/scene.cpp b/harfang/engine/scene.cpp index 58a66c4..9fb8a0f 100644 --- a/harfang/engine/scene.cpp +++ b/harfang/engine/scene.cpp @@ -245,7 +245,7 @@ ViewState Scene::ComputeCameraViewState(NodeRef ref, const Vec2 &aspect_ratio) c if (auto cam_ = GetComponent_(cameras, node_->components[NCI_Camera])) { const auto &world = transform_worlds[trs_ref.idx]; return cam_->ortho ? ComputeOrthographicViewState(world, cam_->size, cam_->zrange.znear, cam_->zrange.zfar, aspect_ratio) - : ComputePerspectiveViewState(world, cam_->fov, cam_->zrange.znear, cam_->zrange.zfar, aspect_ratio); + : ComputePerspectiveViewState(world, cam_->fov, cam_->zrange.znear, cam_->zrange.zfar, aspect_ratio, cam_->center_offset); } else { warn("Invalid node camera"); } diff --git a/harfang/engine/scene.h b/harfang/engine/scene.h index 8af1f61..f50fe9e 100644 --- a/harfang/engine/scene.h +++ b/harfang/engine/scene.h @@ -308,6 +308,8 @@ public: void SetCameraSize(ComponentRef ref, float v); bool GetCameraIsOrthographic(ComponentRef ref) const; void SetCameraIsOrthographic(ComponentRef ref, const bool &v); + void SetCameraCenterOffset(ComponentRef ref, const Vec2 & offset); + Vec2 GetCameraCenterOffset(ComponentRef ref) const; Camera CreateCamera(float znear, float zfar, float fov = Deg(45.f)); Camera CreateOrthographicCamera(float znear, float zfar, float size = 1.f); @@ -739,6 +741,7 @@ private: float fov{Deg(40.f)}; bool ortho{false}; float size{1.f}; + Vec2 center_offset{0.f, 0.f}; }; struct Object_ { diff --git a/harfang/foundation/projection.cpp b/harfang/foundation/projection.cpp index 4e71c19..655235d 100644 --- a/harfang/foundation/projection.cpp +++ b/harfang/foundation/projection.cpp @@ -26,14 +26,17 @@ Mat44 ComputeOrthographicProjectionMatrix(float znear, float zfar, float size, c return {2.f / size / aspect_ratio.x, 0, 0, 0, 0, 2.f / size / aspect_ratio.y, 0, 0, 0, 0, qA, 0, offset.x, offset.y, qB, 1}; } -Mat44 ComputePerspectiveProjectionMatrix(float znear, float zfar, float zoom_factor, const Vec2 &aspect_ratio, const Vec2 &offset) { +Mat44 ComputePerspectiveProjectionMatrix(float znear, float zfar, float zoom_factor, const Vec2 &aspect_ratio, const Vec2 &offset, const Vec2 ¢erOffset) { const NDCInfos &ndc_infos = GetNDCInfos(); const float qA = ndc_infos.homogeneous_depth ? ((zfar + znear) / (zfar - znear)) : (zfar / (zfar - znear)); const float qB = ndc_infos.homogeneous_depth ? (-2 * zfar * znear / (zfar - znear)) : (-qA * znear); - return {zoom_factor / aspect_ratio.x, 0, 0, 0, 0, zoom_factor / aspect_ratio.y, 0, 0, 0, 0, qA, 1, offset.x, offset.y, qB, 0}; + + + return {zoom_factor / aspect_ratio.x, 0, 0, 0, 0, zoom_factor / aspect_ratio.y, 0, 0, centerOffset.x, centerOffset.y, qA, 1, offset.x, offset.y, qB, 0}; } + Mat44 Compute2DProjectionMatrix(float znear, float zfar, float res_x, float res_y, bool y_up) { const NDCInfos &ndc_infos = GetNDCInfos(); diff --git a/harfang/foundation/projection.h b/harfang/foundation/projection.h index 8dcffd5..3fe04cf 100644 --- a/harfang/foundation/projection.h +++ b/harfang/foundation/projection.h @@ -45,7 +45,7 @@ Mat44 ComputeOrthographicProjectionMatrix(float znear, float zfar, float size, c @see ZoomFactorToFov, FovToZoomFactor, ComputeAspectRatioX and ComputeAspectRatioY. */ -Mat44 ComputePerspectiveProjectionMatrix(float znear, float zfar, float zoom_factor, const Vec2 &aspect_ratio, const Vec2 &offset = Vec2::Zero); +Mat44 ComputePerspectiveProjectionMatrix(float znear, float zfar, float zoom_factor, const Vec2 &aspect_ratio, const Vec2 &offset = Vec2::Zero, const Vec2 ¢erOffset = Vec2::Zero); /// Returns a projection matrix from a 2D space to the 3D world, as required by SetViewTransform() for example. Mat44 Compute2DProjectionMatrix(float znear, float zfar, float res_x, float res_y, bool y_up);