-
Notifications
You must be signed in to change notification settings - Fork 71
Cameraz #995
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Cameraz #995
Changes from all commits
cdf867d
6ef4f89
22f505c
51f4ced
7f2c085
f1daa25
2192e99
520b1f5
a0890f0
0109b22
2a29a2f
7673769
fc7bc33
8fc4f89
9a139df
24a80c9
03fa2ca
21b89b4
68bc7be
866e844
8bd6436
de69afe
a55bd39
6f3c5fc
0d126df
31e85e7
08f11f6
5bcd6ef
5a07fe7
f55b268
01f909a
ab90d33
c9f0960
3727ae3
e9f78a2
33f8d01
b3d7710
53f72ec
e3d282b
5124136
fb2ce01
7ce37ba
406fef8
661dae9
183a8fd
a30c409
5f033af
0529f8a
74b8c11
2fdf296
3b68444
b21de61
2693caf
ae315a0
07eeef7
15aa72f
661f999
db1102c
329d98f
52901f2
ba3d7a0
7d81d9c
04ce784
b25a81f
40c1fdb
749175c
037fc08
4b7cbe8
8e76424
69d49fd
1108584
ef5429f
848aabe
7d97b8b
cadefbb
d97f18d
a38d167
3c6fd0e
530883e
abbcfe7
38d92c2
e7b8b4f
5cae47e
23fa6b6
0fb9e90
dac6e97
53f960a
944f5cb
630b7bd
760acaa
7eb2a91
0b50aea
5de70ac
1817146
405b434
37b7075
0314dbf
4a244ca
f12b5b6
3393bbd
fa953f1
90b7c19
1b7a8d8
9cd1fc8
d8776fd
5add016
70e2ce9
e80ef0c
ee188ff
da75579
0b3ec40
1234059
f821947
0bab320
7f78cc2
9a32427
1ac6209
bfae93a
c6fa314
fd191f1
19ebf8b
11d9347
9cfdb18
ca1d35b
eada28c
2bf4590
6289e65
6c0d131
777117d
b88598a
ea56b53
e21be7e
b52527e
36f2668
2cb9950
c257396
7a7172f
d2fe6b1
016c2bf
f783968
c937315
24fc3fb
3cac470
885e330
d74490f
f56a8fb
0068d09
5254830
8c2b795
4182b2d
cc9521f
3a88506
6afa742
5b0e78c
5009f8b
28cc1d3
d5335f2
b582488
e9ac109
f5629c7
f83004a
d825ef2
b9be28a
5f901e7
a80bb82
96e0ccd
7130af4
06b1a4b
33a7793
f89e4f3
8f4cc2f
c92b9b2
89cfa0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O. | ||
| // This file is part of the "Nabla Engine". | ||
| // For conditions of distribution and use, see copyright notice in nabla.h | ||
|
|
||
| #ifndef _C_ARCBALL_CAMERA_HPP_ | ||
| #define _C_ARCBALL_CAMERA_HPP_ | ||
|
|
||
| #include <algorithm> | ||
| #include <cmath> | ||
|
|
||
| #include "CSphericalTargetCamera.hpp" | ||
|
|
||
| namespace nbl::core | ||
| { | ||
|
|
||
| /// @brief Target-relative camera with planar target translation and bounded arcball orbiting. | ||
| /// | ||
| /// The runtime state is inherited from `CSphericalTargetCamera`. Translation | ||
| /// moves the target in the current view plane. Rotation updates orbit yaw and | ||
| /// pitch under a symmetric pitch limit. | ||
| class CArcballCamera final : public CSphericalTargetCamera | ||
| { | ||
| public: | ||
| using base_t = CSphericalTargetCamera; | ||
|
|
||
| CArcballCamera(const hlsl::float64_t3& position, const hlsl::float64_t3& target) | ||
| : base_t(position, target) | ||
| { | ||
| m_orbitUv.y = std::clamp(m_orbitUv.y, MinPitch, MaxPitch); | ||
| applyPose(); | ||
| } | ||
| ~CArcballCamera() = default; | ||
|
|
||
| const typename base_t::CGimbal& getGimbal() override { return m_gimbal; } | ||
|
|
||
| /// @brief Apply one frame of semantic translation and rotation input to the arcball rig. | ||
| virtual bool manipulate(std::span<const CVirtualGimbalEvent> virtualEvents, const hlsl::float64_t4x4* referenceFrame = nullptr) override | ||
| { | ||
| if (not virtualEvents.size() and not referenceFrame) | ||
| return false; | ||
|
|
||
| if (referenceFrame) | ||
| { | ||
| CReferenceTransform reference = {}; | ||
| SCameraTargetRelativeState resolvedState = {}; | ||
| if (!tryExtractReferenceTransform(reference, referenceFrame) || | ||
| !tryResolveReferenceTargetRelativeState(reference, resolvedState)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| resolvedState.orbitUv.y = std::clamp(resolvedState.orbitUv.y, MinPitch, MaxPitch); | ||
| adoptTargetRelativeState(resolvedState); | ||
| } | ||
|
|
||
| const auto impulse = m_gimbal.accumulate<AllowedVirtualEvents>(virtualEvents); | ||
|
|
||
| const auto deltaRotation = scaleVirtualRotation(impulse.dVirtualRotation); | ||
| const auto deltaTranslation = scaleVirtualTranslation(impulse.dVirtualTranslate); | ||
| const double deltaDistance = scaleUnscaledVirtualTranslation(impulse.dVirtualTranslate.z); | ||
|
|
||
| m_orbitUv.x += deltaRotation.y; | ||
| m_orbitUv.y = std::clamp(m_orbitUv.y + deltaRotation.x, MinPitch, MaxPitch); | ||
| m_distance = std::clamp<float>(m_distance + static_cast<float>(deltaDistance), MinDistance, MaxDistance); | ||
|
|
||
| const auto basis = computeBasis(m_orbitUv, m_distance); | ||
| applyPlanarTargetTranslation(deltaTranslation, basis); | ||
|
|
||
| return applyPose(); | ||
| } | ||
|
|
||
| virtual uint32_t getAllowedVirtualEvents() const override { return AllowedVirtualEvents; } | ||
| virtual CameraKind getKind() const override { return CameraKind::Arcball; } | ||
| /// @brief Return the stable user-facing identifier for this concrete camera kind. | ||
| virtual std::string_view getIdentifier() const override { return "Arcball Camera"; } | ||
|
|
||
| static inline constexpr float MinDistance = base_t::MinDistance; | ||
| static inline constexpr float MaxDistance = base_t::MaxDistance; | ||
|
|
||
| private: | ||
|
|
||
| static inline constexpr auto AllowedVirtualEvents = CVirtualGimbalEvent::Translate | CVirtualGimbalEvent::Rotate; | ||
| static inline constexpr double MaxPitch = SCameraTargetRelativeRigDefaults::ArcballPitchLimitRad; | ||
| static inline constexpr double MinPitch = -MaxPitch; | ||
| }; | ||
|
|
||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| #ifndef _C_CAMERA_FILE_UTILITIES_HPP_ | ||
| #define _C_CAMERA_FILE_UTILITIES_HPP_ | ||
|
|
||
| #include <string> | ||
| #include <string_view> | ||
| #include <vector> | ||
|
|
||
| #include "nbl/system/IFile.h" | ||
| #include "nbl/system/ISystem.h" | ||
|
|
||
| namespace nbl::system | ||
| { | ||
|
|
||
| /// @brief Shared file I/O helpers used by camera persistence and scripted-runtime loaders. | ||
| /// | ||
| /// The helpers keep camera-facing persistence code independent from ad-hoc file | ||
| /// handling and provide one place for consistent error propagation. | ||
| struct CCameraFileUtilities final | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To me this doesn't have anything to do with a Camera. it's just reading/writing file into utf8 string.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can drop Camera from the name |
||
| { | ||
| public: | ||
| /// @brief Read a whole file into a byte buffer. | ||
| static inline bool readBinaryFile( | ||
| ISystem& system, | ||
| const path& filePath, | ||
| std::vector<uint8_t>& outPayload, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd use a CPUBuffer here instead of
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CPUBuffer is fine |
||
| std::string* error = nullptr, | ||
| const std::string_view openError = {}) | ||
| { | ||
| ISystem::future_t<core::smart_refctd_ptr<IFile>> future; | ||
| system.createFile(future, filePath, IFile::ECF_READ | IFile::ECF_MAPPABLE); | ||
| auto file = future.acquire(); | ||
| if (!file || !file->get()) | ||
| { | ||
| if (error && !openError.empty()) | ||
| *error = std::string(openError); | ||
| return false; | ||
| } | ||
|
|
||
| auto& input = *file->get(); | ||
| const auto fileSize = input.getSize(); | ||
| outPayload.resize(fileSize); | ||
| if (outPayload.empty()) | ||
| return true; | ||
|
|
||
| IFile::success_t readResult; | ||
| input.read(readResult, outPayload.data(), 0, fileSize); | ||
| if (!static_cast<bool>(readResult)) | ||
| { | ||
| if (error && !openError.empty()) | ||
| *error = std::string(openError); | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| /// @brief Read a whole file and interpret its payload as UTF-8 text. | ||
| static inline bool readTextFile( | ||
| ISystem& system, | ||
| const path& filePath, | ||
| std::string& outText, | ||
| std::string* error = nullptr, | ||
| const std::string_view openError = {}) | ||
| { | ||
| std::vector<uint8_t> payload; | ||
| if (!readBinaryFile(system, filePath, payload, error, openError)) | ||
| return false; | ||
|
|
||
| outText.assign(reinterpret_cast<const char*>(payload.data()), payload.size()); | ||
| return true; | ||
| } | ||
|
|
||
| /// @brief Overwrite a file with the provided text payload. | ||
| static inline bool writeTextFile( | ||
| ISystem& system, | ||
| const path& filePath, | ||
| const std::string_view text) | ||
| { | ||
| ISystem::future_t<core::smart_refctd_ptr<IFile>> future; | ||
| system.createFile(future, filePath, IFile::ECF_WRITE); | ||
| auto file = future.acquire(); | ||
| if (!file || !file->get()) | ||
| return false; | ||
| if (text.empty()) | ||
| return true; | ||
|
|
||
| IFile::success_t writeResult; | ||
| (*file)->write(writeResult, text.data(), 0, text.size()); | ||
| return static_cast<bool>(writeResult); | ||
| } | ||
| }; | ||
|
|
||
| } // namespace nbl::system | ||
|
|
||
| #endif // _C_CAMERA_FILE_UTILITIES_HPP_ | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong namespaces allover
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think Matt and I settled where everything should go yet
IGimbal is not just for cameras, so do we keep everything in ext or move the general parts to core/ui?