#region ================== Namespaces using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; #endregion namespace CodeImp.DoomBuilder.VisualModes { /// /// This class provides the camera in Visual Mode /// public class VisualCamera { #region ================== Constants private const double ANGLE_FROM_MOUSE = 0.0001; public const double MAX_ANGLEZ_LOW = 91.0 / Angle2D.PIDEG; public const double MAX_ANGLEZ_HIGH = (360.0 - 91.0) / Angle2D.PIDEG; public const double THING_Z_OFFSET = 41.0; #endregion #region ================== Variables // Properties private Vector3D position; private Vector3D target; private Vector3D movemultiplier; private double anglexy, anglez; private Sector sector; private double gravity = 1.0; //mxd #endregion #region ================== Properties public Vector3D Position { get { return position; } set { position = value; } } public Vector3D Target { get { return target; } } public double AngleXY { get { return anglexy; } set { anglexy = value; } } public double AngleZ { get { return anglez; } set { anglez = value; } } public Sector Sector { get { return sector; } internal set { sector = value; UpdateGravity(); } } //mxd public Vector3D MoveMultiplier { get { return movemultiplier; } set { movemultiplier = value; } } public double Gravity { get { return gravity; } } //mxd #endregion #region ================== Constructor / Destructor // Constructor public VisualCamera() { // Initialize movemultiplier = new Vector3D(1.0, 1.0, 1.0); anglexy = 0.0; anglez = Angle2D.PI; sector = null; PositionAtThing(); } #endregion #region ================== Methods // Mouse input internal void ProcessMouseInput(Vector2D delta) { // Change camera angles with the mouse changes anglexy -= delta.x * ANGLE_FROM_MOUSE; if(General.Settings.InvertYAxis) anglez -= delta.y * ANGLE_FROM_MOUSE; else anglez += delta.y * ANGLE_FROM_MOUSE; // Normalize angles anglexy = Angle2D.Normalized(anglexy); anglez = Angle2D.Normalized(anglez); // Limit vertical angle if(anglez < MAX_ANGLEZ_LOW) anglez = MAX_ANGLEZ_LOW; if(anglez > MAX_ANGLEZ_HIGH) anglez = MAX_ANGLEZ_HIGH; } // Key input internal void ProcessMovement(Vector3D deltavec) { // Calculate camera direction vectors. Multiply by a biggish number, so the decimal digits // become less important. This is necessary because the vector will be converted to float // when being passed to the renderer, and loss of decimal precision will cause the camera // to become jittery when it's far away from the map origin. Muliplying by 10 seems to be // enough for non-jittery forward/backward movement, but that's still jittery when looking // straight up/down and then moving around, which doesn't happen at something bigger, like // the 100 we're using here Vector3D camvec = Vector3D.FromAngleXYZ(anglexy, anglez) * 100.0; // Position the camera position += deltavec; // Target the camera target = position + camvec; } // This applies the position and angle from the 3D Camera Thing // Returns false when it couldn't find a 3D Camera Thing public virtual bool PositionAtThing() { if(General.Settings.GZSynchCameras) return true; //mxd Thing modething = null; // Find a 3D Mode thing foreach(Thing t in General.Map.Map.Things) { if(t.Type == General.Map.Config.Start3DModeThingType) { modething = t; break; //mxd } } // Found one? if(modething != null) { modething.DetermineSector(); double z = modething.Position.z; if(modething.Sector != null) z += modething.Sector.FloorHeight; // Position camera here Vector3D wantedposition = new Vector3D(modething.Position.x, modething.Position.y, z + THING_Z_OFFSET); Vector3D delta = position - wantedposition; if(delta.GetLength() > 1.0f) position = wantedposition; // Change angle double wantedanglexy = modething.Angle + Angle2D.PI; if(anglexy != wantedanglexy) { anglexy = wantedanglexy; anglez = Angle2D.PI; } return true; } return false; } // This applies the camera position and angle to the 3D Camera Thing // Returns false when it couldn't find a 3D Camera Thing public virtual bool ApplyToThing() { if(General.Settings.GZSynchCameras) return true; //mxd Thing modething = null; // Find a 3D Mode thing foreach(Thing t in General.Map.Map.Things) { if(t.Type == General.Map.Config.Start3DModeThingType) { modething = t; break; //mxd } } // Found one? if(modething != null) { int z = (int)position.z; //mxd if(sector != null) z -= sector.FloorHeight; // Position the thing to match camera modething.Move((int)position.x, (int)position.y, z - THING_Z_OFFSET); modething.Rotate(anglexy - Angle2D.PI); return true; } return false; } //mxd private void UpdateGravity() { if(!General.Map.UDMF || sector == null) return; gravity = sector.Fields.GetValue("gravity", 1.0); } #endregion } }