diff --git a/Source/Builder.csproj b/Source/Builder.csproj index d1b7beb1..2f967c40 100644 --- a/Source/Builder.csproj +++ b/Source/Builder.csproj @@ -685,6 +685,7 @@ + diff --git a/Source/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs index 6f66f697..82d4f934 100644 --- a/Source/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs +++ b/Source/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs @@ -268,8 +268,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Select button pressed public virtual void OnSelectBegin() { - dragstartanglexy = mode.CameraAngleXY; - dragstartanglez = mode.CameraAngleZ; + dragstartanglexy = General.Map.VisualCamera.AngleXY; + dragstartanglez = General.Map.VisualCamera.AngleZ; dragorigin = pickintersect; startoffsetx = Sidedef.OffsetX; startoffsety = Sidedef.OffsetY; @@ -321,8 +321,8 @@ namespace CodeImp.DoomBuilder.BuilderModes if(General.Actions.CheckActionActive(General.ThisAssembly, "visualselect")) { // Check if tolerance is exceeded to start UV dragging - float deltaxy = mode.CameraAngleXY - dragstartanglexy; - float deltaz = mode.CameraAngleZ - dragstartanglez; + float deltaxy = General.Map.VisualCamera.AngleXY - dragstartanglexy; + float deltaz = General.Map.VisualCamera.AngleZ - dragstartanglez; if((Math.Abs(deltaxy) + Math.Abs(deltaz)) > DRAG_ANGLE_TOLERANCE) { General.Map.UndoRedo.CreateUndo("Change texture offsets"); @@ -342,9 +342,9 @@ namespace CodeImp.DoomBuilder.BuilderModes float u_ray; // Calculate intersection position - Line2D ray = new Line2D(mode.CameraPosition, mode.CameraTarget); + Line2D ray = new Line2D(General.Map.VisualCamera.Position, General.Map.VisualCamera.Target); Sidedef.Line.Line.GetIntersection(ray, out u_ray); - Vector3D intersect = mode.CameraPosition + (mode.CameraTarget - mode.CameraPosition) * u_ray; + Vector3D intersect = General.Map.VisualCamera.Position + (General.Map.VisualCamera.Target - General.Map.VisualCamera.Position) * u_ray; // Calculate offsets Vector3D dragdelta = intersect - dragorigin; diff --git a/Source/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/BuilderModes/VisualModes/BaseVisualMode.cs index 50bfabf1..bf37a595 100644 --- a/Source/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/BuilderModes/VisualModes/BaseVisualMode.cs @@ -146,8 +146,8 @@ namespace CodeImp.DoomBuilder.BuilderModes private void PickTarget() { // Find the object we are aiming at - Vector3D start = CameraPosition; - Vector3D delta = CameraTarget - CameraPosition; + Vector3D start = General.Map.VisualCamera.Position; + Vector3D delta = General.Map.VisualCamera.Target - General.Map.VisualCamera.Position; delta = delta.GetFixedLength(General.Settings.ViewDistance * PICK_RANGE); VisualPickResult newtarget = PickObject(start, start + delta); @@ -205,32 +205,34 @@ namespace CodeImp.DoomBuilder.BuilderModes // Setup the move multiplier depending on gravity Vector3D movemultiplier = new Vector3D(1.0f, 1.0f, 1.0f); if(BuilderPlug.Me.UseGravity) movemultiplier.z = 0.0f; - base.MoveMultiplier = movemultiplier; + General.Map.VisualCamera.MoveMultiplier = movemultiplier; // Apply gravity? - if(BuilderPlug.Me.UseGravity && (CameraSector != null)) + if(BuilderPlug.Me.UseGravity && (General.Map.VisualCamera.Sector != null)) { // Camera below floor level? - if(base.CameraPosition.z <= (CameraSector.FloorHeight + CAMERA_FLOOR_OFFSET + 0.1f)) + if(General.Map.VisualCamera.Position.z <= (General.Map.VisualCamera.Sector.FloorHeight + CAMERA_FLOOR_OFFSET + 0.1f)) { // Stay above floor gravity = new Vector3D(0.0f, 0.0f, 0.0f); - base.CameraPosition = new Vector3D(base.CameraPosition.x, base.CameraPosition.y, - CameraSector.FloorHeight + CAMERA_FLOOR_OFFSET); + General.Map.VisualCamera.Position = new Vector3D(General.Map.VisualCamera.Position.x, + General.Map.VisualCamera.Position.y, + General.Map.VisualCamera.Sector.FloorHeight + CAMERA_FLOOR_OFFSET); } else { // Fall down gravity += new Vector3D(0.0f, 0.0f, (float)(GRAVITY * deltatime)); - base.CameraPosition = base.CameraPosition + gravity; + General.Map.VisualCamera.Position += gravity; } // Camera above ceiling level? - if(base.CameraPosition.z >= (CameraSector.CeilHeight - CAMERA_CEILING_OFFSET - 0.1f)) + if(General.Map.VisualCamera.Position.z >= (General.Map.VisualCamera.Sector.CeilHeight - CAMERA_CEILING_OFFSET - 0.1f)) { // Stay below ceiling - base.CameraPosition = new Vector3D(base.CameraPosition.x, base.CameraPosition.y, - CameraSector.CeilHeight - CAMERA_CEILING_OFFSET); + General.Map.VisualCamera.Position = new Vector3D(General.Map.VisualCamera.Position.x, + General.Map.VisualCamera.Position.y, + General.Map.VisualCamera.Sector.CeilHeight - CAMERA_CEILING_OFFSET); } } else diff --git a/Source/General/MapManager.cs b/Source/General/MapManager.cs index 65960ae2..269bcfab 100644 --- a/Source/General/MapManager.cs +++ b/Source/General/MapManager.cs @@ -35,6 +35,7 @@ using CodeImp.DoomBuilder.Actions; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Plugins; using CodeImp.DoomBuilder.Compilers; +using CodeImp.DoomBuilder.VisualModes; #endregion @@ -86,6 +87,7 @@ namespace CodeImp.DoomBuilder private ThingsFilter thingsfilter; private ScriptEditorForm scriptwindow; private List errors; + private VisualCamera visualcamera; // Disposing private bool isdisposed = false; @@ -117,6 +119,7 @@ namespace CodeImp.DoomBuilder public ThingsFilter ThingsFilter { get { return thingsfilter; } } internal List Errors { get { return errors; } } internal ScriptEditorForm ScriptEditor { get { return scriptwindow; } } + public VisualCamera VisualCamera { get { return visualcamera; } set { visualcamera = value; } } public bool IsScriptsWindowOpen { get { return (scriptwindow != null) && !scriptwindow.IsDisposed; } } #endregion @@ -172,6 +175,7 @@ namespace CodeImp.DoomBuilder if(renderer2d != null) renderer2d.Dispose(); if(renderer3d != null) renderer3d.Dispose(); if(graphics != null) graphics.Dispose(); + visualcamera = null; grid = null; launcher = null; copypaste = null; @@ -268,7 +272,8 @@ namespace CodeImp.DoomBuilder // Bind any methods General.Actions.BindMethods(this); - // Set default mode + // Set defaults + this.visualcamera = new VisualCamera(); General.Editing.ChangeMode("VerticesMode"); ClassicMode cmode = (General.Editing.Mode as ClassicMode); if(cmode != null) cmode.SetZoom(0.5f); @@ -292,7 +297,7 @@ namespace CodeImp.DoomBuilder this.filepathname = filepathname; this.changed = false; this.options = options; - + General.WriteLogLine("Opening map '" + options.CurrentName + "' with configuration '" + options.ConfigFile + "'"); // Initiate graphics @@ -357,7 +362,8 @@ namespace CodeImp.DoomBuilder // Bind any methods General.Actions.BindMethods(this); - // Set default mode + // Set defaults + this.visualcamera = new VisualCamera(); General.Editing.ChangeMode("VerticesMode"); renderer2d.SetViewMode((ViewMode)General.Settings.DefaultViewMode); @@ -1326,7 +1332,8 @@ namespace CodeImp.DoomBuilder // Let the plugin and editing mode know General.Plugins.OnMapSetChangeBegin(); if(General.Editing.Mode != null) General.Editing.Mode.OnMapSetChangeBegin(); - + this.visualcamera.Sector = null; + // Can't have a selection in an old map set map.ClearAllSelected(); diff --git a/Source/VisualModes/VisualCamera.cs b/Source/VisualModes/VisualCamera.cs new file mode 100644 index 00000000..6d9f947e --- /dev/null +++ b/Source/VisualModes/VisualCamera.cs @@ -0,0 +1,155 @@ +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; + +#endregion + +namespace CodeImp.DoomBuilder.VisualModes +{ + public class VisualCamera + { + #region ================== Constants + + private const float ANGLE_FROM_MOUSE = 0.0001f; + public const float MAX_ANGLEZ_LOW = 100f / Angle2D.PIDEG; + public const float MAX_ANGLEZ_HIGH = (360f - 100f) / Angle2D.PIDEG; + + #endregion + + #region ================== Variables + + // Properties + private Vector3D position; + private Vector3D target; + private Vector3D movemultiplier; + private float anglexy, anglez; + private Sector sector; + + #endregion + + #region ================== Properties + + public Vector3D Position { get { return position; } set { position = value; } } + public Vector3D Target { get { return target; } } + public float AngleXY { get { return anglexy; } set { anglexy = value; } } + public float AngleZ { get { return anglez; } set { anglez = value; } } + public Sector Sector { get { return sector; } internal set { sector = value; } } + public Vector3D MoveMultiplier { get { return movemultiplier; } set { movemultiplier = value; } } + + #endregion + + #region ================== Constructor / Destructor + + // Constructor + public VisualCamera() + { + // Initialize + this.movemultiplier = new Vector3D(1.0f, 1.0f, 1.0f); + this.position = position; + this.anglexy = 0.0f; + this.anglez = Angle2D.PI; + this.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; + 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 + Vector3D camvec = Vector3D.FromAngleXYZ(anglexy, anglez); + + // 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 bool PositionAtThing() + { + 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; + + // Found one? + if(modething != null) + { + int z = 0; + if(sector != null) + z = (int)position.z - sector.FloorHeight; + + // Position camera here + modething.DetermineSector(); + position = modething.Position + new Vector3D(0.0f, 0.0f, 96.0f); + anglexy = modething.Angle + Angle2D.PI; + anglez = Angle2D.PI; + return true; + } + else + { + 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 bool ApplyToThing() + { + 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; + + // Found one? + if(modething != null) + { + int z = 0; + if(sector != null) + z = (int)position.z - sector.FloorHeight; + + // Position the thing to match camera + modething.Move((int)position.x, (int)position.y, z); + modething.Rotate(anglexy - Angle2D.PI); + return true; + } + else + { + return false; + } + } + + #endregion + } +} diff --git a/Source/VisualModes/VisualMode.cs b/Source/VisualModes/VisualMode.cs index 4c8b7208..8c9cb558 100644 --- a/Source/VisualModes/VisualMode.cs +++ b/Source/VisualModes/VisualMode.cs @@ -45,9 +45,6 @@ namespace CodeImp.DoomBuilder.VisualModes { #region ================== Constants - private const float ANGLE_FROM_MOUSE = 0.0001f; - public const float MAX_ANGLEZ_LOW = 100f / Angle2D.PIDEG; - public const float MAX_ANGLEZ_HIGH = (360f - 100f) / Angle2D.PIDEG; private const double MOVE_SPEED_MULTIPLIER = 0.001d; #endregion @@ -61,13 +58,6 @@ namespace CodeImp.DoomBuilder.VisualModes protected IRenderer3D renderer; private Renderer3D renderer3d; - // Camera - private Vector3D campos; - private Vector3D camtarget; - private Vector3D movemultiplier; - private float camanglexy, camanglez; - private Sector camsector; - // Options private bool processgeometry; private bool processthings; @@ -92,14 +82,8 @@ namespace CodeImp.DoomBuilder.VisualModes #region ================== Properties - public Vector3D CameraPosition { get { return campos; } set { campos = value; } } - public Vector3D CameraTarget { get { return camtarget; } } - public float CameraAngleXY { get { return camanglexy; } set { camanglexy = value; } } - public float CameraAngleZ { get { return camanglez; } set { camanglez = value; } } - public Sector CameraSector { get { return camsector; } } public bool ProcessGeometry { get { return processgeometry; } set { processgeometry = value; } } public bool ProcessThings { get { return processthings; } set { processthings = value; } } - public Vector3D MoveMultiplier { get { return movemultiplier; } set { movemultiplier = value; } } public VisualBlockMap BlockMap { get { return blockmap; } } #endregion @@ -114,9 +98,6 @@ namespace CodeImp.DoomBuilder.VisualModes // Initialize this.renderer = General.Map.Renderer3D; this.renderer3d = (Renderer3D)General.Map.Renderer3D; - this.campos = new Vector3D(0.0f, 0.0f, 96.0f); - this.movemultiplier = new Vector3D(1.0f, 1.0f, 1.0f); - this.camanglez = Angle2D.PI; this.blockmap = new VisualBlockMap(); this.allsectors = new Dictionary(General.Map.Map.Sectors.Count); this.allthings = new Dictionary(General.Map.Map.Things.Count); @@ -161,24 +142,10 @@ namespace CodeImp.DoomBuilder.VisualModes // Update the used textures General.Map.Data.UpdateUsedTextures(); - + // Fill the blockmap FillBlockMap(); - // Find a 3D Mode thing - foreach(Thing t in General.Map.Map.Things) - if(t.Type == General.Map.Config.Start3DModeThingType) modething = t; - - // Found one? - if(modething != null) - { - // Position camera here - modething.DetermineSector(); - campos = modething.Position + new Vector3D(0.0f, 0.0f, 96.0f); - camanglexy = modething.Angle + Angle2D.PI; - camanglez = Angle2D.PI; - } - // Start special input mode General.Interface.SetProcessorState(true); General.Interface.StartExclusiveMouseInput(); @@ -197,13 +164,11 @@ namespace CodeImp.DoomBuilder.VisualModes foreach(KeyValuePair vt in allthings) vt.Value.Dispose(); - // Do we have a 3D Mode thing? - if(modething != null) - { - // Position the thing to match camera - modething.Move((int)campos.x, (int)campos.y, 0); - modething.Rotate(camanglexy - Angle2D.PI); - } + // Apply camera position to thing + General.Map.VisualCamera.ApplyToThing(); + + // Do not leave the sector on the camera + General.Map.VisualCamera.Sector = null; // Stop special input mode General.Interface.SetProcessorState(false); @@ -256,18 +221,7 @@ namespace CodeImp.DoomBuilder.VisualModes public override void OnMouseInput(Vector2D delta) { base.OnMouseInput(delta); - - // Change camera angles with the mouse changes - camanglexy -= delta.x * ANGLE_FROM_MOUSE; - camanglez += delta.y * ANGLE_FROM_MOUSE; - - // Normalize angles - camanglexy = Angle2D.Normalized(camanglexy); - camanglez = Angle2D.Normalized(camanglez); - - // Limit vertical angle - if(camanglez < MAX_ANGLEZ_LOW) camanglez = MAX_ANGLEZ_LOW; - if(camanglez > MAX_ANGLEZ_HIGH) camanglez = MAX_ANGLEZ_HIGH; + General.Map.VisualCamera.ProcessMouseInput(delta); } [BeginAction("moveforward", BaseAction = true)] @@ -338,7 +292,7 @@ namespace CodeImp.DoomBuilder.VisualModes private void DoCulling() { Dictionary visiblelines = new Dictionary(200); - Vector2D campos2d = (Vector2D)campos; + Vector2D campos2d = (Vector2D)General.Map.VisualCamera.Position; float viewdist = General.Settings.ViewDistance; // Make collections @@ -410,7 +364,7 @@ namespace CodeImp.DoomBuilder.VisualModes Linedef nld = MapSet.NearestLinedef(visiblelines.Values, campos2d); if(nld != null) { - camsector = GetCameraSectorFromLinedef(nld); + General.Map.VisualCamera.Sector = GetCameraSectorFromLinedef(nld); } else { @@ -422,10 +376,10 @@ namespace CodeImp.DoomBuilder.VisualModes nld = General.Map.Map.NearestLinedef(campos2d); if(nld != null) { - camsector = GetCameraSectorFromLinedef(nld); - if(camsector != null) + General.Map.VisualCamera.Sector = GetCameraSectorFromLinedef(nld); + if(General.Map.VisualCamera.Sector != null) { - foreach(Sidedef sd in camsector.Sidedefs) + foreach(Sidedef sd in General.Map.VisualCamera.Sector.Sidedefs) { float side = sd.Line.SideOfLine(campos2d); if(((side < 0) && sd.IsFront) || @@ -436,13 +390,13 @@ namespace CodeImp.DoomBuilder.VisualModes else { // Too far away from the map to see anything - camsector = null; + General.Map.VisualCamera.Sector = null; } } else { // Map is empty - camsector = null; + General.Map.VisualCamera.Sector = null; } } } @@ -483,7 +437,7 @@ namespace CodeImp.DoomBuilder.VisualModes // This returns the camera sector from linedef private Sector GetCameraSectorFromLinedef(Linedef ld) { - if(ld.SideOfLine(campos) < 0) + if(ld.SideOfLine(General.Map.VisualCamera.Position) < 0) { if(ld.Front != null) return ld.Front.Sector; @@ -524,10 +478,10 @@ namespace CodeImp.DoomBuilder.VisualModes List pickables = new List(blocks.Count * 10); // Add geometry from the camera sector - if((camsector != null) && allsectors.ContainsKey(camsector)) + if((General.Map.VisualCamera.Sector != null) && allsectors.ContainsKey(General.Map.VisualCamera.Sector)) { - VisualSector vs = allsectors[camsector]; - sectors.Add(camsector, vs); + VisualSector vs = allsectors[General.Map.VisualCamera.Sector]; + sectors.Add(General.Map.VisualCamera.Sector, vs); foreach(VisualGeometry g in vs.FixedGeometry) pickables.Add(g); } @@ -741,22 +695,24 @@ namespace CodeImp.DoomBuilder.VisualModes base.OnProcess(deltatime); - // Calculate camera direction vectors - Vector3D camvec = Vector3D.FromAngleXYZ(camanglexy, camanglez); - Vector3D camvecstrafe = Vector3D.FromAngleXY(camanglexy + Angle2D.PIHALF); + // Camera vectors + Vector3D camvec = Vector3D.FromAngleXYZ(General.Map.VisualCamera.AngleXY, General.Map.VisualCamera.AngleZ); + Vector3D camvecstrafe = Vector3D.FromAngleXY(General.Map.VisualCamera.AngleXY + Angle2D.PIHALF); + Vector3D cammovemul = General.Map.VisualCamera.MoveMultiplier; + Vector3D camdeltapos = new Vector3D(); // Move the camera if(doublespeed) multiplier = MOVE_SPEED_MULTIPLIER * 2.0f; else multiplier = MOVE_SPEED_MULTIPLIER; - if(keyforward) campos += camvec * movemultiplier * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); - if(keybackward) campos -= camvec * movemultiplier * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); - if(keyleft) campos -= camvecstrafe * movemultiplier * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); - if(keyright) campos += camvecstrafe * movemultiplier * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); + if(keyforward) camdeltapos += camvec * cammovemul * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); + if(keybackward) camdeltapos -= camvec * cammovemul * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); + if(keyleft) camdeltapos -= camvecstrafe * cammovemul * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); + if(keyright) camdeltapos += camvecstrafe * cammovemul * (float)((double)General.Settings.MoveSpeed * multiplier * deltatime); - // Target the camera - camtarget = campos + camvec; + // Move the camera + General.Map.VisualCamera.ProcessMovement(camdeltapos); // Apply new camera matrices - renderer.PositionAndLookAt(campos, camtarget); + renderer.PositionAndLookAt(General.Map.VisualCamera.Position, General.Map.VisualCamera.Target); // Visibility culling DoCulling();