Newer
Older
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.VisualModes;
using CodeImp.DoomBuilder.Config;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "GZDB Visual Mode",
SwitchAction = "gzdbvisualmode", // Action name used to switch to this mode
ButtonImage = "VisualModeGZ.png", // Image resource name for the button
ButtonOrder = 1, // Position of the button (lower is more to the left)
ButtonGroup = "001_visual",
UseByDefault = true)]
public class BaseVisualMode : VisualMode
{
#region ================== Constants
// Object picking
private const float PICK_INTERVAL = 80.0f;
private const float PICK_RANGE = 0.98f;
// Gravity
private const float GRAVITY = -0.06f;
#endregion
#region ================== Variables
// Gravity
private Vector3D gravity;
private float cameraflooroffset = 41f; // same as in doom
private float cameraceilingoffset = 10f;
// Object picking
private VisualPickResult target;
private float lastpicktime;
// This keeps extra element info
private Dictionary<Sector, SectorData> sectordata;
private Dictionary<Thing , ThingData> thingdata;
// This is true when a selection was made because the action is performed
// on an object that was not selected. In this case the previous selection
// is cleared and the targeted object is temporarely selected to perform
// the action on. After the action is completed, the object is deselected.
// We keep these to determine if we need to make a new undo level
private bool selectionchanged;
private int lastundogroup;
private VisualActionResult actionresult;
private bool undocreated;
// List of selected objects when an action is performed
private List<IVisualEventReceiver> selectedobjects;
//mxd. Used in Cut/PasteSelection actions
private List<ThingCopyData> copyBuffer;
private static bool gzdoomRenderingEffects = true; //mxd
#endregion
#region ================== Properties
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
public override object HighlightedObject
{
get
{
// Geometry picked?
if(target.picked is VisualGeometry)
{
VisualGeometry pickedgeo = (target.picked as VisualGeometry);
if(pickedgeo.Sidedef != null)
return pickedgeo.Sidedef;
else if(pickedgeo.Sector != null)
return pickedgeo.Sector;
else
return null;
}
// Thing picked?
else if(target.picked is VisualThing)
{
VisualThing pickedthing = (target.picked as VisualThing);
return pickedthing.Thing;
}
else
{
return null;
}
}
}
public IRenderer3D Renderer { get { return renderer; } }
public bool IsSingleSelection { get { return singleselection; } }
public bool SelectionChanged { get { return selectionchanged; } set { selectionchanged |= value; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
public BaseVisualMode()
{
// Initialize
this.gravity = new Vector3D(0.0f, 0.0f, 0.0f);
codeimp
committed
this.selectedobjects = new List<IVisualEventReceiver>();
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
codeimp
committed
// This calculates brightness level
codeimp
committed
internal int CalculateBrightness(int level)
codeimp
committed
{
codeimp
committed
return renderer.CalculateBrightness(level);
codeimp
committed
}
MaxED
committed
//mxd. This calculates brightness level with doom-style shading
internal int CalculateBrightness(int level, Sidedef sd) {
return renderer.CalculateBrightness(level, sd);
}
codeimp
committed
codeimp
committed
// This adds a selected object
internal void AddSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Add(obj);
selectionchanged = true;
}
// This removes a selected object
internal void RemoveSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Remove(obj);
selectionchanged = true;
}
// This is called before an action is performed
public void PreAction(int multiselectionundogroup)
actionresult = new VisualActionResult();
PickTargetUnlocked();
// If the action is not performed on a selected object, clear the
// current selection and make a temporary selection for the target.
codeimp
committed
if((target.picked != null) && !target.picked.Selected && (BuilderPlug.Me.VisualModeClearSelection || (selectedobjects.Count == 0)))
// Single object, no selection
singleselection = true;
ClearSelection();
undocreated = false;
singleselection = false;
// Check if we should make a new undo level
// We don't want to do this if this is the same action with the same
// selection and the action wants to group the undo levels
if((lastundogroup != multiselectionundogroup) || (lastundogroup == UndoGroup.None) ||
(multiselectionundogroup == UndoGroup.None) || selectionchanged)
{
// We want to create a new undo level, but not just yet
lastundogroup = multiselectionundogroup;
undocreated = false;
}
else
// We don't want to make a new undo level (changes will be combined)
undocreated = true;
}
codeimp
committed
// Called before an action is performed. This does not make an undo level
private void PreActionNoChange()
{
actionresult = new VisualActionResult();
singleselection = false;
undocreated = false;
// This is called after an action is performed
if(!string.IsNullOrEmpty(actionresult.displaystatus))
General.Interface.DisplayStatus(StatusType.Action, actionresult.displaystatus);
// Reset changed flags
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
BaseVisualSector bvs = (vs.Value as BaseVisualSector);
foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false;
foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false;
bvs.Floor.Changed = false;
bvs.Ceiling.Changed = false;
}
if(singleselection)
ClearSelection();
UpdateChangedObjects();
ShowTargetInfo();
}
// This sets the result for an action
public void SetActionResult(VisualActionResult result)
{
actionresult = result;
}
// This sets the result for an action
public void SetActionResult(string displaystatus)
{
actionresult = new VisualActionResult();
actionresult.displaystatus = displaystatus;
}
// This creates an undo, when only a single selection is made
// When a multi-selection is made, the undo is created by the PreAction function
public int CreateUndo(string description, int group, int grouptag)
if(!undocreated)
{
undocreated = true;
if(singleselection)
return General.Map.UndoRedo.CreateUndo(description, this, group, grouptag);
else
return General.Map.UndoRedo.CreateUndo(description, this, UndoGroup.None, 0);
}
// This creates an undo, when only a single selection is made
// When a multi-selection is made, the undo is created by the PreAction function
public int CreateUndo(string description)
return CreateUndo(description, UndoGroup.None, 0);
}
// This makes a list of the selected object
codeimp
committed
private void RebuildSelectedObjectsList()
{
// Make list of selected objects
selectedobjects = new List<IVisualEventReceiver>();
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
if(vs.Value != null)
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if((bvs.Floor != null) && bvs.Floor.Selected) selectedobjects.Add(bvs.Floor);
if((bvs.Ceiling != null) && bvs.Ceiling.Selected) selectedobjects.Add(bvs.Ceiling);
foreach(Sidedef sd in vs.Key.Sidedefs)
List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
foreach(VisualGeometry sdg in sidedefgeos)
{
if(sdg.Selected) selectedobjects.Add((sdg as IVisualEventReceiver));
}
}
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Selected) selectedobjects.Add(bvt);
}
//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
internal BaseVisualSector CreateBaseVisualSector(Sector s) {
BaseVisualSector vs = new BaseVisualSector(this, s);
if(vs != null) allsectors.Add(s, vs);
return vs;
}
// This creates a visual sector
protected override VisualSector CreateVisualSector(Sector s)
{
BaseVisualSector vs = new BaseVisualSector(this, s);
return vs;
}
// This creates a visual thing
protected override VisualThing CreateVisualThing(Thing t)
{
BaseVisualThing vt = new BaseVisualThing(this, t);
return vt.Setup() ? vt : null;
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
// This locks the target so that it isn't changed until unlocked
public void LockTarget()
{
locktarget = true;
}
// This unlocks the target so that is changes to the aimed geometry again
public void UnlockTarget()
{
locktarget = false;
}
// This picks a new target, if not locked
private void PickTargetUnlocked()
{
if(!locktarget) PickTarget();
}
// This picks a new target
private void PickTarget()
{
// Find the object we are aiming at
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);
// Should we update the info on panels?
bool updateinfo = (newtarget.picked != target.picked);
// Apply new target
target = newtarget;
// Show target info
if(updateinfo) ShowTargetInfo();
}
// This shows the picked target information
public void ShowTargetInfo()
{
// Any result?
if(target.picked != null)
{
// Geometry picked?
if(target.picked is VisualGeometry)
{
VisualGeometry pickedgeo = (target.picked as VisualGeometry);
// Sidedef?
if(pickedgeo is BaseVisualGeometrySidedef)
{
BaseVisualGeometrySidedef pickedsidedef = (pickedgeo as BaseVisualGeometrySidedef);
General.Interface.ShowLinedefInfo(pickedsidedef.Sidedef.Line);
}
// Sector?
else if(pickedgeo is BaseVisualGeometrySector)
{
BaseVisualGeometrySector pickedsector = (pickedgeo as BaseVisualGeometrySector);
General.Interface.ShowSectorInfo(pickedsector.Level.sector);
}
General.Interface.HideInfo();
}
// Thing picked?
if(target.picked is VisualThing)
{
VisualThing pickedthing = (target.picked as VisualThing);
General.Interface.ShowThingInfo(pickedthing.Thing);
}
}
else
{
General.Interface.HideInfo();
}
}
// This updates the VisualSectors and VisualThings that have their Changed property set
private void UpdateChangedObjects()
{
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
if(vs.Value != null)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Changed) bvs.Rebuild();
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Changed) bvt.Rebuild();
}
protected override void moveSelectedThings(Vector2D direction, bool absolutePosition) {
List<VisualThing> visualThings = GetSelectedVisualThings(true);
General.Interface.DisplayStatus(StatusType.Warning, "Select some Things first!");
return;
}
Vector3D[] coords = new Vector3D[visualThings.Count];
for (int i = 0; i < visualThings.Count; i++)
coords[i] = visualThings[i].Thing.Position;
//move things...
Vector3D[] translatedCoords = translateCoordinates(coords, direction, absolutePosition);
for (int i = 0; i < visualThings.Count; i++) {
BaseVisualThing t = visualThings[i] as BaseVisualThing;
t.OnMove(translatedCoords[i]);
}
PostAction();
}
//mxd
private Vector3D[] translateCoordinates(Vector3D[] coordinates, Vector2D direction, bool absolutePosition) {
if (coordinates.Length == 0) return null;
direction.x = (float)Math.Round(direction.x);
direction.y = (float)Math.Round(direction.y);
Vector3D[] translatedCoords = new Vector3D[coordinates.Length];
//move things...
if (!absolutePosition) { //...relatively (that's easy)
int camAngle = (int)Math.Round(General.Map.VisualCamera.AngleXY * 180 / Math.PI);
int sector = (int)(General.ClampAngle(camAngle - 45f) / 90f);
direction = direction.GetRotated((float)(sector * Math.PI / 2f));
for (int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = coordinates[i] + new Vector3D(direction);
//...to specified location preserving relative positioning (that's harder)
if (coordinates.Length == 1) {//just move it there
translatedCoords[0] = new Vector3D(direction.x, direction.y, coordinates[0].z);
return translatedCoords;
}
//we need some reference
float minX = coordinates[0].x;
float maxX = minX;
float minY = coordinates[0].y;
float maxY = minY;
//get bounding coordinates for selected things
for (int i = 1; i < coordinates.Length; i++) {
if (coordinates[i].x < minX)
minX = coordinates[i].x;
else if (coordinates[i].x > maxX)
maxX = coordinates[i].x;
if (coordinates[i].y < minY)
minY = coordinates[i].y;
else if (coordinates[i].y > maxY)
maxY = coordinates[i].y;
Vector2D selectionCenter = new Vector2D(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2);
//move them
for (int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = new Vector3D((float)Math.Round(direction.x - (selectionCenter.x - coordinates[i].x)), (float)Math.Round(direction.y - (selectionCenter.y - coordinates[i].y)), (float)Math.Round(coordinates[i].z));
return translatedCoords;
#region ================== Extended Methods
// This requests a sector's extra data
internal SectorData GetSectorData(Sector s)
{
// Make fresh sector data when it doesn't exist yet
if(!sectordata.ContainsKey(s))
sectordata[s] = new SectorData(this, s);
return sectordata[s];
}
// This requests a things's extra data
internal ThingData GetThingData(Thing t)
{
// Make fresh sector data when it doesn't exist yet
if(!thingdata.ContainsKey(t))
thingdata[t] = new ThingData(this, t);
return thingdata[t];
}
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
// This rebuilds the sector data
// This requires that the blockmap is up-to-date!
internal void RebuildElementData()
{
//mxd
if (!gzdoomRenderingEffects && sectordata != null && sectordata.Count > 0) {
//rebuild sectors with effects
foreach (KeyValuePair<Sector, SectorData> group in sectordata)
group.Value.Reset();
}
Dictionary<int, List<Sector>> sectortags = new Dictionary<int, List<Sector>>();
sectordata = new Dictionary<Sector, SectorData>(General.Map.Map.Sectors.Count);
thingdata = new Dictionary<Thing, ThingData>(General.Map.Map.Things.Count);
if (!gzdoomRenderingEffects) return; //mxd
// Find all sector who's tag is not 0 and hash them so that we can find them quicly
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag != 0)
{
if(!sectortags.ContainsKey(s.Tag)) sectortags[s.Tag] = new List<Sector>();
sectortags[s.Tag].Add(s);
}
}
// Find sectors with 3 vertices, because they can be sloped
foreach(Sector s in General.Map.Map.Sectors)
{
// ========== Thing vertex slope ==========
if(s.Sidedefs.Count == 3)
{
//mxd. first check if we have vertices with zoffset
bool haveVertexOffset = false;
if (General.Map.UDMF) {
Vertex[] offsets = new Vertex[3];
int counter = 0;
foreach (Sidedef sd in s.Sidedefs) {
Vertex v;
if (sd.IsFront)
v = sd.Line.End;
else
v = sd.Line.Start;
if (v.Fields.ContainsKey("zfloor") && (float)v.Fields["zfloor"].Value != 0) {
offsets[counter] = v;
haveVertexOffset = true;
}
if (offsets[counter] == null && v.Fields.ContainsKey("zceiling") && (float)v.Fields["zceiling"].Value != 0) {
offsets[counter] = v;
haveVertexOffset = true;
}
counter++;
}
//add the effect
if (haveVertexOffset) {
SectorData sd = GetSectorData(s);
sd.AddEffectVertexOffset(offsets);
}
}
if (!haveVertexOffset) {
List<Thing> slopeceilingthings = new List<Thing>(3);
List<Thing> slopefloorthings = new List<Thing>(3);
foreach (Sidedef sd in s.Sidedefs) {
Vertex v;
if (sd.IsFront)
v = sd.Line.End;
else
v = sd.Line.Start;
// Check if a thing is at this vertex
VisualBlockEntry b = blockmap.GetBlock(blockmap.GetBlockCoordinates(v.Position));
foreach (Thing t in b.Things) {
if ((Vector2D)t.Position == v.Position) {
if (t.Type == 1504)
slopefloorthings.Add(t);
else if (t.Type == 1505)
slopeceilingthings.Add(t);
}
}
}
// Slope any floor vertices?
if (slopefloorthings.Count > 0) {
SectorData sd = GetSectorData(s);
sd.AddEffectThingVertexSlope(slopefloorthings, true);
}
// Slope any ceiling vertices?
if (slopeceilingthings.Count > 0) {
SectorData sd = GetSectorData(s);
sd.AddEffectThingVertexSlope(slopeceilingthings, false);
}
}
}
}
// Find interesting linedefs (such as line slopes)
foreach(Linedef l in General.Map.Map.Linedefs)
{
// ========== Plane Align (see http://zdoom.org/wiki/Plane_Align) ==========
if(l.Action == 181)
{
// Slope front
if(((l.Args[0] == 1) || (l.Args[1] == 1)) && (l.Front != null))
{
SectorData sd = GetSectorData(l.Front.Sector);
sd.AddEffectLineSlope(l);
}
// Slope back
if(((l.Args[0] == 2) || (l.Args[1] == 2)) && (l.Back != null))
{
SectorData sd = GetSectorData(l.Back.Sector);
sd.AddEffectLineSlope(l);
}
}
// ========== Sector 3D floor (see http://zdoom.org/wiki/Sector_Set3dFloor) ==========
else if((l.Action == 160) && (l.Front != null))
{
int sectortag = l.Args[0] + (l.Args[4] << 8);
if(sectortags.ContainsKey(sectortag))
{
List<Sector> sectors = sectortags[sectortag];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffect3DFloor(l);
}
}
}
// ========== Transfer Brightness (see http://zdoom.org/wiki/ExtraFloor_LightOnly) =========
else if((l.Action == 50) && (l.Front != null))
{
if(sectortags.ContainsKey(l.Args[0]))
{
List<Sector> sectors = sectortags[l.Args[0]];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffectBrightnessLevel(l);
}
}
}
}
// Find interesting things (such as sector slopes)
foreach(Thing t in General.Map.Map.Things)
{
// ========== Copy slope ==========
if((t.Type == 9510) || (t.Type == 9511))
{
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectCopySlope(t);
}
}
// ========== Thing line slope ==========
else if((t.Type == 9500) || (t.Type == 9501))
{
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectThingLineSlope(t);
}
}
}
}
#endregion
#region ================== Events
// Help!
public override void OnHelp()
{
General.ShowHelp("e_visual.html");
}
codeimp
committed
// When entering this mode
public override void OnEngage()
{
base.OnEngage();
// Read settings
cameraflooroffset = General.Map.Config.ReadSetting("cameraflooroffset", cameraflooroffset);
cameraceilingoffset = General.Map.Config.ReadSetting("cameraceilingoffset", cameraceilingoffset);
RebuildElementData();
}
codeimp
committed
// When returning to another mode
public override void OnDisengage()
{
base.OnDisengage();
codeimp
committed
General.Map.Map.Update();
}
public override void OnProcess(float deltatime)
{
// Process things?
base.ProcessThings = (BuilderPlug.Me.ShowVisualThings != 0);
// 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;
General.Map.VisualCamera.MoveMultiplier = movemultiplier;
// Apply gravity?
if(BuilderPlug.Me.UseGravity && (General.Map.VisualCamera.Sector != null))
{
SectorData sd = GetSectorData(General.Map.VisualCamera.Sector);
if(!sd.Updated) sd.Update();
// Camera below floor level?
Vector3D feetposition = General.Map.VisualCamera.Position;
SectorLevel floorlevel = sd.GetFloorBelow(feetposition) ?? sd.LightLevels[0];
float floorheight = floorlevel.plane.GetZ(General.Map.VisualCamera.Position);
if(General.Map.VisualCamera.Position.z < (floorheight + cameraflooroffset + 0.1f))
{
// Stay above floor
gravity = new Vector3D(0.0f, 0.0f, 0.0f);
General.Map.VisualCamera.Position = new Vector3D(General.Map.VisualCamera.Position.x,
General.Map.VisualCamera.Position.y,
floorheight + cameraflooroffset);
}
else
{
// Fall down
gravity.z += GRAVITY * deltatime;
if(gravity.z > 3.0f) gravity.z = 3.0f;
// Test if we don't go through a floor
if((General.Map.VisualCamera.Position.z + gravity.z) < (floorheight + cameraflooroffset + 0.1f))
{
// Stay above floor
gravity = new Vector3D(0.0f, 0.0f, 0.0f);
General.Map.VisualCamera.Position = new Vector3D(General.Map.VisualCamera.Position.x,
General.Map.VisualCamera.Position.y,
floorheight + cameraflooroffset);
}
else
{
// Apply gravity vector
General.Map.VisualCamera.Position += gravity;
}
// Camera above ceiling?
feetposition = General.Map.VisualCamera.Position - new Vector3D(0, 0, cameraflooroffset - 7.0f);
SectorLevel ceillevel = sd.GetCeilingAbove(feetposition) ?? sd.LightLevels[sd.LightLevels.Count - 1];
float ceilheight = ceillevel.plane.GetZ(General.Map.VisualCamera.Position);
if(General.Map.VisualCamera.Position.z > (ceilheight - cameraceilingoffset - 0.01f))
{
// Stay below ceiling
General.Map.VisualCamera.Position = new Vector3D(General.Map.VisualCamera.Position.x,
General.Map.VisualCamera.Position.y,
ceilheight - cameraceilingoffset);
}
}
else
{
gravity = new Vector3D(0.0f, 0.0f, 0.0f);
}
// Do processing
base.OnProcess(deltatime);
// Process visible geometry
foreach(IVisualEventReceiver g in visiblegeometry)
{
g.OnProcess(deltatime);
}
// Time to pick a new target?
if(General.Clock.CurrentTime > (lastpicktime + PICK_INTERVAL))
{
PickTargetUnlocked();
}
// The mouse is always in motion
MouseEventArgs args = new MouseEventArgs(General.Interface.MouseButtons, 0, 0, 0, 0);
OnMouseMove(args);
}
// This draws a frame
public override void OnRedrawDisplay()
{
// Start drawing
if(renderer.Start())
{
// Use fog!
renderer.SetFogMode(true);
// Set target for highlighting
renderer.ShowSelection = General.Settings.GZOldHighlightMode || BuilderPlug.Me.UseHighlight; //mxd
if(BuilderPlug.Me.UseHighlight)
renderer.SetHighlightedObject(target.picked);
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
// Begin with geometry
renderer.StartGeometry();
// Render all visible sectors
foreach(VisualGeometry g in visiblegeometry)
renderer.AddSectorGeometry(g);
if(BuilderPlug.Me.ShowVisualThings != 0)
{
// Render things in cages?
renderer.DrawThingCages = ((BuilderPlug.Me.ShowVisualThings & 2) != 0);
// Render all visible things
foreach(VisualThing t in visiblethings)
renderer.AddThingGeometry(t);
}
// Done rendering geometry
renderer.FinishGeometry();
// Render crosshair
renderer.RenderCrosshair();
// Present!
renderer.Finish();
}
}
// After resources were reloaded
protected override void ResourcesReloaded()
{
base.ResourcesReloaded();
RebuildElementData();
// This usually happens when geometry is changed by undo, redo, cut or paste actions
// and uses the marks to check what needs to be reloaded.
protected override void ResourcesReloadedPartial()
{
bool sectorsmarked = false;
if(General.Map.UndoRedo.GeometryChanged)
{
// Let the core do this (it will just dispose the sectors that were changed)
base.ResourcesReloadedPartial();
}
else
{
// Neighbour sectors must be updated as well
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Marked)
{
sectorsmarked = true;
foreach(Sidedef sd in s.Sidedefs)
{
sd.Marked = true;
if(sd.Other != null) sd.Other.Marked = true;
}
}
// Go for all sidedefs to update
foreach(Sidedef sd in General.Map.Map.Sidedefs)
{
if(sd.Marked && VisualSectorExists(sd.Sector))
{
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(sd.Sector);
VisualSidedefParts parts = vs.GetSidedefParts(sd);
parts.SetupAllParts();
}
}
// Go for all sectors to update
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Marked)
SectorData sd = GetSectorData(s);
sd.Reset();
// UpdateSectorGeometry for associated sectors (sd.UpdateAlso) as well!
foreach(KeyValuePair<Sector, bool> us in sd.UpdateAlso)
{
if(VisualSectorExists(us.Key))
{
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(us.Key);
vs.UpdateSectorGeometry(us.Value);
}
}
// And update for this sector ofcourse
if(VisualSectorExists(s))
{
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(s);
vs.UpdateSectorGeometry(false);
}
}
}
if(!sectorsmarked)
{
// No sectors or geometry changed. So we only have
// to update things when they have changed.
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
if((vt.Value != null) && vt.Key.Marked) (vt.Value as BaseVisualThing).Rebuild();
}
else
{
// Things depend on the sector they are in and because we can't
// easily determine which ones changed, we dispose all things
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
if(vt.Value != null) vt.Value.Dispose();
codeimp
committed
// Apply new lists
allthings = new Dictionary<Thing, VisualThing>(allthings.Count);
}
// Clear visibility collections
visiblesectors.Clear();
visibleblocks.Clear();
visiblegeometry.Clear();
visiblethings.Clear();
// Make new blockmap
if(sectorsmarked || General.Map.UndoRedo.PopulationChanged)
codeimp
committed
FillBlockMap();