Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#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.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;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Visual Mode",
SwitchAction = "visualmode", // Action name used to switch to this mode
ButtonImage = "VisualMode.png", // Image resource name for the button
ButtonOrder = 0, // 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 double PICK_INTERVAL = 80.0d;
private const float PICK_RANGE = 0.98f;
// Gravity
private const float GRAVITY = -0.06f;
private const float CAMERA_FLOOR_OFFSET = 41f; // same as in doom
private const float CAMERA_CEILING_OFFSET = 10f;
#endregion
#region ================== Variables
// Gravity vector
private Vector3D gravity;
// Object picking
private VisualPickResult target;
private double lastpicktime;
private bool locktarget;
// 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 Action lastaction;
private VisualActionResult actionresult;
#endregion
#region ================== Properties
public IRenderer3D Renderer { get { return renderer; } }
public bool IsSingleSelection { get { return singleselection; } }
public bool SelectionChanged { get { return selectionchanged; } set { selectionchanged |= value; } }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#endregion
#region ================== Constructor / Disposer
// Constructor
public BaseVisualMode()
{
// Initialize
this.gravity = new Vector3D(0.0f, 0.0f, 0.0f);
// 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
// This is called before an action is performed
private void PreAction(string multiundodescription, bool multiseparateundo, UndoGroup singleundogroup)
{
int undogrouptag = 0;
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.
if(!target.picked.Selected)
{
// Single object, no selection
singleselection = true;
ClearSelection();
target.picked.Selected = true;
}
else
{
// 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((lastaction != General.Actions.Current) || selectionchanged || multiseparateundo)
{
General.Map.UndoRedo.CreateUndo(multiundodescription, UndoGroup.None, 0);
}
}
// This is called after an action is performed
if(!string.IsNullOrEmpty(actionresult.displaystatus))
General.Interface.DisplayStatus(StatusType.Action, actionresult.displaystatus);
lastaction = General.Actions.Current;
selectionchanged = false;
UpdateChangedObjects();
ShowTargetInfo();
}
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// 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 CreateSingleUndo(string description, UndoGroup group, int grouptag)
{
if(singleselection)
return General.Map.UndoRedo.CreateUndo(description, group, grouptag);
else
return 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 CreateSingleUndo(string description)
{
if(singleselection)
return General.Map.UndoRedo.CreateUndo(description);
else
return 0;
}
// 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;
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// 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);
if(pickedgeo.Sidedef != null)
General.Interface.ShowLinedefInfo(pickedgeo.Sidedef.Line);
else if(pickedgeo.Sidedef == null)
General.Interface.ShowSectorInfo(pickedgeo.Sector.Sector);
else
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)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Changed) bvs.Rebuild();
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Changed) bvt.Setup();
}
}
#endregion
#region ================== Events
// Help!
public override void OnHelp()
{
General.ShowHelp("e_visual.html");
}
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// Processing
public override void OnProcess(double 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))
{
// Camera below floor level?
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);
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));
General.Map.VisualCamera.Position += gravity;
}
// Camera above ceiling level?
if(General.Map.VisualCamera.Position.z >= (General.Map.VisualCamera.Sector.CeilHeight - CAMERA_CEILING_OFFSET - 0.1f))
{
// Stay below ceiling
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
{
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();
lastpicktime = General.Clock.CurrentTime;
}
// 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.SetHighlightedObject(target.picked);
// 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();
PickTarget();
}
// Mouse moves
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if(target.picked != null) (target.picked as IVisualEventReceiver).OnMouseMove(e);
}
#endregion
#region ================== Actions
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection()
{
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Floor != null) bvs.Floor.Selected = false;
if(bvs.Ceiling != null) bvs.Ceiling.Selected = false;
foreach(Sidedef sd in vs.Key.Sidedefs)
{
List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
foreach(VisualGeometry sdg in sidedefgeos)
{
sdg.Selected = false;
}
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
bvt.Selected = false;
}
}
[BeginAction("visualselect", BaseAction = true)]
public void BeginSelect()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnSelectBegin();
UpdateChangedObjects();
}
[EndAction("visualselect", BaseAction = true)]
public void EndSelect()
{
if(target.picked != null) (target.picked as IVisualEventReceiver).OnSelectEnd();
UpdateChangedObjects();
}
[BeginAction("visualedit", BaseAction = true)]
public void BeginEdit()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnEditBegin();
UpdateChangedObjects();
}
[EndAction("visualedit", BaseAction = true)]
public void EndEdit()
{
if(target.picked != null) (target.picked as IVisualEventReceiver).OnEditEnd();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("raisesector8")]
public void RaiseSector8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTargetHeight(8);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("lowersector8")]
public void LowerSector8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTargetHeight(-8);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("raisesector1")]
public void RaiseSector1()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTargetHeight(1);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("lowersector1")]
public void LowerSector1()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTargetHeight(-1);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("showvisualthings")]
public void ShowVisualThings()
{
BuilderPlug.Me.ShowVisualThings++;
if(BuilderPlug.Me.ShowVisualThings > 2) BuilderPlug.Me.ShowVisualThings = 0;
}
[BeginAction("raisebrightness8")]
public void RaiseBrightness8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTargetBrightness(true);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("lowerbrightness8")]
public void LowerBrightness8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTargetBrightness(false);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetextureleft")]
public void MoveTextureLeft1()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(-1, 0);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetextureright")]
public void MoveTextureRight1()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(1, 0);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetextureup")]
public void MoveTextureUp1()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(0, -1);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetexturedown")]
public void MoveTextureDown1()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(0, 1);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetextureleft8")]
public void MoveTextureLeft8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(-8, 0);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetextureright8")]
public void MoveTextureRight8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(8, 0);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetextureup8")]
public void MoveTextureUp8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(0, -8);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("movetexturedown8")]
public void MoveTextureDown8()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnChangeTextureOffset(0, 8);
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("textureselect")]
public void TextureSelect()
{
PickTargetUnlocked();
renderer.SetCrosshairBusy(true);
General.Interface.RedrawDisplay();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnSelectTexture();
UpdateChangedObjects();
renderer.SetCrosshairBusy(false);
ShowTargetInfo();
}
[BeginAction("texturecopy")]
public void TextureCopy()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnCopyTexture();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("texturepaste")]
public void TexturePaste()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnPasteTexture();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("visualautoalignx")]
public void TextureAutoAlignX()
{
PickTargetUnlocked();
renderer.SetCrosshairBusy(true);
General.Interface.RedrawDisplay();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureAlign(true, false);
UpdateChangedObjects();
renderer.SetCrosshairBusy(false);
ShowTargetInfo();
}
[BeginAction("visualautoaligny")]
public void TextureAutoAlignY()
{
PickTargetUnlocked();
renderer.SetCrosshairBusy(true);
General.Interface.RedrawDisplay();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureAlign(false, true);
UpdateChangedObjects();
renderer.SetCrosshairBusy(false);
ShowTargetInfo();
}
[BeginAction("toggleupperunpegged")]
public void ToggleUpperUnpegged()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnToggleUpperUnpegged();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("togglelowerunpegged")]
public void ToggleLowerUnpegged()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnToggleLowerUnpegged();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("togglegravity")]
public void ToggleGravity()
{
BuilderPlug.Me.UseGravity = !BuilderPlug.Me.UseGravity;
string onoff = BuilderPlug.Me.UseGravity ? "ON" : "OFF";
General.Interface.DisplayStatus(StatusType.Action, "Gravity is now " + onoff + ".");
}
[BeginAction("togglebrightness")]
public void ToggleBrightness()
{
renderer.FullBrightness = !renderer.FullBrightness;
string onoff = renderer.FullBrightness ? "ON" : "OFF";
General.Interface.DisplayStatus(StatusType.Action, "Full Brightness is now " + onoff + ".");
}
[BeginAction("resettexture")]
public void ResetTexture()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnResetTextureOffset();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("floodfilltextures")]
public void FloodfillTextures()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureFloodfill();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("texturecopyoffsets")]
public void TextureCopyOffsets()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnCopyTextureOffsets();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("texturepasteoffsets")]
public void TexturePasteOffsets()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnPasteTextureOffsets();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("copyproperties")]
public void CopyProperties()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnCopyProperties();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("pasteproperties")]
public void PasteProperties()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnPasteProperties();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("insertitem", BaseAction = true)]
public void Insert()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnInsert();
UpdateChangedObjects();
ShowTargetInfo();
}
[BeginAction("deleteitem", BaseAction = true)]
public void Delete()
{
PickTargetUnlocked();
if(target.picked != null) (target.picked as IVisualEventReceiver).OnDelete();
UpdateChangedObjects();