Merged Visual mode and GZDoom Visual mode into GZDB Visual mode. GZDoomEditing.dll is no longer required.
|
@ -1,57 +0,0 @@
|
|||
|
||||
Doom Builder Plugin Information
|
||||
===========================================================================
|
||||
|
||||
Title: (G)ZDoom Editing Plugin
|
||||
|
||||
Author: Pascal vd Heiden
|
||||
|
||||
Plugin version: 0.0
|
||||
|
||||
Core version needed: 2.1.0.1394
|
||||
|
||||
|
||||
|
||||
Description
|
||||
===========================================================================
|
||||
|
||||
This plugins adds features to help editing with the new features in the
|
||||
ZDoom and GZDoom sourceports and those derived from these sourceports.
|
||||
|
||||
List of supported features in this plugin:
|
||||
- Slopes
|
||||
- 3D floors (also sloped)
|
||||
- Colored sector lighting
|
||||
- Light levels in sectors (also sloped)
|
||||
- Flat scaling, rotation and offsets
|
||||
- Texture scaling and offsets
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
===========================================================================
|
||||
|
||||
1) Place the GZDoomEditing.dll file in Doom Builder's "Plugins" directory.
|
||||
|
||||
2) Start Doom Builder and go to Tools menu, Preferences. Choose the
|
||||
Controls tab and find the "GZDoom Visual Mode" action in the Modes group.
|
||||
Set this action to a key you wish to use to switch into and out from
|
||||
Visual Mode. You can give this the same key as your original mode, because
|
||||
now we will replace the original Visual Mode with the new one.
|
||||
|
||||
3) Go to Tools menu, Game Configurations. Choose the game configuration on
|
||||
which you wish to use the new Visual Mode. This plugin is made for UDMF
|
||||
formats, but some features also work for Hexen format. Go to the Modes tab
|
||||
and UNCHECK the original Visual Mode and CHECK the "GZDoom Visual Mode".
|
||||
|
||||
You can also have both Visual Modes together (simply do not uncheck the
|
||||
original Visual Modein step 3) but you will need a different key for the
|
||||
action that switches to the mode.
|
||||
|
||||
|
||||
|
||||
Usage
|
||||
===========================================================================
|
||||
|
||||
I don't feel like writing this now. Figure it out yourself.
|
||||
|
|
@ -5,8 +5,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuilderModes", "..\Plugins\BuilderModes\BuilderModes.csproj", "{B42D5AA0-F9A6-4234-9C4B-A05B11A64851}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GZDoomEditing", "..\Plugins\GZDoomEditing\GZDoomEditing.csproj", "{760A9BC7-CB73-4C36-858B-994C14996FCD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPicker", "..\Plugins\ColorPicker\ColorPicker.csproj", "{A4761900-0EA3-4FE4-A919-847FD5080EFC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UDMFControls", "..\Plugins\UMDFControls\UDMFControls.csproj", "{2D11C828-295C-463A-8545-CA1AD6D51518}"
|
||||
|
@ -45,16 +43,6 @@ Global
|
|||
{B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|x86.ActiveCfg = Release|x86
|
||||
{B42D5AA0-F9A6-4234-9C4B-A05B11A64851}.Release|x86.Build.0 = Release|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Debug|x86.Build.0 = Debug|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|x86.ActiveCfg = Release|x86
|
||||
{760A9BC7-CB73-4C36-858B-994C14996FCD}.Release|x86.Build.0 = Release|x86
|
||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
{
|
||||
public Sidedef sidedef;
|
||||
|
||||
public int offsetx;
|
||||
public float offsetx;
|
||||
|
||||
// When this is true, the previous sidedef was on the left of
|
||||
// this one and the texture X offset of this sidedef can be set
|
||||
|
@ -1566,12 +1566,20 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
|
||||
#region ================== Texture Alignment
|
||||
|
||||
//mxd
|
||||
public static void AutoAlignTextures(Sidedef start, SidedefPart part, ImageData texture, bool alignx, bool aligny, bool resetsidemarks) {
|
||||
if(General.Map.UDMF)
|
||||
autoAlignTextures(start, part, texture, alignx, aligny, resetsidemarks);
|
||||
else
|
||||
autoAlignTextures(start, texture, alignx, aligny, resetsidemarks);
|
||||
}
|
||||
|
||||
// This performs texture alignment along all walls that match with the same texture
|
||||
// NOTE: This method uses the sidedefs marking to indicate which sides have been aligned
|
||||
// When resetsidemarks is set to true, all sidedefs will first be marked false (not aligned).
|
||||
// Setting resetsidemarks to false is usefull to align only within a specific selection
|
||||
// (set the marked property to true for the sidedefs outside the selection)
|
||||
public static void AutoAlignTextures(Sidedef start, ImageData texture, bool alignx, bool aligny, bool resetsidemarks)
|
||||
private static void autoAlignTextures(Sidedef start, ImageData texture, bool alignx, bool aligny, bool resetsidemarks)
|
||||
{
|
||||
Stack<SidedefAlignJob> todo = new Stack<SidedefAlignJob>(50);
|
||||
float scalex = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.x : 1.0f;
|
||||
|
@ -1601,10 +1609,10 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
int backwardoffset;
|
||||
|
||||
// Apply alignment
|
||||
if (alignx) j.sidedef.OffsetX = j.offsetx;
|
||||
if (alignx) j.sidedef.OffsetX = (int)j.offsetx;
|
||||
if (aligny) j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
||||
forwardoffset = j.offsetx + (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
backwardoffset = j.offsetx;
|
||||
forwardoffset = (int)j.offsetx + (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
backwardoffset = (int)j.offsetx;
|
||||
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
|
@ -1631,10 +1639,10 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
int backwardoffset;
|
||||
|
||||
// Apply alignment
|
||||
if (alignx) j.sidedef.OffsetX = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
if(alignx) j.sidedef.OffsetX = (int)j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
if (aligny) j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
||||
forwardoffset = j.offsetx;
|
||||
backwardoffset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
forwardoffset = (int)j.offsetx;
|
||||
backwardoffset = (int)j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
|
@ -1657,8 +1665,140 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
}
|
||||
}
|
||||
|
||||
//mxd. Moved here from GZDoomEditing plugin
|
||||
// This performs UDMF texture alignment along all walls that match with the same texture
|
||||
// NOTE: This method uses the sidedefs marking to indicate which sides have been aligned
|
||||
// When resetsidemarks is set to true, all sidedefs will first be marked false (not aligned).
|
||||
// Setting resetsidemarks to false is usefull to align only within a specific selection
|
||||
// (set the marked property to true for the sidedefs outside the selection)
|
||||
private static void autoAlignTextures(Sidedef start, SidedefPart part, ImageData texture, bool alignx, bool aligny, bool resetsidemarks) {
|
||||
Stack<SidedefAlignJob> todo = new Stack<SidedefAlignJob>(50);
|
||||
float scalex = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.x : 1.0f;
|
||||
float scaley = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.y : 1.0f;
|
||||
|
||||
// Mark all sidedefs false (they will be marked true when the texture is aligned)
|
||||
if(resetsidemarks) General.Map.Map.ClearMarkedSidedefs(false);
|
||||
|
||||
if(!texture.IsImageLoaded) return;
|
||||
|
||||
// Determine the Y alignment
|
||||
float ystartalign = start.OffsetY;
|
||||
switch(part) {
|
||||
case SidedefPart.Upper: ystartalign += start.Fields.GetValue("offsety_top", 0.0f); break;
|
||||
case SidedefPart.Middle: ystartalign += start.Fields.GetValue("offsety_mid", 0.0f); break;
|
||||
case SidedefPart.Lower: ystartalign += start.Fields.GetValue("offsety_bottom", 0.0f); break;
|
||||
}
|
||||
|
||||
// Begin with first sidedef
|
||||
SidedefAlignJob first = new SidedefAlignJob();
|
||||
first.sidedef = start;
|
||||
first.offsetx = start.OffsetX;
|
||||
switch(part) {
|
||||
case SidedefPart.Upper: first.offsetx += start.Fields.GetValue("offsetx_top", 0.0f); break;
|
||||
case SidedefPart.Middle: first.offsetx += start.Fields.GetValue("offsetx_mid", 0.0f); break;
|
||||
case SidedefPart.Lower: first.offsetx += start.Fields.GetValue("offsetx_bottom", 0.0f); break;
|
||||
}
|
||||
first.forward = true;
|
||||
todo.Push(first);
|
||||
|
||||
// Continue until nothing more to align
|
||||
while(todo.Count > 0) {
|
||||
Vertex v;
|
||||
float forwardoffset;
|
||||
float backwardoffset;
|
||||
float offsetscalex = 1.0f;
|
||||
|
||||
// Get the align job to do
|
||||
SidedefAlignJob j = todo.Pop();
|
||||
|
||||
bool matchtop = ((j.sidedef.LongHighTexture == texture.LongName) && j.sidedef.HighRequired());
|
||||
bool matchbottom = ((j.sidedef.LongLowTexture == texture.LongName) && j.sidedef.LowRequired());
|
||||
bool matchmid = ((j.sidedef.LongMiddleTexture == texture.LongName) && (j.sidedef.MiddleRequired() || ((j.sidedef.MiddleTexture.Length > 0) && (j.sidedef.MiddleTexture[0] != '-'))));
|
||||
|
||||
if(matchtop) offsetscalex = j.sidedef.Fields.GetValue("scalex_top", 1.0f);
|
||||
else if(matchbottom) offsetscalex = j.sidedef.Fields.GetValue("scalex_bottom", 1.0f);
|
||||
else if(matchmid) offsetscalex = j.sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
||||
|
||||
if(j.forward) {
|
||||
// Apply alignment
|
||||
if(alignx) {
|
||||
//j.sidedef.OffsetX = j.offsetx;
|
||||
float offset = j.offsetx;
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetX;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
if(aligny) {
|
||||
//j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
||||
float offset = ((float)(start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + ystartalign;
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetY;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
forwardoffset = j.offsetx + (int)Math.Round(j.sidedef.Line.Length / scalex * offsetscalex);
|
||||
backwardoffset = j.offsetx;
|
||||
|
||||
// Done this sidedef
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForAlignment(todo, v, false, backwardoffset, texture.LongName);
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForAlignment(todo, v, true, forwardoffset, texture.LongName);
|
||||
} else {
|
||||
// Apply alignment
|
||||
if(alignx) {
|
||||
//j.sidedef.OffsetX = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
float offset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetX;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
if(aligny) {
|
||||
//j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
||||
float offset = ((float)(start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + ystartalign;
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetY;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
forwardoffset = j.offsetx;
|
||||
backwardoffset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex * offsetscalex);
|
||||
|
||||
// Done this sidedef
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForAlignment(todo, v, true, forwardoffset, texture.LongName);
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForAlignment(todo, v, false, backwardoffset, texture.LongName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This adds the matching, unmarked sidedefs from a vertex for texture alignment
|
||||
private static void AddSidedefsForAlignment(Stack<SidedefAlignJob> stack, Vertex v, bool forward, int offsetx, long texturelongname)
|
||||
private static void AddSidedefsForAlignment(Stack<SidedefAlignJob> stack, Vertex v, bool forward, float offsetx, long texturelongname)
|
||||
{
|
||||
foreach(Linedef ld in v.Linedefs)
|
||||
{
|
||||
|
|
|
@ -122,25 +122,12 @@
|
|||
</Compile>
|
||||
<Compile Include="ClassicModes\DragThingsMode.cs" />
|
||||
<Compile Include="General\LineLengthLabel.cs" />
|
||||
<Compile Include="VisualModes\IVisualEventReceiver.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualGeometrySector.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualGeometrySidedef.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualMode.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualSector.cs" />
|
||||
<Compile Include="ClassicModes\DragVerticesMode.cs" />
|
||||
<Compile Include="ClassicModes\LinedefsMode.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualThing.cs" />
|
||||
<Compile Include="VisualModes\VisualCeiling.cs" />
|
||||
<Compile Include="VisualModes\VisualFloor.cs" />
|
||||
<Compile Include="VisualModes\VisualLower.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddleSingle.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ClassicModes\SectorsMode.cs" />
|
||||
<Compile Include="ClassicModes\ThingsMode.cs" />
|
||||
<Compile Include="ClassicModes\VerticesMode.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddleDouble.cs" />
|
||||
<Compile Include="VisualModes\VisualSidedefParts.cs" />
|
||||
<Compile Include="VisualModes\VisualUpper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Actions.cfg" />
|
||||
|
@ -169,7 +156,6 @@
|
|||
<SubType>Designer</SubType>
|
||||
<DependentUpon>MenusForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\VisualMode.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\Builder.csproj">
|
||||
|
@ -239,8 +225,11 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ClassicModes\BridgeMode.cs" />
|
||||
<Compile Include="ClassicModes\CeilingAlignMode.cs" />
|
||||
<Compile Include="ClassicModes\DrawEllipseMode.cs" />
|
||||
<Compile Include="ClassicModes\DrawRectangleMode.cs" />
|
||||
<Compile Include="ClassicModes\FlatAlignMode.cs" />
|
||||
<Compile Include="ClassicModes\FloorAlignMode.cs" />
|
||||
<Compile Include="ClassicModes\RedrawSectorMode.cs" />
|
||||
<Compile Include="ClassicModes\SnapVerticesMode.cs" />
|
||||
<Compile Include="ErrorChecks\CheckMissingTextures.cs" />
|
||||
|
@ -293,8 +282,37 @@
|
|||
<Compile Include="Interface\UndoRedoPanel.Designer.cs">
|
||||
<DependentUpon>UndoRedoPanel.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="VisualModes\BaseVisualGeometrySector.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualGeometrySidedef.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualMode.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualSector.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualThing.cs" />
|
||||
<Compile Include="VisualModes\Effect3DFloor.cs" />
|
||||
<Compile Include="VisualModes\EffectBrightnessLevel.cs" />
|
||||
<Compile Include="VisualModes\EffectCopySlope.cs" />
|
||||
<Compile Include="VisualModes\EffectLineSlope.cs" />
|
||||
<Compile Include="VisualModes\EffectThingLineSlope.cs" />
|
||||
<Compile Include="VisualModes\EffectThingVertexSlope.cs" />
|
||||
<Compile Include="VisualModes\EffectUDMFVertexOffset.cs" />
|
||||
<Compile Include="VisualModes\IVisualEventReceiver.cs" />
|
||||
<Compile Include="VisualModes\NullVisualEventReceiver.cs" />
|
||||
<Compile Include="VisualModes\SectorData.cs" />
|
||||
<Compile Include="VisualModes\SectorEffect.cs" />
|
||||
<Compile Include="VisualModes\SectorLevel.cs" />
|
||||
<Compile Include="VisualModes\SectorLevelComparer.cs" />
|
||||
<Compile Include="VisualModes\SectorLevelType.cs" />
|
||||
<Compile Include="VisualModes\TexturePlane.cs" />
|
||||
<Compile Include="VisualModes\ThingData.cs" />
|
||||
<Compile Include="VisualModes\VisualActionResult.cs" />
|
||||
<Compile Include="VisualModes\VisualCeiling.cs" />
|
||||
<Compile Include="VisualModes\VisualFloor.cs" />
|
||||
<Compile Include="VisualModes\VisualLower.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddle3D.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddleDouble.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddleSingle.cs" />
|
||||
<Compile Include="VisualModes\VisualSidedefParts.cs" />
|
||||
<Compile Include="VisualModes\VisualUpper.cs" />
|
||||
<Compile Include="VisualModes\WallPolygon.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\ViewSelectionIndex.png" />
|
||||
|
@ -350,6 +368,15 @@
|
|||
<ItemGroup>
|
||||
<None Include="Resources\DrawRectMode.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\CeilingAlign.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\FloorAlign.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\VisualModeGZ.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
|
@ -36,7 +36,7 @@ using CodeImp.DoomBuilder.Actions;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
[EditMode(DisplayName = "Ceiling Align Mode",
|
||||
SwitchAction = "ceilingalignmode",
|
|
@ -37,7 +37,7 @@ using CodeImp.DoomBuilder.Actions;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
public abstract class FlatAlignMode : BaseClassicMode
|
||||
{
|
|
@ -36,7 +36,7 @@ using CodeImp.DoomBuilder.Actions;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
[EditMode(DisplayName = "Floor Align Mode",
|
||||
SwitchAction = "flooralignmode",
|
|
@ -293,15 +293,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
ImageData img = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
||||
if((img != null) && img.IsImageLoaded)
|
||||
{
|
||||
// Make scalars
|
||||
float sw = 1.0f / img.ScaledWidth;
|
||||
float sh = 1.0f / img.ScaledHeight;
|
||||
|
||||
// Make proper texture coordinates
|
||||
for(int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
vertices[i].u = vertices[i].u * sw;
|
||||
vertices[i].v = -vertices[i].v * sh;
|
||||
//mxd. Merged from GZDoomEditing plugin
|
||||
if(General.Map.UDMF) {
|
||||
// Fetch ZDoom fields
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f),
|
||||
s.Fields.GetValue("ypanningfloor", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f),
|
||||
s.Fields.GetValue("yscalefloor", 1.0f));
|
||||
float rotate = s.Fields.GetValue("rotationfloor", 0.0f);
|
||||
int color = s.Fields.GetValue("lightcolor", -1);
|
||||
int light = s.Fields.GetValue("lightfloor", 0);
|
||||
bool absolute = s.Fields.GetValue("lightfloorabsolute", false);
|
||||
|
||||
// Setup the vertices with the given settings
|
||||
SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute);
|
||||
} else {
|
||||
// Make scalars
|
||||
float sw = 1.0f / img.ScaledWidth;
|
||||
float sh = 1.0f / img.ScaledHeight;
|
||||
|
||||
// Make proper texture coordinates
|
||||
for(int i = 0; i < vertices.Length; i++) {
|
||||
vertices[i].u = vertices[i].u * sw;
|
||||
vertices[i].v = -vertices[i].v * sh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,15 +327,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
ImageData img = General.Map.Data.GetFlatImage(s.LongCeilTexture);
|
||||
if((img != null) && img.IsImageLoaded)
|
||||
{
|
||||
// Make scalars
|
||||
float sw = 1.0f / img.ScaledWidth;
|
||||
float sh = 1.0f / img.ScaledHeight;
|
||||
//mxd. Merged from GZDoomEditing plugin
|
||||
if(General.Map.UDMF) {
|
||||
// Fetch ZDoom fields
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
|
||||
s.Fields.GetValue("ypanningceiling", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
|
||||
s.Fields.GetValue("yscaleceiling", 1.0f));
|
||||
float rotate = s.Fields.GetValue("rotationceiling", 0.0f);
|
||||
int color = s.Fields.GetValue("lightcolor", -1);
|
||||
int light = s.Fields.GetValue("lightceiling", 0);
|
||||
bool absolute = s.Fields.GetValue("lightceilingabsolute", false);
|
||||
|
||||
// Make proper texture coordinates
|
||||
for(int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
vertices[i].u = vertices[i].u * sw;
|
||||
vertices[i].v = -vertices[i].v * sh;
|
||||
// Setup the vertices with the given settings
|
||||
SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute);
|
||||
} else {
|
||||
// Make scalars
|
||||
float sw = 1.0f / img.ScaledWidth;
|
||||
float sh = 1.0f / img.ScaledHeight;
|
||||
|
||||
// Make proper texture coordinates
|
||||
for(int i = 0; i < vertices.Length; i++) {
|
||||
vertices[i].u = vertices[i].u * sw;
|
||||
vertices[i].v = -vertices[i].v * sh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,6 +465,31 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Tools
|
||||
|
||||
//mxd. merged from GZDoomEditing plugin
|
||||
// This applies the given values on the vertices
|
||||
private void SetupSurfaceVertices(FlatVertex[] vertices, Sector s, ImageData img, Vector2D offset,
|
||||
Vector2D scale, float rotate, int color, int light, bool absolute) {
|
||||
// Prepare for math!
|
||||
rotate = Angle2D.DegToRad(rotate);
|
||||
Vector2D texscale = new Vector2D(1.0f / img.ScaledWidth, 1.0f / img.ScaledHeight);
|
||||
if(!absolute) light = s.Brightness + light;
|
||||
PixelColor lightcolor = PixelColor.FromInt(color);
|
||||
PixelColor brightness = PixelColor.FromInt(General.Map.Renderer2D.CalculateBrightness(light));
|
||||
PixelColor finalcolor = PixelColor.Modulate(lightcolor, brightness);
|
||||
color = finalcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Do the math for all vertices
|
||||
for(int i = 0; i < vertices.Length; i++) {
|
||||
Vector2D pos = new Vector2D(vertices[i].x, vertices[i].y);
|
||||
pos = pos.GetRotated(rotate);
|
||||
pos.y = -pos.y;
|
||||
pos = (pos + offset) * scale * texscale;
|
||||
vertices[i].u = pos.x;
|
||||
vertices[i].v = pos.y;
|
||||
vertices[i].c = color;
|
||||
}
|
||||
}
|
||||
|
||||
// This adjusts texture coordinates for splitted lines according to the user preferences
|
||||
public void AdjustSplitCoordinates(Linedef oldline, Linedef newline)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public const int SectorBrightnessChange = 3;
|
||||
public const int TextureOffsetChange = 4;
|
||||
public const int SectorHeightChange = 5;
|
||||
public const int ThingMove = 6; //mxd
|
||||
public const int ThingRotate = 7; //mxd
|
||||
public const int ThingMove = 6; //mxd
|
||||
public const int ThingRotate = 7; //mxd
|
||||
public const int SurfaceBrightnessChange = 8; //mxd
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
|
|||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Builder Modes")]
|
||||
[assembly: AssemblyDescription("Doom Builder Editing Modes")]
|
||||
[assembly: AssemblyDescription("GZDoom Builder Editing Modes")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("CodeImp")]
|
||||
[assembly: AssemblyCompany("CodeImp, MaxED")]
|
||||
[assembly: AssemblyProduct("Doom Builder")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2007")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2007, 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// Этот код создан программой.
|
||||
// Исполняемая версия:2.0.50727.5420
|
||||
// Исполняемая версия:2.0.50727.5466
|
||||
//
|
||||
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
|
||||
// повторной генерации кода.
|
||||
|
@ -74,6 +74,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
internal static System.Drawing.Bitmap CeilingAlign {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("CeilingAlign", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
internal static System.Drawing.Bitmap CeilsGradient {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("CeilsGradient", resourceCulture);
|
||||
|
@ -137,6 +144,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
internal static System.Drawing.Bitmap FloorAlign {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("FloorAlign", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
internal static System.Drawing.Bitmap FloorsGradient {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("FloorsGradient", resourceCulture);
|
||||
|
@ -192,5 +206,12 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
internal static System.Drawing.Bitmap VisualModeGZ {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("VisualModeGZ", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,4 +175,13 @@
|
|||
<data name="DrawRectMode" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\DrawRectMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CeilingAlign" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CeilingAlign.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="FloorAlign" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\FloorAlign.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="VisualModeGZ" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\VisualModeGZ.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
|
@ -77,18 +77,6 @@ thingsmode
|
|||
allowscroll = true;
|
||||
}
|
||||
|
||||
/*
|
||||
triangulatormode
|
||||
{
|
||||
title = "Triangulator Mode";
|
||||
category = "modes";
|
||||
description = "Debug stuff";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
*/
|
||||
|
||||
drawlinesmode
|
||||
{
|
||||
title = "Start Drawing";
|
||||
|
@ -226,16 +214,6 @@ finishdraw
|
|||
allowscroll = true;
|
||||
}
|
||||
|
||||
visualmode
|
||||
{
|
||||
title = "Visual Mode";
|
||||
category = "modes";
|
||||
description = "Switches to visual editing mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
|
||||
selectsinglesided
|
||||
{
|
||||
title = "Select Single-sided";
|
||||
|
@ -861,4 +839,47 @@ redrawsectormode
|
|||
allowkeys = true;
|
||||
allowmouse = false;
|
||||
allowscroll = false;
|
||||
}
|
||||
|
||||
//mxd. moved from GZDoomEditing plugin
|
||||
gzdbvisualmode
|
||||
{
|
||||
title = "GZDB Visual Mode";
|
||||
category = "modes";
|
||||
description = "Switches to the (G)ZDoom visual editing mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
default = 81; //Q
|
||||
}
|
||||
|
||||
flooralignmode
|
||||
{
|
||||
title = "Floor Align Mode";
|
||||
category = "modes";
|
||||
description = "Switches to the (G)ZDoom Floor Align mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
|
||||
ceilingalignmode
|
||||
{
|
||||
title = "Ceiling Align Mode";
|
||||
category = "modes";
|
||||
description = "Switches to the (G)ZDoom Ceiling Align mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
|
||||
togglegzdoomrenderingeffects
|
||||
{
|
||||
title = "Toggle GZDoom rendering effects";
|
||||
category = "visual";
|
||||
description = "Toggles rendering of GZDoom rendering effects (slopes, 3D-floors etc.) in GZDoom Visual mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = false;
|
||||
default = 9; //Tab
|
||||
}
|
Before Width: | Height: | Size: 579 B After Width: | Height: | Size: 579 B |
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 583 B |
Before Width: | Height: | Size: 794 B |
BIN
Source/Plugins/BuilderModes/Resources/VisualModeGZ.png
Normal file
After Width: | Height: | Size: 905 B |
|
@ -19,6 +19,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
@ -41,6 +42,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
#region ================== Constants
|
||||
|
||||
private const float DRAG_ANGLE_TOLERANCE = 0.06f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
@ -52,6 +55,25 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// in a multiselection. The Changed property on the BaseVisualSector is
|
||||
// used to indicate a rebuild is needed.
|
||||
protected bool changed;
|
||||
|
||||
protected SectorLevel level;
|
||||
protected Effect3DFloor extrafloor;
|
||||
|
||||
// Undo/redo
|
||||
private int undoticket;
|
||||
|
||||
// UV dragging
|
||||
private float dragstartanglexy;
|
||||
private float dragstartanglez;
|
||||
private Vector3D dragorigin;
|
||||
private Vector3D deltaxy;
|
||||
private Vector3D deltaz;
|
||||
private int startoffsetx;
|
||||
private int startoffsety;
|
||||
protected bool uvdragging;
|
||||
private int prevoffsetx; // We have to provide delta offsets, but I don't
|
||||
private int prevoffsety; // want to calculate with delta offsets to prevent
|
||||
// inaccuracy in the dragging.
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -59,13 +81,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
new public BaseVisualSector Sector { get { return (BaseVisualSector)base.Sector; } }
|
||||
public bool Changed { get { return changed; } set { changed = value; } }
|
||||
public SectorLevel Level { get { return level; } }
|
||||
public Effect3DFloor ExtraFloor { get { return extrafloor; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
// Constructor
|
||||
public BaseVisualGeometrySector(BaseVisualMode mode, VisualSector vs) : base(vs)
|
||||
protected BaseVisualGeometrySector(BaseVisualMode mode, VisualSector vs) : base(vs)
|
||||
{
|
||||
this.mode = mode;
|
||||
}
|
||||
|
@ -76,17 +100,90 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
// This changes the height
|
||||
protected abstract void ChangeHeight(int amount);
|
||||
|
||||
// This swaps triangles so that the plane faces the other way
|
||||
protected void SwapTriangleVertices(WorldVertex[] verts)
|
||||
{
|
||||
// Swap some vertices to flip all triangles
|
||||
for(int i = 0; i < verts.Length; i += 3)
|
||||
{
|
||||
// Swap
|
||||
WorldVertex v = verts[i];
|
||||
verts[i] = verts[i + 1];
|
||||
verts[i + 1] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// This is called to update UV dragging
|
||||
protected virtual void UpdateDragUV()
|
||||
{
|
||||
float u_ray = 1.0f;
|
||||
|
||||
// Calculate intersection position
|
||||
this.Level.plane.GetIntersection(General.Map.VisualCamera.Position, General.Map.VisualCamera.Target, ref u_ray);
|
||||
Vector3D intersect = General.Map.VisualCamera.Position + (General.Map.VisualCamera.Target - General.Map.VisualCamera.Position) * u_ray;
|
||||
|
||||
// Calculate offsets
|
||||
Vector3D dragdelta = intersect - dragorigin;
|
||||
float offsetx = dragdelta.x;
|
||||
float offsety = dragdelta.y;
|
||||
|
||||
//mxd. Modify offsets based on surface and camera angles
|
||||
if (General.Map.UDMF) {
|
||||
float angle = 0;
|
||||
if (GeometryType == VisualGeometryType.CEILING && level.sector.Fields.ContainsKey("rotationceiling"))
|
||||
angle = (float)level.sector.Fields["rotationceiling"].Value * (float)Math.PI / 180f;
|
||||
else if (GeometryType == VisualGeometryType.FLOOR && level.sector.Fields.ContainsKey("rotationfloor"))
|
||||
angle = (float)level.sector.Fields["rotationfloor"].Value * (float)Math.PI / 180f;
|
||||
|
||||
Vector2D v = new Vector2D(offsetx, offsety).GetRotated(angle);
|
||||
Point p = getTranslatedTextureOffset(new Point((int)Math.Round(v.x), (int)Math.Round(v.y)));
|
||||
offsetx = p.X;
|
||||
offsety = p.Y;
|
||||
}
|
||||
|
||||
// Apply offsets
|
||||
int newoffsetx = startoffsetx - (int)Math.Round(offsetx);
|
||||
int newoffsety = startoffsety + (int)Math.Round(offsety);
|
||||
mode.ApplyFlatOffsetChange(prevoffsetx - newoffsetx, prevoffsety - newoffsety);
|
||||
prevoffsetx = newoffsetx;
|
||||
prevoffsety = newoffsety;
|
||||
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override Sector GetControlSector() {
|
||||
return level.sector;
|
||||
}
|
||||
|
||||
//mxd. Modify texture offsets based on camera angle (so "movetextureleft" action always moves texture more or less "left" etc.)
|
||||
protected Point getTranslatedTextureOffset(Point p) {
|
||||
Point tp = new Point();
|
||||
int camAngle = (int)(General.Map.VisualCamera.AngleXY * 180f / (float)Math.PI);
|
||||
|
||||
if (camAngle > 315 || camAngle < 46) {
|
||||
tp = p;
|
||||
} else if (camAngle > 225) {
|
||||
tp.Y = p.X;
|
||||
tp.X = -p.Y;
|
||||
} else if (camAngle > 135) {
|
||||
tp.X = -p.X;
|
||||
tp.Y = -p.Y;
|
||||
}else{
|
||||
tp.Y = -p.X;
|
||||
tp.X = p.Y;
|
||||
}
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
||||
// Unused
|
||||
public abstract bool Setup();
|
||||
public virtual void OnSelectBegin(){ }
|
||||
public virtual void OnEditBegin() { }
|
||||
public virtual void OnMouseMove(MouseEventArgs e) { }
|
||||
public virtual void OnChangeTextureOffset(int horizontal, int vertical) { }
|
||||
public virtual void OnTextureAlign(bool alignx, bool aligny) { }
|
||||
public virtual void OnToggleUpperUnpegged() { }
|
||||
public virtual void OnToggleLowerUnpegged() { }
|
||||
|
@ -98,19 +195,87 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
protected virtual void SetTexture(string texturename) { }
|
||||
public virtual void ApplyUpperUnpegged(bool set) { }
|
||||
public virtual void ApplyLowerUnpegged(bool set) { }
|
||||
protected abstract void MoveTextureOffset(Point xy);
|
||||
protected abstract Point GetTextureOffset();
|
||||
|
||||
// Setup this plane
|
||||
public bool Setup() { return this.Setup(this.level, this.extrafloor); }
|
||||
public virtual bool Setup(SectorLevel level, Effect3DFloor extrafloor)
|
||||
{
|
||||
this.level = level;
|
||||
this.extrafloor = extrafloor;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin select
|
||||
public virtual void OnSelectBegin()
|
||||
{
|
||||
mode.LockTarget();
|
||||
dragstartanglexy = General.Map.VisualCamera.AngleXY;
|
||||
dragstartanglez = General.Map.VisualCamera.AngleZ;
|
||||
dragorigin = pickintersect;
|
||||
startoffsetx = GetTextureOffset().X;
|
||||
startoffsety = GetTextureOffset().Y;
|
||||
prevoffsetx = GetTextureOffset().X;
|
||||
prevoffsety = GetTextureOffset().Y;
|
||||
}
|
||||
|
||||
// Select or deselect
|
||||
public virtual void OnSelectEnd()
|
||||
{
|
||||
if(this.selected)
|
||||
mode.UnlockTarget();
|
||||
|
||||
// Was dragging?
|
||||
if(uvdragging)
|
||||
{
|
||||
this.selected = false;
|
||||
mode.RemoveSelectedObject(this);
|
||||
// Dragging stops now
|
||||
uvdragging = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.selected = true;
|
||||
mode.AddSelectedObject(this);
|
||||
if(this.selected)
|
||||
{
|
||||
this.selected = false;
|
||||
mode.RemoveSelectedObject(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.selected = true;
|
||||
mode.AddSelectedObject(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moving the mouse
|
||||
public virtual void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
// Dragging UV?
|
||||
if(uvdragging)
|
||||
{
|
||||
UpdateDragUV();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select button pressed?
|
||||
if(General.Actions.CheckActionActive(General.ThisAssembly, "visualselect"))
|
||||
{
|
||||
// Check if tolerance is exceeded to start UV dragging
|
||||
float deltaxy = General.Map.VisualCamera.AngleXY - dragstartanglexy;
|
||||
float deltaz = General.Map.VisualCamera.AngleZ - dragstartanglez;
|
||||
if((Math.Abs(deltaxy) + Math.Abs(deltaz)) > DRAG_ANGLE_TOLERANCE)
|
||||
{
|
||||
if(General.Map.UDMF) { //mxd
|
||||
mode.PreAction(UndoGroup.TextureOffsetChange);
|
||||
mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Start drag now
|
||||
uvdragging = true;
|
||||
mode.Renderer.ShowSelection = false;
|
||||
mode.Renderer.ShowHighlight = false;
|
||||
UpdateDragUV();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +369,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Copy properties
|
||||
public virtual void OnCopyProperties()
|
||||
{
|
||||
BuilderPlug.Me.CopiedSectorProps = new SectorProperties(Sector.Sector);
|
||||
BuilderPlug.Me.CopiedSectorProps = new SectorProperties(level.sector);
|
||||
mode.SetActionResult("Copied sector properties.");
|
||||
}
|
||||
|
||||
|
@ -215,8 +380,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
mode.CreateUndo("Paste sector properties");
|
||||
mode.SetActionResult("Pasted sector properties.");
|
||||
BuilderPlug.Me.CopiedSectorProps.Apply(Sector.Sector);
|
||||
Sector.UpdateSectorGeometry(true);
|
||||
BuilderPlug.Me.CopiedSectorProps.Apply(level.sector);
|
||||
if(mode.VisualSectorExists(level.sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
vs.UpdateSectorGeometry(true);
|
||||
}
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
|
@ -267,9 +436,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Rebuild sector
|
||||
foreach(Sector s in sectors)
|
||||
{
|
||||
VisualSector vs = mode.GetVisualSector(s);
|
||||
if(vs != null)
|
||||
(vs as BaseVisualSector).UpdateSectorGeometry(true);
|
||||
if(mode.VisualSectorExists(s))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s);
|
||||
vs.UpdateSectorGeometry(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,11 +450,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
changed = true;
|
||||
|
||||
|
||||
ChangeHeight(amount);
|
||||
|
||||
// Rebuild sector
|
||||
Sector.UpdateSectorGeometry(true);
|
||||
BaseVisualSector vs;
|
||||
if(mode.VisualSectorExists(level.sector)) {
|
||||
vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
//vs.UpdateSectorGeometry(true);
|
||||
} else {//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
|
||||
vs = mode.CreateBaseVisualSector(level.sector);
|
||||
}
|
||||
|
||||
if(vs != null) vs.UpdateSectorGeometry(true);
|
||||
}
|
||||
|
||||
// Sector brightness change
|
||||
|
@ -303,6 +482,27 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
// Texture offset change
|
||||
public virtual void OnChangeTextureOffset(int horizontal, int vertical)
|
||||
{
|
||||
//mxd
|
||||
if (General.Map.UDMF) {
|
||||
if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Apply offsets
|
||||
MoveTextureOffset(new Point(-horizontal, -vertical));
|
||||
|
||||
mode.SetActionResult("Changed texture offsets by " + -horizontal + ", " + -vertical + ".");
|
||||
|
||||
// Update sector geometry
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
Sector.Rebuild();
|
||||
} else {
|
||||
General.ShowErrorMessage("Floor/ceiling texture offsets cannot be changed in this map format!", MessageBoxButtons.OK);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
protected BaseVisualMode mode;
|
||||
|
||||
protected float top;
|
||||
protected float bottom;
|
||||
protected Plane top;
|
||||
protected Plane bottom;
|
||||
protected long setuponloadedtexture;
|
||||
|
||||
// UV dragging
|
||||
|
@ -93,13 +93,52 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Methods
|
||||
|
||||
// This sets the renderstyle from linedef information and returns the alpha value or the vertices
|
||||
protected byte SetLinedefRenderstyle(bool solidasmask)
|
||||
{
|
||||
byte alpha = 255;
|
||||
|
||||
// From TranslucentLine action
|
||||
if(Sidedef.Line.Action == 208)
|
||||
{
|
||||
alpha = (byte)General.Clamp(Sidedef.Line.Args[1], 0, 255);
|
||||
|
||||
if(Sidedef.Line.Args[2] == 1)
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if(alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else if(solidasmask)
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
else
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// From UDMF field
|
||||
string field = Sidedef.Line.Fields.GetValue("renderstyle", "translucent");
|
||||
alpha = (byte)(Sidedef.Line.Fields.GetValue("alpha", 1.0f) * 255.0f);
|
||||
|
||||
if(field == "add")
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if(alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else if(solidasmask)
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
else
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
|
||||
return alpha;
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
// Check if intersection point is between top and bottom
|
||||
return (pickintersect.z >= bottom) && (pickintersect.z <= top);
|
||||
return (pickintersect.z >= bottom.GetZ(pickintersect)) && (pickintersect.z <= top.GetZ(pickintersect));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||
{
|
||||
|
@ -109,6 +148,232 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This creates vertices from a wall polygon and applies lighting
|
||||
protected List<WorldVertex> CreatePolygonVertices(WallPolygon poly, TexturePlane tp, SectorData sd, int lightvalue, bool lightabsolute)
|
||||
{
|
||||
List<WallPolygon> polylist = new List<WallPolygon>(1);
|
||||
polylist.Add(poly);
|
||||
return CreatePolygonVertices(polylist, tp, sd, lightvalue, lightabsolute);
|
||||
}
|
||||
|
||||
// This creates vertices from a wall polygon and applies lighting
|
||||
protected List<WorldVertex> CreatePolygonVertices(List<WallPolygon> poly, TexturePlane tp, SectorData sd, int lightvalue, bool lightabsolute)
|
||||
{
|
||||
List<WallPolygon> polygons = new List<WallPolygon>(poly);
|
||||
List<WorldVertex> verts = new List<WorldVertex>();
|
||||
|
||||
// Go for all levels to build geometry
|
||||
for(int i = sd.LightLevels.Count - 1; i >= 0; i--)
|
||||
{
|
||||
SectorLevel l = sd.LightLevels[i];
|
||||
|
||||
if((l != sd.Floor) && (l != sd.Ceiling) && (l.type != SectorLevelType.Floor))
|
||||
{
|
||||
// Go for all polygons
|
||||
int num = polygons.Count;
|
||||
for(int pi = 0; pi < num; pi++)
|
||||
{
|
||||
// Split by plane
|
||||
WallPolygon p = polygons[pi];
|
||||
WallPolygon np = SplitPoly(ref p, l.plane, false);
|
||||
if(np.Count > 0)
|
||||
{
|
||||
// Determine color
|
||||
int lightlevel = lightabsolute ? lightvalue : l.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
//PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(l.colorbelow, wallbrightness);
|
||||
np.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
if(p.Count == 0)
|
||||
{
|
||||
polygons[pi] = np;
|
||||
}
|
||||
else
|
||||
{
|
||||
polygons[pi] = p;
|
||||
polygons.Add(np);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
polygons[pi] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go for all polygons to make geometry
|
||||
foreach(WallPolygon p in polygons)
|
||||
{
|
||||
// Find texture coordinates for each vertex in the polygon
|
||||
List<Vector2D> texc = new List<Vector2D>(p.Count);
|
||||
foreach(Vector3D v in p)
|
||||
texc.Add(tp.GetTextureCoordsAt(v));
|
||||
|
||||
// Now we create triangles from the polygon.
|
||||
// The polygon is convex and clockwise, so this is a piece of cake.
|
||||
if(p.Count >= 3)
|
||||
{
|
||||
for(int k = 1; k < (p.Count - 1); k++)
|
||||
{
|
||||
verts.Add(new WorldVertex(p[0], p.color, texc[0]));
|
||||
verts.Add(new WorldVertex(p[k], p.color, texc[k]));
|
||||
verts.Add(new WorldVertex(p[k + 1], p.color, texc[k + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verts;
|
||||
}
|
||||
|
||||
// This splits a polygon with a plane and returns the other part as a new polygon
|
||||
// The polygon is expected to be convex and clockwise
|
||||
protected WallPolygon SplitPoly(ref WallPolygon poly, Plane p, bool keepfront)
|
||||
{
|
||||
const float NEAR_ZERO = 0.01f;
|
||||
WallPolygon front = new WallPolygon(poly.Count);
|
||||
WallPolygon back = new WallPolygon(poly.Count);
|
||||
poly.CopyProperties(front);
|
||||
poly.CopyProperties(back);
|
||||
|
||||
if(poly.Count > 0)
|
||||
{
|
||||
// Go for all vertices to see which side they have to be on
|
||||
Vector3D v1 = poly[poly.Count - 1];
|
||||
float side1 = p.Distance(v1);
|
||||
for(int i = 0; i < poly.Count; i++)
|
||||
{
|
||||
// Fetch vertex and determine side
|
||||
Vector3D v2 = poly[i];
|
||||
float side2 = p.Distance(v2);
|
||||
|
||||
// Front?
|
||||
if(side2 > NEAR_ZERO)
|
||||
{
|
||||
if(side1 < -NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
front.Add(v3);
|
||||
back.Add(v3);
|
||||
}
|
||||
|
||||
front.Add(v2);
|
||||
}
|
||||
// Back?
|
||||
else if(side2 < -NEAR_ZERO)
|
||||
{
|
||||
if(side1 > NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
front.Add(v3);
|
||||
back.Add(v3);
|
||||
}
|
||||
|
||||
back.Add(v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// On the plane, add to both polygons
|
||||
front.Add(v2);
|
||||
back.Add(v2);
|
||||
}
|
||||
|
||||
// Next
|
||||
v1 = v2;
|
||||
side1 = side2;
|
||||
}
|
||||
}
|
||||
|
||||
if(keepfront)
|
||||
{
|
||||
poly = front;
|
||||
return back;
|
||||
}
|
||||
else
|
||||
{
|
||||
poly = back;
|
||||
return front;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This crops a polygon with a plane and keeps only a certain part of the polygon
|
||||
protected void CropPoly(ref WallPolygon poly, Plane p, bool keepfront)
|
||||
{
|
||||
const float NEAR_ZERO = 0.01f;
|
||||
float sideswitch = keepfront ? 1 : -1;
|
||||
WallPolygon newp = new WallPolygon(poly.Count);
|
||||
poly.CopyProperties(newp);
|
||||
|
||||
if(poly.Count > 0)
|
||||
{
|
||||
// First split lines that cross the plane so that we have vertices on the plane where the lines cross
|
||||
Vector3D v1 = poly[poly.Count - 1];
|
||||
float side1 = p.Distance(v1) * sideswitch;
|
||||
for(int i = 0; i < poly.Count; i++)
|
||||
{
|
||||
// Fetch vertex and determine side
|
||||
Vector3D v2 = poly[i];
|
||||
float side2 = p.Distance(v2) * sideswitch;
|
||||
|
||||
// Front?
|
||||
if(side2 > NEAR_ZERO)
|
||||
{
|
||||
if(side1 < -NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
newp.Add(v3);
|
||||
}
|
||||
|
||||
newp.Add(v2);
|
||||
}
|
||||
// Back?
|
||||
else if(side2 < -NEAR_ZERO)
|
||||
{
|
||||
if(side1 > NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
newp.Add(v3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// On the plane
|
||||
newp.Add(v2);
|
||||
}
|
||||
|
||||
// Next
|
||||
v1 = v2;
|
||||
side1 = side2;
|
||||
}
|
||||
}
|
||||
|
||||
poly = newp;
|
||||
}
|
||||
|
||||
//mxd
|
||||
protected float getRoundedTextureOffset(float oldValue, float offset, float scale) {
|
||||
if(offset == 0f) return oldValue;
|
||||
float result = (float)Math.Round(oldValue + (offset * scale));
|
||||
if (result == oldValue) result += 1f * (offset < 0 ? -1 : 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
@ -117,6 +382,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnEditBegin() { }
|
||||
protected virtual void SetTexture(string texturename) { }
|
||||
public abstract bool Setup();
|
||||
protected abstract void SetTextureOffsetX(int x);
|
||||
protected abstract void SetTextureOffsetY(int y);
|
||||
protected abstract void MoveTextureOffset(Point xy);
|
||||
protected abstract Point GetTextureOffset();
|
||||
|
||||
// Insert middle texture
|
||||
public virtual void OnInsert()
|
||||
|
@ -209,9 +478,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
mode.SetActionResult("Texture offsets reset.");
|
||||
|
||||
// Apply offsets
|
||||
Sidedef.OffsetX = 0;
|
||||
Sidedef.OffsetY = 0;
|
||||
|
||||
SetTextureOffsetX(0);
|
||||
SetTextureOffsetY(0);
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
parts.SetupAllParts();
|
||||
|
@ -390,9 +659,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
List<Sidedef> sides = mode.GetSelectedSidedefs();
|
||||
foreach(Sidedef sd in sides) sd.Marked = false;
|
||||
}
|
||||
|
||||
SidedefPart part;
|
||||
if(this is VisualLower)
|
||||
part = SidedefPart.Lower;
|
||||
else if(this is VisualUpper)
|
||||
part = SidedefPart.Upper;
|
||||
else
|
||||
part = SidedefPart.Middle;
|
||||
|
||||
// Do the alignment
|
||||
Tools.AutoAlignTextures(this.Sidedef, base.Texture, alignx, aligny, false);
|
||||
Tools.AutoAlignTextures(this.Sidedef, part, base.Texture, alignx, aligny, false);
|
||||
|
||||
// Get the changed sidedefs
|
||||
List<Sidedef> changes = General.Map.Map.GetMarkedSidedefs(true);
|
||||
|
@ -444,9 +721,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnPasteTextureOffsets()
|
||||
{
|
||||
mode.CreateUndo("Paste texture offsets");
|
||||
Sidedef.OffsetX = BuilderPlug.Me.CopiedOffsets.X;
|
||||
Sidedef.OffsetY = BuilderPlug.Me.CopiedOffsets.Y;
|
||||
mode.SetActionResult("Pasted texture offsets " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
|
||||
SetTextureOffsetX(BuilderPlug.Me.CopiedOffsets.X);
|
||||
SetTextureOffsetY(BuilderPlug.Me.CopiedOffsets.Y);
|
||||
mode.SetActionResult("Pasted texture offsets " + BuilderPlug.Me.CopiedOffsets.X + ", " + BuilderPlug.Me.CopiedOffsets.Y + ".");
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
|
@ -464,8 +741,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Copy texture offsets
|
||||
public virtual void OnCopyTextureOffsets()
|
||||
{
|
||||
BuilderPlug.Me.CopiedOffsets = new Point(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
mode.SetActionResult("Copied texture offsets " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
|
||||
BuilderPlug.Me.CopiedOffsets = GetTextureOffset();
|
||||
mode.SetActionResult("Copied texture offsets " + BuilderPlug.Me.CopiedOffsets.X + ", " + BuilderPlug.Me.CopiedOffsets.Y + ".");
|
||||
}
|
||||
|
||||
// Copy properties
|
||||
|
@ -506,10 +783,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
dragstartanglexy = General.Map.VisualCamera.AngleXY;
|
||||
dragstartanglez = General.Map.VisualCamera.AngleZ;
|
||||
dragorigin = pickintersect;
|
||||
startoffsetx = Sidedef.OffsetX;
|
||||
startoffsety = Sidedef.OffsetY;
|
||||
prevoffsetx = Sidedef.OffsetX;
|
||||
prevoffsety = Sidedef.OffsetY;
|
||||
startoffsetx = GetTextureOffset().X;
|
||||
startoffsety = GetTextureOffset().Y;
|
||||
prevoffsetx = GetTextureOffset().X;
|
||||
prevoffsety = GetTextureOffset().Y;
|
||||
}
|
||||
|
||||
// Select button released
|
||||
|
@ -552,18 +829,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
if(l.Front != null)
|
||||
{
|
||||
VisualSector vs = mode.GetVisualSector(l.Front.Sector);
|
||||
if(vs != null)
|
||||
(vs as BaseVisualSector).Changed = true;
|
||||
if(mode.VisualSectorExists(l.Front.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(l.Front.Sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(l.Back != null)
|
||||
{
|
||||
VisualSector vs = mode.GetVisualSector(l.Back.Sector);
|
||||
if(vs != null)
|
||||
(vs as BaseVisualSector).Changed = true;
|
||||
if(mode.VisualSectorExists(l.Back.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(l.Back.Sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode.RebuildElementData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -586,14 +869,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
float deltaz = General.Map.VisualCamera.AngleZ - dragstartanglez;
|
||||
if((Math.Abs(deltaxy) + Math.Abs(deltaz)) > DRAG_ANGLE_TOLERANCE)
|
||||
{
|
||||
mode.PreAction(UndoGroup.TextureOffsetChange);
|
||||
mode.CreateUndo("Change texture offsets");
|
||||
mode.PreAction(UndoGroup.TextureOffsetChange);
|
||||
mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Start drag now
|
||||
uvdragging = true;
|
||||
mode.Renderer.ShowSelection = false;
|
||||
mode.Renderer.ShowHighlight = false;
|
||||
UpdateDragUV();
|
||||
// Start drag now
|
||||
uvdragging = true;
|
||||
mode.Renderer.ShowSelection = false;
|
||||
mode.Renderer.ShowHighlight = false;
|
||||
UpdateDragUV();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -646,7 +929,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
Sector.Sector.UpdateCache();
|
||||
|
||||
// Rebuild sector
|
||||
Sector.Changed = true;
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
|
||||
// Go for all things in this sector
|
||||
foreach(Thing t in General.Map.Map.Things)
|
||||
|
@ -670,11 +953,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Apply offsets
|
||||
Sidedef.OffsetX -= horizontal;
|
||||
Sidedef.OffsetY -= vertical;
|
||||
|
||||
mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
|
||||
//mxd
|
||||
if (General.Map.UDMF) {
|
||||
// Apply UDMF offsets
|
||||
MoveTextureOffset(new Point(-horizontal, -vertical));
|
||||
Point p = GetTextureOffset();
|
||||
mode.SetActionResult("Changed texture offsets to " + p.X + ", " + p.Y + ".");
|
||||
} else {
|
||||
// Apply classic offsets
|
||||
Sidedef.OffsetX -= horizontal;
|
||||
Sidedef.OffsetY -= vertical;
|
||||
mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
|
||||
}
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
@ -39,17 +40,16 @@ using CodeImp.DoomBuilder.GZBuilder.Data;
|
|||
|
||||
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)
|
||||
[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)]
|
||||
UseByDefault = true)]
|
||||
|
||||
public class BaseVisualMode : VisualMode
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
// Object picking
|
||||
private const float PICK_INTERVAL = 80.0f;
|
||||
private const float PICK_RANGE = 0.98f;
|
||||
|
@ -70,6 +70,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
private VisualPickResult target;
|
||||
private float lastpicktime;
|
||||
private bool locktarget;
|
||||
|
||||
// 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
|
||||
|
@ -87,6 +91,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
private List<IVisualEventReceiver> selectedobjects;
|
||||
//mxd. Used in Cut/PasteSelection actions
|
||||
private List<ThingCopyData> copyBuffer;
|
||||
private static bool gzdoomRenderingEffects = true; //mxd
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -159,7 +164,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
|
||||
// This calculates brightness level
|
||||
internal int CalculateBrightness(int level)
|
||||
{
|
||||
|
@ -241,6 +246,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
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;
|
||||
}
|
||||
|
@ -326,6 +333,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
|
@ -387,13 +401,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
General.Interface.HideInfo();
|
||||
}
|
||||
}
|
||||
// Thing picked?
|
||||
if(target.picked is VisualThing)
|
||||
|
@ -409,7 +433,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
// This updates the VisualSectors and VisualThings that have their Changed property set
|
||||
private void UpdateChangedObjects()
|
||||
private void UpdateChangedObjects()
|
||||
{
|
||||
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
|
||||
{
|
||||
|
@ -511,9 +535,211 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#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];
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
|
@ -528,6 +754,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Read settings
|
||||
cameraflooroffset = General.Map.Config.ReadSetting("cameraflooroffset", cameraflooroffset);
|
||||
cameraceilingoffset = General.Map.Config.ReadSetting("cameraceilingoffset", cameraceilingoffset);
|
||||
|
||||
RebuildElementData();
|
||||
}
|
||||
|
||||
// When returning to another mode
|
||||
|
@ -552,29 +780,53 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// 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?
|
||||
if(General.Map.VisualCamera.Position.z <= (General.Map.VisualCamera.Sector.FloorHeight + cameraflooroffset + 0.1f))
|
||||
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,
|
||||
General.Map.VisualCamera.Sector.FloorHeight + cameraflooroffset);
|
||||
floorheight + cameraflooroffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fall down
|
||||
gravity += new Vector3D(0.0f, 0.0f, (float)(GRAVITY * deltatime));
|
||||
General.Map.VisualCamera.Position += gravity;
|
||||
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 level?
|
||||
if(General.Map.VisualCamera.Position.z >= (General.Map.VisualCamera.Sector.CeilHeight - cameraceilingoffset - 0.1f))
|
||||
|
||||
// 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,
|
||||
General.Map.VisualCamera.Sector.CeilHeight - cameraceilingoffset);
|
||||
ceilheight - cameraceilingoffset);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -615,9 +867,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Set target for highlighting
|
||||
renderer.ShowSelection = General.Settings.GZOldHighlightMode || BuilderPlug.Me.UseHighlight; //mxd
|
||||
|
||||
if (BuilderPlug.Me.UseHighlight)
|
||||
renderer.SetHighlightedObject(target.picked);
|
||||
|
||||
if(BuilderPlug.Me.UseHighlight)
|
||||
renderer.SetHighlightedObject(target.picked);
|
||||
|
||||
// Begin with geometry
|
||||
renderer.StartGeometry();
|
||||
|
@ -651,6 +902,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
protected override void ResourcesReloaded()
|
||||
{
|
||||
base.ResourcesReloaded();
|
||||
RebuildElementData();
|
||||
PickTarget();
|
||||
}
|
||||
|
||||
|
@ -695,11 +947,27 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Go for all sectors to update
|
||||
foreach(Sector s in General.Map.Map.Sectors)
|
||||
{
|
||||
if(s.Marked && VisualSectorExists(s))
|
||||
if(s.Marked)
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(s);
|
||||
vs.Floor.Setup();
|
||||
vs.Ceiling.Setup();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,6 +999,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(sectorsmarked || General.Map.UndoRedo.PopulationChanged)
|
||||
FillBlockMap();
|
||||
|
||||
RebuildElementData();
|
||||
UpdateChangedObjects();
|
||||
|
||||
// Visibility culling (this re-creates the needed resources)
|
||||
DoCulling();
|
||||
}
|
||||
|
@ -749,7 +1020,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Undo performed
|
||||
public override void OnUndoEnd()
|
||||
{
|
||||
base.OnUndoEnd();
|
||||
base.OnUndoEnd();
|
||||
|
||||
//mxd
|
||||
foreach(KeyValuePair<Sector, VisualSector> group in visiblesectors){
|
||||
if (group.Value is BaseVisualSector)
|
||||
((BaseVisualSector)group.Value).Rebuild();
|
||||
}
|
||||
|
||||
RebuildSelectedObjectsList();
|
||||
|
||||
// We can't group with this undo level anymore
|
||||
|
@ -760,6 +1038,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public override void OnRedoEnd()
|
||||
{
|
||||
base.OnRedoEnd();
|
||||
|
||||
//mxd
|
||||
foreach (KeyValuePair<Sector, VisualSector> group in visiblesectors) {
|
||||
if (group.Value is BaseVisualSector)
|
||||
((BaseVisualSector)group.Value).Rebuild();
|
||||
}
|
||||
|
||||
RebuildSelectedObjectsList();
|
||||
}
|
||||
|
||||
|
@ -789,6 +1074,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
}
|
||||
|
||||
// Apply flat offsets
|
||||
public void ApplyFlatOffsetChange(int dx, int dy)
|
||||
{
|
||||
Dictionary<Sector, int> donesectors = new Dictionary<Sector, int>(selectedobjects.Count);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, false, false);
|
||||
foreach(IVisualEventReceiver i in objs)
|
||||
{
|
||||
if(i is BaseVisualGeometrySector)
|
||||
{
|
||||
if(!donesectors.ContainsKey((i as BaseVisualGeometrySector).Sector.Sector))
|
||||
{
|
||||
i.OnChangeTextureOffset(dx, dy);
|
||||
donesectors.Add((i as BaseVisualGeometrySector).Sector.Sector, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply upper unpegged flag
|
||||
public void ApplyUpperUnpegged(bool set)
|
||||
{
|
||||
|
@ -863,7 +1166,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
if(i is BaseVisualGeometrySector)
|
||||
{
|
||||
Sector s = (i as BaseVisualGeometrySector).Sector.Sector;
|
||||
Sector s = (i as BaseVisualGeometrySector).Level.sector;
|
||||
if(!added.ContainsKey(s))
|
||||
{
|
||||
sectors.Add(s);
|
||||
|
@ -875,7 +1178,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Add highlight?
|
||||
if((selectedobjects.Count == 0) && (target.picked is BaseVisualGeometrySector))
|
||||
{
|
||||
Sector s = (target.picked as BaseVisualGeometrySector).Sector.Sector;
|
||||
Sector s = (target.picked as BaseVisualGeometrySector).Level.sector;
|
||||
if(!added.ContainsKey(s))
|
||||
sectors.Add(s);
|
||||
}
|
||||
|
@ -1010,7 +1313,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
t.Move(pos);
|
||||
t.UpdateConfiguration();
|
||||
General.Map.IsChanged = true;
|
||||
|
||||
|
||||
// Update things filter so that it includes this thing
|
||||
General.Map.ThingsFilter.Update();
|
||||
|
||||
|
@ -1018,8 +1321,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if (General.Interface.SnapToGrid) {
|
||||
// Snap to grid
|
||||
t.SnapToGrid();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Snap to map format accuracy
|
||||
t.SnapToAccuracy();
|
||||
}
|
||||
|
@ -1044,6 +1346,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
|
||||
if(bvs.Floor != null) bvs.Floor.Selected = false;
|
||||
if(bvs.Ceiling != null) bvs.Ceiling.Selected = false;
|
||||
foreach(VisualFloor vf in bvs.ExtraFloors) vf.Selected = false;
|
||||
foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Selected = false;
|
||||
foreach(Sidedef sd in vs.Key.Sidedefs)
|
||||
{
|
||||
List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
|
||||
|
@ -1126,7 +1430,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
foreach(IVisualEventReceiver i in objs) i.OnChangeTargetHeight(1);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
|
||||
[BeginAction("lowersector1")]
|
||||
public void LowerSector1()
|
||||
{
|
||||
|
@ -1164,73 +1468,73 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
[BeginAction("movetextureleft")]
|
||||
public void MoveTextureLeft1()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(-1, 0);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(-1, 0);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetextureright")]
|
||||
public void MoveTextureRight1()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(1, 0);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(1, 0);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetextureup")]
|
||||
public void MoveTextureUp1()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, -1);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, -1);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetexturedown")]
|
||||
public void MoveTextureDown1()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, 1);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, 1);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetextureleft8")]
|
||||
public void MoveTextureLeft8()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(-8, 0);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(-8, 0);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetextureright8")]
|
||||
public void MoveTextureRight8()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(8, 0);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(8, 0);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetextureup8")]
|
||||
public void MoveTextureUp8()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, -8);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, -8);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("movetexturedown8")]
|
||||
public void MoveTextureDown8()
|
||||
{
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, 8);
|
||||
PostAction();
|
||||
PreAction(UndoGroup.TextureOffsetChange);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true);
|
||||
foreach (IVisualEventReceiver i in objs) i.OnChangeTextureOffset(0, 8);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
[BeginAction("textureselect")]
|
||||
|
@ -1317,7 +1621,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
string onoff = renderer.FullBrightness ? "ON" : "OFF";
|
||||
General.Interface.DisplayStatus(StatusType.Action, "Full Brightness is now " + onoff + ".");
|
||||
}
|
||||
|
||||
|
||||
[BeginAction("togglehighlight")]
|
||||
public void ToggleHighlight()
|
||||
{
|
||||
|
@ -1325,7 +1629,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
string onoff = BuilderPlug.Me.UseHighlight ? "ON" : "OFF";
|
||||
General.Interface.DisplayStatus(StatusType.Action, "Highlight is now " + onoff + ".");
|
||||
}
|
||||
|
||||
|
||||
[BeginAction("resettexture")]
|
||||
public void ResetTexture()
|
||||
{
|
||||
|
@ -1379,17 +1683,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
//mxd. now we can actually insert things in Visual modes
|
||||
[BeginAction("insertitem", BaseAction = true)]
|
||||
public void InsertThing() {
|
||||
public void InsertThing()
|
||||
{
|
||||
Vector2D hitpos = getHitPosition();
|
||||
|
||||
if (!hitpos.IsFinite()) {
|
||||
General.Interface.DisplayStatus(StatusType.Warning, "Cannot insert item here!");
|
||||
General.Interface.DisplayStatus(StatusType.Warning, "Cannot insert thing here!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ClearSelection();
|
||||
PreActionNoChange();
|
||||
|
||||
General.Map.UndoRedo.ClearAllRedos();
|
||||
General.Map.UndoRedo.CreateUndo("Insert thing");
|
||||
|
||||
Thing t = CreateThing(new Vector2D(hitpos.x, hitpos.y));
|
||||
|
@ -1407,18 +1712,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
blockmap.AddThing(t);
|
||||
|
||||
General.Interface.DisplayStatus(StatusType.Action, "Inserted a new thing.");
|
||||
General.Map.IsChanged = true;
|
||||
General.Map.ThingsFilter.Update();
|
||||
PostAction();
|
||||
}
|
||||
}
|
||||
|
||||
[BeginAction("deleteitem", BaseAction = true)] //mxd. now we can actually delete things in Visual modes
|
||||
public void DeleteSelectedThings() {
|
||||
//mxd. now we can actually delete things in Visual modes
|
||||
[BeginAction("deleteitem", BaseAction = true)]
|
||||
public void DeleteSelectedThings()
|
||||
{
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(false, false, true);
|
||||
if (objs.Count == 0) return;
|
||||
|
||||
General.Map.UndoRedo.ClearAllRedos();
|
||||
string rest = objs.Count + " thing" + (objs.Count > 1 ? "s." : ".");
|
||||
|
||||
//make undo
|
||||
General.Map.UndoRedo.CreateUndo("Delete " + rest);
|
||||
General.Interface.DisplayStatus(StatusType.Info, "Deleted " + rest);
|
||||
|
@ -1432,8 +1737,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.IsChanged = true;
|
||||
General.Map.ThingsFilter.Update();
|
||||
|
||||
PostAction();
|
||||
}
|
||||
PostAction();
|
||||
}
|
||||
|
||||
//mxd
|
||||
[BeginAction("copyselection", BaseAction = true)]
|
||||
|
@ -1462,11 +1767,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
//mxd. We'll just use currently selected objects
|
||||
[BeginAction("pasteselection", BaseAction = true)]
|
||||
public void PasteSelection() {
|
||||
if (copyBuffer.Count == 0) {
|
||||
if(copyBuffer.Count == 0){
|
||||
General.Interface.DisplayStatus(StatusType.Warning, "Nothing to paste, cut or copy some Things first!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Vector2D hitpos = getHitPosition();
|
||||
|
||||
if (!hitpos.IsFinite()) {
|
||||
|
@ -1478,13 +1783,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
string rest = copyBuffer.Count + " thing" + (copyBuffer.Count > 1 ? "s." : ".");
|
||||
General.Map.UndoRedo.CreateUndo("Paste " + rest);
|
||||
General.Interface.DisplayStatus(StatusType.Info, "Pasted " + rest);
|
||||
|
||||
|
||||
PreActionNoChange();
|
||||
ClearSelection();
|
||||
|
||||
//get translated positions
|
||||
Vector3D[] coords = new Vector3D[copyBuffer.Count];
|
||||
for (int i = 0; i < copyBuffer.Count; i++)
|
||||
for (int i = 0; i < copyBuffer.Count; i++ )
|
||||
coords[i] = copyBuffer[i].Position;
|
||||
|
||||
Vector3D[] translatedCoords = translateCoordinates(coords, hitpos, true);
|
||||
|
@ -1537,6 +1842,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
PostAction();
|
||||
}
|
||||
|
||||
//mxd
|
||||
[BeginAction("togglegzdoomrenderingeffects")]
|
||||
public void ToggleGZDoomRenderingEffects() {
|
||||
gzdoomRenderingEffects = !gzdoomRenderingEffects;
|
||||
RebuildElementData();
|
||||
UpdateChangedObjects();
|
||||
General.Interface.DisplayStatus(StatusType.Info, "(G)ZDoom rendering effects are " + (gzdoomRenderingEffects ? "ENABLED" : "DISABLED"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -45,20 +45,27 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
|
||||
|
||||
protected VisualFloor floor;
|
||||
protected VisualCeiling ceiling;
|
||||
protected List<VisualFloor> extrafloors;
|
||||
protected List<VisualCeiling> extraceilings;
|
||||
protected Dictionary<Sidedef, VisualSidedefParts> sides;
|
||||
|
||||
// If this is set to true, the sector will be rebuilt after the action is performed.
|
||||
protected bool changed;
|
||||
|
||||
// Prevent recursion
|
||||
protected bool isupdating;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
|
||||
public VisualFloor Floor { get { return floor; } }
|
||||
public VisualCeiling Ceiling { get { return ceiling; } }
|
||||
public List<VisualFloor> ExtraFloors { get { return extrafloors; } }
|
||||
public List<VisualCeiling> ExtraCeilings { get { return extraceilings; } }
|
||||
public bool Changed { get { return changed; } set { changed |= value; } }
|
||||
|
||||
#endregion
|
||||
|
@ -69,6 +76,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public BaseVisualSector(BaseVisualMode mode, Sector s) : base(s)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.extrafloors = new List<VisualFloor>(2);
|
||||
this.extraceilings = new List<VisualCeiling>(2);
|
||||
|
||||
// Initialize
|
||||
Rebuild();
|
||||
|
@ -87,6 +96,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
sides = null;
|
||||
floor = null;
|
||||
ceiling = null;
|
||||
extrafloors = null;
|
||||
extraceilings = null;
|
||||
|
||||
// Dispose base
|
||||
base.Dispose();
|
||||
|
@ -97,12 +108,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Methods
|
||||
|
||||
// Thisvirtuals the secotr and neightbours if needed
|
||||
// This retreives the sector data for this sector
|
||||
public SectorData GetSectorData()
|
||||
{
|
||||
return mode.GetSectorData(this.Sector);
|
||||
}
|
||||
|
||||
// This updates this virtual the sector and neightbours if needed
|
||||
public void UpdateSectorGeometry(bool includeneighbours)
|
||||
{
|
||||
// Rebuild sector
|
||||
this.Changed = true;
|
||||
|
||||
if(isupdating)
|
||||
return;
|
||||
|
||||
isupdating = true;
|
||||
changed = true;
|
||||
|
||||
// Not sure what from this part we need, so commented out for now
|
||||
SectorData data = GetSectorData();
|
||||
data.Reset();
|
||||
|
||||
// Update sectors that rely on this sector
|
||||
foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso)
|
||||
{
|
||||
if(mode.VisualSectorExists(s.Key))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
|
||||
vs.UpdateSectorGeometry(s.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// Go for all things in this sector
|
||||
foreach(Thing t in General.Map.Map.Things)
|
||||
{
|
||||
|
@ -132,7 +166,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
isupdating = false;
|
||||
}
|
||||
|
||||
//mxd. call this to update sector and things in it when Sector.Fields are changed
|
||||
override public void UpdateSectorData() {
|
||||
//update sector data
|
||||
SectorData data = GetSectorData();
|
||||
data.Update(true);
|
||||
|
||||
//update sector
|
||||
Rebuild();
|
||||
|
||||
//update things in this sector
|
||||
foreach (Thing t in General.Map.Map.Things) {
|
||||
if (t.Sector == this.Sector) {
|
||||
if (mode.VisualThingExists(t)) {
|
||||
// Update thing
|
||||
BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
|
||||
vt.Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This (re)builds the visual sector, calculating all geometry from scratch
|
||||
public void Rebuild()
|
||||
|
@ -140,16 +197,40 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Forget old geometry
|
||||
base.ClearGeometry();
|
||||
|
||||
// Get sector data
|
||||
SectorData data = GetSectorData();
|
||||
if(!data.Updated) data.Update();
|
||||
|
||||
// Create floor
|
||||
if(floor == null) floor = new VisualFloor(mode, this);
|
||||
floor.Setup();
|
||||
base.AddGeometry(floor);
|
||||
|
||||
floor = floor ?? new VisualFloor(mode, this);
|
||||
if(floor.Setup(data.Floor, null))
|
||||
base.AddGeometry(floor);
|
||||
|
||||
// Create ceiling
|
||||
if(ceiling == null) ceiling = new VisualCeiling(mode, this);
|
||||
ceiling.Setup();
|
||||
base.AddGeometry(ceiling);
|
||||
ceiling = ceiling ?? new VisualCeiling(mode, this);
|
||||
if(ceiling.Setup(data.Ceiling, null))
|
||||
base.AddGeometry(ceiling);
|
||||
|
||||
// Create 3D floors
|
||||
for(int i = 0; i < data.ExtraFloors.Count; i++)
|
||||
{
|
||||
Effect3DFloor ef = data.ExtraFloors[i];
|
||||
|
||||
// Create a floor
|
||||
VisualFloor vf = (i < extrafloors.Count) ? extrafloors[i] : new VisualFloor(mode, this);
|
||||
if(vf.Setup(ef.Ceiling, ef))
|
||||
base.AddGeometry(vf);
|
||||
if(i >= extrafloors.Count)
|
||||
extrafloors.Add(vf);
|
||||
|
||||
// Create a ceiling
|
||||
VisualCeiling vc = (i < extraceilings.Count) ? extraceilings[i] : new VisualCeiling(mode, this);
|
||||
if(vc.Setup(ef.Floor, ef))
|
||||
base.AddGeometry(vc);
|
||||
if(i >= extraceilings.Count)
|
||||
extraceilings.Add(vc);
|
||||
}
|
||||
|
||||
// Go for all sidedefs
|
||||
Dictionary<Sidedef, VisualSidedefParts> oldsides = sides ?? new Dictionary<Sidedef, VisualSidedefParts>(1);
|
||||
sides = new Dictionary<Sidedef, VisualSidedefParts>(base.Sector.Sidedefs.Count);
|
||||
|
@ -163,28 +244,43 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
// Create upper part
|
||||
VisualUpper vu = parts.upper ?? new VisualUpper(mode, this, sd);
|
||||
vu.Setup();
|
||||
base.AddGeometry(vu);
|
||||
if(vu.Setup())
|
||||
base.AddGeometry(vu);
|
||||
|
||||
// Create lower part
|
||||
VisualLower vl = parts.lower ?? new VisualLower(mode, this, sd);
|
||||
vl.Setup();
|
||||
base.AddGeometry(vl);
|
||||
if(vl.Setup())
|
||||
base.AddGeometry(vl);
|
||||
|
||||
// Create middle part
|
||||
VisualMiddleDouble vm = parts.middledouble ?? new VisualMiddleDouble(mode, this, sd);
|
||||
vm.Setup();
|
||||
base.AddGeometry(vm);
|
||||
if(vm.Setup())
|
||||
base.AddGeometry(vm);
|
||||
|
||||
// Create 3D wall parts
|
||||
SectorData osd = mode.GetSectorData(sd.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
List<VisualMiddle3D> middles = parts.middle3d ?? new List<VisualMiddle3D>(osd.ExtraFloors.Count);
|
||||
for(int i = 0; i < osd.ExtraFloors.Count; i++)
|
||||
{
|
||||
Effect3DFloor ef = osd.ExtraFloors[i];
|
||||
|
||||
VisualMiddle3D vm3 = (i < middles.Count) ? middles[i] : new VisualMiddle3D(mode, this, sd);
|
||||
if(vm3.Setup(ef))
|
||||
base.AddGeometry(vm3);
|
||||
if(i >= middles.Count)
|
||||
middles.Add(vm3);
|
||||
}
|
||||
|
||||
// Store
|
||||
sides.Add(sd, new VisualSidedefParts(vu, vl, vm));
|
||||
sides.Add(sd, new VisualSidedefParts(vu, vl, vm, middles));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create middle part
|
||||
VisualMiddleSingle vm = parts.middlesingle ?? new VisualMiddleSingle(mode, this, sd);
|
||||
vm.Setup();
|
||||
base.AddGeometry(vm);
|
||||
if(vm.Setup())
|
||||
base.AddGeometry(vm);
|
||||
|
||||
// Store
|
||||
sides.Add(sd, new VisualSidedefParts(vm));
|
||||
|
|
|
@ -108,9 +108,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
if(Thing.Sector != null)
|
||||
{
|
||||
// Use sector brightness for color shading
|
||||
byte brightness = (byte)General.Clamp(Thing.Sector.Brightness, 0, 255);
|
||||
sectorcolor = new PixelColor(255, brightness, brightness, brightness);
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
SectorLevel level = sd.GetLevelAbove(new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + Thing.Sector.FloorHeight));
|
||||
if(level != null)
|
||||
{
|
||||
// Use sector brightness for color shading
|
||||
PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(level.brightnessbelow));
|
||||
PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness);
|
||||
sectorcolor = areacolor.WithAlpha(255);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the texture is loaded
|
||||
|
@ -171,7 +177,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
// Determine position
|
||||
Vector3D pos = Thing.Position;
|
||||
if(info.AbsoluteZ)
|
||||
if(Thing.Type == 9501)
|
||||
{
|
||||
// This is a special thing that needs special positioning
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z;
|
||||
}
|
||||
else if(Thing.Type == 9500)
|
||||
{
|
||||
// This is a special thing that needs special positioning
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z;
|
||||
}
|
||||
else if(info.AbsoluteZ)
|
||||
{
|
||||
// Absolute Z position
|
||||
pos.z = Thing.Position.z;
|
||||
|
@ -179,27 +197,45 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
else if(info.Hangs)
|
||||
{
|
||||
// Hang from ceiling
|
||||
if(Thing.Sector != null) pos.z = Thing.Sector.CeilHeight - info.Height;
|
||||
if(Thing.Position.z > 0) pos.z -= Thing.Position.z;
|
||||
|
||||
if(Thing.Sector != null)
|
||||
{
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
if(Thing.Position.z > 0)
|
||||
pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
|
||||
else
|
||||
pos.z = Thing.Sector.CeilHeight - info.Height; //mxd. was [pos.z = Thing.Sector.CeilHeight;]
|
||||
}
|
||||
|
||||
pos.z -= Thing.Position.z;
|
||||
|
||||
// Check if below floor
|
||||
if((Thing.Sector != null) && (pos.z < Thing.Sector.FloorHeight))
|
||||
{
|
||||
// Put thing on the floor
|
||||
pos.z = Thing.Sector.FloorHeight;
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Floor.plane.GetZ(Thing.Position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stand on floor
|
||||
if(Thing.Sector != null) pos.z = Thing.Sector.FloorHeight;
|
||||
if(Thing.Position.z > 0) pos.z += Thing.Position.z;
|
||||
|
||||
if(Thing.Sector != null)
|
||||
{
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
if(Thing.Position.z == 0)
|
||||
pos.z = sd.Floor.plane.GetZ(Thing.Position);
|
||||
else
|
||||
pos.z = Thing.Sector.FloorHeight;
|
||||
}
|
||||
|
||||
pos.z += Thing.Position.z;
|
||||
|
||||
// Check if above ceiling
|
||||
if((Thing.Sector != null) && ((pos.z + info.Height) > Thing.Sector.CeilHeight))
|
||||
{
|
||||
// Put thing against ceiling
|
||||
pos.z = Thing.Sector.CeilHeight - info.Height;
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,7 +504,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
Thing.Move(Thing.Position + new Vector3D(0.0f, 0.0f, (float)amount));
|
||||
|
||||
mode.SetActionResult("Changed thing height to " + Thing.Position.z + ".");
|
||||
|
||||
|
||||
// Update what must be updated
|
||||
ThingData td = mode.GetThingData(this.Thing);
|
||||
foreach(KeyValuePair<Sector, bool> s in td.UpdateAlso)
|
||||
{
|
||||
if(mode.VisualSectorExists(s.Key))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
|
||||
vs.UpdateSectorGeometry(s.Value);
|
||||
}
|
||||
}
|
||||
|
||||
this.Changed = true;
|
||||
}
|
||||
}
|
||||
|
@ -479,6 +526,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
undoticket = mode.CreateUndo("Move thing");
|
||||
Thing.Move(newPosition);
|
||||
mode.SetActionResult("Changed thing position to " + Thing.Position.ToString() + ".");
|
||||
|
||||
// Update what must be updated
|
||||
ThingData td = mode.GetThingData(this.Thing);
|
||||
foreach (KeyValuePair<Sector, bool> s in td.UpdateAlso) {
|
||||
if (mode.VisualSectorExists(s.Key)) {
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
|
||||
vs.UpdateSectorGeometry(s.Value);
|
||||
}
|
||||
}
|
||||
|
||||
this.Changed = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class Effect3DFloor : SectorEffect
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class EffectBrightnessLevel : SectorEffect
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class EffectCopySlope : SectorEffect
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class EffectLineSlope : SectorEffect
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class EffectThingLineSlope : SectorEffect
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class EffectThingVertexSlope : SectorEffect
|
||||
{
|
|
@ -4,7 +4,8 @@ using System.Text;
|
|||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing {
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class EffectUDMFVertexOffset : SectorEffect {
|
||||
|
||||
private Vertex[] vertices;
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class SectorData
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal abstract class SectorEffect
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class SectorLevel
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class SectorLevelComparer : IComparer<SectorLevel>
|
||||
{
|
|
@ -8,7 +8,7 @@ using System.Text;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal enum SectorLevelType
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal struct TexturePlane
|
||||
{
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class ThingData
|
||||
{
|
|
@ -19,6 +19,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
@ -33,6 +34,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
using CodeImp.DoomBuilder.Windows;
|
||||
|
||||
|
@ -67,12 +69,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
public override bool Setup(SectorLevel level, Effect3DFloor extrafloor)
|
||||
{
|
||||
WorldVertex[] verts;
|
||||
WorldVertex v;
|
||||
Sector s = base.Sector.Sector;
|
||||
int brightness = mode.CalculateBrightness(s.Brightness);
|
||||
Sector s = level.sector;
|
||||
Vector2D texscale;
|
||||
|
||||
base.Setup(level, extrafloor);
|
||||
|
||||
// Fetch ZDoom fields
|
||||
float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationceiling", 0.0f));
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
|
||||
s.Fields.GetValue("ypanningceiling", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
|
||||
s.Fields.GetValue("yscaleceiling", 1.0f));
|
||||
|
||||
// Load floor texture
|
||||
base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
|
||||
|
@ -86,42 +97,53 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = s.LongCeilTexture;
|
||||
}
|
||||
|
||||
// Make vertices
|
||||
verts = new WorldVertex[s.Triangles.Vertices.Count];
|
||||
for(int i = 0; i < s.Triangles.Vertices.Count; i++)
|
||||
{
|
||||
// Use sector brightness for color shading
|
||||
verts[i].c = brightness;
|
||||
|
||||
// Grid aligned texture coordinates
|
||||
if(base.Texture.IsImageLoaded)
|
||||
{
|
||||
verts[i].u = s.Triangles.Vertices[i].x / base.Texture.ScaledWidth;
|
||||
verts[i].v = -s.Triangles.Vertices[i].y / base.Texture.ScaledHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
verts[i].u = s.Triangles.Vertices[i].x / 64;
|
||||
verts[i].v = -s.Triangles.Vertices[i].y / 64;
|
||||
}
|
||||
// Determine texture scale
|
||||
if(base.Texture.IsImageLoaded)
|
||||
texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
|
||||
else
|
||||
texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
|
||||
|
||||
// Make vertices
|
||||
ReadOnlyCollection<Vector2D> triverts = base.Sector.Sector.Triangles.Vertices;
|
||||
verts = new WorldVertex[triverts.Count];
|
||||
for(int i = 0; i < triverts.Count; i++)
|
||||
{
|
||||
// Color shading
|
||||
PixelColor c = PixelColor.FromInt(level.color);
|
||||
verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();
|
||||
|
||||
// Vertex coordinates
|
||||
verts[i].x = s.Triangles.Vertices[i].x;
|
||||
verts[i].y = s.Triangles.Vertices[i].y;
|
||||
verts[i].z = (float)s.CeilHeight;
|
||||
}
|
||||
verts[i].x = triverts[i].x;
|
||||
verts[i].y = triverts[i].y;
|
||||
verts[i].z = level.plane.GetZ(triverts[i]); //(float)s.CeilHeight;
|
||||
|
||||
// Texture coordinates
|
||||
Vector2D pos = triverts[i];
|
||||
pos = pos.GetRotated(rotate);
|
||||
pos.y = -pos.y;
|
||||
pos = (pos + offset) * scale * texscale;
|
||||
verts[i].u = pos.x;
|
||||
verts[i].v = pos.y;
|
||||
}
|
||||
|
||||
// The sector triangulation created clockwise triangles that
|
||||
// are right up for the floor. For the ceiling we must flip
|
||||
// the triangles upside down.
|
||||
// Swap some vertices to flip all triangles
|
||||
for(int i = 0; i < verts.Length; i += 3)
|
||||
if((extrafloor == null) || extrafloor.VavoomType)
|
||||
SwapTriangleVertices(verts);
|
||||
|
||||
// Determine render pass
|
||||
if(extrafloor != null)
|
||||
{
|
||||
// Swap
|
||||
v = verts[i];
|
||||
verts[i] = verts[i + 1];
|
||||
verts[i + 1] = v;
|
||||
if(level.alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
|
||||
// Apply vertices
|
||||
|
@ -133,6 +155,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture coordinates
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
Point p = new Point();
|
||||
p.X = (int)Sector.Sector.Fields.GetValue("xpanningceiling", 0.0f);
|
||||
p.Y = (int)Sector.Sector.Fields.GetValue("ypanningceiling", 0.0f);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Move texture coordinates
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
//mxd
|
||||
Sector s = GetControlSector();
|
||||
s.Fields.BeforeFieldsChange();
|
||||
float oldx = s.Fields.GetValue("xpanningceiling", 0.0f);
|
||||
float oldy = s.Fields.GetValue("ypanningceiling", 0.0f);
|
||||
xy = getTranslatedTextureOffset(xy);
|
||||
s.Fields["xpanningceiling"] = new UniValue(UniversalType.Float, oldx + (float)xy.X);
|
||||
s.Fields["ypanningceiling"] = new UniValue(UniversalType.Float, oldy + (float)xy.Y);
|
||||
s.UpdateNeeded = true;
|
||||
}
|
||||
|
||||
// Paste texture
|
||||
public override void OnPasteTexture()
|
||||
{
|
||||
|
@ -144,37 +189,103 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
this.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Call to change the height
|
||||
public override void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
// Only do this when not done yet in this call
|
||||
// Because we may be able to select the same 3D floor multiple times through multiple sectors
|
||||
SectorData sd = mode.GetSectorData(level.sector);
|
||||
if(!sd.CeilingChanged)
|
||||
{
|
||||
sd.CeilingChanged = true;
|
||||
base.OnChangeTargetHeight(amount);
|
||||
}
|
||||
}
|
||||
|
||||
// This changes the height
|
||||
protected override void ChangeHeight(int amount)
|
||||
{
|
||||
mode.CreateUndo("Change ceiling height", UndoGroup.CeilingHeightChange, this.Sector.Sector.FixedIndex);
|
||||
this.Sector.Sector.CeilHeight += amount;
|
||||
mode.SetActionResult("Changed ceiling height to " + Sector.Sector.CeilHeight + ".");
|
||||
mode.CreateUndo("Change ceiling height", UndoGroup.CeilingHeightChange, level.sector.FixedIndex);
|
||||
level.sector.CeilHeight += amount;
|
||||
mode.SetActionResult("Changed ceiling height to " + level.sector.CeilHeight + ".");
|
||||
}
|
||||
|
||||
//mxd. Sector brightness change
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if (level != null && level.sector != Sector.Sector) {
|
||||
int index = -1;
|
||||
for (int i = 0; i < Sector.ExtraCeilings.Count; i++) {
|
||||
if (Sector.ExtraCeilings[i] == this) {
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > -1 && index < Sector.ExtraCeilings.Count) {
|
||||
Sector.ExtraCeilings[index].changeControlSectorBrightness(up);
|
||||
} else {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
}
|
||||
} else {
|
||||
//if a map is not in UDMF format, or this ceiling is part of 3D-floor...
|
||||
if(!General.Map.UDMF || Sector.Sector != level.sector) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sector.Sector.Fields.GetValue("lightceiling", 0);
|
||||
bool absolute = Sector.Sector.Fields.GetValue("lightceilingabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change ceiling brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sector.Sector.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sector.Sector.Fields["lightceiling"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed ceiling brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
private void changeControlSectorBrightness(bool up) {
|
||||
((BaseVisualSector)mode.GetVisualSector(level.sector)).Ceiling.OnChangeTargetBrightness(up);
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
float planez = (float)Sector.Sector.CeilHeight;
|
||||
// Check if our ray starts at the correct side of the plane
|
||||
if(level.plane.Distance(from) > 0.0f)
|
||||
{
|
||||
// Calculate the intersection
|
||||
if(level.plane.GetIntersection(from, to, ref pickrayu))
|
||||
{
|
||||
if(pickrayu > 0.0f)
|
||||
{
|
||||
pickintersect = from + (to - from) * pickrayu;
|
||||
|
||||
// Check if line crosses the z height
|
||||
if((from.z < planez) && (to.z > planez))
|
||||
{
|
||||
// Calculate intersection point using the z height
|
||||
pickrayu = (planez - from.z) / (to.z - from.z);
|
||||
pickintersect = from + (to - from) * pickrayu;
|
||||
|
||||
// Intersection point within bbox?
|
||||
RectangleF bbox = Sector.Sector.BBox;
|
||||
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not even crossing the z height (or not in the right direction)
|
||||
return false;
|
||||
// Intersection point within bbox?
|
||||
RectangleF bbox = Sector.Sector.BBox;
|
||||
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
|
@ -191,15 +302,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return this.Sector.Sector.CeilTexture;
|
||||
return level.sector.CeilTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
this.Sector.Sector.SetCeilTexture(texturename);
|
||||
level.sector.SetCeilTexture(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
if(level.sector == this.Sector.Sector)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
else if(mode.VisualSectorExists(level.sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
@ -33,6 +34,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
using CodeImp.DoomBuilder.Windows;
|
||||
|
||||
|
@ -59,7 +61,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Constructor
|
||||
public VisualFloor(BaseVisualMode mode, VisualSector vs) : base(mode, vs)
|
||||
{
|
||||
//mxd
|
||||
//mxd
|
||||
geoType = VisualGeometryType.FLOOR;
|
||||
|
||||
// We have no destructor
|
||||
|
@ -67,11 +69,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
public override bool Setup(SectorLevel level, Effect3DFloor extrafloor)
|
||||
{
|
||||
WorldVertex[] verts;
|
||||
Sector s = base.Sector.Sector;
|
||||
int brightness = mode.CalculateBrightness(s.Brightness);
|
||||
Sector s = level.sector;
|
||||
Vector2D texscale;
|
||||
|
||||
base.Setup(level, extrafloor);
|
||||
|
||||
// Fetch ZDoom fields
|
||||
float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationfloor", 0.0f));
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f),
|
||||
s.Fields.GetValue("ypanningfloor", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f),
|
||||
s.Fields.GetValue("yscalefloor", 1.0f));
|
||||
|
||||
// Load floor texture
|
||||
base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
||||
|
@ -85,30 +96,53 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = s.LongFloorTexture;
|
||||
}
|
||||
|
||||
|
||||
// Determine texture scale
|
||||
if(base.Texture.IsImageLoaded)
|
||||
texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
|
||||
else
|
||||
texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
|
||||
|
||||
// Make vertices
|
||||
verts = new WorldVertex[s.Triangles.Vertices.Count];
|
||||
for(int i = 0; i < s.Triangles.Vertices.Count; i++)
|
||||
ReadOnlyCollection<Vector2D> triverts = base.Sector.Sector.Triangles.Vertices;
|
||||
verts = new WorldVertex[triverts.Count];
|
||||
for(int i = 0; i < triverts.Count; i++)
|
||||
{
|
||||
// Use sector brightness for color shading
|
||||
verts[i].c = brightness;
|
||||
|
||||
// Grid aligned texture coordinates
|
||||
if(base.Texture.IsImageLoaded)
|
||||
{
|
||||
verts[i].u = s.Triangles.Vertices[i].x / base.Texture.ScaledWidth;
|
||||
verts[i].v = -s.Triangles.Vertices[i].y / base.Texture.ScaledHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
verts[i].u = s.Triangles.Vertices[i].x / 64;
|
||||
verts[i].v = -s.Triangles.Vertices[i].y / 64;
|
||||
}
|
||||
|
||||
// Color shading
|
||||
PixelColor c = PixelColor.FromInt(level.color);
|
||||
verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();
|
||||
|
||||
// Vertex coordinates
|
||||
verts[i].x = s.Triangles.Vertices[i].x;
|
||||
verts[i].y = s.Triangles.Vertices[i].y;
|
||||
verts[i].z = (float)s.FloorHeight;
|
||||
verts[i].x = triverts[i].x;
|
||||
verts[i].y = triverts[i].y;
|
||||
verts[i].z = level.plane.GetZ(triverts[i]); //(float)s.FloorHeight;
|
||||
|
||||
// Texture coordinates
|
||||
Vector2D pos = triverts[i];
|
||||
pos = pos.GetRotated(rotate);
|
||||
pos.y = -pos.y;
|
||||
pos = (pos + offset) * scale * texscale;
|
||||
verts[i].u = pos.x;
|
||||
verts[i].v = pos.y;
|
||||
}
|
||||
|
||||
// The sector triangulation created clockwise triangles that
|
||||
// are right up for the floor. For the ceiling we must flip
|
||||
// the triangles upside down.
|
||||
if((extrafloor != null) && !extrafloor.VavoomType)
|
||||
SwapTriangleVertices(verts);
|
||||
|
||||
// Determine render pass
|
||||
if(extrafloor != null)
|
||||
{
|
||||
if(level.alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
|
||||
// Apply vertices
|
||||
|
@ -119,6 +153,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture coordinates
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
Point p = new Point();
|
||||
p.X = (int)Sector.Sector.Fields.GetValue("xpanningfloor", 0.0f);
|
||||
p.Y = (int)Sector.Sector.Fields.GetValue("ypanningfloor", 0.0f);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Move texture coordinates
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
//mxd
|
||||
Sector s = GetControlSector();
|
||||
s.Fields.BeforeFieldsChange();
|
||||
float oldx = s.Fields.GetValue("xpanningfloor", 0.0f);
|
||||
float oldy = s.Fields.GetValue("ypanningfloor", 0.0f);
|
||||
xy = getTranslatedTextureOffset(xy);
|
||||
s.Fields["xpanningfloor"] = new UniValue(UniversalType.Float, oldx + (float)xy.X);
|
||||
s.Fields["ypanningfloor"] = new UniValue(UniversalType.Float, oldy + (float)xy.Y);
|
||||
s.UpdateNeeded = true;
|
||||
}
|
||||
|
||||
// Paste texture
|
||||
public override void OnPasteTexture()
|
||||
|
@ -132,36 +189,64 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
}
|
||||
|
||||
// Call to change the height
|
||||
public override void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
// Only do this when not done yet in this call
|
||||
// Because we may be able to select the same 3D floor multiple times through multiple sectors
|
||||
SectorData sd = mode.GetSectorData(level.sector);
|
||||
if(!sd.FloorChanged)
|
||||
{
|
||||
sd.FloorChanged = true;
|
||||
base.OnChangeTargetHeight(amount);
|
||||
}
|
||||
}
|
||||
|
||||
// This changes the height
|
||||
protected override void ChangeHeight(int amount)
|
||||
{
|
||||
mode.CreateUndo("Change floor height", UndoGroup.FloorHeightChange, this.Sector.Sector.FixedIndex);
|
||||
this.Sector.Sector.FloorHeight += amount;
|
||||
mode.SetActionResult("Changed floor height to " + Sector.Sector.FloorHeight + ".");
|
||||
mode.CreateUndo("Change floor height", UndoGroup.FloorHeightChange, level.sector.FixedIndex);
|
||||
level.sector.FloorHeight += amount;
|
||||
mode.SetActionResult("Changed floor height to " + level.sector.FloorHeight + ".");
|
||||
}
|
||||
|
||||
//mxd. Sector brightness change
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if (level != null) {
|
||||
if (level.sector != Sector.Sector) {
|
||||
((BaseVisualSector)mode.GetVisualSector(level.sector)).Ceiling.OnChangeTargetBrightness(up);
|
||||
} else if (Sector.ExtraFloors.Count > 0) {
|
||||
Sector.ExtraFloors[0].OnChangeTargetBrightness(up);
|
||||
} else {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
}
|
||||
} else {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
}
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
float planez = (float)Sector.Sector.FloorHeight;
|
||||
// Check if our ray starts at the correct side of the plane
|
||||
if(level.plane.Distance(from) > 0.0f)
|
||||
{
|
||||
// Calculate the intersection
|
||||
if(level.plane.GetIntersection(from, to, ref pickrayu))
|
||||
{
|
||||
if(pickrayu > 0.0f)
|
||||
{
|
||||
pickintersect = from + (to - from) * pickrayu;
|
||||
|
||||
// Intersection point within bbox?
|
||||
RectangleF bbox = Sector.Sector.BBox;
|
||||
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if line crosses the z height
|
||||
if((from.z > planez) && (to.z < planez))
|
||||
{
|
||||
// Calculate intersection point using the z height
|
||||
pickrayu = (planez - from.z) / (to.z - from.z);
|
||||
pickintersect = from + (to - from) * pickrayu;
|
||||
|
||||
// Intersection point within bbox?
|
||||
RectangleF bbox = Sector.Sector.BBox;
|
||||
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not even crossing the z height (or not in the right direction)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
|
@ -178,15 +263,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return this.Sector.Sector.FloorTexture;
|
||||
return level.sector.FloorTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
this.Sector.Sector.SetFloorTexture(texturename);
|
||||
level.sector.SetFloorTexture(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
if(level.sector == this.Sector.Sector)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
else if(mode.VisualSectorExists(level.sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -33,6 +33,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
@ -64,115 +65,140 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
//mxd
|
||||
//int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness);
|
||||
int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness, Sidedef);
|
||||
Vector2D vl, vr;
|
||||
|
||||
// Calculate size of this wall part
|
||||
float geotop = (float)Sidedef.Other.Sector.FloorHeight;
|
||||
float geobottom = (float)Sidedef.Sector.FloorHeight;
|
||||
float geoheight = geotop - geobottom;
|
||||
if(geoheight > 0.001f)
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_bottom", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_bottom", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_bottom", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_bottom", 0.0f));
|
||||
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
Vector2D t1 = new Vector2D();
|
||||
Vector2D t2 = new Vector2D();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.LowTexture.Length > 0) && (Sidedef.LowTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongLowTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongLowTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongLowTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
|
||||
// Determine texture coordinates
|
||||
// See http://doom.wikia.com/wiki/Texture_alignment
|
||||
// We just use pixels for coordinates for now
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the lower texture is bound to the bottom
|
||||
t1.y = (float)Sidedef.Sector.CeilHeight - geotop;
|
||||
}
|
||||
t2.x = t1.x + Sidedef.Line.Length;
|
||||
t2.y = t1.y + geoheight;
|
||||
|
||||
// Apply texture offset
|
||||
if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
{
|
||||
t1 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
|
||||
t2 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
t2 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
}
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
t1 /= tsz;
|
||||
t2 /= tsz;
|
||||
|
||||
// Get world coordinates for geometry
|
||||
Vector2D v1, v2;
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
v1 = Sidedef.Line.Start.Position;
|
||||
v2 = Sidedef.Line.End.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = Sidedef.Line.End.Position;
|
||||
v2 = Sidedef.Line.Start.Position;
|
||||
}
|
||||
|
||||
// Make vertices
|
||||
WorldVertex[] verts = new WorldVertex[6];
|
||||
verts[0] = new WorldVertex(v1.x, v1.y, geobottom, brightness, t1.x, t2.y);
|
||||
verts[1] = new WorldVertex(v1.x, v1.y, geotop, brightness, t1.x, t1.y);
|
||||
verts[2] = new WorldVertex(v2.x, v2.y, geotop, brightness, t2.x, t1.y);
|
||||
verts[3] = verts[0];
|
||||
verts[4] = verts[2];
|
||||
verts[5] = new WorldVertex(v2.x, v2.y, geobottom, brightness, t2.x, t2.y);
|
||||
|
||||
// Keep properties
|
||||
base.top = geotop;
|
||||
base.bottom = geobottom;
|
||||
|
||||
// Apply vertices
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No geometry for invisible wall
|
||||
base.top = geotop;
|
||||
base.bottom = geobottom;
|
||||
WorldVertex[] verts = new WorldVertex[0];
|
||||
base.SetVertices(verts);
|
||||
return false;
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = Sector.GetSectorData();
|
||||
SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.LowTexture.Length > 0) && (Sidedef.LowTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongLowTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongLowTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongLowTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float floorbias = (Sidedef.Other.Sector.FloorHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the lower texture is bound to the bottom
|
||||
tp.tlt.y = (float)Sidedef.Sector.CeilHeight - (float)Sidedef.Other.Sector.FloorHeight;
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Other.Sector.FloorHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Other.Sector.FloorHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Cut off the part above the other floor
|
||||
CropPoly(ref poly, osd.Floor.plane, false);
|
||||
CropPoly(ref poly, osd.Ceiling.plane, true);
|
||||
|
||||
if(poly.Count > 2)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = osd.Floor.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -192,6 +218,67 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_bottom", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_bottom", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_bottom", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_bottom", 1.0f);
|
||||
Sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_bottom", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_bottom", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change lower wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed lower wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ using CodeImp.DoomBuilder.VisualModes;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal sealed class VisualMiddle3D : BaseVisualGeometrySidedef
|
||||
{
|
|
@ -33,6 +33,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
@ -47,6 +48,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Variables
|
||||
|
||||
private bool repeatmidtex;
|
||||
private Plane topclipplane;
|
||||
private Plane bottomclipplane;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
@ -71,27 +76,42 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
WorldVertex[] verts;
|
||||
Vector2D vl, vr;
|
||||
|
||||
//mxd
|
||||
//int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness);
|
||||
int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness, Sidedef);
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
// Calculate size of this wall part
|
||||
float geotop = (float)Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight);
|
||||
float geobottom = (float)Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight);
|
||||
float geoheight = geotop - geobottom;
|
||||
if(geoheight > 0.001f)
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_mid", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_mid", 0.0f));
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = mode.GetSectorData(Sidedef.Sector);
|
||||
SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
Vector2D t1 = new Vector2D();
|
||||
Vector2D t2 = new Vector2D();
|
||||
float textop, texbottom;
|
||||
float cliptop = 0.0f;
|
||||
float clipbottom = 0.0f;
|
||||
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
|
||||
if(base.Texture == null)
|
||||
|
@ -104,95 +124,139 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Because the middle texture on a double sided line does not repeat vertically,
|
||||
// we first determine the visible portion of the texture
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
|
||||
float geotop = (float)Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight);
|
||||
float geobottom = (float)Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight);
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the middle texture is bound to the bottom
|
||||
tp.tlt.y = tsz.y - (float)(geotop - geobottom);
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Cut off the part below the other floor and above the other ceiling
|
||||
CropPoly(ref poly, osd.Ceiling.plane, true);
|
||||
CropPoly(ref poly, osd.Floor.plane, true);
|
||||
|
||||
// Determine if we should repeat the middle texture
|
||||
if(Sidedef.Fields.ContainsKey("wrapmidtex"))
|
||||
repeatmidtex = Sidedef.Fields.GetValue("wrapmidtex", false);
|
||||
else
|
||||
repeatmidtex = Sidedef.Line.IsFlagSet("wrapmidtex");
|
||||
|
||||
if(!repeatmidtex)
|
||||
{
|
||||
// First determine the visible portion of the texture
|
||||
float textop, texbottom;
|
||||
|
||||
// Determine top portion height
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
textop = geobottom + tsz.y;
|
||||
textop = geobottom + tof.y + tsz.y;
|
||||
else
|
||||
textop = geotop;
|
||||
|
||||
// Apply texture offset
|
||||
if (General.Map.Config.ScaledTextureOffsets)
|
||||
{
|
||||
textop += Sidedef.OffsetY * base.Texture.Scale.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
textop += Sidedef.OffsetY;
|
||||
}
|
||||
|
||||
textop = geotop + tof.y;
|
||||
|
||||
// Calculate texture portion bottom
|
||||
// Calculate bottom portion height
|
||||
texbottom = textop - tsz.y;
|
||||
|
||||
// Clip texture portion by geometry
|
||||
if(geotop < textop) { cliptop = textop - geotop; textop = geotop; }
|
||||
if(geobottom > texbottom) { clipbottom = geobottom - texbottom; texbottom = geobottom; }
|
||||
|
||||
// Check if anything is still visible
|
||||
if((textop - texbottom) > 0.001f)
|
||||
// Create crop planes (we also need these for intersection testing)
|
||||
topclipplane = new Plane(new Vector3D(0, 0, -1), textop);
|
||||
bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom);
|
||||
|
||||
// Crop polygon by these heights
|
||||
CropPoly(ref poly, topclipplane, true);
|
||||
CropPoly(ref poly, bottomclipplane, true);
|
||||
}
|
||||
|
||||
if(poly.Count > 2)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = osd.Ceiling.plane;
|
||||
bottom = osd.Floor.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
// Determine texture coordinatess
|
||||
t1.y = cliptop;
|
||||
t2.y = tsz.y - clipbottom;
|
||||
|
||||
if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
// Apply alpha to vertices
|
||||
byte alpha = SetLinedefRenderstyle(true);
|
||||
if(alpha < 255)
|
||||
{
|
||||
t1.x = Sidedef.OffsetX * base.Texture.Scale.x;
|
||||
for(int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
WorldVertex v = verts[i];
|
||||
PixelColor c = PixelColor.FromInt(v.c);
|
||||
v.c = c.WithAlpha(alpha).ToInt();
|
||||
verts[i] = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t1.x = Sidedef.OffsetX;
|
||||
}
|
||||
|
||||
t2.x = t1.x + Sidedef.Line.Length;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
t1 /= tsz;
|
||||
t2 /= tsz;
|
||||
|
||||
// Get world coordinates for geometry
|
||||
Vector2D v1, v2;
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
v1 = Sidedef.Line.Start.Position;
|
||||
v2 = Sidedef.Line.End.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = Sidedef.Line.End.Position;
|
||||
v2 = Sidedef.Line.Start.Position;
|
||||
}
|
||||
|
||||
// Make vertices
|
||||
verts = new WorldVertex[6];
|
||||
verts[0] = new WorldVertex(v1.x, v1.y, texbottom, brightness, t1.x, t2.y);
|
||||
verts[1] = new WorldVertex(v1.x, v1.y, textop, brightness, t1.x, t1.y);
|
||||
verts[2] = new WorldVertex(v2.x, v2.y, textop, brightness, t2.x, t1.y);
|
||||
verts[3] = verts[0];
|
||||
verts[4] = verts[2];
|
||||
verts[5] = new WorldVertex(v2.x, v2.y, texbottom, brightness, t2.x, t2.y);
|
||||
|
||||
// Keep properties
|
||||
base.top = textop;
|
||||
base.bottom = texbottom;
|
||||
|
||||
// Apply vertices
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No geometry for invisible wall
|
||||
base.top = geotop;
|
||||
base.bottom = geotop; // bottom same as top so that it has a height of 0 (otherwise it will still be picked up by object picking)
|
||||
verts = new WorldVertex[0];
|
||||
base.SetVertices(verts);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -200,6 +264,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Methods
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
if(!repeatmidtex)
|
||||
{
|
||||
// Whe nthe texture is not repeated, leave when outside crop planes
|
||||
if((pickintersect.z < bottomclipplane.GetZ(pickintersect)) ||
|
||||
(pickintersect.z > topclipplane.GetZ(pickintersect)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.PickFastReject(from, to, dir);
|
||||
}
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
|
@ -213,6 +291,67 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_mid", 1.0f);
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed middle wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
@ -44,17 +45,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
|
||||
// Constructor
|
||||
public VisualMiddleSingle(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
|
@ -64,119 +65,145 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
//mxd
|
||||
//int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness);
|
||||
int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness, Sidedef);
|
||||
Vector2D vl, vr;
|
||||
|
||||
// Calculate size of this wall part
|
||||
float geotop = (float)Sidedef.Sector.CeilHeight;
|
||||
float geobottom = (float)Sidedef.Sector.FloorHeight;
|
||||
float geoheight = geotop - geobottom;
|
||||
if(geoheight > 0.001f)
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_mid", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_mid", 0.0f));
|
||||
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
Vector2D t1 = new Vector2D();
|
||||
Vector2D t2 = new Vector2D();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
|
||||
// Determine texture coordinates
|
||||
// See http://doom.wikia.com/wiki/Texture_alignment
|
||||
// We just use pixels for coordinates for now
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the middle texture is bound to the bottom
|
||||
t1.y = tsz.y - geoheight;
|
||||
}
|
||||
t2.x = t1.x + Sidedef.Line.Length;
|
||||
t2.y = t1.y + geoheight;
|
||||
|
||||
// Apply texture offset
|
||||
if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
{
|
||||
t1 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
|
||||
t2 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
t2 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
}
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
t1 /= tsz;
|
||||
t2 /= tsz;
|
||||
|
||||
// Get world coordinates for geometry
|
||||
Vector2D v1, v2;
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
v1 = Sidedef.Line.Start.Position;
|
||||
v2 = Sidedef.Line.End.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = Sidedef.Line.End.Position;
|
||||
v2 = Sidedef.Line.Start.Position;
|
||||
}
|
||||
|
||||
// Make vertices
|
||||
WorldVertex[] verts = new WorldVertex[6];
|
||||
verts[0] = new WorldVertex(v1.x, v1.y, geobottom, brightness, t1.x, t2.y);
|
||||
verts[1] = new WorldVertex(v1.x, v1.y, geotop, brightness, t1.x, t1.y);
|
||||
verts[2] = new WorldVertex(v2.x, v2.y, geotop, brightness, t2.x, t1.y);
|
||||
verts[3] = verts[0];
|
||||
verts[4] = verts[2];
|
||||
verts[5] = new WorldVertex(v2.x, v2.y, geobottom, brightness, t2.x, t2.y);
|
||||
|
||||
// Keep properties
|
||||
base.top = geotop;
|
||||
base.bottom = geobottom;
|
||||
|
||||
// Apply vertices
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No geometry for invisible wall
|
||||
base.top = geotop;
|
||||
base.bottom = geobottom;
|
||||
WorldVertex[] verts = new WorldVertex[0];
|
||||
base.SetVertices(verts);
|
||||
return false;
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = mode.GetSectorData(Sidedef.Sector);
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the middle texture is bound to the bottom
|
||||
tp.tlt.y = tsz.y - (float)(Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight);
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Get ceiling and floor heights
|
||||
float fl = sd.Floor.plane.GetZ(vl);
|
||||
float fr = sd.Floor.plane.GetZ(vr);
|
||||
float cl = sd.Ceiling.plane.GetZ(vl);
|
||||
float cr = sd.Ceiling.plane.GetZ(vr);
|
||||
|
||||
// Anything to see?
|
||||
if(((cl - fl) > 0.01f) || ((cr - fr) > 0.01f))
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, fl));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, cl));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, cr));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, fr));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture name
|
||||
|
@ -192,6 +219,67 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_mid", 1.0f);
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed middle wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -43,16 +43,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualLower lower;
|
||||
public VisualMiddleDouble middledouble;
|
||||
public VisualMiddleSingle middlesingle;
|
||||
|
||||
public List<VisualMiddle3D> middle3d;
|
||||
|
||||
// Constructor
|
||||
public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m)
|
||||
public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m, List<VisualMiddle3D> e)
|
||||
{
|
||||
this.upper = u;
|
||||
this.lower = l;
|
||||
this.middledouble = m;
|
||||
this.middlesingle = null;
|
||||
this.middle3d = e;
|
||||
}
|
||||
|
||||
|
||||
// Constructor
|
||||
public VisualSidedefParts(VisualMiddleSingle m)
|
||||
{
|
||||
|
@ -60,8 +62,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
this.lower = null;
|
||||
this.middledouble = null;
|
||||
this.middlesingle = m;
|
||||
this.middle3d = null;
|
||||
}
|
||||
|
||||
|
||||
// This calls Setup() on all parts
|
||||
public void SetupAllParts()
|
||||
{
|
||||
|
@ -69,6 +72,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(middledouble != null) middledouble.Setup();
|
||||
if(middlesingle != null) middlesingle.Setup();
|
||||
if(upper != null) upper.Setup();
|
||||
if(middle3d != null)
|
||||
{
|
||||
foreach(VisualMiddle3D m in middle3d)
|
||||
m.Setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
@ -68,111 +69,135 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
//mxd
|
||||
//int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness);
|
||||
int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness, Sidedef);
|
||||
|
||||
// Calculate size of this wall part
|
||||
float geotop = (float)Sidedef.Sector.CeilHeight;
|
||||
float geobottom = (float)Sidedef.Other.Sector.CeilHeight;
|
||||
float geoheight = geotop - geobottom;
|
||||
if(geoheight > 0.001f)
|
||||
Vector2D vl, vr;
|
||||
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_top", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_top", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_top", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_top", 0.0f));
|
||||
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
Vector2D t1 = new Vector2D();
|
||||
Vector2D t2 = new Vector2D();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.HighTexture.Length > 0) && (Sidedef.HighTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongHighTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongHighTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongHighTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
|
||||
// Determine texture coordinates
|
||||
// See http://doom.wikia.com/wiki/Texture_alignment
|
||||
// We just use pixels for coordinates for now
|
||||
if(!Sidedef.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag))
|
||||
{
|
||||
// When upper unpegged is NOT set, the upper texture is bound to the bottom
|
||||
t1.y = tsz.y - geoheight;
|
||||
}
|
||||
t2.x = t1.x + Sidedef.Line.Length;
|
||||
t2.y = t1.y + geoheight;
|
||||
|
||||
// Apply texture offset
|
||||
if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
{
|
||||
t1 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
|
||||
t2 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
t2 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
}
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
t1 /= tsz;
|
||||
t2 /= tsz;
|
||||
|
||||
// Get world coordinates for geometry
|
||||
Vector2D v1, v2;
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
v1 = Sidedef.Line.Start.Position;
|
||||
v2 = Sidedef.Line.End.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = Sidedef.Line.End.Position;
|
||||
v2 = Sidedef.Line.Start.Position;
|
||||
}
|
||||
|
||||
// Make vertices
|
||||
WorldVertex[] verts = new WorldVertex[6];
|
||||
verts[0] = new WorldVertex(v1.x, v1.y, geobottom, brightness, t1.x, t2.y);
|
||||
verts[1] = new WorldVertex(v1.x, v1.y, geotop, brightness, t1.x, t1.y);
|
||||
verts[2] = new WorldVertex(v2.x, v2.y, geotop, brightness, t2.x, t1.y);
|
||||
verts[3] = verts[0];
|
||||
verts[4] = verts[2];
|
||||
verts[5] = new WorldVertex(v2.x, v2.y, geobottom, brightness, t2.x, t2.y);
|
||||
|
||||
// Keep properties
|
||||
base.top = geotop;
|
||||
base.bottom = geobottom;
|
||||
|
||||
// Apply vertices
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No geometry for invisible wall
|
||||
base.top = geotop;
|
||||
base.bottom = geobottom;
|
||||
WorldVertex[] verts = new WorldVertex[0];
|
||||
base.SetVertices(verts);
|
||||
return false;
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = Sector.GetSectorData();
|
||||
SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.HighTexture.Length > 0) && (Sidedef.HighTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongHighTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongHighTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongHighTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float ceilbias = (Sidedef.Other.Sector.CeilHeight == Sidedef.Sector.CeilHeight) ? 1.0f : 0.0f;
|
||||
if(!Sidedef.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the lower texture is bound to the bottom
|
||||
tp.tlt.y = tsz.y - ((float)Sidedef.Sector.CeilHeight - (float)Sidedef.Other.Sector.CeilHeight);
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Other.Sector.CeilHeight + ceilbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Other.Sector.CeilHeight + ceilbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Cut off the part below the other ceiling
|
||||
CropPoly(ref poly, osd.Ceiling.plane, false);
|
||||
|
||||
if(poly.Count > 2)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = osd.Ceiling.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -192,6 +217,67 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_top", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_top", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_top", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_top", 1.0f);
|
||||
Sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_top", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_top", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change upper wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed upper wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
|
|||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal class WallPolygon : List<Vector3D>
|
||||
{
|
|
@ -1,209 +0,0 @@
|
|||
|
||||
#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.Types;
|
||||
using CodeImp.DoomBuilder.Config;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
public abstract class BaseClassicMode : ClassicMode
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Disposer
|
||||
|
||||
// Constructor
|
||||
public BaseClassicMode()
|
||||
{
|
||||
// Initialize
|
||||
|
||||
// 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 occurs when the user presses Copy. All selected geometry must be marked for copying!
|
||||
public override bool OnCopyBegin()
|
||||
{
|
||||
General.Map.Map.MarkAllSelectedGeometry(true, false, true, true, false);
|
||||
|
||||
// Return true when anything is selected so that the copy continues
|
||||
// We only have to check vertices for the geometry, because without selected
|
||||
// vertices, no complete structure can exist.
|
||||
return (General.Map.Map.GetMarkedVertices(true).Count > 0) ||
|
||||
(General.Map.Map.GetMarkedThings(true).Count > 0);
|
||||
}
|
||||
|
||||
// This is called when pasting begins
|
||||
public override bool OnPasteBegin(PasteOptions options)
|
||||
{
|
||||
// These modes support pasting
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is called when something was pasted.
|
||||
public override void OnPasteEnd(PasteOptions options)
|
||||
{
|
||||
General.Map.Map.ClearAllSelected();
|
||||
General.Map.Map.SelectMarkedGeometry(true, true);
|
||||
|
||||
// Switch to EditSelectionMode
|
||||
//EditSelectionMode editmode = new EditSelectionMode();
|
||||
//editmode.Pasting = true;
|
||||
//editmode.PasteOptions = options;
|
||||
General.Editing.ChangeMode("EditSelectionMode");
|
||||
}
|
||||
|
||||
// Double-clicking
|
||||
public override void OnMouseDoubleClick(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDoubleClick(e);
|
||||
|
||||
int k = 0;
|
||||
if(e.Button == MouseButtons.Left) k = (int)Keys.LButton;
|
||||
if(e.Button == MouseButtons.Middle) k = (int)Keys.MButton;
|
||||
if(e.Button == MouseButtons.Right) k = (int)Keys.RButton;
|
||||
if(e.Button == MouseButtons.XButton1) k = (int)Keys.XButton1;
|
||||
if(e.Button == MouseButtons.XButton2) k = (int)Keys.XButton2;
|
||||
|
||||
// Double select-click? Make that the same as single edit-click
|
||||
if(General.Actions.GetActionByName("builder_classicselect").KeyMatches(k))
|
||||
{
|
||||
Actions.Action a = General.Actions.GetActionByName("builder_classicedit");
|
||||
if(a != null) a.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Actions
|
||||
|
||||
[BeginAction("placevisualstart", Library = "BuilderModes")]
|
||||
public void Place3VisualStartThing()
|
||||
{
|
||||
Thing thingfound = null;
|
||||
|
||||
// Not during volatile mode
|
||||
if(this.Attributes.Volatile) return;
|
||||
|
||||
// Mouse must be inside window
|
||||
if(!mouseinside) return;
|
||||
|
||||
General.Interface.DisplayStatus(StatusType.Action, "Placed Visual Mode camera start thing.");
|
||||
|
||||
// Go for all things
|
||||
List<Thing> things = new List<Thing>(General.Map.Map.Things);
|
||||
foreach(Thing t in things)
|
||||
{
|
||||
if(t.Type == General.Map.Config.Start3DModeThingType)
|
||||
{
|
||||
if(thingfound == null)
|
||||
{
|
||||
// Move this thing
|
||||
t.Move(mousemappos);
|
||||
thingfound = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
// One was already found and moved, delete this one
|
||||
t.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No thing found?
|
||||
if(thingfound == null)
|
||||
{
|
||||
// Make a new one
|
||||
Thing t = General.Map.Map.CreateThing();
|
||||
if(t != null)
|
||||
{
|
||||
t.Type = General.Map.Config.Start3DModeThingType;
|
||||
t.Move(mousemappos);
|
||||
t.UpdateConfiguration();
|
||||
General.Map.ThingsFilter.Update();
|
||||
thingfound = t;
|
||||
}
|
||||
}
|
||||
|
||||
if(thingfound != null)
|
||||
{
|
||||
// Make sure that the found thing is between ceiling and floor
|
||||
thingfound.DetermineSector();
|
||||
if(thingfound.Position.z < 0.0f) thingfound.Move(thingfound.Position.x, thingfound.Position.y, 0.0f);
|
||||
if(thingfound.Sector != null)
|
||||
{
|
||||
if((thingfound.Position.z + 50.0f) > (thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight))
|
||||
thingfound.Move(thingfound.Position.x, thingfound.Position.y,
|
||||
thingfound.Sector.CeilHeight - thingfound.Sector.FloorHeight - 50.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Visual Mode camera
|
||||
General.Map.VisualCamera.PositionAtThing();
|
||||
|
||||
// Redraw display to show changes
|
||||
General.Interface.RedrawDisplay();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{760A9BC7-CB73-4C36-858B-994C14996FCD}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CodeImp.DoomBuilder.GZDoomEditing</RootNamespace>
|
||||
<AssemblyName>GZDoomEditing</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\..\Build\Plugins\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<OutputPath>..\..\..\Build\Plugins\</OutputPath>
|
||||
<DefineConstants>
|
||||
</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ClassicModes\BaseClassicMode.cs" />
|
||||
<Compile Include="ClassicModes\CeilingAlignMode.cs" />
|
||||
<Compile Include="ClassicModes\FlatAlignMode.cs" />
|
||||
<Compile Include="ClassicModes\FloorAlignMode.cs" />
|
||||
<Compile Include="General\BuilderPlug.cs" />
|
||||
<Compile Include="General\CopyStructures.cs" />
|
||||
<Compile Include="General\UndoGroup.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="VisualModes\BaseVisualGeometrySector.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualGeometrySidedef.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualMode.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualSector.cs" />
|
||||
<Compile Include="VisualModes\BaseVisualThing.cs" />
|
||||
<Compile Include="VisualModes\EffectCopySlope.cs" />
|
||||
<Compile Include="VisualModes\EffectLineSlope.cs" />
|
||||
<Compile Include="VisualModes\EffectThingLineSlope.cs" />
|
||||
<Compile Include="VisualModes\EffectThingVertexSlope.cs" />
|
||||
<Compile Include="VisualModes\EffectUDMFVertexOffset.cs" />
|
||||
<Compile Include="VisualModes\IVisualEventReceiver.cs" />
|
||||
<Compile Include="VisualModes\NullVisualEventReceiver.cs" />
|
||||
<Compile Include="VisualModes\Effect3DFloor.cs" />
|
||||
<Compile Include="VisualModes\EffectBrightnessLevel.cs" />
|
||||
<Compile Include="VisualModes\SectorEffect.cs" />
|
||||
<Compile Include="VisualModes\SectorLevelComparer.cs" />
|
||||
<Compile Include="VisualModes\ThingData.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddle3D.cs" />
|
||||
<Compile Include="VisualModes\WallPolygon.cs" />
|
||||
<Compile Include="VisualModes\SectorData.cs" />
|
||||
<Compile Include="VisualModes\SectorLevel.cs" />
|
||||
<Compile Include="VisualModes\SectorLevelType.cs" />
|
||||
<Compile Include="VisualModes\TexturePlane.cs" />
|
||||
<Compile Include="VisualModes\VisualActionResult.cs" />
|
||||
<Compile Include="VisualModes\VisualCeiling.cs" />
|
||||
<Compile Include="VisualModes\VisualFloor.cs" />
|
||||
<Compile Include="VisualModes\VisualLower.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddleDouble.cs" />
|
||||
<Compile Include="VisualModes\VisualMiddleSingle.cs" />
|
||||
<Compile Include="VisualModes\VisualSidedefParts.cs" />
|
||||
<Compile Include="VisualModes\VisualUpper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\Builder.csproj">
|
||||
<Project>{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}</Project>
|
||||
<Name>Builder</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\VisualModeZ.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Actions.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="GZDoomEditing.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\CeilingAlign.png" />
|
||||
<EmbeddedResource Include="Resources\FloorAlign.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
Doom Builder Plugin Information
|
||||
===========================================================================
|
||||
|
||||
Title: (G)ZDoom Editing Plugin
|
||||
|
||||
Author: Pascal vd Heiden
|
||||
|
||||
Plugin version: 0.0
|
||||
|
||||
Core version needed: 2.1.0.1394
|
||||
|
||||
|
||||
|
||||
Description
|
||||
===========================================================================
|
||||
|
||||
This plugins adds features to help editing with the new features in the
|
||||
ZDoom and GZDoom sourceports and those derived from these sourceports.
|
||||
|
||||
List of supported features in this plugin:
|
||||
- Slopes
|
||||
- 3D floors (also sloped)
|
||||
- Colored sector lighting
|
||||
- Light levels in sectors (also sloped)
|
||||
- Flat scaling, rotation and offsets
|
||||
- Texture scaling and offsets
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
===========================================================================
|
||||
|
||||
1) Place the GZDoomEditing.dll file in Doom Builder's "Plugins" directory.
|
||||
|
||||
2) Start Doom Builder and go to Tools menu, Preferences. Choose the
|
||||
Controls tab and find the "GZDoom Visual Mode" action in the Modes group.
|
||||
Set this action to a key you wish to use to switch into and out from
|
||||
Visual Mode. You can give this the same key as your original mode, because
|
||||
now we will replace the original Visual Mode with the new one.
|
||||
|
||||
3) Go to Tools menu, Game Configurations. Choose the game configuration on
|
||||
which you wish to use the new Visual Mode. This plugin is made for UDMF
|
||||
formats, but some features also work for Hexen format. Go to the Modes tab
|
||||
and UNCHECK the original Visual Mode and CHECK the "GZDoom Visual Mode".
|
||||
|
||||
You can also have both Visual Modes together (simply do not uncheck the
|
||||
original Visual Modein step 3) but you will need a different key for the
|
||||
action that switches to the mode.
|
||||
|
||||
|
||||
|
||||
Usage
|
||||
===========================================================================
|
||||
|
||||
I don't feel like writing this now. Figure it out yourself.
|
||||
|
|
@ -1,435 +0,0 @@
|
|||
|
||||
#region ================== Copyright (c) 2010 Pascal vd Heiden
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Pascal vd Heiden
|
||||
* 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.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using CodeImp.DoomBuilder.Controls;
|
||||
using CodeImp.DoomBuilder.Windows;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.Plugins;
|
||||
using CodeImp.DoomBuilder.Actions;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
public class BuilderPlug : Plug
|
||||
{
|
||||
#region ================== Structures
|
||||
|
||||
private struct SidedefAlignJob
|
||||
{
|
||||
public Sidedef sidedef;
|
||||
|
||||
public float offsetx;
|
||||
|
||||
// When this is true, the previous sidedef was on the left of
|
||||
// this one and the texture X offset of this sidedef can be set
|
||||
// directly. When this is false, the length of this sidedef
|
||||
// must be subtracted from the X offset first.
|
||||
public bool forward;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
// Static instance
|
||||
private static BuilderPlug me;
|
||||
|
||||
// Settings
|
||||
private int showvisualthings; // 0 = none, 1 = sprite only, 2 = sprite caged
|
||||
private int changeheightbysidedef; // 0 = nothing, 1 = change ceiling, 2 = change floor
|
||||
private bool visualmodeclearselection;
|
||||
private bool usegravity;
|
||||
private bool usehighlight;
|
||||
private float stitchrange;
|
||||
|
||||
//mxd
|
||||
private bool editnewthing;
|
||||
|
||||
// Copy/paste
|
||||
private string copiedtexture;
|
||||
private string copiedflat;
|
||||
private Point copiedoffsets;
|
||||
private VertexProperties copiedvertexprops;
|
||||
private SectorProperties copiedsectorprops;
|
||||
private SidedefProperties copiedsidedefprops;
|
||||
private LinedefProperties copiedlinedefprops;
|
||||
private ThingProperties copiedthingprops;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
// Static property to access the BuilderPlug
|
||||
public static BuilderPlug Me { get { return me; } }
|
||||
|
||||
// This is the lowest Doom Builder core revision that is required for this plugin to work
|
||||
public override int MinimumRevision { get { return 1394; } }
|
||||
|
||||
// Settings
|
||||
public int ShowVisualThings { get { return showvisualthings; } set { showvisualthings = value; } }
|
||||
public int ChangeHeightBySidedef { get { return changeheightbysidedef; } }
|
||||
public bool VisualModeClearSelection { get { return visualmodeclearselection; } }
|
||||
public bool UseGravity { get { return usegravity; } set { usegravity = value; } }
|
||||
public bool UseHighlight { get { return usehighlight; } set { usehighlight = value; } }
|
||||
public float StitchRange { get { return stitchrange; } }
|
||||
|
||||
//mxd
|
||||
public bool EditNewThing { get { return editnewthing; } }
|
||||
|
||||
// Copy/paste
|
||||
public string CopiedTexture { get { return copiedtexture; } set { copiedtexture = value; } }
|
||||
public string CopiedFlat { get { return copiedflat; } set { copiedflat = value; } }
|
||||
public Point CopiedOffsets { get { return copiedoffsets; } set { copiedoffsets = value; } }
|
||||
public VertexProperties CopiedVertexProps { get { return copiedvertexprops; } set { copiedvertexprops = value; } }
|
||||
public SectorProperties CopiedSectorProps { get { return copiedsectorprops; } set { copiedsectorprops = value; } }
|
||||
public SidedefProperties CopiedSidedefProps { get { return copiedsidedefprops; } set { copiedsidedefprops = value; } }
|
||||
public LinedefProperties CopiedLinedefProps { get { return copiedlinedefprops; } set { copiedlinedefprops = value; } }
|
||||
public ThingProperties CopiedThingProps { get { return copiedthingprops; } set { copiedthingprops = value; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Initialize / Dispose
|
||||
|
||||
// This event is called when the plugin is initialized
|
||||
public override void OnInitialize()
|
||||
{
|
||||
base.OnInitialize();
|
||||
|
||||
// Keep a static reference
|
||||
me = this;
|
||||
|
||||
// Settings
|
||||
showvisualthings = 2;
|
||||
usegravity = false;
|
||||
usehighlight = true;
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
// This is called when the plugin is terminated
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This loads the plugin settings
|
||||
private void LoadSettings()
|
||||
{
|
||||
changeheightbysidedef = General.Settings.ReadPluginSetting("BuilderModes", "changeheightbysidedef", 0);
|
||||
visualmodeclearselection = General.Settings.ReadPluginSetting("BuilderModes", "visualmodeclearselection", false);
|
||||
stitchrange = (float)General.Settings.ReadPluginSetting("BuilderModes", "stitchrange", 20);
|
||||
|
||||
//mxd
|
||||
editnewthing = General.Settings.ReadPluginSetting("BuilderModes", "editnewthing", true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
||||
// When the Preferences dialog is closed
|
||||
public override void OnClosePreferences(PreferencesController controller)
|
||||
{
|
||||
base.OnClosePreferences(controller);
|
||||
|
||||
// Apply settings that could have been changed
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Classic Mode Surfaces
|
||||
|
||||
// This is called when the vertices are created for the classic mode surfaces
|
||||
public override void OnSectorFloorSurfaceUpdate(Sector s, ref FlatVertex[] vertices)
|
||||
{
|
||||
ImageData img = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
||||
if((img != null) && img.IsImageLoaded)
|
||||
{
|
||||
// Fetch ZDoom fields
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f),
|
||||
s.Fields.GetValue("ypanningfloor", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f),
|
||||
s.Fields.GetValue("yscalefloor", 1.0f));
|
||||
float rotate = s.Fields.GetValue("rotationfloor", 0.0f);
|
||||
int color = s.Fields.GetValue("lightcolor", -1);
|
||||
int light = s.Fields.GetValue("lightfloor", 0);
|
||||
bool absolute = s.Fields.GetValue("lightfloorabsolute", false);
|
||||
|
||||
// Setup the vertices with the given settings
|
||||
SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute);
|
||||
}
|
||||
}
|
||||
|
||||
// This is called when the vertices are created for the classic mode surfaces
|
||||
public override void OnSectorCeilingSurfaceUpdate(Sector s, ref FlatVertex[] vertices)
|
||||
{
|
||||
ImageData img = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
||||
if((img != null) && img.IsImageLoaded)
|
||||
{
|
||||
// Fetch ZDoom fields
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
|
||||
s.Fields.GetValue("ypanningceiling", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
|
||||
s.Fields.GetValue("yscaleceiling", 1.0f));
|
||||
float rotate = s.Fields.GetValue("rotationceiling", 0.0f);
|
||||
int color = s.Fields.GetValue("lightcolor", -1);
|
||||
int light = s.Fields.GetValue("lightceiling", 0);
|
||||
bool absolute = s.Fields.GetValue("lightceilingabsolute", false);
|
||||
|
||||
// Setup the vertices with the given settings
|
||||
SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute);
|
||||
}
|
||||
}
|
||||
|
||||
// This applies the given values on the vertices
|
||||
private void SetupSurfaceVertices(FlatVertex[] vertices, Sector s, ImageData img, Vector2D offset,
|
||||
Vector2D scale, float rotate, int color, int light, bool absolute)
|
||||
{
|
||||
// Prepare for math!
|
||||
rotate = Angle2D.DegToRad(rotate);
|
||||
Vector2D texscale = new Vector2D(1.0f / img.ScaledWidth, 1.0f / img.ScaledHeight);
|
||||
if(!absolute) light = s.Brightness + light;
|
||||
PixelColor lightcolor = PixelColor.FromInt(color);
|
||||
PixelColor brightness = PixelColor.FromInt(General.Map.Renderer2D.CalculateBrightness(light));
|
||||
PixelColor finalcolor = PixelColor.Modulate(lightcolor, brightness);
|
||||
color = finalcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Do the math for all vertices
|
||||
for(int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
Vector2D pos = new Vector2D(vertices[i].x, vertices[i].y);
|
||||
pos = pos.GetRotated(rotate);
|
||||
pos.y = -pos.y;
|
||||
pos = (pos + offset) * scale * texscale;
|
||||
vertices[i].u = pos.x;
|
||||
vertices[i].v = pos.y;
|
||||
vertices[i].c = color;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Texture Alignment
|
||||
|
||||
// This performs texture alignment along all walls that match with the same texture
|
||||
// NOTE: This method uses the sidedefs marking to indicate which sides have been aligned
|
||||
// When resetsidemarks is set to true, all sidedefs will first be marked false (not aligned).
|
||||
// Setting resetsidemarks to false is usefull to align only within a specific selection
|
||||
// (set the marked property to true for the sidedefs outside the selection)
|
||||
public static void AutoAlignTextures(Sidedef start, SidedefPart part, ImageData texture, bool alignx, bool aligny, bool resetsidemarks)
|
||||
{
|
||||
Stack<SidedefAlignJob> todo = new Stack<SidedefAlignJob>(50);
|
||||
float scalex = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.x : 1.0f;
|
||||
float scaley = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.y : 1.0f;
|
||||
|
||||
// Mark all sidedefs false (they will be marked true when the texture is aligned)
|
||||
if(resetsidemarks) General.Map.Map.ClearMarkedSidedefs(false);
|
||||
|
||||
if(!texture.IsImageLoaded) return;
|
||||
|
||||
// Determine the Y alignment
|
||||
float ystartalign = start.OffsetY;
|
||||
switch(part)
|
||||
{
|
||||
case SidedefPart.Upper: ystartalign += start.Fields.GetValue("offsety_top", 0.0f); break;
|
||||
case SidedefPart.Middle: ystartalign += start.Fields.GetValue("offsety_mid", 0.0f); break;
|
||||
case SidedefPart.Lower: ystartalign += start.Fields.GetValue("offsety_bottom", 0.0f); break;
|
||||
}
|
||||
|
||||
// Begin with first sidedef
|
||||
SidedefAlignJob first = new SidedefAlignJob();
|
||||
first.sidedef = start;
|
||||
first.offsetx = start.OffsetX;
|
||||
switch(part)
|
||||
{
|
||||
case SidedefPart.Upper: first.offsetx += start.Fields.GetValue("offsetx_top", 0.0f); break;
|
||||
case SidedefPart.Middle: first.offsetx += start.Fields.GetValue("offsetx_mid", 0.0f); break;
|
||||
case SidedefPart.Lower: first.offsetx += start.Fields.GetValue("offsetx_bottom", 0.0f); break;
|
||||
}
|
||||
first.forward = true;
|
||||
todo.Push(first);
|
||||
|
||||
// Continue until nothing more to align
|
||||
while(todo.Count > 0)
|
||||
{
|
||||
Vertex v;
|
||||
float forwardoffset;
|
||||
float backwardoffset;
|
||||
float offsetscalex = 1.0f;
|
||||
|
||||
// Get the align job to do
|
||||
SidedefAlignJob j = todo.Pop();
|
||||
|
||||
bool matchtop = ((j.sidedef.LongHighTexture == texture.LongName) && j.sidedef.HighRequired());
|
||||
bool matchbottom = ((j.sidedef.LongLowTexture == texture.LongName) && j.sidedef.LowRequired());
|
||||
bool matchmid = ((j.sidedef.LongMiddleTexture == texture.LongName) && (j.sidedef.MiddleRequired() || ((j.sidedef.MiddleTexture.Length > 0) && (j.sidedef.MiddleTexture[0] != '-'))));
|
||||
|
||||
if(matchtop) offsetscalex = j.sidedef.Fields.GetValue("scalex_top", 1.0f);
|
||||
else if(matchbottom) offsetscalex = j.sidedef.Fields.GetValue("scalex_bottom", 1.0f);
|
||||
else if(matchmid) offsetscalex = j.sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
||||
|
||||
if(j.forward)
|
||||
{
|
||||
// Apply alignment
|
||||
if(alignx)
|
||||
{
|
||||
//j.sidedef.OffsetX = j.offsetx;
|
||||
float offset = j.offsetx;
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetX;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
if(aligny)
|
||||
{
|
||||
//j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
||||
float offset = ((float)(start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + ystartalign;
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetY;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
forwardoffset = j.offsetx + (int)Math.Round(j.sidedef.Line.Length / scalex * offsetscalex);
|
||||
backwardoffset = j.offsetx;
|
||||
|
||||
// Done this sidedef
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForAlignment(todo, v, false, backwardoffset, texture.LongName);
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForAlignment(todo, v, true, forwardoffset, texture.LongName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply alignment
|
||||
if(alignx)
|
||||
{
|
||||
//j.sidedef.OffsetX = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
float offset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetX;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
if(aligny)
|
||||
{
|
||||
//j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
||||
float offset = ((float)(start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + ystartalign;
|
||||
offset %= (float)texture.Height;
|
||||
offset -= j.sidedef.OffsetY;
|
||||
|
||||
j.sidedef.Fields.BeforeFieldsChange();
|
||||
if(matchtop) j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchbottom) j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, offset);
|
||||
if(matchmid) j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);
|
||||
}
|
||||
forwardoffset = j.offsetx;
|
||||
backwardoffset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex * offsetscalex);
|
||||
|
||||
// Done this sidedef
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForAlignment(todo, v, true, forwardoffset, texture.LongName);
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForAlignment(todo, v, false, backwardoffset, texture.LongName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This adds the matching, unmarked sidedefs from a vertex for texture alignment
|
||||
private static void AddSidedefsForAlignment(Stack<SidedefAlignJob> stack, Vertex v, bool forward, float offsetx, long texturelongname)
|
||||
{
|
||||
foreach(Linedef ld in v.Linedefs)
|
||||
{
|
||||
Sidedef side1 = forward ? ld.Front : ld.Back;
|
||||
Sidedef side2 = forward ? ld.Back : ld.Front;
|
||||
if((ld.Start == v) && (side1 != null) && !side1.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(side1, texturelongname))
|
||||
{
|
||||
SidedefAlignJob nj = new SidedefAlignJob();
|
||||
nj.forward = forward;
|
||||
nj.offsetx = offsetx;
|
||||
nj.sidedef = side1;
|
||||
stack.Push(nj);
|
||||
}
|
||||
}
|
||||
else if((ld.End == v) && (side2 != null) && !side2.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(side2, texturelongname))
|
||||
{
|
||||
SidedefAlignJob nj = new SidedefAlignJob();
|
||||
nj.forward = forward;
|
||||
nj.offsetx = offsetx;
|
||||
nj.sidedef = side2;
|
||||
stack.Push(nj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This checks if any of the sidedef texture match the given texture
|
||||
private static bool SidedefTextureMatch(Sidedef sd, long texturelongname)
|
||||
{
|
||||
return ((sd.LongHighTexture == texturelongname) && sd.HighRequired()) ||
|
||||
((sd.LongLowTexture == texturelongname) && sd.LowRequired()) ||
|
||||
((sd.LongMiddleTexture == texturelongname) && (sd.MiddleRequired() || ((sd.MiddleTexture.Length > 0) && (sd.MiddleTexture[0] != '-'))));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
|
||||
#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 System.Drawing;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.Plugins;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
// Vertex
|
||||
public class VertexProperties
|
||||
{
|
||||
private UniFields fields;
|
||||
|
||||
public VertexProperties(Vertex v)
|
||||
{
|
||||
fields = new UniFields(v.Fields);
|
||||
}
|
||||
|
||||
public void Apply(Vertex v)
|
||||
{
|
||||
v.Fields.BeforeFieldsChange();
|
||||
v.Fields.Clear();
|
||||
foreach(KeyValuePair<string, UniValue> uv in fields)
|
||||
v.Fields.Add(uv.Key, new UniValue(uv.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Sector
|
||||
public class SectorProperties
|
||||
{
|
||||
private int floorheight;
|
||||
private int ceilheight;
|
||||
private string floortexture;
|
||||
private string ceilingtexture;
|
||||
private int effect;
|
||||
private int brightness;
|
||||
private int tag;
|
||||
private UniFields fields;
|
||||
|
||||
public SectorProperties(Sector s)
|
||||
{
|
||||
floorheight = s.FloorHeight;
|
||||
ceilheight = s.CeilHeight;
|
||||
floortexture = s.FloorTexture;
|
||||
ceilingtexture = s.CeilTexture;
|
||||
brightness = s.Brightness;
|
||||
effect = s.Effect;
|
||||
tag = s.Tag;
|
||||
fields = new UniFields(s.Fields);
|
||||
}
|
||||
|
||||
public void Apply(Sector s)
|
||||
{
|
||||
s.FloorHeight = floorheight;
|
||||
s.CeilHeight = ceilheight;
|
||||
s.SetFloorTexture(floortexture);
|
||||
s.SetCeilTexture(ceilingtexture);
|
||||
s.Brightness = brightness;
|
||||
s.Tag = tag;
|
||||
s.Effect = effect;
|
||||
s.Fields.BeforeFieldsChange();
|
||||
s.Fields.Clear();
|
||||
foreach(KeyValuePair<string, UniValue> v in fields)
|
||||
s.Fields.Add(v.Key, new UniValue(v.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Sidedef
|
||||
public class SidedefProperties
|
||||
{
|
||||
private string hightexture;
|
||||
private string middletexture;
|
||||
private string lowtexture;
|
||||
private int offsetx;
|
||||
private int offsety;
|
||||
private UniFields fields;
|
||||
|
||||
public SidedefProperties(Sidedef s)
|
||||
{
|
||||
hightexture = s.HighTexture;
|
||||
middletexture = s.MiddleTexture;
|
||||
lowtexture = s.LowTexture;
|
||||
offsetx = s.OffsetX;
|
||||
offsety = s.OffsetY;
|
||||
fields = new UniFields(s.Fields);
|
||||
}
|
||||
|
||||
public void Apply(Sidedef s)
|
||||
{
|
||||
s.SetTextureHigh(hightexture);
|
||||
s.SetTextureMid(middletexture);
|
||||
s.SetTextureLow(lowtexture);
|
||||
s.OffsetX = offsetx;
|
||||
s.OffsetY = offsety;
|
||||
s.Fields.BeforeFieldsChange();
|
||||
s.Fields.Clear();
|
||||
foreach(KeyValuePair<string, UniValue> v in fields)
|
||||
s.Fields.Add(v.Key, new UniValue(v.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Linedef
|
||||
public class LinedefProperties
|
||||
{
|
||||
private SidedefProperties front;
|
||||
private SidedefProperties back;
|
||||
private Dictionary<string, bool> flags;
|
||||
private int action;
|
||||
private int activate;
|
||||
private int tag;
|
||||
private int[] args;
|
||||
private UniFields fields;
|
||||
|
||||
public LinedefProperties(Linedef l)
|
||||
{
|
||||
if(l.Front != null)
|
||||
front = new SidedefProperties(l.Front);
|
||||
else
|
||||
front = null;
|
||||
|
||||
if(l.Back != null)
|
||||
back = new SidedefProperties(l.Back);
|
||||
else
|
||||
back = null;
|
||||
|
||||
flags = l.GetFlags();
|
||||
action = l.Action;
|
||||
activate = l.Activate;
|
||||
tag = l.Tag;
|
||||
args = (int[])(l.Args.Clone());
|
||||
fields = new UniFields(l.Fields);
|
||||
}
|
||||
|
||||
public void Apply(Linedef l)
|
||||
{
|
||||
if((front != null) && (l.Front != null)) front.Apply(l.Front);
|
||||
if((back != null) && (l.Back != null)) back.Apply(l.Back);
|
||||
l.ClearFlags();
|
||||
foreach(KeyValuePair<string, bool> f in flags)
|
||||
l.SetFlag(f.Key, f.Value);
|
||||
l.Action = action;
|
||||
l.Activate = activate;
|
||||
l.Tag = tag;
|
||||
for(int i = 0; i < l.Args.Length; i++)
|
||||
l.Args[i] = args[i];
|
||||
l.Fields.BeforeFieldsChange();
|
||||
l.Fields.Clear();
|
||||
foreach(KeyValuePair<string, UniValue> v in fields)
|
||||
l.Fields.Add(v.Key, new UniValue(v.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Thing
|
||||
public class ThingProperties
|
||||
{
|
||||
private int type;
|
||||
private float angle;
|
||||
private Dictionary<string, bool> flags;
|
||||
private int tag;
|
||||
private int action;
|
||||
private int[] args;
|
||||
private UniFields fields;
|
||||
|
||||
public ThingProperties(Thing t)
|
||||
{
|
||||
type = t.Type;
|
||||
angle = t.Angle;
|
||||
flags = t.GetFlags();
|
||||
tag = t.Tag;
|
||||
action = t.Action;
|
||||
args = (int[])(t.Args.Clone());
|
||||
fields = new UniFields(t.Fields);
|
||||
}
|
||||
|
||||
public void Apply(Thing t)
|
||||
{
|
||||
t.Type = type;
|
||||
t.Rotate(angle);
|
||||
t.ClearFlags();
|
||||
foreach(KeyValuePair<string, bool> f in flags)
|
||||
t.SetFlag(f.Key, f.Value);
|
||||
t.Tag = tag;
|
||||
t.Action = action;
|
||||
for(int i = 0; i < t.Args.Length; i++)
|
||||
t.Args[i] = args[i];
|
||||
t.Fields.BeforeFieldsChange();
|
||||
t.Fields.Clear();
|
||||
foreach(KeyValuePair<string, UniValue> v in fields)
|
||||
t.Fields.Add(v.Key, new UniValue(v.Value));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
|
||||
#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.Map;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
public class UndoGroup
|
||||
{
|
||||
public const int None = 0;
|
||||
public const int FloorHeightChange = 1;
|
||||
public const int CeilingHeightChange = 2;
|
||||
public const int SectorBrightnessChange = 3;
|
||||
public const int TextureOffsetChange = 4;
|
||||
public const int SectorHeightChange = 5;
|
||||
public const int ThingMove = 6; //mxd
|
||||
public const int ThingRotate = 7; //mxd
|
||||
public const int SurfaceBrightnessChange = 8; //mxd
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GZDoomEditing")]
|
||||
[assembly: AssemblyDescription("(G)ZDoom Editing Plugin")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Doom Builder")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2010")]
|
||||
[assembly: AssemblyTrademark("CodeImp")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("954411b0-01e9-416f-9254-432cc1a02e3c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,70 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.269
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeImp.DoomBuilder.GZDoomEditing.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static System.Drawing.Bitmap VisualModeZ {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("VisualModeZ", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="VisualModeZ" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\VisualModeZ.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1,46 +0,0 @@
|
|||
/******************************************\
|
||||
Doom Builder Actions Configuration
|
||||
\******************************************/
|
||||
|
||||
gzdoomvisualmode
|
||||
{
|
||||
title = "GZDoom Visual Mode";
|
||||
category = "modes";
|
||||
description = "Switches to the (G)ZDoom visual editing mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
default = 81;
|
||||
}
|
||||
|
||||
flooralignmode
|
||||
{
|
||||
title = "Floor Align Mode";
|
||||
category = "modes";
|
||||
description = "Switches to the (G)ZDoom Floor Align mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
|
||||
ceilingalignmode
|
||||
{
|
||||
title = "Ceiling Align Mode";
|
||||
category = "modes";
|
||||
description = "Switches to the (G)ZDoom Ceiling Align mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
|
||||
togglegzdoomrenderingeffects
|
||||
{
|
||||
title = "Toggle GZDoom rendering effects";
|
||||
category = "visual";
|
||||
description = "Toggles rendering of GZDoom rendering effects (slopes, 3D-floors etc.) in GZDoom Visual mode.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = false;
|
||||
default = 9; //Tab
|
||||
}
|
||||
|
Before Width: | Height: | Size: 905 B |
|
@ -1,509 +0,0 @@
|
|||
|
||||
#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.Data;
|
||||
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.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal abstract class BaseVisualGeometrySector : VisualGeometry, IVisualEventReceiver
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
private const float DRAG_ANGLE_TOLERANCE = 0.06f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
protected long setuponloadedtexture;
|
||||
|
||||
// This is only used to see if this object has already received a change
|
||||
// in a multiselection. The Changed property on the BaseVisualSector is
|
||||
// used to indicate a rebuild is needed.
|
||||
protected bool changed;
|
||||
|
||||
protected SectorLevel level;
|
||||
protected Effect3DFloor extrafloor;
|
||||
|
||||
// Undo/redo
|
||||
private int undoticket;
|
||||
|
||||
// UV dragging
|
||||
private float dragstartanglexy;
|
||||
private float dragstartanglez;
|
||||
private Vector3D dragorigin;
|
||||
private Vector3D deltaxy;
|
||||
private Vector3D deltaz;
|
||||
private int startoffsetx;
|
||||
private int startoffsety;
|
||||
protected bool uvdragging;
|
||||
private int prevoffsetx; // We have to provide delta offsets, but I don't
|
||||
private int prevoffsety; // want to calculate with delta offsets to prevent
|
||||
// inaccuracy in the dragging.
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
new public BaseVisualSector Sector { get { return (BaseVisualSector)base.Sector; } }
|
||||
public bool Changed { get { return changed; } set { changed = value; } }
|
||||
public SectorLevel Level { get { return level; } }
|
||||
public Effect3DFloor ExtraFloor { get { return extrafloor; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
// Constructor
|
||||
protected BaseVisualGeometrySector(BaseVisualMode mode, VisualSector vs) : base(vs)
|
||||
{
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This changes the height
|
||||
protected abstract void ChangeHeight(int amount);
|
||||
|
||||
// This swaps triangles so that the plane faces the other way
|
||||
protected void SwapTriangleVertices(WorldVertex[] verts)
|
||||
{
|
||||
// Swap some vertices to flip all triangles
|
||||
for(int i = 0; i < verts.Length; i += 3)
|
||||
{
|
||||
// Swap
|
||||
WorldVertex v = verts[i];
|
||||
verts[i] = verts[i + 1];
|
||||
verts[i + 1] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// This is called to update UV dragging
|
||||
protected virtual void UpdateDragUV()
|
||||
{
|
||||
float u_ray = 1.0f;
|
||||
|
||||
// Calculate intersection position
|
||||
this.Level.plane.GetIntersection(General.Map.VisualCamera.Position, General.Map.VisualCamera.Target, ref u_ray);
|
||||
Vector3D intersect = General.Map.VisualCamera.Position + (General.Map.VisualCamera.Target - General.Map.VisualCamera.Position) * u_ray;
|
||||
|
||||
// Calculate offsets
|
||||
Vector3D dragdelta = intersect - dragorigin;
|
||||
float offsetx = dragdelta.x;
|
||||
float offsety = dragdelta.y;
|
||||
|
||||
//mxd. Modify offsets based on surface and camera angles
|
||||
if (General.Map.UDMF) {
|
||||
float angle = 0;
|
||||
if (GeometryType == VisualGeometryType.CEILING && level.sector.Fields.ContainsKey("rotationceiling"))
|
||||
angle = (float)level.sector.Fields["rotationceiling"].Value * (float)Math.PI / 180f;
|
||||
else if (GeometryType == VisualGeometryType.FLOOR && level.sector.Fields.ContainsKey("rotationfloor"))
|
||||
angle = (float)level.sector.Fields["rotationfloor"].Value * (float)Math.PI / 180f;
|
||||
|
||||
Vector2D v = new Vector2D(offsetx, offsety).GetRotated(angle);
|
||||
Point p = getTranslatedTextureOffset(new Point((int)Math.Round(v.x), (int)Math.Round(v.y)));
|
||||
offsetx = p.X;
|
||||
offsety = p.Y;
|
||||
}
|
||||
|
||||
// Apply offsets
|
||||
int newoffsetx = startoffsetx - (int)Math.Round(offsetx);
|
||||
int newoffsety = startoffsety + (int)Math.Round(offsety);
|
||||
mode.ApplyFlatOffsetChange(prevoffsetx - newoffsetx, prevoffsety - newoffsety);
|
||||
prevoffsetx = newoffsetx;
|
||||
prevoffsety = newoffsety;
|
||||
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override Sector GetControlSector() {
|
||||
return level.sector;
|
||||
}
|
||||
|
||||
//mxd. Modify texture offsets based on camera angle (so "movetextureleft" action always moves texture more or less "left" etc.)
|
||||
protected Point getTranslatedTextureOffset(Point p) {
|
||||
Point tp = new Point();
|
||||
int camAngle = (int)(General.Map.VisualCamera.AngleXY * 180f / (float)Math.PI);
|
||||
|
||||
if (camAngle > 315 || camAngle < 46) {
|
||||
tp = p;
|
||||
} else if (camAngle > 225) {
|
||||
tp.Y = p.X;
|
||||
tp.X = -p.Y;
|
||||
} else if (camAngle > 135) {
|
||||
tp.X = -p.X;
|
||||
tp.Y = -p.Y;
|
||||
}else{
|
||||
tp.Y = -p.X;
|
||||
tp.X = p.Y;
|
||||
}
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
||||
// Unused
|
||||
public virtual void OnEditBegin() { }
|
||||
public virtual void OnTextureAlign(bool alignx, bool aligny) { }
|
||||
public virtual void OnToggleUpperUnpegged() { }
|
||||
public virtual void OnToggleLowerUnpegged() { }
|
||||
public virtual void OnResetTextureOffset() { }
|
||||
public virtual void OnCopyTextureOffsets() { }
|
||||
public virtual void OnPasteTextureOffsets() { }
|
||||
public virtual void OnInsert() { }
|
||||
public virtual void OnDelete() { }
|
||||
protected virtual void SetTexture(string texturename) { }
|
||||
public virtual void ApplyUpperUnpegged(bool set) { }
|
||||
public virtual void ApplyLowerUnpegged(bool set) { }
|
||||
protected abstract void MoveTextureOffset(Point xy);
|
||||
protected abstract Point GetTextureOffset();
|
||||
|
||||
// Setup this plane
|
||||
public bool Setup() { return this.Setup(this.level, this.extrafloor); }
|
||||
public virtual bool Setup(SectorLevel level, Effect3DFloor extrafloor)
|
||||
{
|
||||
this.level = level;
|
||||
this.extrafloor = extrafloor;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin select
|
||||
public virtual void OnSelectBegin()
|
||||
{
|
||||
mode.LockTarget();
|
||||
dragstartanglexy = General.Map.VisualCamera.AngleXY;
|
||||
dragstartanglez = General.Map.VisualCamera.AngleZ;
|
||||
dragorigin = pickintersect;
|
||||
startoffsetx = GetTextureOffset().X;
|
||||
startoffsety = GetTextureOffset().Y;
|
||||
prevoffsetx = GetTextureOffset().X;
|
||||
prevoffsety = GetTextureOffset().Y;
|
||||
}
|
||||
|
||||
// Select or deselect
|
||||
public virtual void OnSelectEnd()
|
||||
{
|
||||
mode.UnlockTarget();
|
||||
|
||||
// Was dragging?
|
||||
if(uvdragging)
|
||||
{
|
||||
// Dragging stops now
|
||||
uvdragging = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this.selected)
|
||||
{
|
||||
this.selected = false;
|
||||
mode.RemoveSelectedObject(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.selected = true;
|
||||
mode.AddSelectedObject(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moving the mouse
|
||||
public virtual void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
// Dragging UV?
|
||||
if(uvdragging)
|
||||
{
|
||||
UpdateDragUV();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select button pressed?
|
||||
if(General.Actions.CheckActionActive(General.ThisAssembly, "visualselect"))
|
||||
{
|
||||
// Check if tolerance is exceeded to start UV dragging
|
||||
float deltaxy = General.Map.VisualCamera.AngleXY - dragstartanglexy;
|
||||
float deltaz = General.Map.VisualCamera.AngleZ - dragstartanglez;
|
||||
if((Math.Abs(deltaxy) + Math.Abs(deltaz)) > DRAG_ANGLE_TOLERANCE)
|
||||
{
|
||||
if(General.Map.UDMF) { //mxd
|
||||
mode.PreAction(UndoGroup.TextureOffsetChange);
|
||||
mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Start drag now
|
||||
uvdragging = true;
|
||||
mode.Renderer.ShowSelection = false;
|
||||
mode.Renderer.ShowHighlight = false;
|
||||
UpdateDragUV();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Processing
|
||||
public virtual void OnProcess(float deltatime)
|
||||
{
|
||||
// If the texture was not loaded, but is loaded now, then re-setup geometry
|
||||
if(setuponloadedtexture != 0)
|
||||
{
|
||||
ImageData t = General.Map.Data.GetFlatImage(setuponloadedtexture);
|
||||
if(t != null)
|
||||
{
|
||||
if(t.IsImageLoaded)
|
||||
{
|
||||
setuponloadedtexture = 0;
|
||||
Setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flood-fill textures
|
||||
public virtual void OnTextureFloodfill()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedFlat != null)
|
||||
{
|
||||
string oldtexture = GetTextureName();
|
||||
long oldtexturelong = Lump.MakeLongName(oldtexture);
|
||||
string newtexture = BuilderPlug.Me.CopiedFlat;
|
||||
if(newtexture != oldtexture)
|
||||
{
|
||||
// Get the texture
|
||||
ImageData newtextureimage = General.Map.Data.GetFlatImage(newtexture);
|
||||
if(newtextureimage != null)
|
||||
{
|
||||
bool fillceilings = (this is VisualCeiling);
|
||||
|
||||
if(fillceilings)
|
||||
{
|
||||
mode.CreateUndo("Flood-fill ceilings with " + newtexture);
|
||||
mode.SetActionResult("Flood-filled ceilings with " + newtexture + ".");
|
||||
}
|
||||
else
|
||||
{
|
||||
mode.CreateUndo("Flood-fill floors with " + newtexture);
|
||||
mode.SetActionResult("Flood-filled floors with " + newtexture + ".");
|
||||
}
|
||||
|
||||
mode.Renderer.SetCrosshairBusy(true);
|
||||
General.Interface.RedrawDisplay();
|
||||
|
||||
if(mode.IsSingleSelection)
|
||||
{
|
||||
// Clear all marks, this will align everything it can
|
||||
General.Map.Map.ClearMarkedSectors(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Limit the alignment to selection only
|
||||
General.Map.Map.ClearMarkedSectors(true);
|
||||
List<Sector> sectors = mode.GetSelectedSectors();
|
||||
foreach(Sector s in sectors) s.Marked = false;
|
||||
}
|
||||
|
||||
// Do the fill
|
||||
Tools.FloodfillFlats(this.Sector.Sector, fillceilings, oldtexturelong, newtextureimage, false);
|
||||
|
||||
// Get the changed sectors
|
||||
List<Sector> changes = General.Map.Map.GetMarkedSectors(true);
|
||||
foreach(Sector s in changes)
|
||||
{
|
||||
// Update the visual sector
|
||||
if(mode.VisualSectorExists(s))
|
||||
{
|
||||
BaseVisualSector vs = (mode.GetVisualSector(s) as BaseVisualSector);
|
||||
if(fillceilings)
|
||||
vs.Ceiling.Setup();
|
||||
else
|
||||
vs.Floor.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
mode.Renderer.SetCrosshairBusy(false);
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy properties
|
||||
public virtual void OnCopyProperties()
|
||||
{
|
||||
BuilderPlug.Me.CopiedSectorProps = new SectorProperties(level.sector);
|
||||
mode.SetActionResult("Copied sector properties.");
|
||||
}
|
||||
|
||||
// Paste properties
|
||||
public virtual void OnPasteProperties()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedSectorProps != null)
|
||||
{
|
||||
mode.CreateUndo("Paste sector properties");
|
||||
mode.SetActionResult("Pasted sector properties.");
|
||||
BuilderPlug.Me.CopiedSectorProps.Apply(level.sector);
|
||||
if(mode.VisualSectorExists(level.sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
vs.UpdateSectorGeometry(true);
|
||||
}
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// Select texture
|
||||
public virtual void OnSelectTexture()
|
||||
{
|
||||
if(General.Interface.IsActiveWindow)
|
||||
{
|
||||
string oldtexture = GetTextureName();
|
||||
string newtexture = General.Interface.BrowseFlat(General.Interface, oldtexture);
|
||||
if(newtexture != oldtexture)
|
||||
{
|
||||
mode.ApplySelectTexture(newtexture, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Texture
|
||||
public virtual void ApplyTexture(string texture)
|
||||
{
|
||||
mode.CreateUndo("Change flat " + texture);
|
||||
SetTexture(texture);
|
||||
}
|
||||
|
||||
// Copy texture
|
||||
public virtual void OnCopyTexture()
|
||||
{
|
||||
BuilderPlug.Me.CopiedFlat = GetTextureName();
|
||||
if(General.Map.Config.MixTexturesFlats) BuilderPlug.Me.CopiedTexture = GetTextureName();
|
||||
mode.SetActionResult("Copied flat " + GetTextureName() + ".");
|
||||
}
|
||||
|
||||
public virtual void OnPasteTexture() { }
|
||||
|
||||
// Return texture name
|
||||
public virtual string GetTextureName() { return ""; }
|
||||
|
||||
// Edit button released
|
||||
public virtual void OnEditEnd()
|
||||
{
|
||||
if(General.Interface.IsActiveWindow)
|
||||
{
|
||||
List<Sector> sectors = mode.GetSelectedSectors();
|
||||
DialogResult result = General.Interface.ShowEditSectors(sectors);
|
||||
if(result == DialogResult.OK)
|
||||
{
|
||||
// Rebuild sector
|
||||
foreach(Sector s in sectors)
|
||||
{
|
||||
if(mode.VisualSectorExists(s))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s);
|
||||
vs.UpdateSectorGeometry(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sector height change
|
||||
public virtual void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
changed = true;
|
||||
|
||||
ChangeHeight(amount);
|
||||
|
||||
// Rebuild sector
|
||||
BaseVisualSector vs;
|
||||
if(mode.VisualSectorExists(level.sector)) {
|
||||
vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
//vs.UpdateSectorGeometry(true);
|
||||
} else {//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
|
||||
vs = mode.CreateBaseVisualSector(level.sector);
|
||||
}
|
||||
|
||||
if(vs != null) vs.UpdateSectorGeometry(true);
|
||||
}
|
||||
|
||||
// Sector brightness change
|
||||
public virtual void OnChangeTargetBrightness(bool up)
|
||||
{
|
||||
mode.CreateUndo("Change sector brightness", UndoGroup.SectorBrightnessChange, Sector.Sector.FixedIndex);
|
||||
|
||||
if(up)
|
||||
Sector.Sector.Brightness = General.Map.Config.BrightnessLevels.GetNextHigher(Sector.Sector.Brightness);
|
||||
else
|
||||
Sector.Sector.Brightness = General.Map.Config.BrightnessLevels.GetNextLower(Sector.Sector.Brightness);
|
||||
|
||||
mode.SetActionResult("Changed sector brightness to " + Sector.Sector.Brightness + ".");
|
||||
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
// Rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
// Texture offset change
|
||||
public virtual void OnChangeTextureOffset(int horizontal, int vertical)
|
||||
{
|
||||
//mxd
|
||||
if (General.Map.UDMF) {
|
||||
if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Apply offsets
|
||||
MoveTextureOffset(new Point(-horizontal, -vertical));
|
||||
|
||||
mode.SetActionResult("Changed texture offsets by " + -horizontal + ", " + -vertical + ".");
|
||||
|
||||
// Update sector geometry
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
Sector.Rebuild();
|
||||
} else {
|
||||
General.ShowErrorMessage("Floor/ceiling texture offsets cannot be changed in this map format!", MessageBoxButtons.OK);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,976 +0,0 @@
|
|||
|
||||
#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.Data;
|
||||
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.VisualModes;
|
||||
using System.Drawing;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal abstract class BaseVisualGeometrySidedef : VisualGeometry, IVisualEventReceiver
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
private const float DRAG_ANGLE_TOLERANCE = 0.06f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
|
||||
protected Plane top;
|
||||
protected Plane bottom;
|
||||
protected long setuponloadedtexture;
|
||||
|
||||
// UV dragging
|
||||
private float dragstartanglexy;
|
||||
private float dragstartanglez;
|
||||
private Vector3D dragorigin;
|
||||
private Vector3D deltaxy;
|
||||
private Vector3D deltaz;
|
||||
private int startoffsetx;
|
||||
private int startoffsety;
|
||||
protected bool uvdragging;
|
||||
private int prevoffsetx; // We have to provide delta offsets, but I don't
|
||||
private int prevoffsety; // want to calculate with delta offsets to prevent
|
||||
// inaccuracy in the dragging.
|
||||
// Undo/redo
|
||||
private int undoticket;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public bool IsDraggingUV { get { return uvdragging; } }
|
||||
new public BaseVisualSector Sector { get { return (BaseVisualSector)base.Sector; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
// Constructor for sidedefs
|
||||
public BaseVisualGeometrySidedef(BaseVisualMode mode, VisualSector vs, Sidedef sd) : base(vs, sd)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.deltaz = new Vector3D(0.0f, 0.0f, 1.0f);
|
||||
this.deltaxy = (sd.Line.End.Position - sd.Line.Start.Position) * sd.Line.LengthInv;
|
||||
if(!sd.IsFront) this.deltaxy = -this.deltaxy;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This sets the renderstyle from linedef information and returns the alpha value or the vertices
|
||||
protected byte SetLinedefRenderstyle(bool solidasmask)
|
||||
{
|
||||
byte alpha = 255;
|
||||
|
||||
// From TranslucentLine action
|
||||
if(Sidedef.Line.Action == 208)
|
||||
{
|
||||
alpha = (byte)General.Clamp(Sidedef.Line.Args[1], 0, 255);
|
||||
|
||||
if(Sidedef.Line.Args[2] == 1)
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if(alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else if(solidasmask)
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
else
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// From UDMF field
|
||||
string field = Sidedef.Line.Fields.GetValue("renderstyle", "translucent");
|
||||
alpha = (byte)(Sidedef.Line.Fields.GetValue("alpha", 1.0f) * 255.0f);
|
||||
|
||||
if(field == "add")
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if(alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else if(solidasmask)
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
else
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
|
||||
return alpha;
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
// Check if intersection point is between top and bottom
|
||||
return (pickintersect.z >= bottom.GetZ(pickintersect)) && (pickintersect.z <= top.GetZ(pickintersect));
|
||||
}
|
||||
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||
{
|
||||
// The fast reject pass is already as accurate as it gets,
|
||||
// so we just return the intersection distance here
|
||||
u_ray = pickrayu;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This creates vertices from a wall polygon and applies lighting
|
||||
protected List<WorldVertex> CreatePolygonVertices(WallPolygon poly, TexturePlane tp, SectorData sd, int lightvalue, bool lightabsolute)
|
||||
{
|
||||
List<WallPolygon> polylist = new List<WallPolygon>(1);
|
||||
polylist.Add(poly);
|
||||
return CreatePolygonVertices(polylist, tp, sd, lightvalue, lightabsolute);
|
||||
}
|
||||
|
||||
// This creates vertices from a wall polygon and applies lighting
|
||||
protected List<WorldVertex> CreatePolygonVertices(List<WallPolygon> poly, TexturePlane tp, SectorData sd, int lightvalue, bool lightabsolute)
|
||||
{
|
||||
List<WallPolygon> polygons = new List<WallPolygon>(poly);
|
||||
List<WorldVertex> verts = new List<WorldVertex>();
|
||||
|
||||
// Go for all levels to build geometry
|
||||
for(int i = sd.LightLevels.Count - 1; i >= 0; i--)
|
||||
{
|
||||
SectorLevel l = sd.LightLevels[i];
|
||||
|
||||
if((l != sd.Floor) && (l != sd.Ceiling) && (l.type != SectorLevelType.Floor))
|
||||
{
|
||||
// Go for all polygons
|
||||
int num = polygons.Count;
|
||||
for(int pi = 0; pi < num; pi++)
|
||||
{
|
||||
// Split by plane
|
||||
WallPolygon p = polygons[pi];
|
||||
WallPolygon np = SplitPoly(ref p, l.plane, false);
|
||||
if(np.Count > 0)
|
||||
{
|
||||
// Determine color
|
||||
int lightlevel = lightabsolute ? lightvalue : l.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
//PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(l.colorbelow, wallbrightness);
|
||||
np.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
if(p.Count == 0)
|
||||
{
|
||||
polygons[pi] = np;
|
||||
}
|
||||
else
|
||||
{
|
||||
polygons[pi] = p;
|
||||
polygons.Add(np);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
polygons[pi] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go for all polygons to make geometry
|
||||
foreach(WallPolygon p in polygons)
|
||||
{
|
||||
// Find texture coordinates for each vertex in the polygon
|
||||
List<Vector2D> texc = new List<Vector2D>(p.Count);
|
||||
foreach(Vector3D v in p)
|
||||
texc.Add(tp.GetTextureCoordsAt(v));
|
||||
|
||||
// Now we create triangles from the polygon.
|
||||
// The polygon is convex and clockwise, so this is a piece of cake.
|
||||
if(p.Count >= 3)
|
||||
{
|
||||
for(int k = 1; k < (p.Count - 1); k++)
|
||||
{
|
||||
verts.Add(new WorldVertex(p[0], p.color, texc[0]));
|
||||
verts.Add(new WorldVertex(p[k], p.color, texc[k]));
|
||||
verts.Add(new WorldVertex(p[k + 1], p.color, texc[k + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verts;
|
||||
}
|
||||
|
||||
// This splits a polygon with a plane and returns the other part as a new polygon
|
||||
// The polygon is expected to be convex and clockwise
|
||||
protected WallPolygon SplitPoly(ref WallPolygon poly, Plane p, bool keepfront)
|
||||
{
|
||||
const float NEAR_ZERO = 0.01f;
|
||||
WallPolygon front = new WallPolygon(poly.Count);
|
||||
WallPolygon back = new WallPolygon(poly.Count);
|
||||
poly.CopyProperties(front);
|
||||
poly.CopyProperties(back);
|
||||
|
||||
if(poly.Count > 0)
|
||||
{
|
||||
// Go for all vertices to see which side they have to be on
|
||||
Vector3D v1 = poly[poly.Count - 1];
|
||||
float side1 = p.Distance(v1);
|
||||
for(int i = 0; i < poly.Count; i++)
|
||||
{
|
||||
// Fetch vertex and determine side
|
||||
Vector3D v2 = poly[i];
|
||||
float side2 = p.Distance(v2);
|
||||
|
||||
// Front?
|
||||
if(side2 > NEAR_ZERO)
|
||||
{
|
||||
if(side1 < -NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
front.Add(v3);
|
||||
back.Add(v3);
|
||||
}
|
||||
|
||||
front.Add(v2);
|
||||
}
|
||||
// Back?
|
||||
else if(side2 < -NEAR_ZERO)
|
||||
{
|
||||
if(side1 > NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
front.Add(v3);
|
||||
back.Add(v3);
|
||||
}
|
||||
|
||||
back.Add(v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// On the plane, add to both polygons
|
||||
front.Add(v2);
|
||||
back.Add(v2);
|
||||
}
|
||||
|
||||
// Next
|
||||
v1 = v2;
|
||||
side1 = side2;
|
||||
}
|
||||
}
|
||||
|
||||
if(keepfront)
|
||||
{
|
||||
poly = front;
|
||||
return back;
|
||||
}
|
||||
else
|
||||
{
|
||||
poly = back;
|
||||
return front;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This crops a polygon with a plane and keeps only a certain part of the polygon
|
||||
protected void CropPoly(ref WallPolygon poly, Plane p, bool keepfront)
|
||||
{
|
||||
const float NEAR_ZERO = 0.01f;
|
||||
float sideswitch = keepfront ? 1 : -1;
|
||||
WallPolygon newp = new WallPolygon(poly.Count);
|
||||
poly.CopyProperties(newp);
|
||||
|
||||
if(poly.Count > 0)
|
||||
{
|
||||
// First split lines that cross the plane so that we have vertices on the plane where the lines cross
|
||||
Vector3D v1 = poly[poly.Count - 1];
|
||||
float side1 = p.Distance(v1) * sideswitch;
|
||||
for(int i = 0; i < poly.Count; i++)
|
||||
{
|
||||
// Fetch vertex and determine side
|
||||
Vector3D v2 = poly[i];
|
||||
float side2 = p.Distance(v2) * sideswitch;
|
||||
|
||||
// Front?
|
||||
if(side2 > NEAR_ZERO)
|
||||
{
|
||||
if(side1 < -NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
newp.Add(v3);
|
||||
}
|
||||
|
||||
newp.Add(v2);
|
||||
}
|
||||
// Back?
|
||||
else if(side2 < -NEAR_ZERO)
|
||||
{
|
||||
if(side1 > NEAR_ZERO)
|
||||
{
|
||||
// Split line with plane and insert the vertex
|
||||
float u = 0.0f;
|
||||
p.GetIntersection(v1, v2, ref u);
|
||||
Vector3D v3 = v1 + (v2 - v1) * u;
|
||||
newp.Add(v3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// On the plane
|
||||
newp.Add(v2);
|
||||
}
|
||||
|
||||
// Next
|
||||
v1 = v2;
|
||||
side1 = side2;
|
||||
}
|
||||
}
|
||||
|
||||
poly = newp;
|
||||
}
|
||||
|
||||
//mxd
|
||||
protected float getRoundedTextureOffset(float oldValue, float offset, float scale) {
|
||||
if(offset == 0f) return oldValue;
|
||||
float result = (float)Math.Round(oldValue + (offset * scale));
|
||||
if (result == oldValue) result += 1f * (offset < 0 ? -1 : 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
||||
// Unused
|
||||
public virtual void OnEditBegin() { }
|
||||
protected virtual void SetTexture(string texturename) { }
|
||||
public abstract bool Setup();
|
||||
protected abstract void SetTextureOffsetX(int x);
|
||||
protected abstract void SetTextureOffsetY(int y);
|
||||
protected abstract void MoveTextureOffset(Point xy);
|
||||
protected abstract Point GetTextureOffset();
|
||||
|
||||
// Insert middle texture
|
||||
public virtual void OnInsert()
|
||||
{
|
||||
// No middle texture yet?
|
||||
if(!Sidedef.MiddleRequired() && (string.IsNullOrEmpty(Sidedef.MiddleTexture) || (Sidedef.MiddleTexture[0] == '-')))
|
||||
{
|
||||
// Make it now
|
||||
mode.CreateUndo("Create middle texture");
|
||||
mode.SetActionResult("Created middle texture.");
|
||||
General.Settings.FindDefaultDrawSettings();
|
||||
Sidedef.SetTextureMid(General.Settings.DefaultTexture);
|
||||
|
||||
// Update
|
||||
Sector.Changed = true;
|
||||
|
||||
// Other side as well
|
||||
if(string.IsNullOrEmpty(Sidedef.Other.MiddleTexture) || (Sidedef.Other.MiddleTexture[0] == '-'))
|
||||
{
|
||||
Sidedef.Other.SetTextureMid(General.Settings.DefaultTexture);
|
||||
|
||||
// Update
|
||||
VisualSector othersector = mode.GetVisualSector(Sidedef.Other.Sector);
|
||||
if(othersector is BaseVisualSector) (othersector as BaseVisualSector).Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete texture
|
||||
public virtual void OnDelete()
|
||||
{
|
||||
// Remove texture
|
||||
mode.CreateUndo("Delete texture");
|
||||
mode.SetActionResult("Deleted a texture.");
|
||||
SetTexture("-");
|
||||
|
||||
// Update
|
||||
Sector.Changed = true;
|
||||
}
|
||||
|
||||
// Processing
|
||||
public virtual void OnProcess(float deltatime)
|
||||
{
|
||||
// If the texture was not loaded, but is loaded now, then re-setup geometry
|
||||
if(setuponloadedtexture != 0)
|
||||
{
|
||||
ImageData t = General.Map.Data.GetTextureImage(setuponloadedtexture);
|
||||
if(t != null)
|
||||
{
|
||||
if(t.IsImageLoaded)
|
||||
{
|
||||
setuponloadedtexture = 0;
|
||||
Setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change target height
|
||||
public virtual void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
switch(BuilderPlug.Me.ChangeHeightBySidedef)
|
||||
{
|
||||
// Change ceiling
|
||||
case 1:
|
||||
if(!this.Sector.Ceiling.Changed)
|
||||
this.Sector.Ceiling.OnChangeTargetHeight(amount);
|
||||
break;
|
||||
|
||||
// Change floor
|
||||
case 2:
|
||||
if(!this.Sector.Floor.Changed)
|
||||
this.Sector.Floor.OnChangeTargetHeight(amount);
|
||||
break;
|
||||
|
||||
// Change both
|
||||
case 3:
|
||||
if(!this.Sector.Floor.Changed)
|
||||
this.Sector.Floor.OnChangeTargetHeight(amount);
|
||||
if(!this.Sector.Ceiling.Changed)
|
||||
this.Sector.Ceiling.OnChangeTargetHeight(amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset texture offsets
|
||||
public virtual void OnResetTextureOffset()
|
||||
{
|
||||
mode.CreateUndo("Reset texture offsets");
|
||||
mode.SetActionResult("Texture offsets reset.");
|
||||
|
||||
// Apply offsets
|
||||
SetTextureOffsetX(0);
|
||||
SetTextureOffsetY(0);
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
|
||||
// Toggle upper-unpegged
|
||||
public virtual void OnToggleUpperUnpegged()
|
||||
{
|
||||
if(this.Sidedef.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag))
|
||||
{
|
||||
// Remove flag
|
||||
mode.ApplyUpperUnpegged(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add flag
|
||||
mode.ApplyUpperUnpegged(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle lower-unpegged
|
||||
public virtual void OnToggleLowerUnpegged()
|
||||
{
|
||||
if(this.Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// Remove flag
|
||||
mode.ApplyLowerUnpegged(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add flag
|
||||
mode.ApplyLowerUnpegged(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This sets the Upper Unpegged flag
|
||||
public virtual void ApplyUpperUnpegged(bool set)
|
||||
{
|
||||
if(!set)
|
||||
{
|
||||
// Remove flag
|
||||
mode.CreateUndo("Remove upper-unpegged setting");
|
||||
mode.SetActionResult("Removed upper-unpegged setting.");
|
||||
this.Sidedef.Line.SetFlag(General.Map.Config.UpperUnpeggedFlag, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add flag
|
||||
mode.CreateUndo("Set upper-unpegged setting");
|
||||
mode.SetActionResult("Set upper-unpegged setting.");
|
||||
this.Sidedef.Line.SetFlag(General.Map.Config.UpperUnpeggedFlag, true);
|
||||
}
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
parts.SetupAllParts();
|
||||
|
||||
// Update other sidedef geometry
|
||||
if(Sidedef.Other != null)
|
||||
{
|
||||
BaseVisualSector othersector = (BaseVisualSector)mode.GetVisualSector(Sidedef.Other.Sector);
|
||||
parts = othersector.GetSidedefParts(Sidedef.Other);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This sets the Lower Unpegged flag
|
||||
public virtual void ApplyLowerUnpegged(bool set)
|
||||
{
|
||||
if(!set)
|
||||
{
|
||||
// Remove flag
|
||||
mode.CreateUndo("Remove lower-unpegged setting");
|
||||
mode.SetActionResult("Removed lower-unpegged setting.");
|
||||
this.Sidedef.Line.SetFlag(General.Map.Config.LowerUnpeggedFlag, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add flag
|
||||
mode.CreateUndo("Set lower-unpegged setting");
|
||||
mode.SetActionResult("Set lower-unpegged setting.");
|
||||
this.Sidedef.Line.SetFlag(General.Map.Config.LowerUnpeggedFlag, true);
|
||||
}
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
parts.SetupAllParts();
|
||||
|
||||
// Update other sidedef geometry
|
||||
if(Sidedef.Other != null)
|
||||
{
|
||||
BaseVisualSector othersector = (BaseVisualSector)mode.GetVisualSector(Sidedef.Other.Sector);
|
||||
parts = othersector.GetSidedefParts(Sidedef.Other);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Flood-fill textures
|
||||
public virtual void OnTextureFloodfill()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedTexture != null)
|
||||
{
|
||||
string oldtexture = GetTextureName();
|
||||
long oldtexturelong = Lump.MakeLongName(oldtexture);
|
||||
string newtexture = BuilderPlug.Me.CopiedTexture;
|
||||
if(newtexture != oldtexture)
|
||||
{
|
||||
mode.CreateUndo("Flood-fill textures with " + newtexture);
|
||||
mode.SetActionResult("Flood-filled textures with " + newtexture + ".");
|
||||
|
||||
mode.Renderer.SetCrosshairBusy(true);
|
||||
General.Interface.RedrawDisplay();
|
||||
|
||||
// Get the texture
|
||||
ImageData newtextureimage = General.Map.Data.GetTextureImage(newtexture);
|
||||
if(newtextureimage != null)
|
||||
{
|
||||
if(mode.IsSingleSelection)
|
||||
{
|
||||
// Clear all marks, this will align everything it can
|
||||
General.Map.Map.ClearMarkedSidedefs(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Limit the alignment to selection only
|
||||
General.Map.Map.ClearMarkedSidedefs(true);
|
||||
List<Sidedef> sides = mode.GetSelectedSidedefs();
|
||||
foreach(Sidedef sd in sides) sd.Marked = false;
|
||||
}
|
||||
|
||||
// Do the alignment
|
||||
Tools.FloodfillTextures(this.Sidedef, oldtexturelong, newtextureimage, false);
|
||||
|
||||
// Get the changed sidedefs
|
||||
List<Sidedef> changes = General.Map.Map.GetMarkedSidedefs(true);
|
||||
foreach(Sidedef sd in changes)
|
||||
{
|
||||
// Update the parts for this sidedef!
|
||||
if(mode.VisualSectorExists(sd.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (mode.GetVisualSector(sd.Sector) as BaseVisualSector);
|
||||
VisualSidedefParts parts = vs.GetSidedefParts(sd);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
}
|
||||
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
mode.Renderer.SetCrosshairBusy(false);
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-align texture X offsets
|
||||
public virtual void OnTextureAlign(bool alignx, bool aligny)
|
||||
{
|
||||
mode.CreateUndo("Auto-align textures");
|
||||
mode.SetActionResult("Auto-aligned textures.");
|
||||
|
||||
// Make sure the texture is loaded (we need the texture size)
|
||||
if(!base.Texture.IsImageLoaded) base.Texture.LoadImage();
|
||||
|
||||
if(mode.IsSingleSelection)
|
||||
{
|
||||
// Clear all marks, this will align everything it can
|
||||
General.Map.Map.ClearMarkedSidedefs(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Limit the alignment to selection only
|
||||
General.Map.Map.ClearMarkedSidedefs(true);
|
||||
List<Sidedef> sides = mode.GetSelectedSidedefs();
|
||||
foreach(Sidedef sd in sides) sd.Marked = false;
|
||||
}
|
||||
|
||||
SidedefPart part;
|
||||
if(this is VisualLower)
|
||||
part = SidedefPart.Lower;
|
||||
else if(this is VisualUpper)
|
||||
part = SidedefPart.Upper;
|
||||
else
|
||||
part = SidedefPart.Middle;
|
||||
|
||||
// Do the alignment
|
||||
BuilderPlug.AutoAlignTextures(this.Sidedef, part, base.Texture, alignx, aligny, false);
|
||||
|
||||
// Get the changed sidedefs
|
||||
List<Sidedef> changes = General.Map.Map.GetMarkedSidedefs(true);
|
||||
foreach(Sidedef sd in changes)
|
||||
{
|
||||
// Update the parts for this sidedef!
|
||||
if(mode.VisualSectorExists(sd.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (mode.GetVisualSector(sd.Sector) as BaseVisualSector);
|
||||
VisualSidedefParts parts = vs.GetSidedefParts(sd);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select texture
|
||||
public virtual void OnSelectTexture()
|
||||
{
|
||||
if(General.Interface.IsActiveWindow)
|
||||
{
|
||||
string oldtexture = GetTextureName();
|
||||
string newtexture = General.Interface.BrowseTexture(General.Interface, oldtexture);
|
||||
if(newtexture != oldtexture)
|
||||
{
|
||||
mode.ApplySelectTexture(newtexture, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Texture
|
||||
public virtual void ApplyTexture(string texture)
|
||||
{
|
||||
mode.CreateUndo("Change texture " + texture);
|
||||
SetTexture(texture);
|
||||
}
|
||||
|
||||
// Paste texture
|
||||
public virtual void OnPasteTexture()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedTexture != null)
|
||||
{
|
||||
mode.CreateUndo("Paste texture " + BuilderPlug.Me.CopiedTexture);
|
||||
mode.SetActionResult("Pasted texture " + BuilderPlug.Me.CopiedTexture + ".");
|
||||
SetTexture(BuilderPlug.Me.CopiedTexture);
|
||||
}
|
||||
}
|
||||
|
||||
// Paste texture offsets
|
||||
public virtual void OnPasteTextureOffsets()
|
||||
{
|
||||
mode.CreateUndo("Paste texture offsets");
|
||||
SetTextureOffsetX(BuilderPlug.Me.CopiedOffsets.X);
|
||||
SetTextureOffsetY(BuilderPlug.Me.CopiedOffsets.Y);
|
||||
mode.SetActionResult("Pasted texture offsets " + BuilderPlug.Me.CopiedOffsets.X + ", " + BuilderPlug.Me.CopiedOffsets.Y + ".");
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
|
||||
// Copy texture
|
||||
public virtual void OnCopyTexture()
|
||||
{
|
||||
BuilderPlug.Me.CopiedTexture = GetTextureName();
|
||||
if(General.Map.Config.MixTexturesFlats) BuilderPlug.Me.CopiedFlat = GetTextureName();
|
||||
mode.SetActionResult("Copied texture " + GetTextureName() + ".");
|
||||
}
|
||||
|
||||
// Copy texture offsets
|
||||
public virtual void OnCopyTextureOffsets()
|
||||
{
|
||||
BuilderPlug.Me.CopiedOffsets = GetTextureOffset();
|
||||
mode.SetActionResult("Copied texture offsets " + BuilderPlug.Me.CopiedOffsets.X + ", " + BuilderPlug.Me.CopiedOffsets.Y + ".");
|
||||
}
|
||||
|
||||
// Copy properties
|
||||
public virtual void OnCopyProperties()
|
||||
{
|
||||
BuilderPlug.Me.CopiedSidedefProps = new SidedefProperties(Sidedef);
|
||||
mode.SetActionResult("Copied sidedef properties.");
|
||||
}
|
||||
|
||||
// Paste properties
|
||||
public virtual void OnPasteProperties()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedSidedefProps != null)
|
||||
{
|
||||
mode.CreateUndo("Paste sidedef properties");
|
||||
mode.SetActionResult("Pasted sidedef properties.");
|
||||
BuilderPlug.Me.CopiedSidedefProps.Apply(Sidedef);
|
||||
|
||||
// Update sectors on both sides
|
||||
BaseVisualSector front = (BaseVisualSector)mode.GetVisualSector(Sidedef.Sector);
|
||||
if(front != null) front.Changed = true;
|
||||
if(Sidedef.Other != null)
|
||||
{
|
||||
BaseVisualSector back = (BaseVisualSector)mode.GetVisualSector(Sidedef.Other.Sector);
|
||||
if(back != null) back.Changed = true;
|
||||
}
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// Return texture name
|
||||
public virtual string GetTextureName() { return ""; }
|
||||
|
||||
// Select button pressed
|
||||
public virtual void OnSelectBegin()
|
||||
{
|
||||
mode.LockTarget();
|
||||
dragstartanglexy = General.Map.VisualCamera.AngleXY;
|
||||
dragstartanglez = General.Map.VisualCamera.AngleZ;
|
||||
dragorigin = pickintersect;
|
||||
startoffsetx = GetTextureOffset().X;
|
||||
startoffsety = GetTextureOffset().Y;
|
||||
prevoffsetx = GetTextureOffset().X;
|
||||
prevoffsety = GetTextureOffset().Y;
|
||||
}
|
||||
|
||||
// Select button released
|
||||
public virtual void OnSelectEnd()
|
||||
{
|
||||
mode.UnlockTarget();
|
||||
|
||||
// Was dragging?
|
||||
if(uvdragging)
|
||||
{
|
||||
// Dragging stops now
|
||||
uvdragging = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add/remove selection
|
||||
if(this.selected)
|
||||
{
|
||||
this.selected = false;
|
||||
mode.RemoveSelectedObject(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.selected = true;
|
||||
mode.AddSelectedObject(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Edit button released
|
||||
public virtual void OnEditEnd()
|
||||
{
|
||||
if(General.Interface.IsActiveWindow)
|
||||
{
|
||||
List<Linedef> linedefs = mode.GetSelectedLinedefs();
|
||||
DialogResult result = General.Interface.ShowEditLinedefs(linedefs);
|
||||
if(result == DialogResult.OK)
|
||||
{
|
||||
foreach(Linedef l in linedefs)
|
||||
{
|
||||
if(l.Front != null)
|
||||
{
|
||||
if(mode.VisualSectorExists(l.Front.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(l.Front.Sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(l.Back != null)
|
||||
{
|
||||
if(mode.VisualSectorExists(l.Back.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(l.Back.Sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mode.RebuildElementData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse moves
|
||||
public virtual void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
// Dragging UV?
|
||||
if(uvdragging)
|
||||
{
|
||||
UpdateDragUV();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select button pressed?
|
||||
if(General.Actions.CheckActionActive(General.ThisAssembly, "visualselect"))
|
||||
{
|
||||
// Check if tolerance is exceeded to start UV dragging
|
||||
float deltaxy = General.Map.VisualCamera.AngleXY - dragstartanglexy;
|
||||
float deltaz = General.Map.VisualCamera.AngleZ - dragstartanglez;
|
||||
if((Math.Abs(deltaxy) + Math.Abs(deltaz)) > DRAG_ANGLE_TOLERANCE)
|
||||
{
|
||||
mode.PreAction(UndoGroup.TextureOffsetChange);
|
||||
mode.CreateUndo("Change texture offsets");
|
||||
|
||||
// Start drag now
|
||||
uvdragging = true;
|
||||
mode.Renderer.ShowSelection = false;
|
||||
mode.Renderer.ShowHighlight = false;
|
||||
UpdateDragUV();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is called to update UV dragging
|
||||
protected virtual void UpdateDragUV()
|
||||
{
|
||||
float u_ray;
|
||||
|
||||
// Calculate intersection position
|
||||
Line2D ray = new Line2D(General.Map.VisualCamera.Position, General.Map.VisualCamera.Target);
|
||||
Sidedef.Line.Line.GetIntersection(ray, out u_ray);
|
||||
Vector3D intersect = General.Map.VisualCamera.Position + (General.Map.VisualCamera.Target - General.Map.VisualCamera.Position) * u_ray;
|
||||
|
||||
// Calculate offsets
|
||||
Vector3D dragdelta = intersect - dragorigin;
|
||||
Vector3D dragdeltaxy = dragdelta * deltaxy;
|
||||
Vector3D dragdeltaz = dragdelta * deltaz;
|
||||
float offsetx = dragdeltaxy.GetLength();
|
||||
float offsety = dragdeltaz.GetLength();
|
||||
if((Math.Sign(dragdeltaxy.x) < 0) || (Math.Sign(dragdeltaxy.y) < 0) || (Math.Sign(dragdeltaxy.z) < 0)) offsetx = -offsetx;
|
||||
if((Math.Sign(dragdeltaz.x) < 0) || (Math.Sign(dragdeltaz.y) < 0) || (Math.Sign(dragdeltaz.z) < 0)) offsety = -offsety;
|
||||
|
||||
// Apply offsets
|
||||
int newoffsetx = startoffsetx - (int)Math.Round(offsetx);
|
||||
int newoffsety = startoffsety + (int)Math.Round(offsety);
|
||||
mode.ApplyTextureOffsetChange(prevoffsetx - newoffsetx, prevoffsety - newoffsety);
|
||||
prevoffsetx = newoffsetx;
|
||||
prevoffsety = newoffsety;
|
||||
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
|
||||
// Sector brightness change
|
||||
public virtual void OnChangeTargetBrightness(bool up)
|
||||
{
|
||||
if(!Sector.Changed)
|
||||
{
|
||||
// Change brightness
|
||||
mode.CreateUndo("Change sector brightness", UndoGroup.SectorBrightnessChange, Sector.Sector.FixedIndex);
|
||||
|
||||
if(up)
|
||||
Sector.Sector.Brightness = General.Map.Config.BrightnessLevels.GetNextHigher(Sector.Sector.Brightness);
|
||||
else
|
||||
Sector.Sector.Brightness = General.Map.Config.BrightnessLevels.GetNextLower(Sector.Sector.Brightness);
|
||||
|
||||
mode.SetActionResult("Changed sector brightness to " + Sector.Sector.Brightness + ".");
|
||||
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
// Rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
|
||||
// Go for all things in this sector
|
||||
foreach(Thing t in General.Map.Map.Things)
|
||||
{
|
||||
if(t.Sector == Sector.Sector)
|
||||
{
|
||||
if(mode.VisualThingExists(t))
|
||||
{
|
||||
// Update thing
|
||||
BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
|
||||
vt.Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Texture offset change
|
||||
public virtual void OnChangeTextureOffset(int horizontal, int vertical)
|
||||
{
|
||||
if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Change texture offsets");
|
||||
|
||||
//mxd
|
||||
if (General.Map.UDMF) {
|
||||
// Apply UDMF offsets
|
||||
MoveTextureOffset(new Point(-horizontal, -vertical));
|
||||
Point p = GetTextureOffset();
|
||||
mode.SetActionResult("Changed texture offsets to " + p.X + ", " + p.Y + ".");
|
||||
} else {
|
||||
// Apply classic offsets
|
||||
Sidedef.OffsetX -= horizontal;
|
||||
Sidedef.OffsetY -= vertical;
|
||||
mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
|
||||
}
|
||||
|
||||
// Update sidedef geometry
|
||||
VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
|
||||
parts.SetupAllParts();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,305 +0,0 @@
|
|||
|
||||
#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.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal class BaseVisualSector : VisualSector
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
|
||||
protected VisualFloor floor;
|
||||
protected VisualCeiling ceiling;
|
||||
protected List<VisualFloor> extrafloors;
|
||||
protected List<VisualCeiling> extraceilings;
|
||||
protected Dictionary<Sidedef, VisualSidedefParts> sides;
|
||||
|
||||
// If this is set to true, the sector will be rebuilt after the action is performed.
|
||||
protected bool changed;
|
||||
|
||||
// Prevent recursion
|
||||
protected bool isupdating;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public VisualFloor Floor { get { return floor; } }
|
||||
public VisualCeiling Ceiling { get { return ceiling; } }
|
||||
public List<VisualFloor> ExtraFloors { get { return extrafloors; } }
|
||||
public List<VisualCeiling> ExtraCeilings { get { return extraceilings; } }
|
||||
public bool Changed { get { return changed; } set { changed |= value; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Disposer
|
||||
|
||||
// Constructor
|
||||
public BaseVisualSector(BaseVisualMode mode, Sector s) : base(s)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.extrafloors = new List<VisualFloor>(2);
|
||||
this.extraceilings = new List<VisualCeiling>(2);
|
||||
|
||||
// Initialize
|
||||
Rebuild();
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Disposer
|
||||
public override void Dispose()
|
||||
{
|
||||
// Not already disposed?
|
||||
if(!IsDisposed)
|
||||
{
|
||||
// Clean up
|
||||
sides = null;
|
||||
floor = null;
|
||||
ceiling = null;
|
||||
extrafloors = null;
|
||||
extraceilings = null;
|
||||
|
||||
// Dispose base
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This retreives the sector data for this sector
|
||||
public SectorData GetSectorData()
|
||||
{
|
||||
return mode.GetSectorData(this.Sector);
|
||||
}
|
||||
|
||||
// This updates this virtual the sector and neightbours if needed
|
||||
public void UpdateSectorGeometry(bool includeneighbours)
|
||||
{
|
||||
if(isupdating)
|
||||
return;
|
||||
|
||||
isupdating = true;
|
||||
changed = true;
|
||||
|
||||
// Not sure what from this part we need, so commented out for now
|
||||
SectorData data = GetSectorData();
|
||||
data.Reset();
|
||||
|
||||
// Update sectors that rely on this sector
|
||||
foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso)
|
||||
{
|
||||
if(mode.VisualSectorExists(s.Key))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
|
||||
vs.UpdateSectorGeometry(s.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// Go for all things in this sector
|
||||
foreach(Thing t in General.Map.Map.Things)
|
||||
{
|
||||
if(t.Sector == this.Sector)
|
||||
{
|
||||
if(mode.VisualThingExists(t))
|
||||
{
|
||||
// Update thing
|
||||
BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
|
||||
vt.Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(includeneighbours)
|
||||
{
|
||||
// Also rebuild surrounding sectors, because outside sidedefs may need to be adjusted
|
||||
foreach(Sidedef sd in this.Sector.Sidedefs)
|
||||
{
|
||||
if(sd.Other != null)
|
||||
{
|
||||
if(mode.VisualSectorExists(sd.Other.Sector))
|
||||
{
|
||||
BaseVisualSector bvs = (BaseVisualSector)mode.GetVisualSector(sd.Other.Sector);
|
||||
bvs.Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isupdating = false;
|
||||
}
|
||||
|
||||
//mxd. call this to update sector and things in it when Sector.Fields are changed
|
||||
override public void UpdateSectorData() {
|
||||
//update sector data
|
||||
SectorData data = GetSectorData();
|
||||
data.Update(true);
|
||||
|
||||
//update sector
|
||||
Rebuild();
|
||||
|
||||
//update things in this sector
|
||||
foreach (Thing t in General.Map.Map.Things) {
|
||||
if (t.Sector == this.Sector) {
|
||||
if (mode.VisualThingExists(t)) {
|
||||
// Update thing
|
||||
BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
|
||||
vt.Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This (re)builds the visual sector, calculating all geometry from scratch
|
||||
public void Rebuild()
|
||||
{
|
||||
// Forget old geometry
|
||||
base.ClearGeometry();
|
||||
|
||||
// Get sector data
|
||||
SectorData data = GetSectorData();
|
||||
if(!data.Updated) data.Update();
|
||||
|
||||
// Create floor
|
||||
floor = floor ?? new VisualFloor(mode, this);
|
||||
if(floor.Setup(data.Floor, null))
|
||||
base.AddGeometry(floor);
|
||||
|
||||
// Create ceiling
|
||||
ceiling = ceiling ?? new VisualCeiling(mode, this);
|
||||
if(ceiling.Setup(data.Ceiling, null))
|
||||
base.AddGeometry(ceiling);
|
||||
|
||||
// Create 3D floors
|
||||
for(int i = 0; i < data.ExtraFloors.Count; i++)
|
||||
{
|
||||
Effect3DFloor ef = data.ExtraFloors[i];
|
||||
|
||||
// Create a floor
|
||||
VisualFloor vf = (i < extrafloors.Count) ? extrafloors[i] : new VisualFloor(mode, this);
|
||||
if(vf.Setup(ef.Ceiling, ef))
|
||||
base.AddGeometry(vf);
|
||||
if(i >= extrafloors.Count)
|
||||
extrafloors.Add(vf);
|
||||
|
||||
// Create a ceiling
|
||||
VisualCeiling vc = (i < extraceilings.Count) ? extraceilings[i] : new VisualCeiling(mode, this);
|
||||
if(vc.Setup(ef.Floor, ef))
|
||||
base.AddGeometry(vc);
|
||||
if(i >= extraceilings.Count)
|
||||
extraceilings.Add(vc);
|
||||
}
|
||||
|
||||
// Go for all sidedefs
|
||||
Dictionary<Sidedef, VisualSidedefParts> oldsides = sides ?? new Dictionary<Sidedef, VisualSidedefParts>(1);
|
||||
sides = new Dictionary<Sidedef, VisualSidedefParts>(base.Sector.Sidedefs.Count);
|
||||
foreach(Sidedef sd in base.Sector.Sidedefs)
|
||||
{
|
||||
// VisualSidedef already exists?
|
||||
VisualSidedefParts parts = oldsides.ContainsKey(sd) ? oldsides[sd] : new VisualSidedefParts();
|
||||
|
||||
// Doublesided or singlesided?
|
||||
if(sd.Other != null)
|
||||
{
|
||||
// Create upper part
|
||||
VisualUpper vu = parts.upper ?? new VisualUpper(mode, this, sd);
|
||||
if(vu.Setup())
|
||||
base.AddGeometry(vu);
|
||||
|
||||
// Create lower part
|
||||
VisualLower vl = parts.lower ?? new VisualLower(mode, this, sd);
|
||||
if(vl.Setup())
|
||||
base.AddGeometry(vl);
|
||||
|
||||
// Create middle part
|
||||
VisualMiddleDouble vm = parts.middledouble ?? new VisualMiddleDouble(mode, this, sd);
|
||||
if(vm.Setup())
|
||||
base.AddGeometry(vm);
|
||||
|
||||
// Create 3D wall parts
|
||||
SectorData osd = mode.GetSectorData(sd.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
List<VisualMiddle3D> middles = parts.middle3d ?? new List<VisualMiddle3D>(osd.ExtraFloors.Count);
|
||||
for(int i = 0; i < osd.ExtraFloors.Count; i++)
|
||||
{
|
||||
Effect3DFloor ef = osd.ExtraFloors[i];
|
||||
|
||||
VisualMiddle3D vm3 = (i < middles.Count) ? middles[i] : new VisualMiddle3D(mode, this, sd);
|
||||
if(vm3.Setup(ef))
|
||||
base.AddGeometry(vm3);
|
||||
if(i >= middles.Count)
|
||||
middles.Add(vm3);
|
||||
}
|
||||
|
||||
// Store
|
||||
sides.Add(sd, new VisualSidedefParts(vu, vl, vm, middles));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create middle part
|
||||
VisualMiddleSingle vm = parts.middlesingle ?? new VisualMiddleSingle(mode, this, sd);
|
||||
if(vm.Setup())
|
||||
base.AddGeometry(vm);
|
||||
|
||||
// Store
|
||||
sides.Add(sd, new VisualSidedefParts(vm));
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
changed = false;
|
||||
}
|
||||
|
||||
// This returns the visual sidedef parts for a given sidedef
|
||||
public VisualSidedefParts GetSidedefParts(Sidedef sd)
|
||||
{
|
||||
if(sides.ContainsKey(sd))
|
||||
return sides[sd];
|
||||
else
|
||||
return new VisualSidedefParts();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,553 +0,0 @@
|
|||
|
||||
#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.VisualModes;
|
||||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal class BaseVisualThing : VisualThing, IVisualEventReceiver
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
|
||||
private ThingTypeInfo info;
|
||||
private bool isloaded;
|
||||
private ImageData sprite;
|
||||
private float cageradius2;
|
||||
private Vector2D pos2d;
|
||||
private Vector3D boxp1;
|
||||
private Vector3D boxp2;
|
||||
|
||||
// Undo/redo
|
||||
private int undoticket;
|
||||
|
||||
// If this is set to true, the thing will be rebuilt after the action is performed.
|
||||
protected bool changed;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public bool Changed { get { return changed; } set { changed |= value; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public BaseVisualThing(BaseVisualMode mode, Thing t) : base(t)
|
||||
{
|
||||
this.mode = mode;
|
||||
|
||||
// Find thing information
|
||||
info = General.Map.Data.GetThingInfo(Thing.Type);
|
||||
|
||||
// Find sprite texture
|
||||
if(info.Sprite.Length > 0)
|
||||
{
|
||||
sprite = General.Map.Data.GetSpriteImage(info.Sprite);
|
||||
if(sprite != null) sprite.AddReference();
|
||||
}
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the thing geometry. Returns false when nothing was created.
|
||||
public virtual bool Setup()
|
||||
{
|
||||
PixelColor sectorcolor = new PixelColor(255, 255, 255, 255);
|
||||
|
||||
// Must have a width and height!
|
||||
if((info.Radius < 0.1f) || (info.Height < 0.1f)) return false;
|
||||
|
||||
// Find the sector in which the thing resides
|
||||
Thing.DetermineSector(mode.BlockMap);
|
||||
|
||||
if(sprite != null)
|
||||
{
|
||||
if(Thing.Sector != null)
|
||||
{
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
SectorLevel level = sd.GetLevelAbove(new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + Thing.Sector.FloorHeight));
|
||||
if(level != null)
|
||||
{
|
||||
// Use sector brightness for color shading
|
||||
PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(level.brightnessbelow));
|
||||
PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness);
|
||||
sectorcolor = areacolor.WithAlpha(255);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the texture is loaded
|
||||
sprite.LoadImage();
|
||||
isloaded = sprite.IsImageLoaded;
|
||||
if(isloaded)
|
||||
{
|
||||
float offsetx = 0.0f;
|
||||
float offsety = 0.0f;
|
||||
|
||||
base.Texture = sprite;
|
||||
|
||||
// Determine sprite size and offset
|
||||
float radius = sprite.ScaledWidth * 0.5f;
|
||||
float height = sprite.ScaledHeight;
|
||||
if(sprite is SpriteImage)
|
||||
{
|
||||
offsetx = (sprite as SpriteImage).OffsetX - radius;
|
||||
offsety = (sprite as SpriteImage).OffsetY - height;
|
||||
}
|
||||
|
||||
// Scale by thing type/actor scale
|
||||
// We do this after the offset x/y determination above, because that is entirely in sprite pixels space
|
||||
radius *= info.SpriteScale.Width;
|
||||
height *= info.SpriteScale.Height;
|
||||
offsetx *= info.SpriteScale.Width;
|
||||
offsety *= info.SpriteScale.Height;
|
||||
|
||||
// Make vertices
|
||||
WorldVertex[] verts = new WorldVertex[6];
|
||||
verts[0] = new WorldVertex(-radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor.ToInt(), 0.0f, 1.0f);
|
||||
verts[1] = new WorldVertex(-radius + offsetx, 0.0f, height + offsety, sectorcolor.ToInt(), 0.0f, 0.0f);
|
||||
verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor.ToInt(), 1.0f, 0.0f);
|
||||
verts[3] = verts[0];
|
||||
verts[4] = verts[2];
|
||||
verts[5] = new WorldVertex(+radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor.ToInt(), 1.0f, 1.0f);
|
||||
SetVertices(verts);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Texture = General.Map.Data.Hourglass3D;
|
||||
|
||||
// Determine sprite size
|
||||
float radius = Math.Min(info.Radius, info.Height / 2f);
|
||||
float height = Math.Min(info.Radius * 2f, info.Height);
|
||||
|
||||
// Make vertices
|
||||
WorldVertex[] verts = new WorldVertex[6];
|
||||
verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor.ToInt(), 0.0f, 1.0f);
|
||||
verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor.ToInt(), 0.0f, 0.0f);
|
||||
verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor.ToInt(), 1.0f, 0.0f);
|
||||
verts[3] = verts[0];
|
||||
verts[4] = verts[2];
|
||||
verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor.ToInt(), 1.0f, 1.0f);
|
||||
SetVertices(verts);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine position
|
||||
Vector3D pos = Thing.Position;
|
||||
if(Thing.Type == 9501)
|
||||
{
|
||||
// This is a special thing that needs special positioning
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z;
|
||||
}
|
||||
else if(Thing.Type == 9500)
|
||||
{
|
||||
// This is a special thing that needs special positioning
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z;
|
||||
}
|
||||
else if(info.AbsoluteZ)
|
||||
{
|
||||
// Absolute Z position
|
||||
pos.z = Thing.Position.z;
|
||||
}
|
||||
else if(info.Hangs)
|
||||
{
|
||||
// Hang from ceiling
|
||||
if(Thing.Sector != null)
|
||||
{
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
if(Thing.Position.z > 0)
|
||||
pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
|
||||
else
|
||||
pos.z = Thing.Sector.CeilHeight - info.Height; //mxd. was [pos.z = Thing.Sector.CeilHeight;]
|
||||
}
|
||||
|
||||
pos.z -= Thing.Position.z;
|
||||
|
||||
// Check if below floor
|
||||
if((Thing.Sector != null) && (pos.z < Thing.Sector.FloorHeight))
|
||||
{
|
||||
// Put thing on the floor
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Floor.plane.GetZ(Thing.Position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stand on floor
|
||||
if(Thing.Sector != null)
|
||||
{
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
if(Thing.Position.z == 0)
|
||||
pos.z = sd.Floor.plane.GetZ(Thing.Position);
|
||||
else
|
||||
pos.z = Thing.Sector.FloorHeight;
|
||||
}
|
||||
|
||||
pos.z += Thing.Position.z;
|
||||
|
||||
// Check if above ceiling
|
||||
if((Thing.Sector != null) && ((pos.z + info.Height) > Thing.Sector.CeilHeight))
|
||||
{
|
||||
// Put thing against ceiling
|
||||
SectorData sd = mode.GetSectorData(Thing.Sector);
|
||||
pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply settings
|
||||
SetPosition(pos);
|
||||
SetCageSize(info.Radius, info.Height);
|
||||
SetCageColor(Thing.Color);
|
||||
|
||||
// Keep info for object picking
|
||||
cageradius2 = info.Radius * Angle2D.SQRT2;
|
||||
cageradius2 = cageradius2 * cageradius2;
|
||||
pos2d = pos;
|
||||
boxp1 = new Vector3D(pos.x - info.Radius, pos.y - info.Radius, pos.z);
|
||||
boxp2 = new Vector3D(pos.x + info.Radius, pos.y + info.Radius, pos.z + info.Height);
|
||||
|
||||
// Done
|
||||
changed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disposing
|
||||
public override void Dispose()
|
||||
{
|
||||
if(!IsDisposed)
|
||||
{
|
||||
if(sprite != null)
|
||||
{
|
||||
sprite.RemoveReference();
|
||||
sprite = null;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This forces to rebuild the whole thing
|
||||
public void Rebuild()
|
||||
{
|
||||
// Find thing information
|
||||
info = General.Map.Data.GetThingInfo(Thing.Type);
|
||||
|
||||
// Find sprite texture
|
||||
if(info.Sprite.Length > 0)
|
||||
{
|
||||
sprite = General.Map.Data.GetSpriteImage(info.Sprite);
|
||||
if(sprite != null) sprite.AddReference();
|
||||
}
|
||||
|
||||
// Setup visual thing
|
||||
Setup();
|
||||
}
|
||||
|
||||
// This updates the thing when needed
|
||||
public override void Update()
|
||||
{
|
||||
if(!isloaded)
|
||||
{
|
||||
// Rebuild sprite geometry when sprite is loaded
|
||||
if(sprite.IsImageLoaded)
|
||||
{
|
||||
Setup();
|
||||
}
|
||||
}
|
||||
|
||||
// Let the base update
|
||||
base.Update();
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
float distance2 = Line2D.GetDistanceToLineSq(from, to, pos2d, false);
|
||||
return (distance2 <= cageradius2);
|
||||
}
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||
{
|
||||
Vector3D delta = to - from;
|
||||
float tfar = float.MaxValue;
|
||||
float tnear = float.MinValue;
|
||||
|
||||
// Ray-Box intersection code
|
||||
// See http://www.masm32.com/board/index.php?topic=9941.0
|
||||
|
||||
// Check X slab
|
||||
if(delta.x == 0.0f)
|
||||
{
|
||||
if(from.x > boxp2.x || from.x < boxp1.x)
|
||||
{
|
||||
// Ray is parallel to the planes & outside slab
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float tmp = 1.0f / delta.x;
|
||||
float t1 = (boxp1.x - from.x) * tmp;
|
||||
float t2 = (boxp2.x - from.x) * tmp;
|
||||
if(t1 > t2) General.Swap(ref t1, ref t2);
|
||||
if(t1 > tnear) tnear = t1;
|
||||
if(t2 < tfar) tfar = t2;
|
||||
if(tnear > tfar || tfar < 0.0f)
|
||||
{
|
||||
// Ray missed box or box is behind ray
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check Y slab
|
||||
if(delta.y == 0.0f)
|
||||
{
|
||||
if(from.y > boxp2.y || from.y < boxp1.y)
|
||||
{
|
||||
// Ray is parallel to the planes & outside slab
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float tmp = 1.0f / delta.y;
|
||||
float t1 = (boxp1.y - from.y) * tmp;
|
||||
float t2 = (boxp2.y - from.y) * tmp;
|
||||
if(t1 > t2) General.Swap(ref t1, ref t2);
|
||||
if(t1 > tnear) tnear = t1;
|
||||
if(t2 < tfar) tfar = t2;
|
||||
if(tnear > tfar || tfar < 0.0f)
|
||||
{
|
||||
// Ray missed box or box is behind ray
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check Z slab
|
||||
if(delta.z == 0.0f)
|
||||
{
|
||||
if(from.z > boxp2.z || from.z < boxp1.z)
|
||||
{
|
||||
// Ray is parallel to the planes & outside slab
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float tmp = 1.0f / delta.z;
|
||||
float t1 = (boxp1.z - from.z) * tmp;
|
||||
float t2 = (boxp2.z - from.z) * tmp;
|
||||
if(t1 > t2) General.Swap(ref t1, ref t2);
|
||||
if(t1 > tnear) tnear = t1;
|
||||
if(t2 < tfar) tfar = t2;
|
||||
if(tnear > tfar || tfar < 0.0f)
|
||||
{
|
||||
// Ray missed box or box is behind ray
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set interpolation point
|
||||
u_ray = (tnear > 0.0f) ? tnear : tfar;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
||||
// Unused
|
||||
public virtual void OnSelectBegin() { }
|
||||
public virtual void OnEditBegin() { }
|
||||
public virtual void OnMouseMove(MouseEventArgs e) { }
|
||||
public virtual void OnChangeTargetBrightness(bool up) { }
|
||||
public virtual void OnChangeTextureOffset(int horizontal, int vertical) { }
|
||||
public virtual void OnSelectTexture() { }
|
||||
public virtual void OnCopyTexture() { }
|
||||
public virtual void OnPasteTexture() { }
|
||||
public virtual void OnCopyTextureOffsets() { }
|
||||
public virtual void OnPasteTextureOffsets() { }
|
||||
public virtual void OnTextureAlign(bool alignx, bool aligny) { }
|
||||
public virtual void OnToggleUpperUnpegged() { }
|
||||
public virtual void OnToggleLowerUnpegged() { }
|
||||
public virtual void OnResetTextureOffset() { }
|
||||
public virtual void OnProcess(float deltatime) { }
|
||||
public virtual void OnTextureFloodfill() { }
|
||||
public virtual void OnInsert() { }
|
||||
//public virtual void OnDelete() { }
|
||||
public virtual void ApplyTexture(string texture) { }
|
||||
public virtual void ApplyUpperUnpegged(bool set) { }
|
||||
public virtual void ApplyLowerUnpegged(bool set) { }
|
||||
|
||||
// Return texture name
|
||||
public virtual string GetTextureName() { return ""; }
|
||||
|
||||
// Select or deselect
|
||||
public virtual void OnSelectEnd()
|
||||
{
|
||||
if(this.selected)
|
||||
{
|
||||
this.selected = false;
|
||||
mode.RemoveSelectedObject(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.selected = true;
|
||||
mode.AddSelectedObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
//mxd. Delete thing
|
||||
public virtual void OnDelete() {
|
||||
this.Thing.Dispose();
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
// Copy properties
|
||||
public virtual void OnCopyProperties()
|
||||
{
|
||||
BuilderPlug.Me.CopiedThingProps = new ThingProperties(Thing);
|
||||
mode.SetActionResult("Copied thing properties.");
|
||||
}
|
||||
|
||||
// Paste properties
|
||||
public virtual void OnPasteProperties()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedThingProps != null)
|
||||
{
|
||||
mode.CreateUndo("Paste thing properties");
|
||||
mode.SetActionResult("Pasted thing properties.");
|
||||
BuilderPlug.Me.CopiedThingProps.Apply(Thing);
|
||||
Thing.UpdateConfiguration();
|
||||
this.Rebuild();
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// Edit button released
|
||||
public virtual void OnEditEnd()
|
||||
{
|
||||
if(General.Interface.IsActiveWindow)
|
||||
{
|
||||
List<Thing> things = mode.GetSelectedThings();
|
||||
DialogResult result = General.Interface.ShowEditThings(things);
|
||||
if(result == DialogResult.OK)
|
||||
{
|
||||
foreach(Thing t in things)
|
||||
{
|
||||
VisualThing vt = mode.GetVisualThing(t);
|
||||
if(vt != null)
|
||||
(vt as BaseVisualThing).Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Raise/lower thing
|
||||
public virtual void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
if(General.Map.FormatInterface.HasThingHeight)
|
||||
{
|
||||
if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Change thing height");
|
||||
|
||||
Thing.Move(Thing.Position + new Vector3D(0.0f, 0.0f, (float)amount));
|
||||
|
||||
mode.SetActionResult("Changed thing height to " + Thing.Position.z + ".");
|
||||
|
||||
// Update what must be updated
|
||||
ThingData td = mode.GetThingData(this.Thing);
|
||||
foreach(KeyValuePair<Sector, bool> s in td.UpdateAlso)
|
||||
{
|
||||
if(mode.VisualSectorExists(s.Key))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
|
||||
vs.UpdateSectorGeometry(s.Value);
|
||||
}
|
||||
}
|
||||
|
||||
this.Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
public void OnMove(Vector3D newPosition) {
|
||||
if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Move thing");
|
||||
Thing.Move(newPosition);
|
||||
mode.SetActionResult("Changed thing position to " + Thing.Position.ToString() + ".");
|
||||
|
||||
// Update what must be updated
|
||||
ThingData td = mode.GetThingData(this.Thing);
|
||||
foreach (KeyValuePair<Sector, bool> s in td.UpdateAlso) {
|
||||
if (mode.VisualSectorExists(s.Key)) {
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
|
||||
vs.UpdateSectorGeometry(s.Value);
|
||||
}
|
||||
}
|
||||
|
||||
this.Changed = true;
|
||||
}
|
||||
|
||||
//mxd
|
||||
public void OnRotate(int ammount) {
|
||||
if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
|
||||
undoticket = mode.CreateUndo("Rotate thing");
|
||||
Thing.Rotate(ammount);
|
||||
mode.SetActionResult("Changed thing rotation to " + Thing.AngleDoom.ToString() + ".");
|
||||
this.Changed = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
|
||||
#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.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal interface IVisualEventReceiver
|
||||
{
|
||||
// The events that must be handled
|
||||
void OnSelectBegin();
|
||||
void OnSelectEnd();
|
||||
void OnEditBegin();
|
||||
void OnEditEnd();
|
||||
void OnMouseMove(MouseEventArgs e);
|
||||
void OnChangeTargetHeight(int amount);
|
||||
void OnChangeTargetBrightness(bool up);
|
||||
void OnChangeTextureOffset(int horizontal, int vertical);
|
||||
void OnResetTextureOffset();
|
||||
void OnSelectTexture();
|
||||
void OnCopyTexture();
|
||||
void OnPasteTexture();
|
||||
void OnCopyTextureOffsets();
|
||||
void OnPasteTextureOffsets();
|
||||
void OnCopyProperties();
|
||||
void OnPasteProperties();
|
||||
void OnTextureAlign(bool alignx, bool aligny);
|
||||
void OnTextureFloodfill();
|
||||
void OnToggleUpperUnpegged();
|
||||
void OnToggleLowerUnpegged();
|
||||
void OnProcess(float deltatime);
|
||||
void OnInsert();
|
||||
void OnDelete();
|
||||
|
||||
// Assist functions
|
||||
void ApplyTexture(string texture);
|
||||
void ApplyUpperUnpegged(bool set);
|
||||
void ApplyLowerUnpegged(bool set);
|
||||
|
||||
// Other methods
|
||||
string GetTextureName();
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
|
||||
#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.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
// This doesn't do jack shit.
|
||||
internal class NullVisualEventReceiver : IVisualEventReceiver
|
||||
{
|
||||
public NullVisualEventReceiver()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSelectBegin()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSelectEnd()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnEditBegin()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnEditEnd()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnChangeTargetBrightness(bool up)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnChangeTextureOffset(int horizontal, int vertical)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnResetTextureOffset()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSelectTexture()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnCopyTexture()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnPasteTexture()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnCopyTextureOffsets()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnPasteTextureOffsets()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnCopyProperties()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnPasteProperties()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnTextureAlign(bool alignx, bool aligny)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnTextureFloodfill()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnToggleUpperUnpegged()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnToggleLowerUnpegged()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnProcess(float deltatime)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnInsert()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDelete()
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyTexture(string texture)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyUpperUnpegged(bool set)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyLowerUnpegged(bool set)
|
||||
{
|
||||
}
|
||||
|
||||
public string GetTextureName()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
#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.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
public struct VisualActionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Status description to show after action hasbeen performed. Set to null to show no message.
|
||||
/// </summary>
|
||||
public string displaystatus;
|
||||
}
|
||||
}
|
|
@ -1,326 +0,0 @@
|
|||
|
||||
#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.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
using CodeImp.DoomBuilder.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal sealed class VisualCeiling : BaseVisualGeometrySector
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public VisualCeiling(BaseVisualMode mode, VisualSector vs) : base(mode, vs)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.CEILING;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup(SectorLevel level, Effect3DFloor extrafloor)
|
||||
{
|
||||
WorldVertex[] verts;
|
||||
WorldVertex v;
|
||||
Sector s = level.sector;
|
||||
Vector2D texscale;
|
||||
|
||||
base.Setup(level, extrafloor);
|
||||
|
||||
// Fetch ZDoom fields
|
||||
float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationceiling", 0.0f));
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
|
||||
s.Fields.GetValue("ypanningceiling", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
|
||||
s.Fields.GetValue("yscaleceiling", 1.0f));
|
||||
|
||||
// Load floor texture
|
||||
base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = s.LongCeilTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = s.LongCeilTexture;
|
||||
}
|
||||
|
||||
// Determine texture scale
|
||||
if(base.Texture.IsImageLoaded)
|
||||
texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
|
||||
else
|
||||
texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
|
||||
|
||||
// Make vertices
|
||||
ReadOnlyCollection<Vector2D> triverts = base.Sector.Sector.Triangles.Vertices;
|
||||
verts = new WorldVertex[triverts.Count];
|
||||
for(int i = 0; i < triverts.Count; i++)
|
||||
{
|
||||
// Color shading
|
||||
PixelColor c = PixelColor.FromInt(level.color);
|
||||
verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();
|
||||
|
||||
// Vertex coordinates
|
||||
verts[i].x = triverts[i].x;
|
||||
verts[i].y = triverts[i].y;
|
||||
verts[i].z = level.plane.GetZ(triverts[i]); //(float)s.CeilHeight;
|
||||
|
||||
// Texture coordinates
|
||||
Vector2D pos = triverts[i];
|
||||
pos = pos.GetRotated(rotate);
|
||||
pos.y = -pos.y;
|
||||
pos = (pos + offset) * scale * texscale;
|
||||
verts[i].u = pos.x;
|
||||
verts[i].v = pos.y;
|
||||
}
|
||||
|
||||
// The sector triangulation created clockwise triangles that
|
||||
// are right up for the floor. For the ceiling we must flip
|
||||
// the triangles upside down.
|
||||
if((extrafloor == null) || extrafloor.VavoomType)
|
||||
SwapTriangleVertices(verts);
|
||||
|
||||
// Determine render pass
|
||||
if(extrafloor != null)
|
||||
{
|
||||
if(level.alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
|
||||
// Apply vertices
|
||||
base.SetVertices(verts);
|
||||
return (verts.Length > 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture coordinates
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
Point p = new Point();
|
||||
p.X = (int)Sector.Sector.Fields.GetValue("xpanningceiling", 0.0f);
|
||||
p.Y = (int)Sector.Sector.Fields.GetValue("ypanningceiling", 0.0f);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Move texture coordinates
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
//mxd
|
||||
Sector s = GetControlSector();
|
||||
s.Fields.BeforeFieldsChange();
|
||||
float oldx = s.Fields.GetValue("xpanningceiling", 0.0f);
|
||||
float oldy = s.Fields.GetValue("ypanningceiling", 0.0f);
|
||||
xy = getTranslatedTextureOffset(xy);
|
||||
s.Fields["xpanningceiling"] = new UniValue(UniversalType.Float, oldx + (float)xy.X);
|
||||
s.Fields["ypanningceiling"] = new UniValue(UniversalType.Float, oldy + (float)xy.Y);
|
||||
s.UpdateNeeded = true;
|
||||
}
|
||||
|
||||
// Paste texture
|
||||
public override void OnPasteTexture()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedFlat != null)
|
||||
{
|
||||
mode.CreateUndo("Paste ceiling " + BuilderPlug.Me.CopiedFlat);
|
||||
mode.SetActionResult("Pasted flat " + BuilderPlug.Me.CopiedFlat + " on ceiling.");
|
||||
SetTexture(BuilderPlug.Me.CopiedFlat);
|
||||
this.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
// Call to change the height
|
||||
public override void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
// Only do this when not done yet in this call
|
||||
// Because we may be able to select the same 3D floor multiple times through multiple sectors
|
||||
SectorData sd = mode.GetSectorData(level.sector);
|
||||
if(!sd.CeilingChanged)
|
||||
{
|
||||
sd.CeilingChanged = true;
|
||||
base.OnChangeTargetHeight(amount);
|
||||
}
|
||||
}
|
||||
|
||||
// This changes the height
|
||||
protected override void ChangeHeight(int amount)
|
||||
{
|
||||
mode.CreateUndo("Change ceiling height", UndoGroup.CeilingHeightChange, level.sector.FixedIndex);
|
||||
level.sector.CeilHeight += amount;
|
||||
mode.SetActionResult("Changed ceiling height to " + level.sector.CeilHeight + ".");
|
||||
}
|
||||
|
||||
//mxd. Sector brightness change
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if (level != null && level.sector != Sector.Sector) {
|
||||
int index = -1;
|
||||
for (int i = 0; i < Sector.ExtraCeilings.Count; i++) {
|
||||
if (Sector.ExtraCeilings[i] == this) {
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > -1 && index < Sector.ExtraCeilings.Count) {
|
||||
Sector.ExtraCeilings[index].changeControlSectorBrightness(up);
|
||||
} else {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
}
|
||||
} else {
|
||||
//if a map is not in UDMF format, or this ceiling is part of 3D-floor...
|
||||
if(!General.Map.UDMF || Sector.Sector != level.sector) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sector.Sector.Fields.GetValue("lightceiling", 0);
|
||||
bool absolute = Sector.Sector.Fields.GetValue("lightceilingabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change ceiling brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sector.Sector.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sector.Sector.Fields["lightceiling"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed ceiling brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
private void changeControlSectorBrightness(bool up) {
|
||||
((BaseVisualSector)mode.GetVisualSector(level.sector)).Ceiling.OnChangeTargetBrightness(up);
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
// Check if our ray starts at the correct side of the plane
|
||||
if(level.plane.Distance(from) > 0.0f)
|
||||
{
|
||||
// Calculate the intersection
|
||||
if(level.plane.GetIntersection(from, to, ref pickrayu))
|
||||
{
|
||||
if(pickrayu > 0.0f)
|
||||
{
|
||||
pickintersect = from + (to - from) * pickrayu;
|
||||
|
||||
// Intersection point within bbox?
|
||||
RectangleF bbox = Sector.Sector.BBox;
|
||||
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||
{
|
||||
u_ray = pickrayu;
|
||||
|
||||
// Check on which side of the nearest sidedef we are
|
||||
Sidedef sd = MapSet.NearestSidedef(Sector.Sector.Sidedefs, pickintersect);
|
||||
float side = sd.Line.SideOfLine(pickintersect);
|
||||
return (((side <= 0.0f) && sd.IsFront) || ((side > 0.0f) && !sd.IsFront));
|
||||
}
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return level.sector.CeilTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
level.sector.SetCeilTexture(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
if(level.sector == this.Sector.Sector)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
else if(mode.VisualSectorExists(level.sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
|
||||
#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.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
using CodeImp.DoomBuilder.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal sealed class VisualFloor : BaseVisualGeometrySector
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public VisualFloor(BaseVisualMode mode, VisualSector vs) : base(mode, vs)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.FLOOR;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup(SectorLevel level, Effect3DFloor extrafloor)
|
||||
{
|
||||
WorldVertex[] verts;
|
||||
Sector s = level.sector;
|
||||
Vector2D texscale;
|
||||
|
||||
base.Setup(level, extrafloor);
|
||||
|
||||
// Fetch ZDoom fields
|
||||
float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationfloor", 0.0f));
|
||||
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f),
|
||||
s.Fields.GetValue("ypanningfloor", 0.0f));
|
||||
Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f),
|
||||
s.Fields.GetValue("yscalefloor", 1.0f));
|
||||
|
||||
// Load floor texture
|
||||
base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = s.LongFloorTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = s.LongFloorTexture;
|
||||
}
|
||||
|
||||
// Determine texture scale
|
||||
if(base.Texture.IsImageLoaded)
|
||||
texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
|
||||
else
|
||||
texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
|
||||
|
||||
// Make vertices
|
||||
ReadOnlyCollection<Vector2D> triverts = base.Sector.Sector.Triangles.Vertices;
|
||||
verts = new WorldVertex[triverts.Count];
|
||||
for(int i = 0; i < triverts.Count; i++)
|
||||
{
|
||||
// Color shading
|
||||
PixelColor c = PixelColor.FromInt(level.color);
|
||||
verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();
|
||||
|
||||
// Vertex coordinates
|
||||
verts[i].x = triverts[i].x;
|
||||
verts[i].y = triverts[i].y;
|
||||
verts[i].z = level.plane.GetZ(triverts[i]); //(float)s.FloorHeight;
|
||||
|
||||
// Texture coordinates
|
||||
Vector2D pos = triverts[i];
|
||||
pos = pos.GetRotated(rotate);
|
||||
pos.y = -pos.y;
|
||||
pos = (pos + offset) * scale * texscale;
|
||||
verts[i].u = pos.x;
|
||||
verts[i].v = pos.y;
|
||||
}
|
||||
|
||||
// The sector triangulation created clockwise triangles that
|
||||
// are right up for the floor. For the ceiling we must flip
|
||||
// the triangles upside down.
|
||||
if((extrafloor != null) && !extrafloor.VavoomType)
|
||||
SwapTriangleVertices(verts);
|
||||
|
||||
// Determine render pass
|
||||
if(extrafloor != null)
|
||||
{
|
||||
if(level.alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RenderPass = RenderPass.Solid;
|
||||
}
|
||||
|
||||
// Apply vertices
|
||||
base.SetVertices(verts);
|
||||
return (verts.Length > 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture coordinates
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
Point p = new Point();
|
||||
p.X = (int)Sector.Sector.Fields.GetValue("xpanningfloor", 0.0f);
|
||||
p.Y = (int)Sector.Sector.Fields.GetValue("ypanningfloor", 0.0f);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Move texture coordinates
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
//mxd
|
||||
Sector s = GetControlSector();
|
||||
s.Fields.BeforeFieldsChange();
|
||||
float oldx = s.Fields.GetValue("xpanningfloor", 0.0f);
|
||||
float oldy = s.Fields.GetValue("ypanningfloor", 0.0f);
|
||||
xy = getTranslatedTextureOffset(xy);
|
||||
s.Fields["xpanningfloor"] = new UniValue(UniversalType.Float, oldx + (float)xy.X);
|
||||
s.Fields["ypanningfloor"] = new UniValue(UniversalType.Float, oldy + (float)xy.Y);
|
||||
s.UpdateNeeded = true;
|
||||
}
|
||||
|
||||
// Paste texture
|
||||
public override void OnPasteTexture()
|
||||
{
|
||||
if(BuilderPlug.Me.CopiedFlat != null)
|
||||
{
|
||||
mode.CreateUndo("Paste floor " + BuilderPlug.Me.CopiedFlat);
|
||||
mode.SetActionResult("Pasted flat " + BuilderPlug.Me.CopiedFlat + " on floor.");
|
||||
SetTexture(BuilderPlug.Me.CopiedFlat);
|
||||
this.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
// Call to change the height
|
||||
public override void OnChangeTargetHeight(int amount)
|
||||
{
|
||||
// Only do this when not done yet in this call
|
||||
// Because we may be able to select the same 3D floor multiple times through multiple sectors
|
||||
SectorData sd = mode.GetSectorData(level.sector);
|
||||
if(!sd.FloorChanged)
|
||||
{
|
||||
sd.FloorChanged = true;
|
||||
base.OnChangeTargetHeight(amount);
|
||||
}
|
||||
}
|
||||
|
||||
// This changes the height
|
||||
protected override void ChangeHeight(int amount)
|
||||
{
|
||||
mode.CreateUndo("Change floor height", UndoGroup.FloorHeightChange, level.sector.FixedIndex);
|
||||
level.sector.FloorHeight += amount;
|
||||
mode.SetActionResult("Changed floor height to " + level.sector.FloorHeight + ".");
|
||||
}
|
||||
|
||||
//mxd. Sector brightness change
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if (level != null) {
|
||||
if (level.sector != Sector.Sector) {
|
||||
((BaseVisualSector)mode.GetVisualSector(level.sector)).Ceiling.OnChangeTargetBrightness(up);
|
||||
} else if (Sector.ExtraFloors.Count > 0) {
|
||||
Sector.ExtraFloors[0].OnChangeTargetBrightness(up);
|
||||
} else {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
}
|
||||
} else {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
}
|
||||
}
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
// Check if our ray starts at the correct side of the plane
|
||||
if(level.plane.Distance(from) > 0.0f)
|
||||
{
|
||||
// Calculate the intersection
|
||||
if(level.plane.GetIntersection(from, to, ref pickrayu))
|
||||
{
|
||||
if(pickrayu > 0.0f)
|
||||
{
|
||||
pickintersect = from + (to - from) * pickrayu;
|
||||
|
||||
// Intersection point within bbox?
|
||||
RectangleF bbox = Sector.Sector.BBox;
|
||||
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This performs an accurate test for object picking
|
||||
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||
{
|
||||
u_ray = pickrayu;
|
||||
|
||||
// Check on which side of the nearest sidedef we are
|
||||
Sidedef sd = MapSet.NearestSidedef(Sector.Sector.Sidedefs, pickintersect);
|
||||
float side = sd.Line.SideOfLine(pickintersect);
|
||||
return (((side <= 0.0f) && sd.IsFront) || ((side > 0.0f) && !sd.IsFront));
|
||||
}
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return level.sector.FloorTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
level.sector.SetFloorTexture(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
if(level.sector == this.Sector.Sector)
|
||||
{
|
||||
this.Setup();
|
||||
}
|
||||
else if(mode.VisualSectorExists(level.sector))
|
||||
{
|
||||
BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||
vs.UpdateSectorGeometry(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
|
||||
#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 System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal sealed class VisualLower : BaseVisualGeometrySidedef
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public VisualLower(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_BOTTOM;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
Vector2D vl, vr;
|
||||
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_bottom", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_bottom", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_bottom", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_bottom", 0.0f));
|
||||
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = Sector.GetSectorData();
|
||||
SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.LowTexture.Length > 0) && (Sidedef.LowTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongLowTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongLowTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongLowTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float floorbias = (Sidedef.Other.Sector.FloorHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the lower texture is bound to the bottom
|
||||
tp.tlt.y = (float)Sidedef.Sector.CeilHeight - (float)Sidedef.Other.Sector.FloorHeight;
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Other.Sector.FloorHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Other.Sector.FloorHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Cut off the part above the other floor
|
||||
CropPoly(ref poly, osd.Floor.plane, false);
|
||||
CropPoly(ref poly, osd.Ceiling.plane, true);
|
||||
|
||||
if(poly.Count > 2)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = osd.Floor.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return this.Sidedef.LowTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
this.Sidedef.SetTextureLow(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_bottom", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_bottom", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_bottom", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_bottom", 1.0f);
|
||||
Sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_bottom", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_bottom", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change lower wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed lower wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,358 +0,0 @@
|
|||
|
||||
#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 System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal sealed class VisualMiddleDouble : BaseVisualGeometrySidedef
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
private bool repeatmidtex;
|
||||
private Plane topclipplane;
|
||||
private Plane bottomclipplane;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public VisualMiddleDouble(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_MIDDLE;
|
||||
|
||||
// Set render pass
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
Vector2D vl, vr;
|
||||
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_mid", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_mid", 0.0f));
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = mode.GetSectorData(Sidedef.Sector);
|
||||
SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
|
||||
float geotop = (float)Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight);
|
||||
float geobottom = (float)Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight);
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the middle texture is bound to the bottom
|
||||
tp.tlt.y = tsz.y - (float)(geotop - geobottom);
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Cut off the part below the other floor and above the other ceiling
|
||||
CropPoly(ref poly, osd.Ceiling.plane, true);
|
||||
CropPoly(ref poly, osd.Floor.plane, true);
|
||||
|
||||
// Determine if we should repeat the middle texture
|
||||
if(Sidedef.Fields.ContainsKey("wrapmidtex"))
|
||||
repeatmidtex = Sidedef.Fields.GetValue("wrapmidtex", false);
|
||||
else
|
||||
repeatmidtex = Sidedef.Line.IsFlagSet("wrapmidtex");
|
||||
|
||||
if(!repeatmidtex)
|
||||
{
|
||||
// First determine the visible portion of the texture
|
||||
float textop, texbottom;
|
||||
|
||||
// Determine top portion height
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
textop = geobottom + tof.y + tsz.y;
|
||||
else
|
||||
textop = geotop + tof.y;
|
||||
|
||||
// Calculate bottom portion height
|
||||
texbottom = textop - tsz.y;
|
||||
|
||||
// Create crop planes (we also need these for intersection testing)
|
||||
topclipplane = new Plane(new Vector3D(0, 0, -1), textop);
|
||||
bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom);
|
||||
|
||||
// Crop polygon by these heights
|
||||
CropPoly(ref poly, topclipplane, true);
|
||||
CropPoly(ref poly, bottomclipplane, true);
|
||||
}
|
||||
|
||||
if(poly.Count > 2)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = osd.Ceiling.plane;
|
||||
bottom = osd.Floor.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
// Apply alpha to vertices
|
||||
byte alpha = SetLinedefRenderstyle(true);
|
||||
if(alpha < 255)
|
||||
{
|
||||
for(int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
WorldVertex v = verts[i];
|
||||
PixelColor c = PixelColor.FromInt(v.c);
|
||||
v.c = c.WithAlpha(alpha).ToInt();
|
||||
verts[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This performs a fast test in object picking
|
||||
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||
{
|
||||
if(!repeatmidtex)
|
||||
{
|
||||
// Whe nthe texture is not repeated, leave when outside crop planes
|
||||
if((pickintersect.z < bottomclipplane.GetZ(pickintersect)) ||
|
||||
(pickintersect.z > topclipplane.GetZ(pickintersect)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.PickFastReject(from, to, dir);
|
||||
}
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return this.Sidedef.MiddleTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
this.Sidedef.SetTextureMid(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_mid", 1.0f);
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed middle wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,286 +0,0 @@
|
|||
|
||||
#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 System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal sealed class VisualMiddleSingle : BaseVisualGeometrySidedef
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public VisualMiddleSingle(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_MIDDLE;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
Vector2D vl, vr;
|
||||
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_mid", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_mid", 0.0f));
|
||||
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = mode.GetSectorData(Sidedef.Sector);
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongMiddleTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
|
||||
if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the middle texture is bound to the bottom
|
||||
tp.tlt.y = tsz.y - (float)(Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight);
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Get ceiling and floor heights
|
||||
float fl = sd.Floor.plane.GetZ(vl);
|
||||
float fr = sd.Floor.plane.GetZ(vr);
|
||||
float cl = sd.Ceiling.plane.GetZ(vl);
|
||||
float cr = sd.Ceiling.plane.GetZ(vr);
|
||||
|
||||
// Anything to see?
|
||||
if(((cl - fl) > 0.01f) || ((cr - fr) > 0.01f))
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, fl));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, cl));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, cr));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, fr));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return this.Sidedef.MiddleTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
this.Sidedef.SetTextureMid(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_mid", 1.0f);
|
||||
Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed middle wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
|
||||
#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.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal struct VisualSidedefParts
|
||||
{
|
||||
// Members
|
||||
public VisualUpper upper;
|
||||
public VisualLower lower;
|
||||
public VisualMiddleDouble middledouble;
|
||||
public VisualMiddleSingle middlesingle;
|
||||
public List<VisualMiddle3D> middle3d;
|
||||
|
||||
// Constructor
|
||||
public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m, List<VisualMiddle3D> e)
|
||||
{
|
||||
this.upper = u;
|
||||
this.lower = l;
|
||||
this.middledouble = m;
|
||||
this.middlesingle = null;
|
||||
this.middle3d = e;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
public VisualSidedefParts(VisualMiddleSingle m)
|
||||
{
|
||||
this.upper = null;
|
||||
this.lower = null;
|
||||
this.middledouble = null;
|
||||
this.middlesingle = m;
|
||||
this.middle3d = null;
|
||||
}
|
||||
|
||||
// This calls Setup() on all parts
|
||||
public void SetupAllParts()
|
||||
{
|
||||
if(lower != null) lower.Setup();
|
||||
if(middledouble != null) middledouble.Setup();
|
||||
if(middlesingle != null) middlesingle.Setup();
|
||||
if(upper != null) upper.Setup();
|
||||
if(middle3d != null)
|
||||
{
|
||||
foreach(VisualMiddle3D m in middle3d)
|
||||
m.Setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
|
||||
#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 System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CodeImp.DoomBuilder.GZDoomEditing;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Editing;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
{
|
||||
internal sealed class VisualUpper : BaseVisualGeometrySidedef
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
||||
// Constructor
|
||||
public VisualUpper(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_UPPER;
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// This builds the geometry. Returns false when no geometry created.
|
||||
public override bool Setup()
|
||||
{
|
||||
Vector2D vl, vr;
|
||||
|
||||
//mxd. lightfog flag support
|
||||
bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
bool ignoreUDMFLight = (!Sidedef.Fields.GetValue("lightfog", false) || !lightabsolute) && Sector.Sector.Fields.ContainsKey("fadecolor");
|
||||
int lightvalue = ignoreUDMFLight ? 0 : Sidedef.Fields.GetValue("light", 0); //mxd
|
||||
if (ignoreUDMFLight) lightabsolute = false;
|
||||
|
||||
Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_top", 1.0f),
|
||||
Sidedef.Fields.GetValue("scaley_top", 1.0f));
|
||||
Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_top", 0.0f),
|
||||
Sidedef.Fields.GetValue("offsety_top", 0.0f));
|
||||
|
||||
// Left and right vertices for this sidedef
|
||||
if(Sidedef.IsFront)
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
|
||||
vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
|
||||
}
|
||||
|
||||
// Load sector data
|
||||
SectorData sd = Sector.GetSectorData();
|
||||
SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
|
||||
if(!osd.Updated) osd.Update();
|
||||
|
||||
// Texture given?
|
||||
if((Sidedef.HighTexture.Length > 0) && (Sidedef.HighTexture[0] != '-'))
|
||||
{
|
||||
// Load texture
|
||||
base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongHighTexture);
|
||||
if(base.Texture == null)
|
||||
{
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = Sidedef.LongHighTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!base.Texture.IsImageLoaded)
|
||||
setuponloadedtexture = Sidedef.LongHighTexture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use missing texture
|
||||
base.Texture = General.Map.Data.MissingTexture3D;
|
||||
setuponloadedtexture = 0;
|
||||
}
|
||||
|
||||
// Get texture scaled size
|
||||
Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
|
||||
tsz = tsz / tscale;
|
||||
|
||||
// Get texture offsets
|
||||
Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
|
||||
tof = tof + toffset;
|
||||
tof = tof / tscale;
|
||||
if(General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
|
||||
tof = tof * base.Texture.Scale;
|
||||
|
||||
// Determine texture coordinates plane as they would be in normal circumstances.
|
||||
// We can then use this plane to find any texture coordinate we need.
|
||||
// The logic here is the same as in the original VisualMiddleSingle (except that
|
||||
// the values are stored in a TexturePlane)
|
||||
// NOTE: I use a small bias for the floor height, because if the difference in
|
||||
// height is 0 then the TexturePlane doesn't work!
|
||||
TexturePlane tp = new TexturePlane();
|
||||
float ceilbias = (Sidedef.Other.Sector.CeilHeight == Sidedef.Sector.CeilHeight) ? 1.0f : 0.0f;
|
||||
if(!Sidedef.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag))
|
||||
{
|
||||
// When lower unpegged is set, the lower texture is bound to the bottom
|
||||
tp.tlt.y = tsz.y - ((float)Sidedef.Sector.CeilHeight - (float)Sidedef.Other.Sector.CeilHeight);
|
||||
}
|
||||
tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
|
||||
tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Other.Sector.CeilHeight + ceilbias));
|
||||
|
||||
// Apply texture offset
|
||||
tp.tlt += tof;
|
||||
tp.trb += tof;
|
||||
|
||||
// Transform pixel coordinates to texture coordinates
|
||||
tp.tlt /= tsz;
|
||||
tp.trb /= tsz;
|
||||
|
||||
// Left top and right bottom of the geometry that
|
||||
tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
|
||||
tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Other.Sector.CeilHeight + ceilbias);
|
||||
|
||||
// Make the right-top coordinates
|
||||
tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
|
||||
tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);
|
||||
|
||||
// Create initial polygon, which is just a quad between floor and ceiling
|
||||
WallPolygon poly = new WallPolygon();
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
|
||||
poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));
|
||||
|
||||
// Determine initial color
|
||||
int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
|
||||
//mxd
|
||||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Cut off the part below the other ceiling
|
||||
CropPoly(ref poly, osd.Ceiling.plane, false);
|
||||
|
||||
if(poly.Count > 2)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = osd.Ceiling.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// Return texture name
|
||||
public override string GetTextureName()
|
||||
{
|
||||
return this.Sidedef.HighTexture;
|
||||
}
|
||||
|
||||
// This changes the texture
|
||||
protected override void SetTexture(string texturename)
|
||||
{
|
||||
this.Sidedef.SetTextureHigh(texturename);
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
this.Setup();
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetX(int x)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, (float)x);
|
||||
}
|
||||
|
||||
protected override void SetTextureOffsetY(int y)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
Sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, (float)y);
|
||||
}
|
||||
|
||||
protected override void MoveTextureOffset(Point xy)
|
||||
{
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_top", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_top", 0.0f);
|
||||
float scalex = Sidedef.Fields.GetValue("scalex_top", 1.0f);
|
||||
float scaley = Sidedef.Fields.GetValue("scaley_top", 1.0f);
|
||||
Sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldx, (float)xy.X, scalex)); //mxd
|
||||
Sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, getRoundedTextureOffset(oldy, (float)xy.Y, scaley)); //mxd
|
||||
}
|
||||
|
||||
protected override Point GetTextureOffset()
|
||||
{
|
||||
float oldx = Sidedef.Fields.GetValue("offsetx_top", 0.0f);
|
||||
float oldy = Sidedef.Fields.GetValue("offsety_top", 0.0f);
|
||||
return new Point((int)oldx, (int)oldy);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnChangeTargetBrightness(bool up) {
|
||||
if(!General.Map.UDMF) {
|
||||
base.OnChangeTargetBrightness(up);
|
||||
return;
|
||||
}
|
||||
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight = 0;
|
||||
|
||||
if(up)
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute);
|
||||
else
|
||||
newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute);
|
||||
|
||||
if(newLight == light) return;
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Change upper wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed upper wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|