Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
//Adds functionality to the normal engine camera to make it
|
||||
//more intelligent and context-sensitive
|
||||
|
||||
import double getElevation(double x, double z) from "navigation.elevation";
|
||||
import double getAverageElevation() from "navigation.elevation";
|
||||
import bool getElevationIntersect(const line3dd& line, vec3d& point) from "navigation.elevation";
|
||||
import Object@ get_hoveredObject() from "obj_selection";
|
||||
import saving;
|
||||
|
||||
bool CAM_PANNED = false;
|
||||
bool CAM_ZOOMED = false;
|
||||
bool CAM_ROTATED = false;
|
||||
|
||||
double OBJLOCK_ZOOMDIST = 5.0;
|
||||
|
||||
class SmartCamera : Savable {
|
||||
//Main engine camera
|
||||
Camera camera;
|
||||
|
||||
//Configuration
|
||||
double camAnglesPerPixel;
|
||||
double movePerPixel;
|
||||
double tickZoom;
|
||||
|
||||
//Object locks
|
||||
Object@ lockedObject;
|
||||
vec3d lockOffset;
|
||||
|
||||
SmartCamera() {
|
||||
camAnglesPerPixel = 0.22 * twopi / 360.0;
|
||||
movePerPixel = 8.0;
|
||||
tickZoom = 1.2;
|
||||
camera.setPositionBound(vec3d(-200000), vec3d(200000));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
//Set the camera to the normal angle
|
||||
camera.resetRotation();
|
||||
camera.resetZoom();
|
||||
camera.zoom(5.0);
|
||||
camera.pitch(0.7);
|
||||
camera.snap();
|
||||
}
|
||||
|
||||
vec3d get_lookAt() {
|
||||
return camera.lookAt;
|
||||
}
|
||||
|
||||
vec3d get_finalLookAt() {
|
||||
return camera.finalLookAt;
|
||||
}
|
||||
|
||||
double screenAngle(const vec3d& pos) {
|
||||
return camera.screenAngle(pos);
|
||||
}
|
||||
|
||||
double get_distance() {
|
||||
return camera.distance;
|
||||
}
|
||||
|
||||
//Rotate by a certain amount of screen pixels dragged
|
||||
void rotate(int dx, int dy) {
|
||||
CAM_ROTATED = true;
|
||||
if(settings::bInvertHorizRot)
|
||||
dx = -dx;
|
||||
if(settings::bInvertVertRot)
|
||||
dy = -dy;
|
||||
|
||||
if(settings::bFreeCamera) {
|
||||
camera.yaw(clamp(double(dx) * camAnglesPerPixel, -pi * 0.5, pi * 0.5));
|
||||
camera.pitch(clamp(double(dy) * camAnglesPerPixel, -pi * 0.5, pi * 0.5));
|
||||
}
|
||||
else {
|
||||
camera.abs_yaw(clamp(double(dx) * camAnglesPerPixel, -pi * 0.5, pi * 0.5));
|
||||
camera.pitch(clamp(double(dy) * camAnglesPerPixel, -pi * 0.5, pi * 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
//Roll based on dragged script pixels
|
||||
void roll(int delta) {
|
||||
CAM_ROTATED = true;
|
||||
camera.roll(double(delta) * camAnglesPerPixel);
|
||||
}
|
||||
|
||||
//Zoom with world plane
|
||||
void zoom(int delta) {
|
||||
//Get zoom speed
|
||||
double factor;
|
||||
if(settings::bInvertZoom)
|
||||
factor = pow(tickZoom, delta * settings::dZoomSpeed);
|
||||
else
|
||||
factor = pow(tickZoom, -delta * settings::dZoomSpeed);
|
||||
CAM_ZOOMED = true;
|
||||
|
||||
if(lockedObject !is null) {
|
||||
camera.zoom(factor);
|
||||
return;
|
||||
}
|
||||
|
||||
if(factor < 1.0 ? settings::bZoomToCursor : settings::bZoomFromCursor) {
|
||||
if(hoveredObject !is null) {
|
||||
double minDist = hoveredObject.radius * getMinZoomDist(hoveredObject);
|
||||
vec3d point = hoveredObject.position;
|
||||
camera.zoomTo(factor, point, minDist);
|
||||
}
|
||||
else {
|
||||
//Interpolate plane position
|
||||
line3dd ray = screenToRay(mousePos);
|
||||
if(factor > 1.0)
|
||||
ray.start -= ray.direction * 1.0;
|
||||
|
||||
vec3d point;
|
||||
if(!getElevationIntersect(ray, point))
|
||||
return;
|
||||
|
||||
double minDist = 0.0;
|
||||
camera.zoomTo(factor, point, minDist);
|
||||
}
|
||||
}
|
||||
else {
|
||||
camera.zoom(factor);
|
||||
}
|
||||
}
|
||||
|
||||
void zoomTo(Object@ obj) {
|
||||
clearObjectLock();
|
||||
zoomTo(obj.position);
|
||||
}
|
||||
|
||||
void zoomTo(const vec3d& pos) {
|
||||
clearObjectLock();
|
||||
vec3d finalPos = camera.finalLookAt;
|
||||
vec3d movement;
|
||||
movement.x = pos.x - finalPos.x;
|
||||
movement.z = pos.z - finalPos.z;
|
||||
movement.y = getElevation(pos.x, pos.z) - finalPos.y;
|
||||
|
||||
camera.move_abs(movement);
|
||||
}
|
||||
|
||||
double getMinZoomDist(Object@ obj) {
|
||||
switch(obj.type) {
|
||||
case OT_Star:
|
||||
return 1.4;
|
||||
case OT_Planet:
|
||||
return 1.6;
|
||||
}
|
||||
return 1.15;
|
||||
}
|
||||
|
||||
//Pan on top of the world plane
|
||||
void pan(int dx, int dy) {
|
||||
if(!settings::bInvertPanX)
|
||||
dx = -dx;
|
||||
if(settings::bInvertPanY)
|
||||
dy = -dy;
|
||||
|
||||
//Normal world plane movement
|
||||
vec2d movement;
|
||||
movement.x = movePerPixel * double(dx);
|
||||
movement.y = movePerPixel * double(dy);
|
||||
|
||||
pan(movement);
|
||||
}
|
||||
|
||||
void pan(vec2d movement) {
|
||||
clearObjectLock();
|
||||
|
||||
//Speed based on zoom and modifiers
|
||||
double speed = camera.distance / 2500.0;
|
||||
if(settings::bModSpeedPan) {
|
||||
if(shiftKey)
|
||||
speed *= 3.0;
|
||||
else if(altKey)
|
||||
speed *= 0.333;
|
||||
}
|
||||
|
||||
movement *= settings::dPanSpeed * speed;
|
||||
|
||||
//Normal world plane movement
|
||||
vec3d prevPos = camera.finalLookAt;
|
||||
camera.move_world_abs(vec3d(movement.x, 0, movement.y));
|
||||
|
||||
//Change in elevation
|
||||
vec3d nextPos = camera.finalLookAt;
|
||||
camera.move_abs(vec3d(0, getElevation(nextPos.x, nextPos.z) - prevPos.y, 0));
|
||||
CAM_PANNED = true;
|
||||
}
|
||||
|
||||
bool panTo(const vec3d& pos, double speed, double threshold = 10.0) {
|
||||
clearObjectLock();
|
||||
|
||||
//Modify speed
|
||||
speed *= max(camera.distance / 2500.0, 0.2);
|
||||
if(settings::bModSpeedPan) {
|
||||
if(shiftKey)
|
||||
speed *= 3.0;
|
||||
else if(altKey)
|
||||
speed *= 0.333;
|
||||
}
|
||||
speed *= settings::dPanSpeed;
|
||||
|
||||
//Pan on a flat plane
|
||||
vec3d cur = lookAt;
|
||||
vec3d final = finalLookAt;
|
||||
|
||||
vec3d flatPos = pos;
|
||||
flatPos.y = 0;
|
||||
cur.y = 0;
|
||||
final.y = 0;
|
||||
|
||||
vec3d panDir = flatPos - final;
|
||||
double len = panDir.length;
|
||||
if(len <= threshold) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if(len > speed)
|
||||
panDir.length = speed;
|
||||
|
||||
vec3d prevPos = camera.finalLookAt;
|
||||
camera.move_abs(panDir);
|
||||
vec3d nextPos = camera.finalLookAt;
|
||||
camera.move_abs(vec3d(0, getElevation(nextPos.x, nextPos.z) - prevPos.y, 0));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
line3dd screenToRay(const vec2i& pos) {
|
||||
vec2i size = screenSize;
|
||||
return camera.screenToRay(double(pos.x) / double(size.x),
|
||||
double(pos.y) / double(size.y));
|
||||
}
|
||||
|
||||
vec3d screenToPoint(const vec2i& pos) {
|
||||
line3dd ray = screenToRay(mousePos);
|
||||
vec3d point;
|
||||
if(!getElevationIntersect(ray, point))
|
||||
ray.intersectY(point, getAverageElevation(), false);
|
||||
return point;
|
||||
}
|
||||
|
||||
void clearObjectLock() {
|
||||
@lockedObject = null;
|
||||
}
|
||||
|
||||
void zoomLockObject(Object& obj) {
|
||||
zoomTo(obj.position);
|
||||
camera.move_abs(obj.node_position - camera.finalLookAt);
|
||||
if(!shiftKey)
|
||||
camera.zoom((obj.radius * OBJLOCK_ZOOMDIST) / camera.distance);
|
||||
setLocked(obj);
|
||||
}
|
||||
|
||||
void setLocked(Object& obj) {
|
||||
@lockedObject = obj;
|
||||
lockOffset = camera.finalLookAt - obj.node_position;
|
||||
}
|
||||
|
||||
void animateLocked(double time) {
|
||||
if(lockedObject is null)
|
||||
return;
|
||||
if(!lockedObject.visible) {
|
||||
@lockedObject = null;
|
||||
return;
|
||||
}
|
||||
|
||||
vec3d finalPos = camera.finalLookAt;
|
||||
double tDiff = frameGameTime - lockedObject.lastTick;
|
||||
vec3d objPos = lockedObject.position + (lockedObject.velocity + lockedObject.acceleration * (tDiff * 0.5)) * tDiff;
|
||||
if(finalPos.distanceToSQ(objPos) > sqr(lockedObject.radius * 2.0 + lockedObject.velocity.length)) {
|
||||
@lockedObject = null;
|
||||
return;
|
||||
}
|
||||
|
||||
objPos += lockOffset;
|
||||
vec3d movement = objPos - finalPos;
|
||||
bool snap = camera.lookAt.distanceTo(finalPos) < 15.0;
|
||||
camera.move_abs(movement);
|
||||
if(snap)
|
||||
camera.snapTranslation();
|
||||
}
|
||||
|
||||
void animate(double time) {
|
||||
camera.animate(time);
|
||||
if(lockedObject !is null)
|
||||
animateLocked(time);
|
||||
}
|
||||
|
||||
void save(SaveFile& file) {
|
||||
file << camera.finalLookAt;
|
||||
file << camera.radius;
|
||||
}
|
||||
|
||||
void load(SaveFile& file) {
|
||||
vec3d position;
|
||||
file >> position;
|
||||
if(file >= SV_0149) {
|
||||
double radius = 0;
|
||||
file >> radius;
|
||||
camera.radius = radius;
|
||||
}
|
||||
camera.move_abs(position - camera.finalLookAt);
|
||||
camera.snap();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user