Merged Visual mode and GZDoom Visual mode into GZDB Visual mode. GZDoomEditing.dll is no longer required.

This commit is contained in:
MaxED 2012-11-27 21:12:20 +00:00
parent c018e05805
commit a3f28cfe94
71 changed files with 2614 additions and 8590 deletions

View file

@ -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.

View file

@ -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

View file

@ -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)
{

View file

@ -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.

View file

@ -36,7 +36,7 @@ using CodeImp.DoomBuilder.Actions;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Ceiling Align Mode",
SwitchAction = "ceilingalignmode",

View file

@ -37,7 +37,7 @@ using CodeImp.DoomBuilder.Actions;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
public abstract class FlatAlignMode : BaseClassicMode
{

View file

@ -36,7 +36,7 @@ using CodeImp.DoomBuilder.Actions;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Floor Align Mode",
SwitchAction = "flooralignmode",

View file

@ -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)
{

View file

@ -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
}
}

View file

@ -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("")]

View file

@ -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));
}
}
}
}

View file

@ -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>

View file

@ -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
}

View file

Before

Width:  |  Height:  |  Size: 579 B

After

Width:  |  Height:  |  Size: 579 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 583 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

View file

@ -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
}

View file

@ -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);

View file

@ -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
}

View file

@ -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));

View file

@ -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;
}

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class Effect3DFloor : SectorEffect
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class EffectBrightnessLevel : SectorEffect
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class EffectCopySlope : SectorEffect
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class EffectLineSlope : SectorEffect
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class EffectThingLineSlope : SectorEffect
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class EffectThingVertexSlope : SectorEffect
{

View file

@ -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;

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class SectorData
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal abstract class SectorEffect
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class SectorLevel
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class SectorLevelComparer : IComparer<SectorLevel>
{

View file

@ -8,7 +8,7 @@ using System.Text;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal enum SectorLevelType
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal struct TexturePlane
{

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class ThingData
{

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -38,7 +38,7 @@ using CodeImp.DoomBuilder.VisualModes;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal sealed class VisualMiddle3D : BaseVisualGeometrySidedef
{

View file

@ -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
}

View file

@ -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
}

View file

@ -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();
}
}
}
}

View file

@ -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
}

View file

@ -11,7 +11,7 @@ using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.GZDoomEditing
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class WallPolygon : List<Vector3D>
{

View file

@ -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
}
}

View file

@ -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>

View file

@ -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.

View file

@ -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
}
}

View file

@ -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));
}
}
}

View file

@ -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
}
}

View file

@ -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")]

View file

@ -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));
}
}
}
}

View file

@ -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>

View file

@ -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
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

View file

@ -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
}
}

View file

@ -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
}
}

File diff suppressed because it is too large Load diff

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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();
}
}

View file

@ -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 "";
}
}
}

View file

@ -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;
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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();
}
}
}
}

View file

@ -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
}
}