diff --git a/Client/App/App.vcproj b/Client/App/App.vcproj
index 813b5c2f..7e86a783 100644
--- a/Client/App/App.vcproj
+++ b/Client/App/App.vcproj
@@ -804,11 +804,11 @@
-
-
+
-
+
@@ -1286,6 +1286,10 @@
RelativePath=".\v8datamodel\BrickColor.cpp"
>
+
+
diff --git a/Client/App/include/util/Extents.h b/Client/App/include/util/Extents.h
index 8e28bb5f..b711c765 100644
--- a/Client/App/include/util/Extents.h
+++ b/Client/App/include/util/Extents.h
@@ -42,7 +42,11 @@ namespace RBX
NormalId closestFace(const G3D::Vector3& point);
void unionWith(const Extents& other);
void shift(const G3D::Vector3&);
- void scale(float);
+ void scale(float scale)
+ {
+ this->low *= scale;
+ this->high *= scale;
+ }
void expand(float f)
{
this->low -= G3D::Vector3(f, f, f);
diff --git a/Client/App/include/v8datamodel/Camera.h b/Client/App/include/v8datamodel/Camera.h
index 0651b621..6e3c8e12 100644
--- a/Client/App/include/v8datamodel/Camera.h
+++ b/Client/App/include/v8datamodel/Camera.h
@@ -1,9 +1,9 @@
#pragma once
-#include "v8tree/Instance.h"
#include
#include
#include
#include
+#include "v8tree/Instance.h"
#include "util/Extents.h"
namespace RBX
@@ -54,17 +54,17 @@ namespace RBX
void updateFocus();
void updateGoal();
bool characterZoom(float);
- bool nonCharacterZoom(float);
- void tryZoomExtents(float, float, float, const Extents&, const G3D::Rect2D&);
+ bool nonCharacterZoom(float in);
+ void tryZoomExtents(float low, float current, float high, const RBX::Extents& extents, const G3D::Rect2D& viewPort);
ContactManager& getContactManager();
float goalToFocusDistance() const;
void setGCameraCoordinateFrame(const G3D::CoordinateFrame&);
G3D::CoordinateFrame computeLineOfSiteGoal();
- void getHeadingElevationDistance(float&, float&, float&);
+ void getHeadingElevationDistance(float& heading, float& elevation, float& distance);
void setHeadingElevationDistance(float, float, float);
void tellCameraMoved();
void getIgnorePrims(G3D::Array&);
- virtual bool askSetParent(const Instance*) const;
+ virtual bool askSetParent(const Instance* instance) const;
public:
//Camera(const Camera&);
Camera();
@@ -81,29 +81,32 @@ namespace RBX
bool isFirstPersonCamera() const;
ICameraSubject* getCameraSubject() const;
Instance* getCameraSubjectInstance() const;
- void setCameraSubject(Instance*);
- const G3D::CoordinateFrame& getCameraFocus() const;
- void setCameraFocus(const G3D::CoordinateFrame&);
+ void setCameraSubject(Instance* newSubject);
+ const G3D::CoordinateFrame& getCameraFocus() const
+ {
+ return cameraFocus;
+ }
+ void setCameraFocus(const G3D::CoordinateFrame& value);
G3D::CoordinateFrame getCameraCoordinateFrame() const
{
return gCamera.getCoordinateFrame();
}
- void setCameraCoordinateFrameNoLerp(const G3D::CoordinateFrame&);
+ void setCameraCoordinateFrameNoLerp(const G3D::CoordinateFrame& value);
void goalToCamera();
CameraType getCameraType() const;
- void setCameraType(CameraType);
+ void setCameraType(CameraType type);
bool canZoom(int) const;
bool canTilt(int) const;
void onWrapMouse(const G3D::Vector2&);
- bool zoom(float);
- bool setDistanceFromTarget(float);
- void zoomExtents(Extents, const G3D::Rect2D&, ZoomType);
- bool zoomExtents(const G3D::Rect2D&);
- void panRadians(float);
+ bool zoom(float in);
+ bool setDistanceFromTarget(float newDistance);
+ void zoomExtents(Extents extents, const G3D::Rect2D& viewPort, ZoomType zoomType);
+ bool zoomExtents(const G3D::Rect2D& viewPort);
+ void panRadians(float angle);
void panUnits(int);
bool tiltRadians(float);
bool tiltUnits(int);
- void lookAt(const G3D::Vector3&);
+ void lookAt(const G3D::Vector3& point);
void setImageServerViewNoLerp(const G3D::CoordinateFrame&, const G3D::Rect2D&);
public:
//Camera& operator=(const Camera&);
diff --git a/Client/App/v8datamodel/Camera.cpp b/Client/App/v8datamodel/Camera.cpp
new file mode 100644
index 00000000..0bddea9d
--- /dev/null
+++ b/Client/App/v8datamodel/Camera.cpp
@@ -0,0 +1,446 @@
+#include "v8datamodel/Camera.h"
+#include "v8datamodel/Workspace.h"
+#include "v8datamodel/ICharacterSubject.h"
+#include "util/Math.h"
+
+namespace RBX
+{
+ const char* sCamera = "Camera";
+
+ static const Reflection::EnumPropDescriptor desc_cameraType("CameraType", "Camera", &Camera::getCameraType, &Camera::setCameraType, Reflection::PropertyDescriptor::STANDARD);
+ static const Reflection::PropDescriptor desc_CoordFrame("CoordinateFrame", "Data", &Camera::getCameraCoordinateFrame, &Camera::setCameraCoordinateFrameNoLerp, Reflection::PropertyDescriptor::STREAMING);
+ static const Reflection::PropDescriptor desc_Focus("Focus", "Data", &Camera::getCameraFocus, &Camera::setCameraFocus, Reflection::PropertyDescriptor::STREAMING);
+ static const Reflection::RefPropDescriptor cameraSubjectProp("CameraSubject", "Camera", &Camera::getCameraSubjectInstance, &Camera::setCameraSubject, Reflection::PropertyDescriptor::STANDARD);
+
+ Camera::Camera()
+ : Base(),
+ cameraFocus(G3D::Vector3(0, 0, -5)),
+ cameraType(FIXED_CAMERA),
+ animationType(AUTO),
+ cameraExternallyAdjusted(false)
+ {
+ setName("Camera");
+ gCamera.setNearPlaneZ(1.25);
+ gCamera.setFarPlaneZ(5000);
+ gCamera.setFieldOfView(G3D::toRadians(60));
+
+ G3D::CoordinateFrame cameraCoord(G3D::Vector3(0, 5, 5));
+ cameraCoord.lookAt(G3D::Vector3::zero());
+
+ if (Math::legalCameraCoord(cameraCoord))
+ {
+ gCamera.setCoordinateFrame(cameraCoord);
+ }
+ else
+ {
+ RBXASSERT(0);
+ }
+ }
+
+ Camera::~Camera()
+ {
+ }
+
+ bool Camera::askSetParent(const Instance* instance) const
+ {
+ return fastDynamicCast(instance) != NULL;
+ }
+
+ ICameraOwner* Camera::getCameraOwner()
+ {
+ Instance* instance = getParent();
+ while (instance != NULL)
+ {
+ ICameraOwner* cameraOwner = fastDynamicCast(instance);
+ if (cameraOwner)
+ return cameraOwner;
+
+ instance = getParent();
+ }
+
+ return NULL;
+ }
+
+ void Camera::lookAt(const G3D::Vector3& point)
+ {
+ cameraFocus.translation = point;
+ cameraGoal.lookAt(point);
+ }
+
+ void Camera::getHeadingElevationDistance(float& heading, float& elevation, float& distance)
+ {
+ Math::getHeadingElevation(cameraGoal, heading, elevation);
+ distance = (cameraGoal.translation - cameraFocus.translation).magnitude();
+ }
+
+ //70.53% matching.
+ bool Camera::setDistanceFromTarget(float newDistance)
+ {
+ G3D::Vector3 lookVector = cameraFocus.translation - cameraGoal.translation;
+ float currentDistance = lookVector.magnitude();
+
+ if (newDistance < 0.5 && currentDistance == 0.5 || newDistance > 1000.0 && currentDistance == 1000.0)
+ return false;
+
+ newDistance = (newDistance < 0.5) ? 0.5 : newDistance;
+ newDistance = (newDistance > 1000.0) ? 1000.0 : newDistance;
+
+ lookVector *= newDistance;
+ cameraGoal.translation = cameraFocus.translation - (lookVector / currentDistance);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+
+ return true;
+ }
+
+ void Camera::alwaysMode()
+ {
+ animationType = ALWAYS;
+ }
+
+ bool Camera::nonCharacterZoom(float in)
+ {
+ G3D::Vector3 lookVector = cameraFocus.translation - cameraGoal.translation;
+
+ float currentDistance = lookVector.magnitude();
+ float newZoomDistance = getNewZoomDistance(currentDistance, in);
+
+ if (currentDistance == newZoomDistance)
+ return false;
+
+ cameraGoal.translation -= lookVector * (newZoomDistance / currentDistance - 1.0f);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+
+ return true;
+ }
+
+ void Camera::setHeadingElevationDistance(float heading, float elevation, float distance)
+ {
+ Math::setHeadingElevation(cameraGoal, heading, elevation);
+ cameraFocus.rotation = cameraGoal.rotation;
+
+ G3D::Vector3 lookVector = cameraFocus.lookVector();
+ cameraGoal.translation = cameraFocus.translation - lookVector * distance;
+ cameraExternallyAdjusted = true;
+ }
+
+ void Camera::panRadians(float angle)
+ {
+ RBXASSERT(angle > -100);
+ RBXASSERT(angle < 100);
+
+ if (angle != 0)
+ {
+ float heading, elevation, distance;
+
+ getHeadingElevationDistance(heading, elevation, distance);
+ heading = Math::radWrap(heading + angle);
+ setHeadingElevationDistance(heading, elevation, distance);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ void Camera::updateFocus()
+ {
+ cameraFocus = getCameraSubject()->getLocation();
+ }
+
+ //87.80% matching.
+ void Camera::updateGoal()
+ {
+ switch(cameraType)
+ {
+ case WATCH_CAMERA:
+ {
+ updateFocus();
+ break;
+ }
+ case ATTACH_CAMERA:
+ {
+ G3D::Vector3 v1 = cameraGoal.translation - cameraFocus.translation;
+ double distance = v1.xz().length();
+
+ updateFocus();
+
+ G3D::Vector2 direction = cameraFocus.lookVector().xz().direction();
+
+ cameraGoal.translation = G3D::Vector3(cameraFocus.translation.x - direction.x * distance,
+ cameraFocus.translation.y + v1.y,
+ cameraFocus.translation.z - direction.y * distance);
+ break;
+ }
+ case TRACK_CAMERA:
+ {
+ G3D::Vector3 v1 = cameraFocus.translation;
+
+ updateFocus();
+
+ cameraGoal.translation += cameraFocus.translation - v1;
+ break;
+ }
+ case FOLLOW_CAMERA:
+ {
+ G3D::Vector3 v1 = cameraFocus.translation - cameraGoal.translation;
+ double distance = v1.xz().length();
+
+ updateFocus();
+
+ G3D::Vector2 direction = (cameraGoal.translation.xz() - cameraFocus.translation.xz()).direction();
+
+ cameraGoal.translation = G3D::Vector3(cameraFocus.translation.x - direction.x * distance,
+ cameraFocus.translation.y - v1.y,
+ cameraFocus.translation.z - direction.y * distance);
+
+ break;
+ }
+ case CUSTOM_CAMERA:
+ {
+ ICameraSubject* cameraSubject = getCameraSubject();
+ if(cameraSubject)
+ cameraSubject->stepGoalAndFocus(cameraGoal, cameraFocus, cameraExternallyAdjusted);
+ cameraExternallyAdjusted = false;
+ break;
+ }
+ }
+ cameraGoal.lookAt(cameraFocus.translation);
+ }
+
+ bool Camera::zoom(float in)
+ {
+ if (cameraType == CUSTOM_CAMERA)
+ {
+ ICameraSubject* cameraSubject = getCameraSubject();
+ if (cameraSubject)
+ return cameraSubject->zoom(in, cameraGoal, cameraFocus);
+ }
+ else if (getCameraSubjectInstance() &&
+ (cameraType == FOLLOW_CAMERA ||
+ cameraType == ATTACH_CAMERA ||
+ cameraType == TRACK_CAMERA))
+ {
+ return characterZoom(in);
+ }
+ else
+ {
+ return nonCharacterZoom(in);
+ }
+
+ return false;
+ }
+
+ void Camera::onHeartbeat()
+ {
+ updateGoal();
+ G3D::CoordinateFrame adjustedGoal = cameraGoal;
+ ICameraSubject* cameraSubject = getCameraSubject();
+ ICharacterSubject* characterSubject = dynamic_cast(cameraSubject);
+
+ if (characterSubject)
+ characterSubject->onHeartBeat(cameraGoal, cameraFocus);
+
+ G3D::CoordinateFrame cameraCoord = gCamera.getCoordinateFrame();
+ G3D::CoordinateFrame LerpFrame = cameraCoord.lerp(adjustedGoal, 0.9f);
+
+ if (Math::legalCameraCoord(LerpFrame))
+ {
+ gCamera.setCoordinateFrame(LerpFrame);
+ }
+ else
+ {
+ RBXASSERT(0);
+ }
+
+ if (animationType == ALWAYS || !Math::fuzzyEq(LerpFrame, cameraCoord, 0.01f, 0.01f))
+ {
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ Instance* Camera::getCameraSubjectInstance() const
+ {
+ return cameraSubject.get();
+ }
+
+ ICameraSubject* Camera::getCameraSubject() const
+ {
+ Instance* instance = getCameraSubjectInstance();
+ if (instance)
+ {
+ ICameraSubject* subject = fastDynamicCast(instance);
+ RBXASSERT(subject);
+ return subject;
+ }
+ return NULL;
+ }
+
+ void Camera::autoMode()
+ {
+ if (animationType != AUTO)
+ {
+ animationType = AUTO;
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ void Camera::setCameraType(CameraType type)
+ {
+ if (cameraType != type)
+ {
+ cameraType = type;
+ raisePropertyChanged(desc_cameraType);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ void Camera::setCameraSubject(Instance* newSubject)
+ {
+ if (newSubject != getCameraSubjectInstance())
+ {
+ if (fastDynamicCast(newSubject))
+ {
+ cameraSubject = shared_from((ModelInstance*) newSubject);
+ raisePropertyChanged(cameraSubjectProp);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+ }
+
+ void Camera::setCameraFocus(const G3D::CoordinateFrame& value)
+ {
+ if (value != cameraFocus)
+ {
+ cameraFocus = value;
+ raisePropertyChanged(desc_Focus);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ void Camera::goalToCamera()
+ {
+ if (gCamera.getCoordinateFrame() != cameraGoal)
+ {
+ cameraExternallyAdjusted = true;
+ if (Math::legalCameraCoord(cameraGoal))
+ {
+ gCamera.setCoordinateFrame(cameraGoal);
+ }
+ else
+ {
+ RBXASSERT(0);
+ }
+ raisePropertyChanged(desc_CoordFrame);
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ //84.84% matching.
+ void Camera::tryZoomExtents(float low, float current, float high, const RBX::Extents& extents, const G3D::Rect2D& viewPort)
+ {
+ RBXASSERT(current >= low);
+ RBXASSERT(current <= high);
+
+ if (high - low > 0.1)
+ {
+ setDistanceFromTarget(current);
+ updateGoal();
+ goalToCamera();
+
+ bool isContained = extents.containedByFrustum(gCamera.frustum(viewPort));
+
+ float newLow = (isContained) ? low : current;
+ float newHigh = (isContained) ? current : high;
+ float newCurrent = (newHigh + newLow) * 0.5;
+
+ tryZoomExtents(newLow, newCurrent, newHigh, extents, viewPort);
+ }
+ }
+
+ //87.82% matching.
+ void Camera::zoomExtents(Extents extents, const G3D::Rect2D& viewPort, Camera::ZoomType zoomType)
+ {
+ G3D::CoordinateFrame currentCoord = gCamera.getCoordinateFrame();
+ extents.expand(0.1f);
+
+ if (zoomType != ZOOM_CHAR_PART_DRAG || cameraType == CUSTOM_CAMERA)
+ {
+ double low = 0.5;
+
+ if (cameraType == FIXED_CAMERA)
+ {
+ G3D::Vector3 scaler = extents.center() - cameraFocus.translation;
+
+ cameraFocus.translation += scaler;
+ cameraGoal.translation += scaler;
+ }
+
+ if (zoomType == ZOOM_OUT_ONLY || zoomType == ZOOM_CHAR_PART_DRAG)
+ low = (cameraGoal.translation - cameraFocus.translation).magnitude();
+
+ double current = (cameraGoal.translation - cameraFocus.translation).magnitude();
+
+ RBXASSERT(G3D::isFinite(current));
+
+ if (zoomType == ZOOM_CHAR_PART_DRAG)
+ extents.scale(1.1f);
+
+ if (G3D::isFinite(low) && G3D::isFinite(current) && G3D::isFinite(1000.0))
+ tryZoomExtents(low, current, 1000.0, extents, viewPort);
+
+ cameraGoal = gCamera.getCoordinateFrame();
+ if (Math::legalCameraCoord(currentCoord))
+ {
+ gCamera.setCoordinateFrame(currentCoord);
+ }
+ else
+ {
+ RBXASSERT(0);
+ }
+
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ owner->cameraMoved();
+ }
+ }
+
+ bool Camera::zoomExtents(const G3D::Rect2D& viewPort)
+ {
+ ICameraOwner* owner = getCameraOwner();
+ if (owner)
+ {
+ zoomExtents(owner->computeCameraOwnerExtents(), viewPort, ZOOM_IN_OR_OUT);
+ return true;
+ }
+ return false;
+ }
+
+ void Camera::setCameraCoordinateFrameNoLerp(const G3D::CoordinateFrame& value)
+ {
+ cameraGoal = value;
+ goalToCamera();
+ }
+}
\ No newline at end of file