Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+409
View File
@@ -0,0 +1,409 @@
#include "render/camera.h"
#include "constants.h"
#include <stdio.h>
namespace render {
const double pctPerSecond = 0.9999;
Camera::Camera()
: radius(300), qd_yaw(0), qd_pitch(0), qd_roll(0), qd_zoom(1), qd_zoom_min_distance(0), positionBound(vec3d(-1e7), vec3d(1e7)), maxDist(1e7),
qd_abs_yaw(0), qd_abs_pitch(0), zNear(1), zFar(1000), fov(0.8), aspect(1), objectCamera(false), linearZoom(false), lockedRotation(true)
{
}
void Camera::yaw(double radians, bool snap) {
if(snap)
rotation = rotation * quaterniond::fromAxisAngle(vec3d::up(), radians);
else
qd_yaw += radians;
}
void Camera::pitch(double radians, bool snap) {
if(snap) {
rotation = rotation * quaterniond::fromAxisAngle(vec3d::right(), radians);
rotation.normalize();
}
else {
qd_pitch += radians;
}
}
void Camera::abs_yaw(double radians, bool snap) {
if(snap) {
rotation = rotation * quaterniond::fromAxisAngle(rotation.inverted() * vec3d::up(), radians);
rotation.normalize();
}
else {
qd_abs_yaw += radians;
}
}
void Camera::abs_yaw_to(double radians, bool snap) {
if(snap) {
double amount = getYaw() - radians;
rotation = rotation * quaterniond::fromAxisAngle(rotation.inverted() * vec3d::up(), amount);
}
else
qd_abs_yaw = getYaw() - radians;
}
void Camera::abs_pitch(double radians, bool snap) {
if(snap) {
rotation = rotation * quaterniond::fromAxisAngle(rotation.inverted() * vec3d::right(), radians);
rotation.normalize();
}
else {
qd_abs_pitch += radians;
}
}
void Camera::abs_pitch_to(double radians, bool snap) {
if(snap) {
double amount = getPitch() - radians;
rotation = rotation * quaterniond::fromAxisAngle(rotation.inverted() * vec3d::right(), amount);
}
else {
qd_abs_pitch = getPitch() - radians;
}
}
void Camera::roll(double radians, bool snap) {
if(snap)
rotation = rotation * quaterniond::fromAxisAngle(vec3d::front(), radians);
else
qd_roll += radians;
}
void Camera::zoom(double factor) {
qd_zoom *= factor;
qd_zoom_point = vec3d();
qd_zoom_min_distance = 0;
}
void Camera::zoomTo(double factor, const vec3d& towards, double minDistance) {
qd_zoom *= factor;
qd_zoom_point = towards;
qd_zoom_line = vec3d();
qd_zoom_min_distance = minDistance;
}
void Camera::zoomAlong(double factor, const vec3d& line) {
qd_zoom *= factor;
qd_zoom_line = line;
qd_zoom_point = vec3d();
qd_zoom_min_distance = 0;
}
void Camera::setRadius(double amount) {
radius = amount;
if(radius > maxDist)
radius = maxDist;
if(radius < 0)
radius = 1.0;
}
double Camera::getRadius() {
return radius;
}
void Camera::move_world(const vec3d& motion) {
qd_world_motion += motion * radius;
}
void Camera::move_world_abs(const vec3d& motion) {
qd_world_motion += motion;
}
void Camera::move_cam(const vec3d& motion) {
qd_cam_motion += motion * radius;
}
void Camera::move_cam_abs(const vec3d& motion) {
qd_cam_motion += motion;
}
void Camera::move_abs(const vec3d& motion) {
qd_abs_motion += motion;
}
void Camera::setPositionBound(const vec3d& minimum, const vec3d& maximum) {
positionBound = AABBoxd(minimum, maximum);
}
void Camera::setMaxDistance(double dist) {
maxDist = dist;
}
void Camera::setRenderConstraints(double ZNear, double ZFar, double FOV, double Aspect, double w, double h) {
zNear = ZNear;
zFar = ZFar;
fov = FOV * (twopi / 360.0);
aspect = Aspect;
pxWidth = w;
pxHeight = h;
}
bool Camera::inverted() {
return getUp().y <= 0;
}
vec3d Camera::getPosition() const {
if(objectCamera)
return center;
else
return center + (rotation * vec3d::front(-radius));
}
vec3d Camera::getMovedPosition(vec3d pos, double pct) const {
//Camera motion
if(qd_cam_motion.getLength() > 0.00001) {
vec3d cam_x = rotation * vec3d::right(); cam_x.normalize();
vec3d cam_y = rotation * vec3d::up(); cam_y.normalize();
vec3d cam_z = rotation * vec3d::front(); cam_z.normalize();
pos += (cam_x * qd_cam_motion.x * pct) + (cam_y * qd_cam_motion.y * pct) + (cam_z * qd_cam_motion.z * pct);
}
//World motion
if(qd_world_motion.getLength() > 0.00001) {
vec3d world_x = rotation * vec3d::right(); world_x.y = 0; world_x.normalize();
vec3d world_y = rotation * vec3d::up(); world_y.x = 0; world_y.z = 0; world_y.normalize();
vec3d world_z = rotation * vec3d::front(); world_z.y = 0; world_z.normalize();
pos += (world_x * qd_world_motion.x * pct) + (world_y * qd_world_motion.y * pct) + (world_z * qd_world_motion.z * pct);
}
//Absolute motion
if(qd_abs_motion.getLength() > 0.00001)
pos += qd_abs_motion * pct;
pos = pos.elementMax(positionBound.minimum).elementMin(positionBound.maximum);
return pos;
}
vec3d Camera::getFinalPosition() const {
return getMovedPosition(getPosition(), 1.0);
}
vec3d Camera::getFacing() const {
return rotation * vec3d::front();
}
vec3d Camera::getRight() const {
return rotation * vec3d::right();
}
vec3d Camera::getUp() const {
return (rotation * vec3d::up()).normalized();
}
quaterniond Camera::getRotation() const {
return rotation;
}
vec3d Camera::getLookAt() const {
return center;
}
vec3d Camera::getFinalLookAt() const {
return getMovedPosition(getLookAt(), 1.0);
}
double Camera::getDistance() const {
return radius;
}
double Camera::getYaw() const {
vec3d rotated = rotation * vec3d::front();
return atan2(rotated.z, rotated.x);
}
double Camera::getPitch() const {
return 0.0;
}
double Camera::getRoll() const {
return 0.0;
}
vec2i Camera::screenPos(const vec3d& point) const {
//Transform to camera space
vec3d transformed = rotation.inverted() * (point - getPosition());
//Transform to OpenGL's space
vec3d converted = vec3d(vec3d::right().dot(transformed), vec3d::up().dot(transformed), -vec3d::front().dot(transformed));
Matrix projection = Matrix::projection(fov / (twopi / 360.0), aspect, zNear, zFar);
//Apply projection and return final result (Left-Right and Top-Bottom are x[-1,1] and y[-1,1])
vec4d pos = projection * vec4d(converted.x, converted.y, converted.z, 1.0);
pos.x /= -pos.w; pos.y /= -pos.w;
return vec2i((int)(pxWidth * (pos.x + 1.0) * 0.5), (int)(pxHeight * (pos.y + 1.0) * 0.5));
}
double Camera::screenAngle(const vec3d& toPoint) const {
quaterniond inv = rotation.inverted();
vec3d cam = inv * center;
vec3d pos = inv * toPoint;
vec2d flatOffset(cam.x - pos.x, pos.y - cam.y);
return flatOffset.radians() / pi;
}
line3dd Camera::screenToRay(double x, double y) const {
double tan_fov = tan(fov/2.0);
vec3d view_dir =
vec3d::front(1.0)
+ vec3d::right(tan_fov * 2.0 * (0.5-x) * aspect)
+ vec3d::up(tan_fov * 2.0 * (0.5-y));
view_dir = rotation * view_dir.normalized();
vec3d start = view_dir * zNear, end = view_dir * zFar;
vec3d camPos = getPosition();
start += camPos; end += camPos;
return line3dd(start, end);
}
void Camera::setLockedRotation(bool locked) {
lockedRotation = locked;
}
void Camera::animatePercentage(double pct) {
{ //Rotation
auto prevRot = rotation;
auto rotLock = [&prevRot,this]() {
if(lockedRotation && (rotation * vec3d::up()).y < 0.001)
rotation = prevRot;
else
prevRot = rotation;
};
if(fabs(qd_abs_pitch) > 0.00001)
rotation = rotation * quaterniond::fromAxisAngle(rotation.inverted() * vec3d::right(), pct * qd_abs_pitch);
qd_abs_pitch *= 1.0 - pct;
rotLock();
if(fabs(qd_pitch) > 0.00001)
rotation = rotation * quaterniond::fromAxisAngle(vec3d::right(), pct * qd_pitch);
qd_pitch *= 1.0 - pct;
rotLock();
if(fabs(qd_roll) > 0.00001)
rotation = rotation * quaterniond::fromAxisAngle(vec3d::front(), pct * qd_roll);
qd_roll *= 1.0 - pct;
rotLock();
//Quaternion rotations
if(fabs(qd_yaw) > 0.00001)
rotation = rotation * quaterniond::fromAxisAngle(vec3d::up(), pct * qd_yaw);
qd_yaw *= 1.0 - pct;
//Absolute rotations around world axes
if(fabs(qd_abs_yaw) > 0.00001)
rotation = rotation * quaterniond::fromAxisAngle(rotation.inverted() * vec3d::up(), pct * qd_abs_yaw);
qd_abs_yaw *= 1.0 - pct;
rotation.normalize();
}
center = getMovedPosition(center, pct);
//Move the center of the camera
qd_cam_motion *= 1.0 - pct;
qd_world_motion *= 1.0 - pct;
qd_abs_motion *= 1.0 - pct;
//Zoom level
if(fabs(qd_zoom-1) > 0.00001) {
if(linearZoom) {
double dest = (qd_zoom * radius);
double zoomDist = dest - radius;
radius += pct * zoomDist;
qd_zoom = dest / radius;
}
else {
double doZoom = pow(qd_zoom, pct);
qd_zoom /= doZoom;
radius *= doZoom;
if(!qd_zoom_line.zero()) {
//Screw you and your entire 3D vector family
}
else if(!qd_zoom_point.zero()) {
center = qd_zoom_point.interpolate(center, doZoom);
}
}
if(radius > maxDist)
radius = maxDist;
if(radius < qd_zoom_min_distance)
radius = qd_zoom_min_distance;
}
else {
qd_zoom = 1;
}
}
void Camera::animate(double seconds) {
//Interpolate the camera's current state to its destination state
if(seconds <= 0)
return;
double pct = 1.0 - pow(1.0 - pctPerSecond,seconds);
animatePercentage(pct);
}
void Camera::snap() {
animatePercentage(1.0);
}
void Camera::snapTranslation() {
center = getMovedPosition(center, 1.0);
//Move the center of the camera
qd_cam_motion *= 0.0;
qd_world_motion *= 0.0;
qd_abs_motion *= 0.0;
}
void Camera::toLookAt(vec3d& cameraPosition, vec3d& cameraLookAt, vec3d& cameraUp) const {
cameraPosition = getPosition();
cameraLookAt = cameraPosition + getFacing();
cameraUp = getUp();
}
void Camera::setObjectCamera(bool ObjectCamera) {
objectCamera = ObjectCamera;
}
void Camera::setLinearZoom(bool linear) {
linearZoom = linear;
}
void Camera::resetRotation() {
//TODO: Make this calculate the required yaw/pitch/roll to
//reset back to defaults, so that this can be animated instead
//of always needing to snap.
rotation = quaterniond();
qd_yaw = 0;
qd_pitch = 0;
qd_roll = 0;
qd_zoom = 1;
}
void Camera::resetZoom() {
qd_zoom = 1;
radius = 300;
}
};