Visual mode: "Fit Textures" action can now fit textures across multiple selected surfaces. A number of times to repeat a texture can now be specified.
Visual mode: removed "Fit Texture's Width" and "Fit Texture's Height" actions. Visual mode: "Auto-align texture offsets" actions were incorrectly aligning double-sided middle walls in some cases. Visual mode: "Auto-align texture offsets" actions now align non-wrapped double-sided middle walls to vertical offset closest to their initial vertical offset. Visual mode: middle parts of double-sided walls were ignored when Shift-selecting walls. Nodebuilders/Game configurations: GL nodes definitions were missing from game configurations. Nodebuilders/Game configurations: "~MAP" wildcard can now be a part of a lump name. Nodebuilders: GL nodes were not properly handled by the editor. Main Window: the window is now moved into the view when stored position is ouside of screen bounds. Classic and Visual modes: changing thing pitch was ignored in some cases. Visual mode: raising and lowering a thing with "+SPAWNCEILING" flag now works the same way as when raising/lowering a regular thing. Visual mode: using "Raise/Lower Floor/Ceiling to adjacent sector" actions on a thing with "+SPAWNCEILING" flag now works the same way as when using them on a regular thing. Rendering: even more fixes to MODELDEF and UDMF properties-related model rendering logic. Internal, ResourceListEditor: rewritten resource validation check in a more OOP-ish way. Configurations: fixed an infinite loop crash when a file was trying to include() itself. UDMF thing flags: added Skill 6-8 to the flags list (because there are thing filters for these). ZDoom_ACS.cfg: added definitions for SetTeleFog and SwapTeleFog. ZDoom_DECORATE.cfg: added definitions for A_SetTeleFog and A_SwapTeleFog. Updated ZDoom ACC. Updated documentation.
|
@ -329,6 +329,8 @@ special
|
|||
-83:PickActor(5,8),
|
||||
-84:IsPointerEqual(2,4),
|
||||
-85:CanRaiseActor(1),
|
||||
-86:SetActorTeleFog(3),
|
||||
-87:SwapActorTeleFog(1),
|
||||
|
||||
// Zandronum's
|
||||
-100:ResetMap(0),
|
||||
|
|
|
@ -3,10 +3,11 @@ mapformat_doom
|
|||
// The format interface handles the map data format
|
||||
formatinterface = "DoomMapSetIO";
|
||||
|
||||
maplumpnames
|
||||
{
|
||||
include("Doom_misc.cfg", "doommaplumpnames");
|
||||
}
|
||||
maplumpnames
|
||||
{
|
||||
include("Doom_misc.cfg", "doommaplumpnames");
|
||||
include("Boom_misc.cfg", "boommaplumpnames");
|
||||
}
|
||||
|
||||
// When this is set to true, sectors with the same tag will light up when a line is highlighted
|
||||
linetagindicatesectors = true;
|
||||
|
|
|
@ -35,25 +35,29 @@ thingflagstranslation
|
|||
// How thing flags should be compared (for the stuck thing error check)
|
||||
thingflagscompare
|
||||
{
|
||||
skills {
|
||||
skills
|
||||
{
|
||||
1;
|
||||
2;
|
||||
4;
|
||||
}
|
||||
|
||||
gamemodes {
|
||||
16 {
|
||||
//invert = true;
|
||||
gamemodes
|
||||
{
|
||||
16
|
||||
{
|
||||
ignoredgroup = "skills";
|
||||
ingnorethisgroupwhenunset = true;
|
||||
}
|
||||
|
||||
32 {
|
||||
32
|
||||
{
|
||||
invert = true;
|
||||
requiredflag = "16";
|
||||
}
|
||||
|
||||
64 {
|
||||
64
|
||||
{
|
||||
invert = true;
|
||||
requiredflag = "16";
|
||||
requiredgroup = "skills";
|
||||
|
@ -101,85 +105,8 @@ allowempty = The nodebuilder is allowed to leave this lump empty.
|
|||
script = This lump is a text-based script. Specify the filename of the script configuration to use.
|
||||
*/
|
||||
|
||||
doommaplumpnames
|
||||
boommaplumpnames
|
||||
{
|
||||
~MAP
|
||||
{
|
||||
required = true;
|
||||
blindcopy = true;
|
||||
nodebuild = false;
|
||||
}
|
||||
|
||||
THINGS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = true;
|
||||
}
|
||||
|
||||
LINEDEFS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SIDEDEFS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
VERTEXES
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SEGS
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SSECTORS
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
NODES
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
SECTORS
|
||||
{
|
||||
required = true;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
REJECT
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
BLOCKMAP
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
DEHACKED
|
||||
{
|
||||
required = false;
|
||||
|
|
|
@ -9,6 +9,9 @@ thingflags
|
|||
skill3 = "Skill 3";
|
||||
skill4 = "Skill 4";
|
||||
skill5 = "Skill 5";
|
||||
skill6 = "Skill 6";
|
||||
skill7 = "Skill 7";
|
||||
skill8 = "Skill 8";
|
||||
ambush = "Deaf";
|
||||
single = "Singleplayer";
|
||||
dm = "Deathmatch";
|
||||
|
@ -30,6 +33,9 @@ defaultthingflags
|
|||
skill3;
|
||||
skill4;
|
||||
skill5;
|
||||
skill6;
|
||||
skill7;
|
||||
skill8;
|
||||
single;
|
||||
coop;
|
||||
dm;
|
||||
|
@ -39,27 +45,36 @@ defaultthingflags
|
|||
// How thing flags should be compared (for the stuck thing error check)
|
||||
thingflagscompare
|
||||
{
|
||||
skills {
|
||||
skills
|
||||
{
|
||||
skill1;
|
||||
skill2;
|
||||
skill3;
|
||||
skill4;
|
||||
skill5;
|
||||
skill6;
|
||||
skill7;
|
||||
skill8;
|
||||
}
|
||||
|
||||
gamemodes {
|
||||
single {
|
||||
gamemodes
|
||||
{
|
||||
single
|
||||
{
|
||||
requiredgroup = "skills";
|
||||
}
|
||||
coop {
|
||||
coop
|
||||
{
|
||||
requiredgroup = "skills";
|
||||
}
|
||||
dm {
|
||||
dm
|
||||
{
|
||||
ignoredgroup = "skills";
|
||||
}
|
||||
}
|
||||
|
||||
classes {
|
||||
classes
|
||||
{
|
||||
class1;
|
||||
class2;
|
||||
class3;
|
||||
|
|
|
@ -90,6 +90,7 @@ mapformat_doom
|
|||
{
|
||||
include("Doom_misc.cfg", "doommaplumpnames");
|
||||
include("ZDoom_misc.cfg", "doommaplumpnames");
|
||||
include("ZDoom_misc.cfg", "glmaplumpnames");
|
||||
}
|
||||
|
||||
// When this is set to true, sectors with the same tag will light up when a line is highlighted
|
||||
|
@ -203,6 +204,7 @@ mapformat_hexen
|
|||
{
|
||||
include("Doom_misc.cfg", "hexenmaplumpnames");
|
||||
include("ZDoom_misc.cfg", "hexenmaplumpnames");
|
||||
include("ZDoom_misc.cfg", "glmaplumpnames");
|
||||
}
|
||||
|
||||
// When this is set to true, sectors with the same tag will light up when a line is highlighted
|
||||
|
|
|
@ -110,6 +110,9 @@ defaultthingflags_udmf
|
|||
skill3;
|
||||
skill4;
|
||||
skill5;
|
||||
skill6;
|
||||
skill7;
|
||||
skill8;
|
||||
single;
|
||||
coop;
|
||||
dm;
|
||||
|
@ -123,10 +126,8 @@ defaultthingflags_udmf
|
|||
// How thing flags should be compared (for the stuck thing error check)
|
||||
thingflagscompare_udmf
|
||||
{
|
||||
skills {
|
||||
skill6;
|
||||
skill7;
|
||||
skill8;
|
||||
skills
|
||||
{
|
||||
skill9;
|
||||
skill10;
|
||||
skill11;
|
||||
|
@ -137,7 +138,8 @@ thingflagscompare_udmf
|
|||
skill16;
|
||||
}
|
||||
|
||||
classes {
|
||||
classes
|
||||
{
|
||||
class4;
|
||||
class5;
|
||||
class6;
|
||||
|
@ -403,6 +405,52 @@ scriptbuild = This lump is a text-based script, which should be compiled using c
|
|||
script = This lump is a text-based script. Specify the filename of the script configuration to use.
|
||||
*/
|
||||
|
||||
// GL nodebuilders generate this stuff
|
||||
glmaplumpnames
|
||||
{
|
||||
GL_~MAP
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = true;
|
||||
}
|
||||
|
||||
GL_VERT
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
GL_SEGS
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
GL_SSECT
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
GL_NODES
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = false;
|
||||
}
|
||||
|
||||
GL_PVS
|
||||
{
|
||||
required = false;
|
||||
nodebuild = true;
|
||||
allowempty = true;
|
||||
}
|
||||
}
|
||||
|
||||
doommaplumpnames
|
||||
{
|
||||
REJECT
|
||||
|
|
|
@ -397,6 +397,7 @@ keywords
|
|||
SetPointer = "bool SetPointer(int assign_slot, int tid[, int pointer_selector[, int flags]])\nSet the value of one of the caller's stored pointers.";
|
||||
SetResultValue = "void SetResultValue(int value)";
|
||||
SetSkyScrollSpeed = "void SetSkyScrollSpeed(int sky, fixed skyspeed)\nChanges the scrolling speed of a sky.\nThis is useful in conjunction with ChangeSky.\nsky: either 1 or 2.\nskyspeed: the desired scrolling speed.";
|
||||
SetTeleFog = "void SetTeleFog(int tid, str telefogsrcclass, str telefogdestclass";
|
||||
SetThingSpecial = "void SetThingSpecial(int tid, int special [, int arg0 [, int arg1 [, int arg2 [, int arg3 [, int arg4]]]]])\nSets the special for any things with the same TID.\nThis is similar to Thing_SetSpecial, except it can only be used from ACS,\nand it can set all of a thing's special arguments.\nIf tid is 0, then the activator is used.";
|
||||
SetUserArray = "void SetUserArray(int tid, str name, int pos, int value)\nSets one of the affected actor's user array-bound variables.";
|
||||
SetUserCVar = "bool SetUserCVar(int playernumber, str cvar, int value)\nSets the console variable of a particular player.\nOnly mod-defined console variables through CVARINFO can be changed by using this function.\nReturns FALSE if cvar is invalid, it is not writable, or the player doesn't exist.";
|
||||
|
@ -437,6 +438,7 @@ keywords
|
|||
StrParam = "int StrParam(type:expression)\nStrParam will create a new string formatted based upon the same method for Print or Log.\nThe return value is the string table index of the new string.";
|
||||
StrRight = "str StrRight(str string, int length)\nCreates a new string containing the length last characters of string.\nIf string does not exist, an empty string is returned.\nIf string is shorter than length characters, the entire string is returned.";
|
||||
Suspend = "Suspend";
|
||||
SwapTeleFog = "int SwapTeleFog(int tid)";
|
||||
Switch = "Switch(expression)";
|
||||
TagWait = "void TagWait(int tag)";
|
||||
TakeActorInventory = "void TakeActorInventory(int tid, str inventory_item, int amount)\nThis function will take the amount of items from the specified actor.\nTakeActorInventory can remove items that are flagged as undroppable.";
|
||||
|
|
|
@ -55,6 +55,8 @@ keywords
|
|||
A_RemoveTracer = "A_RemoveTracer[(int flags)]\nflags: RMVF flags.";
|
||||
A_Remove = "A_Remove(int pointer, int flags)\nflags: RMVF flags.";
|
||||
A_SentinelBob = "A_SentinelBob";
|
||||
A_SetTeleFog = "A_SetTeleFog(string telefogsourceclass, string telefogdestclass)";
|
||||
A_SwapTeleFog = "A_SwapTeleFog";
|
||||
A_TurretLook = "A_TurretLook";
|
||||
A_Teleport = "A_Teleport[(string teleportstate = \"Teleport\"[, string targettype = \"BossSpot\"[, string fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0[, float maxdist = 0]]]]])]";
|
||||
A_VileChase = "A_VileChase";
|
||||
|
|
BIN
Help/gzdb/features/classic_modes/import_terrain_settings.jpg
Normal file
After Width: | Height: | Size: 17 KiB |
|
@ -23,12 +23,16 @@
|
|||
<b>Action category:</b> Tools.<br />
|
||||
<b>Default key:</b> none.</p>
|
||||
<p><strong>Usage:</strong><br />
|
||||
Create a terrain model in your favorite 3d modeling app (<a href="http://www.blender.org/">Blender</a>, <a href="http://www.earthsculptor.com/">Earth Sculptor</a> or any other, which can save a model to Wavefront .obj format)<br />
|
||||
Use <strong>File -> Import -> Wavefront .obj as Terrain</strong> action to import it as sectors. Each polygon in your model will be transformed into sector.</p>
|
||||
Create a terrain model in your favorite 3d modeling app (<a href="http://www.blender.org/">Blender</a>, <a href="http://www.earthsculptor.com/">Earth Sculptor</a> or any other, which can save or export a model to Wavefront .obj format)<br />
|
||||
Use <strong>File -> Import -> Wavefront .obj as Terrain</strong> action to import it as sectors. Each polygon in your model will be transformed into a sector.</p>
|
||||
<strong>Settings:</strong><img style="float:right" src="import_terrain_settings.jpg"/><br />
|
||||
<em>Scale:</em> self explanatory. The default is 1.0.<br />
|
||||
<em>Up axis:</em> should be the same as vertical axis in the 3d modeling app used to create a terrain model.<br />
|
||||
<em>Sloped terrain:</em> when enabled, the mode will generate sloped terrain using floor vertex height offsets ("ZFloor") in UDMF or Vertex slope floor (1504) things. Regardless of this setting, the mode will also set each new sector's floor height to the averaged height of a polygon it was created from.<br />
|
||||
<br />
|
||||
<strong>Limitations:</strong><br />
|
||||
The model should be triangulated.<br />
|
||||
Polygons should not overlap each other when viewed from the top.<br />
|
||||
<strong>UDMF only</strong>, because the mode uses vertex height offsets to create sloped floors ("zfloor" vertex field).
|
||||
<p><img src="terrain1.jpg" alt="" width="842" height="722" /></p>
|
||||
<p><img src="terrain2.jpg" alt="" width="842" height="632" /></p>
|
||||
</div>
|
||||
|
|
|
@ -10,20 +10,23 @@
|
|||
<param name="keyword" value="Template">
|
||||
</object>
|
||||
<div id="gz_title">
|
||||
<h1>"Fit Texture" actions</h1>
|
||||
<h1>"Fit Textures" action</h1>
|
||||
</div>
|
||||
<div id="contents">
|
||||
<p><strong>Action names:</strong> Fit Texture, Fit Texture's Width, Fit Texture's Height<br />
|
||||
<p><strong>Action name:</strong> Fit Textures.<br />
|
||||
<b>Action category:</b> Visual Modes.<br />
|
||||
<b>Default keys:</b> Ctrl-Alt-A, Alt-A, Alt-Shift-A.</p>
|
||||
<p><strong>Example:</strong><br />
|
||||
Initial scaling:<br />
|
||||
<img src="texturefit1.jpg"/></p>
|
||||
<p>After "Fit Texture's Width" action:<br />
|
||||
<b>Default key:</b> Ctrl-Alt-A.</p>
|
||||
<p>This action allows you to align textures to selected surfaces in Visual mode. "<em>Fit across connected surfaces</em>" setting controls whether adjacent surfaces sharing the same texture are threated as a continuous surface.</p>
|
||||
<p><strong>Examples:</strong><br /><br />
|
||||
Initial setup:<br />
|
||||
<img src="texturefit1.jpg"/></p><br />
|
||||
<p>Examples of various settings in action:<br />
|
||||
<img src="texturefit2.jpg"/></p>
|
||||
<p>After "Fit Texture's Height" action:<br />
|
||||
<img src="texturefit3.jpg"/></p>
|
||||
<p>After "Fit Texture" action:<br />
|
||||
<img src="texturefit4.jpg"/></p>
|
||||
<br />
|
||||
<img src="texturefit3.jpg"/>
|
||||
<br />
|
||||
<img src="texturefit4.jpg"/>
|
||||
<br />
|
||||
<img src="texturefit5.jpg"/>
|
||||
</div>
|
||||
</body>
|
||||
|
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 157 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 163 KiB |
BIN
Help/gzdb/features/visual_mode/texturefit5.jpg
Normal file
After Width: | Height: | Size: 185 KiB |
|
@ -113,8 +113,8 @@ namespace CodeImp.DoomBuilder.Compilers
|
|||
}
|
||||
|
||||
//mxd
|
||||
string outErr = process.StandardError.ReadToEnd();
|
||||
string outMsg = process.StandardOutput.ReadToEnd();
|
||||
string outErr = process.StandardError.ReadToEnd().Trim().Replace("\b", "");
|
||||
string outMsg = process.StandardOutput.ReadToEnd().Trim().Replace("\b", "");
|
||||
|
||||
// Wait for compiler to complete
|
||||
process.WaitForExit();
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
resourceitems.Items[0].ForeColor = SystemColors.GrayText;
|
||||
|
||||
// Validate path (mxd)
|
||||
resourceitems.Items[0].BackColor = (LocationValid(list[i]) ? resourceitems.BackColor : Color.MistyRose);
|
||||
resourceitems.Items[0].BackColor = (list[i].IsValid() ? resourceitems.BackColor : Color.MistyRose);
|
||||
}
|
||||
|
||||
// Done
|
||||
|
@ -211,7 +211,7 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
resourceitems.Items[index].ForeColor = SystemColors.WindowText;
|
||||
|
||||
// Validate path (mxd)
|
||||
resourceitems.Items[index].BackColor = (LocationValid(rl) ? resourceitems.BackColor : Color.MistyRose);
|
||||
resourceitems.Items[index].BackColor = (rl.IsValid() ? resourceitems.BackColor : Color.MistyRose);
|
||||
|
||||
// Done
|
||||
resourceitems.EndUpdate();
|
||||
|
@ -249,23 +249,6 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
internal static bool LocationValid(DataLocation location)
|
||||
{
|
||||
switch(location.type)
|
||||
{
|
||||
case DataLocation.RESOURCE_DIRECTORY:
|
||||
return Directory.Exists(location.location);
|
||||
|
||||
case DataLocation.RESOURCE_WAD:
|
||||
case DataLocation.RESOURCE_PK3:
|
||||
return File.Exists(location.location);
|
||||
|
||||
default:
|
||||
throw new NotImplementedException("ResourceListEditor.FixedResourceLocationList: got unknown location type: " + location.type);
|
||||
}
|
||||
}
|
||||
|
||||
// This fixes the column header in the list
|
||||
private void ResizeColumnHeader()
|
||||
|
@ -413,7 +396,7 @@ namespace CodeImp.DoomBuilder.Controls
|
|||
{
|
||||
foreach(ListViewItem item in resourceitems.Items)
|
||||
{
|
||||
if (!LocationValid((DataLocation) item.Tag)) return false;
|
||||
if (!((DataLocation)item.Tag).IsValid()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -71,5 +72,26 @@ namespace CodeImp.DoomBuilder.Data
|
|||
{
|
||||
return (this.CompareTo(other) == 0);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public bool IsValid()
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case RESOURCE_DIRECTORY:
|
||||
if(!Directory.Exists(location)) return false;
|
||||
break;
|
||||
|
||||
case RESOURCE_WAD:
|
||||
case RESOURCE_PK3:
|
||||
if(!File.Exists(location)) return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException("ResourceListEditor.FixedResourceLocationList: got unknown location type: " + type);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
|
@ -107,6 +109,13 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// Write to config
|
||||
cfg.WriteSetting(path, resinfo);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public bool IsValid()
|
||||
{
|
||||
foreach (DataLocation location in this) if (!location.IsValid()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using SlimDX;
|
||||
using SlimDX.Direct3D9;
|
||||
|
||||
|
@ -15,6 +15,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
|
|||
#region ================== Variables
|
||||
|
||||
private ModelLoadState loadstate;
|
||||
private Vector3 scale;
|
||||
private Matrix transform;
|
||||
private Matrix transformstretched;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -25,14 +28,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
|
|||
|
||||
internal GZModel Model;
|
||||
|
||||
internal Matrix Scale;
|
||||
internal Vector2D OffsetXY;
|
||||
internal float OffsetZ;
|
||||
|
||||
internal float AngleOffset; //in radians
|
||||
internal float PitchOffset; //in radians
|
||||
internal float RollOffset; //in radians
|
||||
internal bool OverridePalette; //used for voxel models only
|
||||
internal Vector3 Scale { get { return scale; } }
|
||||
internal Matrix Transform { get { return (General.Settings.GZStretchView ? transformstretched : transform); } }
|
||||
internal bool OverridePalette; //used for voxel models only
|
||||
internal bool InheritActorPitch;
|
||||
internal bool InheritActorRoll;
|
||||
|
||||
|
@ -48,8 +46,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
|
|||
{
|
||||
ModelNames = new List<string>();
|
||||
TextureNames = new List<string>();
|
||||
Scale = Matrix.Identity;
|
||||
OffsetXY = new Vector2D();
|
||||
transform = Matrix.Identity;
|
||||
transformstretched = Matrix.Identity;
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
|
@ -62,6 +60,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
|
|||
}
|
||||
}
|
||||
|
||||
internal void SetTransform(Matrix rotation, Matrix offset, Vector3 scale)
|
||||
{
|
||||
this.scale = scale;
|
||||
this.transform = Matrix.Scaling(scale) * rotation * offset;
|
||||
this.transformstretched = Matrix.Scaling(scale.X, scale.Y, scale.Z * Renderer3D.GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH) * rotation * offset;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -409,14 +409,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
|
|||
|
||||
//classname is set in ModeldefParser
|
||||
ModelData mde = new ModelData();
|
||||
mde.Scale = Matrix.Scaling(scale);
|
||||
mde.OffsetXY = new Vector2D(offset.Y, -offset.X); // Things are complicated in GZDoom...
|
||||
mde.OffsetZ = offset.Z;
|
||||
mde.AngleOffset = Angle2D.DegToRad(angleOffset);
|
||||
mde.RollOffset = Angle2D.DegToRad(rollOffset);
|
||||
mde.PitchOffset = Angle2D.DegToRad(pitchOffset);
|
||||
mde.InheritActorPitch = inheritactorpitch;
|
||||
mde.InheritActorRoll = inheritactorroll;
|
||||
Matrix moffset = Matrix.Translation(offset.Y, -offset.X, offset.Z); // Things are complicated in GZDoom...
|
||||
Matrix mrotation = Matrix.RotationY(inheritactorroll ? -Angle2D.DegToRad(rollOffset) : 0)
|
||||
* Matrix.RotationX(inheritactorpitch ? -Angle2D.DegToRad(pitchOffset) : 0)
|
||||
* Matrix.RotationZ(Angle2D.DegToRad(angleOffset));
|
||||
mde.SetTransform(mrotation, moffset, scale);
|
||||
|
||||
for(int i = 0; i < modelNames.Length; i++)
|
||||
{
|
||||
|
|
|
@ -734,12 +734,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
|
|||
|
||||
//create bounding box
|
||||
BoundingBoxSizes bbs = new BoundingBoxSizes();
|
||||
bbs.MinX = (short)((xsize / 2 - pivot.x) * mde.Scale.M11); //That should be scale x
|
||||
bbs.MaxX = (short)((xsize / 2 + pivot.x) * mde.Scale.M11);
|
||||
bbs.MinZ = (short)((zsize / 2 - pivot.z) * mde.Scale.M11);
|
||||
bbs.MaxZ = (short)((zsize / 2 + pivot.z) * mde.Scale.M11);
|
||||
bbs.MinY = (short)((ysize / 2 - pivot.y) * mde.Scale.M11);
|
||||
bbs.MaxY = (short)((ysize / 2 + pivot.y) * mde.Scale.M11);
|
||||
bbs.MinX = (short)((xsize / 2f - pivot.x) * mde.Scale.X);
|
||||
bbs.MaxX = (short)((xsize / 2f + pivot.x) * mde.Scale.X);
|
||||
bbs.MinZ = (short)((zsize / 2f - pivot.z) * mde.Scale.Z);
|
||||
bbs.MaxZ = (short)((zsize / 2f + pivot.z) * mde.Scale.Z);
|
||||
bbs.MinY = (short)((ysize / 2f - pivot.y) * mde.Scale.Y);
|
||||
bbs.MaxY = (short)((ysize / 2f + pivot.y) * mde.Scale.Y);
|
||||
|
||||
mde.Model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs);
|
||||
|
||||
|
|
|
@ -686,6 +686,7 @@ namespace CodeImp.DoomBuilder {
|
|||
|
||||
// Determine original map name
|
||||
origmapname = (options.PreviousName != "" && purpose != SavePurpose.IntoFile) ? options.PreviousName : options.CurrentName;
|
||||
string origwadfile = string.Empty; //mxd
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -736,7 +737,7 @@ namespace CodeImp.DoomBuilder {
|
|||
if (File.Exists(newfilepathname))
|
||||
{
|
||||
// Move the target file aside
|
||||
string origwadfile = newfilepathname + ".temp";
|
||||
origwadfile = newfilepathname + ".temp";
|
||||
File.Move(newfilepathname, origwadfile);
|
||||
|
||||
// Open original file
|
||||
|
@ -772,6 +773,7 @@ namespace CodeImp.DoomBuilder {
|
|||
catch (IOException)
|
||||
{
|
||||
General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
|
||||
if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up
|
||||
data.Resume();
|
||||
General.WriteLogLine("Map saving failed");
|
||||
return false;
|
||||
|
@ -779,6 +781,7 @@ namespace CodeImp.DoomBuilder {
|
|||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
|
||||
if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up
|
||||
data.Resume();
|
||||
General.WriteLogLine("Map saving failed");
|
||||
return false;
|
||||
|
@ -923,6 +926,9 @@ namespace CodeImp.DoomBuilder {
|
|||
// Determine source file
|
||||
string sourcefile = (filepathname.Length > 0 ? filepathname : tempwad.Filename);
|
||||
|
||||
//mxd.
|
||||
RemoveUnneededLumps(tempwad, TEMP_MAP_HEADER, true);
|
||||
|
||||
// Copy lumps to buildwad
|
||||
General.WriteLogLine("Copying map lumps to temporary build file...");
|
||||
CopyLumpsByType(tempwad, TEMP_MAP_HEADER, buildwad, BUILD_MAP_HEADER, true, false, false, true);
|
||||
|
@ -976,7 +982,7 @@ namespace CodeImp.DoomBuilder {
|
|||
//mxd. collect errors
|
||||
string compilererrors = "";
|
||||
foreach (CompilerError e in compiler.Errors)
|
||||
compilererrors += "Error: " + Environment.NewLine + e.description;
|
||||
compilererrors += Environment.NewLine + e.description;
|
||||
|
||||
// Nodebuilder did not build the lumps!
|
||||
if (failaswarning)
|
||||
|
@ -993,7 +999,7 @@ namespace CodeImp.DoomBuilder {
|
|||
//collect errors
|
||||
string compilererrors = "";
|
||||
foreach (CompilerError e in compiler.Errors)
|
||||
compilererrors += "Error: " + Environment.NewLine + e.description;
|
||||
compilererrors += Environment.NewLine + e.description;
|
||||
|
||||
// Nodebuilder did not build the lumps!
|
||||
General.ShowErrorMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures" + (compiler.Errors.Length > 0 ? ":" + Environment.NewLine + compilererrors : "."), MessageBoxButtons.OK);
|
||||
|
@ -1023,10 +1029,14 @@ namespace CodeImp.DoomBuilder {
|
|||
foreach (KeyValuePair<string, MapLumpInfo> group in config.MapLumps)
|
||||
{
|
||||
// Check if this lump should exist
|
||||
if (group.Value.NodeBuild && !group.Value.AllowEmpty)
|
||||
if(group.Value.NodeBuild && !group.Value.AllowEmpty && group.Value.Required)
|
||||
{
|
||||
//mxd
|
||||
string lumpname = group.Key;
|
||||
if (lumpname.Contains(CONFIG_MAP_HEADER)) lumpname = lumpname.Replace(CONFIG_MAP_HEADER, mapheader);
|
||||
|
||||
// Find the lump in the source
|
||||
if(wad.FindLump(group.Key, srcindex, srcindex + config.MapLumps.Count + 2) == null)
|
||||
if(wad.FindLump(lumpname, srcindex, srcindex + config.MapLumps.Count + 2) == null)
|
||||
{
|
||||
// Missing a lump!
|
||||
lumpscomplete = false;
|
||||
|
@ -1103,7 +1113,7 @@ namespace CodeImp.DoomBuilder {
|
|||
if(group.Value.Required)
|
||||
{
|
||||
// Get the lump name
|
||||
string lumpname = (group.Key == CONFIG_MAP_HEADER ? mapname : group.Key);
|
||||
string lumpname = (group.Key.Contains(CONFIG_MAP_HEADER) ? group.Key.Replace(CONFIG_MAP_HEADER, mapname) : group.Key); //mxd
|
||||
|
||||
// Check if the lump is missing at the target
|
||||
int targetindex = FindSpecificLump(target, lumpname, headerindex, mapname, config.MapLumps);
|
||||
|
@ -1127,15 +1137,16 @@ namespace CodeImp.DoomBuilder {
|
|||
}
|
||||
|
||||
//mxd. This is called on tempwad, which should only have the current map inside it.
|
||||
private void RemoveUnneededLumps(WAD target, string mapname)
|
||||
private void RemoveUnneededLumps(WAD target, string mapname, bool glnodesonly)
|
||||
{
|
||||
//Get the list of lumps required by current map format
|
||||
List<string> requiredLumps = new List<string>();
|
||||
foreach(KeyValuePair<string, MapLumpInfo> group in config.MapLumps)
|
||||
{
|
||||
if(group.Value.NodeBuild) continue; //this lump well be recreated by a nodebuilder when saving the map
|
||||
//(or it won't be if the new map format doesn't require this lump,
|
||||
//so it will just stay there, possibly messing things up)
|
||||
//this lump well be recreated by a nodebuilder when saving the map
|
||||
//(or it won't be if the new map format or nodebuilder doesn't require / build this lump,
|
||||
//so it will just stay there, possibly messing things up)
|
||||
if(group.Value.NodeBuild && (!glnodesonly || group.Key.ToUpperInvariant().StartsWith("GL_"))) continue;
|
||||
|
||||
string lumpname = group.Key;
|
||||
if(lumpname == CONFIG_MAP_HEADER) lumpname = mapname;
|
||||
|
@ -1158,10 +1169,17 @@ namespace CodeImp.DoomBuilder {
|
|||
foreach (Lump srclump in source.Lumps)
|
||||
{
|
||||
// Check if we should stop skipping lumps here
|
||||
if (skipping && !mapconfig.MapLumps.ContainsKey(srclump.Name))
|
||||
if (skipping)
|
||||
{
|
||||
// Stop skipping
|
||||
skipping = false;
|
||||
//mxd
|
||||
string srclumpname = srclump.Name;
|
||||
if (srclumpname.Contains(sourcemapname)) srclumpname = srclumpname.Replace(sourcemapname, CONFIG_MAP_HEADER);
|
||||
|
||||
if (!mapconfig.MapLumps.ContainsKey(srclumpname))
|
||||
{
|
||||
// Stop skipping
|
||||
skipping = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should start skipping lumps here
|
||||
|
@ -1211,8 +1229,8 @@ namespace CodeImp.DoomBuilder {
|
|||
(group.Value.NodeBuild && copynodebuild) || ((group.Value.Script != null || group.Value.ScriptBuild) && copyscript))
|
||||
{
|
||||
// Get the lump name
|
||||
string srclumpname = (group.Key == CONFIG_MAP_HEADER ? sourcemapname : group.Key);
|
||||
string tgtlumpname = (group.Key == CONFIG_MAP_HEADER ? targetmapname : group.Key);
|
||||
string srclumpname = (group.Key.Contains(CONFIG_MAP_HEADER) ? group.Key.Replace(CONFIG_MAP_HEADER, sourcemapname) : group.Key); //mxd
|
||||
string tgtlumpname = (group.Key.Contains(CONFIG_MAP_HEADER) ? group.Key.Replace(CONFIG_MAP_HEADER, targetmapname) : group.Key); //mxd
|
||||
|
||||
// Find the lump in the source
|
||||
int sourceindex = FindSpecificLump(source, srclumpname, srcheaderindex, sourcemapname, config.MapLumps);
|
||||
|
@ -1249,7 +1267,7 @@ namespace CodeImp.DoomBuilder {
|
|||
|
||||
// This finds a lump within the range of known lump names
|
||||
// Returns -1 when the lump cannot be found
|
||||
internal static int FindSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, Dictionary<string, MapLumpInfo> maplumps)
|
||||
private static int FindSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, Dictionary<string, MapLumpInfo> maplumps)
|
||||
{
|
||||
// Use the configured map lump names to find the specific lump within range,
|
||||
// because when an unknown lump is met, this search must stop.
|
||||
|
@ -1261,8 +1279,10 @@ namespace CodeImp.DoomBuilder {
|
|||
if ((mapheaderindex + i) < source.Lumps.Count)
|
||||
{
|
||||
// Check if this is a known lump name
|
||||
if (maplumps.ContainsKey(source.Lumps[mapheaderindex + i].Name) ||
|
||||
(maplumps.ContainsKey(CONFIG_MAP_HEADER) && (source.Lumps[mapheaderindex + i].Name == mapheadername)))
|
||||
string srclumpname = source.Lumps[mapheaderindex + i].Name; //mxd
|
||||
if (srclumpname.Contains(mapheadername)) srclumpname = srclumpname.Replace(mapheadername, CONFIG_MAP_HEADER);
|
||||
|
||||
if (maplumps.ContainsKey(srclumpname)) //mxd
|
||||
{
|
||||
// Is this the lump we are looking for?
|
||||
if (source.Lumps[mapheaderindex + i].Name == lumpname)
|
||||
|
@ -1897,7 +1917,7 @@ namespace CodeImp.DoomBuilder {
|
|||
|
||||
//mxd. Some lumps may've become unneeded during map format conversion.
|
||||
if(oldFormatInterface != config.FormatInterface)
|
||||
RemoveUnneededLumps(tempwad, TEMP_MAP_HEADER);
|
||||
RemoveUnneededLumps(tempwad, TEMP_MAP_HEADER, false);
|
||||
|
||||
// Create required lumps if they don't exist yet
|
||||
CreateRequiredLumps(tempwad, TEMP_MAP_HEADER);
|
||||
|
|
|
@ -27,6 +27,7 @@ using CodeImp.DoomBuilder.Config;
|
|||
using CodeImp.DoomBuilder.Types;
|
||||
using System.Windows.Forms;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Tools;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -1799,6 +1800,26 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
((sd.LongMiddleTexture == texturelongname) && (sd.MiddleRequired() || sd.LongMiddleTexture != MapSet.EmptyLongName)) ;
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given wall part
|
||||
public static float GetSidedefOffsetY(Sidedef side, VisualGeometryType part, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
switch (part)
|
||||
{
|
||||
case VisualGeometryType.WALL_UPPER:
|
||||
return GetSidedefTopOffsetY(side, offset, scaleY, fromNormalized);
|
||||
|
||||
case VisualGeometryType.WALL_MIDDLE:
|
||||
case VisualGeometryType.WALL_MIDDLE_3D:
|
||||
return GetSidedefMiddleOffsetY(side, offset, scaleY, fromNormalized);
|
||||
|
||||
case VisualGeometryType.WALL_LOWER:
|
||||
return GetSidedefBottomOffsetY(side, offset, scaleY, fromNormalized);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException("Tools.GetSidedefOffsetY: '" + part + "' geometry type is not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given upper wall
|
||||
public static float GetSidedefTopOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
|
@ -1806,7 +1827,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
return offset;
|
||||
|
||||
//if we don't have UpperUnpegged flag, normalize offset
|
||||
float surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY;
|
||||
float surfaceHeight = side.GetHighHeight() * scaleY;
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
|
@ -1815,13 +1836,38 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
//mxd. This converts offsetY from/to "normalized" offset for given middle wall
|
||||
public static float GetSidedefMiddleOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
if(!side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || side.Sector == null)
|
||||
return offset;
|
||||
if(side.Sector == null) return offset;
|
||||
|
||||
// If we have LowerUnpegged flag, normalize offset
|
||||
// Absolute value is used because ceiling height of vavoom-type 3d floors
|
||||
// is lower than floor height
|
||||
float surfaceHeight = (Math.Abs(side.Sector.CeilHeight - side.Sector.FloorHeight)) * scaleY;
|
||||
// Normalize offset
|
||||
float surfaceHeight;
|
||||
if(side.Other != null && side.Other.Sector != null)
|
||||
{
|
||||
if(side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// Double-sided with LowerUnpeggedFlag set
|
||||
surfaceHeight = (side.Sector.CeilHeight - Math.Max(side.Sector.FloorHeight, side.Other.Sector.FloorHeight)) * scaleY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Double-sided without LowerUnpeggedFlag
|
||||
surfaceHeight = Math.Abs(side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
// Single-sided with LowerUnpeggedFlag set
|
||||
// Absolute value is used because ceiling height of vavoom-type 3d floors
|
||||
// is lower than floor height
|
||||
surfaceHeight = (Math.Abs(side.Sector.CeilHeight - side.Sector.FloorHeight)) * scaleY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single-sided without LowerUnpeggedFlag
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
|
|
|
@ -839,6 +839,7 @@ namespace CodeImp.DoomBuilder.IO
|
|||
if(args.Count < 1) RaiseError(file, line, ERROR_INVALID_ARGS);
|
||||
if(!(args[0] is string)) RaiseError(file, line, ERROR_INVALID_ARGS + " Expected a string for argument 1.");
|
||||
if((args.Count > 1) && !(args[1] is string)) RaiseError(file, line, ERROR_INVALID_ARGS + " Expected a string for argument 2.");
|
||||
if(args[0].ToString().ToUpperInvariant() == Path.GetFileName(file).ToUpperInvariant()) RaiseError(file, line, " A file cannot call include() on itself."); //mxd
|
||||
if(cpErrorResult) return;
|
||||
|
||||
// Determine the full path of the file to include
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace CodeImp.DoomBuilder.Map
|
|||
#region ================== Properties
|
||||
|
||||
public MapSet Map { get { return map; } }
|
||||
public int Type { get { return type; } set { BeforePropsChange(); type = value; /*UpdateCache();*/ } } //mxd
|
||||
public int Type { get { return type; } set { BeforePropsChange(); type = value; } } //mxd
|
||||
public Vector3D Position { get { return pos; } }
|
||||
public float ScaleX { get { return scaleX; } } //mxd. This is UDMF property, not actual scale!
|
||||
public float ScaleY { get { return scaleY; } } //mxd. This is UDMF property, not actual scale!
|
||||
|
@ -431,7 +431,7 @@ namespace CodeImp.DoomBuilder.Map
|
|||
BeforePropsChange();
|
||||
|
||||
pitch = p;
|
||||
pitchrad = ((isModel && General.Map.Data.ModeldefEntries[type].InheritActorRoll) ? Angle2D.DegToRad(pitch) : 0);
|
||||
pitchrad = ((isModel && General.Map.Data.ModeldefEntries[type].InheritActorPitch) ? Angle2D.DegToRad(pitch) : 0);
|
||||
|
||||
if (type != General.Map.Config.Start3DModeThingType)
|
||||
General.Map.IsChanged = true;
|
||||
|
@ -444,7 +444,6 @@ namespace CodeImp.DoomBuilder.Map
|
|||
|
||||
roll = r;
|
||||
rollrad = ((isModel && General.Map.Data.ModeldefEntries[type].InheritActorRoll) ? Angle2D.DegToRad(roll) : 0);
|
||||
//rotation = Matrix.RotationYawPitchRoll(rollrad, pitchrad, anglerad); //mxd
|
||||
|
||||
if (type != General.Map.Config.Start3DModeThingType)
|
||||
General.Map.IsChanged = true;
|
||||
|
|
|
@ -1339,7 +1339,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
foreach(Thing t in group.Value)
|
||||
{
|
||||
if(General.Settings.GZDrawModelsMode == ModelRenderMode.SELECTION && !t.Selected) continue;
|
||||
Vector2D screenpos = ((Vector2D)t.Position + General.Map.Data.ModeldefEntries[t.Type].OffsetXY.GetScaled(t.ScaleX).GetRotated(t.Angle)).GetTransformed(translatex, translatey, scale, -scale);
|
||||
Vector2D screenpos = ((Vector2D)t.Position).GetTransformed(translatex, translatey, scale, -scale);
|
||||
float modelScale = scale * t.ActorScale.Width * t.ScaleX;
|
||||
|
||||
//should we render this model?
|
||||
|
@ -1355,12 +1355,9 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
float sy = t.ScaleY * t.ActorScale.Height;
|
||||
|
||||
Matrix modelscale = Matrix.Scaling(sx, sx, sy);
|
||||
Matrix mdescale = General.Map.Data.ModeldefEntries[t.Type].Scale;
|
||||
Matrix rotation = Matrix.RotationY(-(t.RollRad + General.Map.Data.ModeldefEntries[t.Type].RollOffset))
|
||||
* Matrix.RotationX(-(t.PitchRad + General.Map.Data.ModeldefEntries[t.Type].PitchOffset))
|
||||
* Matrix.RotationZ(t.Angle + General.Map.Data.ModeldefEntries[t.Type].AngleOffset);
|
||||
Matrix rotation = Matrix.RotationY(-t.RollRad) * Matrix.RotationX(-t.PitchRad) * Matrix.RotationZ(t.Angle);
|
||||
Matrix position = Matrix.Translation(screenpos.x, screenpos.y, 0.0f);
|
||||
Matrix world = mdescale * rotation * modelscale * viewscale * position;
|
||||
Matrix world = General.Map.Data.ModeldefEntries[t.Type].Transform * rotation * modelscale * viewscale * position;
|
||||
|
||||
graphics.Shaders.Things2D.SetTransformSettings(world);
|
||||
graphics.Shaders.Things2D.ApplySettings();
|
||||
|
|
|
@ -42,7 +42,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
private const float PROJ_NEAR_PLANE = 1f;
|
||||
private const float CROSSHAIR_SCALE = 0.06f;
|
||||
private const float FOG_RANGE = 0.9f;
|
||||
private const float INVERTED_VERTICAL_STRETCH = 1.0f / 1.2f;
|
||||
internal const float GZDOOM_VERTICAL_VIEW_STRETCH = 1.2f;
|
||||
internal const float GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH = 1.0f / GZDOOM_VERTICAL_VIEW_STRETCH;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -55,7 +56,6 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
private Matrix worldviewproj;
|
||||
private Matrix view2d;
|
||||
private Matrix world;
|
||||
private float viewstretch; //mxd
|
||||
private Vector3D cameraposition;
|
||||
private int shaderpass;
|
||||
|
||||
|
@ -257,7 +257,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
internal void CreateProjection()
|
||||
{
|
||||
// Calculate aspect
|
||||
float screenheight = General.Map.Graphics.RenderTarget.ClientSize.Height * (General.Settings.GZStretchView ? INVERTED_VERTICAL_STRETCH : 1.0f); //mxd
|
||||
float screenheight = General.Map.Graphics.RenderTarget.ClientSize.Height * (General.Settings.GZStretchView ? GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH : 1.0f); //mxd
|
||||
float aspect = General.Map.Graphics.RenderTarget.ClientSize.Width / screenheight;
|
||||
|
||||
// The DirectX PerspectiveFovRH matrix method calculates the scaling in X and Y as follows:
|
||||
|
@ -273,9 +273,6 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
// Make the projection matrix
|
||||
projection = Matrix.PerspectiveFovRH(fovy, aspect, PROJ_NEAR_PLANE, General.Settings.ViewDistance);
|
||||
|
||||
// Update the view stretch scaler (mxd)
|
||||
viewstretch = (General.Settings.GZStretchView ? INVERTED_VERTICAL_STRETCH : 1.0f);
|
||||
|
||||
// Apply matrices
|
||||
ApplyMatrices3D();
|
||||
}
|
||||
|
@ -1121,19 +1118,12 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
|
||||
// Create the matrix for positioning / rotation
|
||||
float sx = t.Thing.ScaleX * t.Thing.ActorScale.Width;
|
||||
float sy = t.Thing.ScaleY * t.Thing.ActorScale.Height * viewstretch;
|
||||
float sy = t.Thing.ScaleY * t.Thing.ActorScale.Height;
|
||||
|
||||
Matrix modelscale = Matrix.Scaling(sx, sx, sy);
|
||||
Matrix mdescale = General.Map.Data.ModeldefEntries[t.Thing.Type].Scale;
|
||||
Matrix modelrotation = Matrix.RotationY(-t.Thing.RollRad) * Matrix.RotationX(-t.Thing.PitchRad) * Matrix.RotationZ(t.Thing.Angle);
|
||||
|
||||
Matrix rotation = Matrix.RotationY(-(t.Thing.RollRad + General.Map.Data.ModeldefEntries[t.Thing.Type].RollOffset))
|
||||
* Matrix.RotationX(-(t.Thing.PitchRad + General.Map.Data.ModeldefEntries[t.Thing.Type].PitchOffset))
|
||||
* Matrix.RotationZ(t.Thing.Angle + General.Map.Data.ModeldefEntries[t.Thing.Type].AngleOffset);
|
||||
|
||||
Vector2D offset2d = General.Map.Data.ModeldefEntries[t.Thing.Type].OffsetXY.GetScaled(t.Thing.ScaleX).GetRotated(t.Thing.Angle);
|
||||
Matrix position = Matrix.Translation(offset2d.x, offset2d.y, General.Map.Data.ModeldefEntries[t.Thing.Type].OffsetZ * t.Thing.ScaleY) * t.Position;
|
||||
|
||||
world = mdescale * rotation * modelscale * position;
|
||||
world = General.Map.Data.ModeldefEntries[t.Thing.Type].Transform * modelrotation * modelscale * t.Position;
|
||||
ApplyMatrices3D();
|
||||
|
||||
//mxd. set variables for fog rendering
|
||||
|
|
|
@ -69,7 +69,8 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
|
||||
//mxd
|
||||
private Vector3[] boundingBox;
|
||||
protected VisualGeometryType geoType;
|
||||
protected VisualGeometryType geometrytype;
|
||||
protected string partname; //UDMF part name
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -83,7 +84,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
|
||||
//mxd
|
||||
public Vector3[] BoundingBox { get { return boundingBox; } }
|
||||
public VisualGeometryType GeometryType { get { return geoType; } }
|
||||
public VisualGeometryType GeometryType { get { return geometrytype; } }
|
||||
|
||||
/// <summary>
|
||||
/// Render pass in which this geometry must be rendered. Default is Solid.
|
||||
|
@ -126,8 +127,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
{
|
||||
this.sector = vs;
|
||||
this.ModulateColor = new PixelColor(255, 255, 255, 255);
|
||||
//mxd
|
||||
geoType = VisualGeometryType.UNKNOWN;
|
||||
this.geometrytype = VisualGeometryType.UNKNOWN; //mxd
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -139,8 +139,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
this.sector = vs;
|
||||
this.sidedef = sd;
|
||||
this.ModulateColor = new PixelColor(255, 255, 255, 255);
|
||||
//mxd
|
||||
geoType = VisualGeometryType.UNKNOWN;
|
||||
this.geometrytype = VisualGeometryType.UNKNOWN; //mxd
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -360,16 +360,13 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
{
|
||||
// Get configuration item
|
||||
ci = listconfigs.Items[i].Tag as ConfigurationInfo;
|
||||
foreach (DataLocation location in ci.Resources)
|
||||
if(!ci.Resources.IsValid())
|
||||
{
|
||||
if (!ResourceListEditor.LocationValid(location))
|
||||
{
|
||||
MessageBox.Show(this, "At least one resource doesn't exist in '" + ci.Name + "' game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
tabs.SelectedTab = tabresources;
|
||||
listconfigs.Focus();
|
||||
listconfigs.Items[i].Selected = true;
|
||||
return;
|
||||
}
|
||||
MessageBox.Show(this, "At least one resource doesn't exist in '" + ci.Name + "' game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
tabs.SelectedTab = tabresources;
|
||||
listconfigs.Focus();
|
||||
listconfigs.Items[i].Selected = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -508,10 +508,14 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
{
|
||||
// Position window from configuration settings
|
||||
this.SuspendLayout();
|
||||
this.Location = new Point(General.Settings.ReadSetting("mainwindow.positionx", this.Location.X),
|
||||
General.Settings.ReadSetting("mainwindow.positiony", this.Location.Y));
|
||||
this.Size = new Size(General.Settings.ReadSetting("mainwindow.sizewidth", this.Size.Width),
|
||||
General.Settings.ReadSetting("mainwindow.sizeheight", this.Size.Height));
|
||||
this.Location = new Point(General.Clamp(General.Settings.ReadSetting("mainwindow.positionx", this.Location.X),
|
||||
SystemInformation.VirtualScreen.Left - this.Size.Width + 128,
|
||||
SystemInformation.VirtualScreen.Right - 128),
|
||||
General.Clamp(General.Settings.ReadSetting("mainwindow.positiony", this.Location.Y),
|
||||
SystemInformation.VirtualScreen.Top,
|
||||
SystemInformation.VirtualScreen.Bottom - 128));
|
||||
this.WindowState = (FormWindowState)General.Settings.ReadSetting("mainwindow.windowstate", (int)FormWindowState.Maximized);
|
||||
this.ResumeLayout(true);
|
||||
|
||||
|
|
|
@ -64,8 +64,10 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
}
|
||||
else if(token == "{") //read the settings
|
||||
{
|
||||
ModelData data = new ModelData();
|
||||
data.IsVoxel = true;
|
||||
ModelData mde = new ModelData();
|
||||
mde.IsVoxel = true;
|
||||
float scale = 1.0f;
|
||||
float angleoffset = 0;
|
||||
|
||||
while(SkipWhitespace(true))
|
||||
{
|
||||
|
@ -79,17 +81,18 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
{
|
||||
if(!string.IsNullOrEmpty(modelName) && spriteNames.Count > 0)
|
||||
{
|
||||
data.ModelNames.Add(modelName);
|
||||
mde.ModelNames.Add(modelName);
|
||||
mde.SetTransform(Matrix.RotationZ(Angle2D.DegToRad(angleoffset)), Matrix.Identity, new Vector3(scale));
|
||||
|
||||
foreach(string s in spriteNames)
|
||||
{
|
||||
if(entries.ContainsKey(s)) //TODO: is this a proper behaviour?
|
||||
{
|
||||
entries[s] = data;
|
||||
entries[s] = mde;
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(s, data);
|
||||
entries.Add(s, mde);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +106,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
}
|
||||
else if(token == "overridepalette")
|
||||
{
|
||||
data.OverridePalette = true;
|
||||
mde.OverridePalette = true;
|
||||
}
|
||||
else if(token == "angleoffset")
|
||||
{
|
||||
|
@ -116,15 +119,12 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
break;
|
||||
}
|
||||
|
||||
float angleOffset = 0; //90?
|
||||
token = StripTokenQuotes(ReadToken());
|
||||
if(!ReadSignedFloat(token, ref angleOffset))
|
||||
if(!ReadSignedFloat(token, ref angleoffset))
|
||||
{
|
||||
// Not numeric!
|
||||
General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected AngleOffset value, but got '" + token + "'");
|
||||
}
|
||||
data.AngleOffset = Angle2D.DegToRad(angleOffset);
|
||||
|
||||
}
|
||||
else if(token == "scale")
|
||||
{
|
||||
|
@ -137,15 +137,12 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
break;
|
||||
}
|
||||
|
||||
float scale = 1.0f;
|
||||
token = StripTokenQuotes(ReadToken());
|
||||
if(!ReadSignedFloat(token, ref scale))
|
||||
{
|
||||
// Not numeric!
|
||||
General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'");
|
||||
}
|
||||
|
||||
data.Scale = Matrix.Scaling(scale, scale, scale);
|
||||
}
|
||||
prevToken = token.ToUpperInvariant();
|
||||
}
|
||||
|
|
|
@ -326,6 +326,12 @@
|
|||
<Compile Include="Interface\FilterSelectedThingsForm.Designer.cs">
|
||||
<DependentUpon>FilterSelectedThingsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Interface\FitTexturesForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Interface\FitTexturesForm.Designer.cs">
|
||||
<DependentUpon>FitTexturesForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Interface\PastePropertiesOptionsForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -504,6 +510,9 @@
|
|||
<EmbeddedResource Include="Interface\FilterSelectedThingsForm.resx">
|
||||
<DependentUpon>FilterSelectedThingsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Interface\FitTexturesForm.resx">
|
||||
<DependentUpon>FitTexturesForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Interface\PastePropertiesOptionsForm.resx">
|
||||
<DependentUpon>PastePropertiesOptionsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Tools;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
|
@ -9,68 +12,157 @@ using CodeImp.DoomBuilder.VisualModes;
|
|||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
public static class BuilderModesTools
|
||||
// A struct, which contains information about visual sides connected to start and end of given visual side
|
||||
internal class SortedVisualSide
|
||||
{
|
||||
internal readonly BaseVisualGeometrySidedef Side;
|
||||
internal readonly Vector2D Start;
|
||||
internal readonly Vector2D End;
|
||||
internal Rectangle Bounds;
|
||||
internal readonly Dictionary<SortedVisualSide, bool> NextSides;
|
||||
internal readonly Dictionary<SortedVisualSide, bool> PreviousSides;
|
||||
internal readonly int Index;
|
||||
private static int index;
|
||||
|
||||
//Initial texture coordinates
|
||||
private readonly float OffsetX;
|
||||
private readonly float OffsetY;
|
||||
private readonly float ScaleX;
|
||||
private readonly float ScaleY;
|
||||
|
||||
internal SortedVisualSide(BaseVisualGeometrySidedef side)
|
||||
{
|
||||
Side = side;
|
||||
Bounds = BuilderModesTools.GetSidedefPartSize(side);
|
||||
Index = index++;
|
||||
|
||||
if (side.Sidedef.Line.Front == side.Sidedef)
|
||||
{
|
||||
Start = side.Sidedef.Line.Start.Position;
|
||||
End = side.Sidedef.Line.End.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
Start = side.Sidedef.Line.End.Position;
|
||||
End = side.Sidedef.Line.Start.Position;
|
||||
}
|
||||
|
||||
switch (side.GeometryType)
|
||||
{
|
||||
case VisualGeometryType.WALL_UPPER:
|
||||
OffsetX = UDMFTools.GetFloat(side.Sidedef.Fields, "offsetx_top");
|
||||
OffsetY = UDMFTools.GetFloat(side.Sidedef.Fields, "offsety_top");
|
||||
ScaleX = UDMFTools.GetFloat(side.Sidedef.Fields, "scalex_top", 1.0f);
|
||||
ScaleY = UDMFTools.GetFloat(side.Sidedef.Fields, "scaley_top", 1.0f);
|
||||
break;
|
||||
|
||||
case VisualGeometryType.WALL_MIDDLE:
|
||||
OffsetX = UDMFTools.GetFloat(side.Sidedef.Fields, "offsetx_mid");
|
||||
OffsetY = UDMFTools.GetFloat(side.Sidedef.Fields, "offsety_mid");
|
||||
ScaleX = UDMFTools.GetFloat(side.Sidedef.Fields, "scalex_mid", 1.0f);
|
||||
ScaleY = UDMFTools.GetFloat(side.Sidedef.Fields, "scaley_mid", 1.0f);
|
||||
break;
|
||||
|
||||
case VisualGeometryType.WALL_MIDDLE_3D:
|
||||
Sidedef cs = side.GetControlLinedef().Front;
|
||||
OffsetX = UDMFTools.GetFloat(cs.Fields, "offsetx_mid");
|
||||
OffsetY = UDMFTools.GetFloat(cs.Fields, "offsety_mid");
|
||||
ScaleX = UDMFTools.GetFloat(cs.Fields, "scalex_mid", 1.0f);
|
||||
ScaleY = UDMFTools.GetFloat(cs.Fields, "scaley_mid", 1.0f);
|
||||
break;
|
||||
|
||||
case VisualGeometryType.WALL_LOWER:
|
||||
OffsetX = UDMFTools.GetFloat(side.Sidedef.Fields, "offsetx_bottom");
|
||||
OffsetY = UDMFTools.GetFloat(side.Sidedef.Fields, "offsety_bottom");
|
||||
ScaleX = UDMFTools.GetFloat(side.Sidedef.Fields, "scalex_bottom", 1.0f);
|
||||
ScaleY = UDMFTools.GetFloat(side.Sidedef.Fields, "scaley_bottom", 1.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
NextSides = new Dictionary<SortedVisualSide, bool>();
|
||||
PreviousSides = new Dictionary<SortedVisualSide, bool>();
|
||||
}
|
||||
|
||||
internal void OnTextureFit(FitTextureOptions options)
|
||||
{
|
||||
options.Bounds = Bounds;
|
||||
options.InitialOffsetX = OffsetX;
|
||||
options.InitialOffsetY = OffsetY;
|
||||
options.InitialScaleX = ScaleX;
|
||||
options.InitialScaleY = ScaleY;
|
||||
|
||||
Side.OnTextureFit(options);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class BuilderModesTools
|
||||
{
|
||||
#region ================== Sidedef
|
||||
|
||||
internal static Rectangle GetSidedefPartSize(BaseVisualGeometrySidedef side, VisualGeometryType type)
|
||||
internal static Rectangle GetSidedefPartSize(BaseVisualGeometrySidedef side)
|
||||
{
|
||||
if(type == VisualGeometryType.WALL_MIDDLE_3D)
|
||||
if(side.GeometryType == VisualGeometryType.WALL_MIDDLE_3D)
|
||||
{
|
||||
Rectangle rect = new Rectangle(0, 0, 1, 0);
|
||||
Rectangle rect = new Rectangle(0, 0, Math.Max(1, (int)Math.Round(side.Sidedef.Line.Length)), 0);
|
||||
Linedef cl = side.GetControlLinedef();
|
||||
|
||||
if(cl.Front != null && cl.Front.Sector != null)
|
||||
{
|
||||
// Use ceiling height for vavoom-type 3d floors. Also, FloorHeight is > CeilHeight for these...
|
||||
// Use floor height for vavoom-type 3d floors, because FloorHeight should be > CeilHeight for this type of 3d floor.
|
||||
if (cl.Args[1] == 0)
|
||||
{
|
||||
rect.Y = cl.Front.Sector.CeilHeight;
|
||||
rect.Y = -cl.Front.Sector.FloorHeight;
|
||||
rect.Height = cl.Front.Sector.FloorHeight - cl.Front.Sector.CeilHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.Y = cl.Front.Sector.FloorHeight;
|
||||
rect.Y = -cl.Front.Sector.CeilHeight;
|
||||
rect.Height = cl.Front.GetMiddleHeight();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.Y = side.Sidedef.Sector.FloorHeight;
|
||||
rect.Y = -side.Sidedef.Sector.CeilHeight;
|
||||
rect.Height = side.Sidedef.GetMiddleHeight();
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return GetSidedefPartSize(side.Sidedef, type);
|
||||
return GetSidedefPartSize(side.Sidedef, side.GeometryType);
|
||||
}
|
||||
|
||||
public static Rectangle GetSidedefPartSize(Sidedef side, VisualGeometryType type)
|
||||
{
|
||||
Rectangle rect = new Rectangle(0, 0, 1, 0);
|
||||
Rectangle rect = new Rectangle(0, 0, Math.Max(1, (int)Math.Round(side.Line.Length)), 0);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case VisualGeometryType.WALL_LOWER:
|
||||
rect.Y = side.Sector.FloorHeight;
|
||||
rect.Height = side.GetLowHeight();
|
||||
break;
|
||||
|
||||
case VisualGeometryType.WALL_UPPER:
|
||||
if(side.Other != null && side.Other.Sector != null)
|
||||
if (side.LowRequired())
|
||||
{
|
||||
rect.Y = side.Other.Sector.CeilHeight;
|
||||
rect.Height = side.GetHighHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.Height = 0;
|
||||
rect.Y = -side.Other.Sector.FloorHeight;
|
||||
rect.Height = side.GetLowHeight();
|
||||
}
|
||||
break;
|
||||
|
||||
case VisualGeometryType.WALL_UPPER:
|
||||
if(side.HighRequired())
|
||||
{
|
||||
rect.Y = -side.Sector.CeilHeight;
|
||||
rect.Height = side.GetHighHeight();
|
||||
}
|
||||
break;
|
||||
|
||||
case VisualGeometryType.WALL_MIDDLE:
|
||||
rect.Y = side.Sector.FloorHeight;
|
||||
if(side.MiddleRequired())
|
||||
{
|
||||
rect.Y = -side.Sector.CeilHeight;
|
||||
}
|
||||
else if (side.Other.Sector != null) // Double-sided
|
||||
{
|
||||
rect.Y = -Math.Min(side.Sector.CeilHeight, side.Other.Sector.CeilHeight);
|
||||
}
|
||||
rect.Height = side.GetMiddleHeight();
|
||||
break;
|
||||
|
||||
|
@ -81,6 +173,124 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
return rect;
|
||||
}
|
||||
|
||||
public static List<SortedVisualSide> SortVisualSides(IEnumerable<BaseVisualGeometrySidedef> tosort)
|
||||
{
|
||||
List<SortedVisualSide> result = new List<SortedVisualSide>();
|
||||
|
||||
// Sort by texture
|
||||
Dictionary<long, List<BaseVisualGeometrySidedef>> sidesbytexture = new Dictionary<long, List<BaseVisualGeometrySidedef>>();
|
||||
foreach (BaseVisualGeometrySidedef side in tosort)
|
||||
{
|
||||
long texturelong;
|
||||
if (side is VisualLower) texturelong = side.Sidedef.LongLowTexture;
|
||||
else if (side is VisualUpper) texturelong = side.Sidedef.LongHighTexture;
|
||||
else texturelong = side.Sidedef.LongMiddleTexture;
|
||||
|
||||
if(texturelong == MapSet.EmptyLongName) continue; //not interested...
|
||||
|
||||
if(!sidesbytexture.ContainsKey(texturelong)) sidesbytexture.Add(texturelong, new List<BaseVisualGeometrySidedef>());
|
||||
sidesbytexture[texturelong].Add(side);
|
||||
}
|
||||
|
||||
// Connect sides
|
||||
foreach (KeyValuePair<long, List<BaseVisualGeometrySidedef>> pair in sidesbytexture)
|
||||
{
|
||||
IEnumerable<SortedVisualSide> group = ConnectSides(pair.Value);
|
||||
result.AddRange(group);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Connect sides, left to right
|
||||
// NextSides - sides connected to the right (Start) vertex,
|
||||
// PreviousSides - sides connected to the left (End) vertex
|
||||
private static IEnumerable<SortedVisualSide> ConnectSides(List<BaseVisualGeometrySidedef> allsides)
|
||||
{
|
||||
List<SortedVisualSide> result = new List<SortedVisualSide>();
|
||||
List<SortedVisualSide> sides = new List<SortedVisualSide>(allsides.Count);
|
||||
foreach (BaseVisualGeometrySidedef side in allsides)
|
||||
{
|
||||
sides.Add(new SortedVisualSide(side));
|
||||
}
|
||||
|
||||
foreach(SortedVisualSide curside in sides)
|
||||
{
|
||||
// Find sides connected to the end of curside
|
||||
foreach(SortedVisualSide nextside in sides)
|
||||
{
|
||||
if(curside.Index == nextside.Index) continue;
|
||||
if(nextside.Start == curside.End && nextside.End != curside.Start)
|
||||
{
|
||||
// Add both ways
|
||||
if(!nextside.PreviousSides.ContainsKey(curside)) nextside.PreviousSides.Add(curside, false);
|
||||
if(!curside.NextSides.ContainsKey(nextside)) curside.NextSides.Add(nextside, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Find sides connected to the start of curside
|
||||
foreach(SortedVisualSide prevside in sides)
|
||||
{
|
||||
if(curside.Index == prevside.Index) continue;
|
||||
if(prevside.End == curside.Start && prevside.Start != curside.End)
|
||||
{
|
||||
// Add both ways
|
||||
if(!prevside.NextSides.ContainsKey(curside)) prevside.NextSides.Add(curside, false);
|
||||
if(!curside.PreviousSides.ContainsKey(prevside)) curside.PreviousSides.Add(prevside, false);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(curside);
|
||||
}
|
||||
|
||||
// Try to find the left-most side
|
||||
SortedVisualSide start = result[0];
|
||||
foreach (SortedVisualSide side in result)
|
||||
{
|
||||
if (side.PreviousSides.Count == 0)
|
||||
{
|
||||
start = side;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set horizontal offsets...
|
||||
ApplyHorizontalOffset(start, null, true, new Dictionary<int, bool>());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void ApplyHorizontalOffset(SortedVisualSide side, SortedVisualSide prevside, bool forward, Dictionary<int, bool> processed)
|
||||
{
|
||||
// Set offset
|
||||
if (!processed.ContainsKey(side.Index))
|
||||
{
|
||||
if (prevside != null)
|
||||
{
|
||||
if (forward)
|
||||
side.Bounds.X = prevside.Bounds.X + (int)Math.Round(prevside.Side.Sidedef.Line.Length);
|
||||
else
|
||||
side.Bounds.X = prevside.Bounds.X - (int)Math.Round(side.Side.Sidedef.Line.Length);
|
||||
}
|
||||
|
||||
processed.Add(side.Index, false);
|
||||
}
|
||||
|
||||
// Repeat for NextSides
|
||||
foreach (KeyValuePair<SortedVisualSide, bool> pair in side.NextSides)
|
||||
{
|
||||
if (!processed.ContainsKey(pair.Key.Index))
|
||||
ApplyHorizontalOffset(pair.Key, side, true, processed);
|
||||
}
|
||||
|
||||
// Repeat for PreviousSides
|
||||
foreach(KeyValuePair<SortedVisualSide, bool> pair in side.PreviousSides)
|
||||
{
|
||||
if(!processed.ContainsKey(pair.Key.Index))
|
||||
ApplyHorizontalOffset(pair.Key, side, false, processed);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
257
Source/Plugins/BuilderModes/Interface/FitTexturesForm.Designer.cs
generated
Normal file
|
@ -0,0 +1,257 @@
|
|||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
partial class FitTexturesForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) {
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent() {
|
||||
this.labelhorizrepeat = new System.Windows.Forms.Label();
|
||||
this.repeatgroup = new System.Windows.Forms.GroupBox();
|
||||
this.labelvertrepeat = new System.Windows.Forms.Label();
|
||||
this.horizrepeat = new System.Windows.Forms.NumericUpDown();
|
||||
this.vertrepeat = new System.Windows.Forms.NumericUpDown();
|
||||
this.resethoriz = new System.Windows.Forms.Button();
|
||||
this.resetvert = new System.Windows.Forms.Button();
|
||||
this.cbfitwidth = new System.Windows.Forms.CheckBox();
|
||||
this.accept = new System.Windows.Forms.Button();
|
||||
this.cancel = new System.Windows.Forms.Button();
|
||||
this.cbfitheight = new System.Windows.Forms.CheckBox();
|
||||
this.cbfitconnected = new System.Windows.Forms.CheckBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.repeatgroup.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.horizrepeat)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.vertrepeat)).BeginInit();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// labelhorizrepeat
|
||||
//
|
||||
this.labelhorizrepeat.AutoSize = true;
|
||||
this.labelhorizrepeat.Location = new System.Drawing.Point(23, 26);
|
||||
this.labelhorizrepeat.Name = "labelhorizrepeat";
|
||||
this.labelhorizrepeat.Size = new System.Drawing.Size(57, 13);
|
||||
this.labelhorizrepeat.TabIndex = 0;
|
||||
this.labelhorizrepeat.Text = "Horizontal:";
|
||||
//
|
||||
// repeatgroup
|
||||
//
|
||||
this.repeatgroup.Controls.Add(this.resetvert);
|
||||
this.repeatgroup.Controls.Add(this.resethoriz);
|
||||
this.repeatgroup.Controls.Add(this.vertrepeat);
|
||||
this.repeatgroup.Controls.Add(this.horizrepeat);
|
||||
this.repeatgroup.Controls.Add(this.labelvertrepeat);
|
||||
this.repeatgroup.Controls.Add(this.labelhorizrepeat);
|
||||
this.repeatgroup.Location = new System.Drawing.Point(12, 107);
|
||||
this.repeatgroup.Name = "repeatgroup";
|
||||
this.repeatgroup.Size = new System.Drawing.Size(183, 80);
|
||||
this.repeatgroup.TabIndex = 1;
|
||||
this.repeatgroup.TabStop = false;
|
||||
this.repeatgroup.Text = " Texture Repeating ";
|
||||
//
|
||||
// labelvertrepeat
|
||||
//
|
||||
this.labelvertrepeat.AutoSize = true;
|
||||
this.labelvertrepeat.Location = new System.Drawing.Point(33, 52);
|
||||
this.labelvertrepeat.Name = "labelvertrepeat";
|
||||
this.labelvertrepeat.Size = new System.Drawing.Size(45, 13);
|
||||
this.labelvertrepeat.TabIndex = 1;
|
||||
this.labelvertrepeat.Text = "Vertical:";
|
||||
//
|
||||
// horizrepeat
|
||||
//
|
||||
this.horizrepeat.Location = new System.Drawing.Point(84, 22);
|
||||
this.horizrepeat.Maximum = new decimal(new int[] {
|
||||
512,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.horizrepeat.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.horizrepeat.Name = "horizrepeat";
|
||||
this.horizrepeat.Size = new System.Drawing.Size(60, 20);
|
||||
this.horizrepeat.TabIndex = 2;
|
||||
this.horizrepeat.Value = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.horizrepeat.ValueChanged += new System.EventHandler(this.repeat_ValueChanged);
|
||||
//
|
||||
// vertrepeat
|
||||
//
|
||||
this.vertrepeat.Location = new System.Drawing.Point(84, 48);
|
||||
this.vertrepeat.Maximum = new decimal(new int[] {
|
||||
512,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.vertrepeat.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.vertrepeat.Name = "vertrepeat";
|
||||
this.vertrepeat.Size = new System.Drawing.Size(60, 20);
|
||||
this.vertrepeat.TabIndex = 3;
|
||||
this.vertrepeat.Value = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.vertrepeat.ValueChanged += new System.EventHandler(this.repeat_ValueChanged);
|
||||
//
|
||||
// resethoriz
|
||||
//
|
||||
this.resethoriz.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset;
|
||||
this.resethoriz.Location = new System.Drawing.Point(150, 20);
|
||||
this.resethoriz.Name = "resethoriz";
|
||||
this.resethoriz.Size = new System.Drawing.Size(24, 24);
|
||||
this.resethoriz.TabIndex = 4;
|
||||
this.resethoriz.UseVisualStyleBackColor = true;
|
||||
this.resethoriz.Click += new System.EventHandler(this.resethoriz_Click);
|
||||
//
|
||||
// resetvert
|
||||
//
|
||||
this.resetvert.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset;
|
||||
this.resetvert.Location = new System.Drawing.Point(150, 46);
|
||||
this.resetvert.Name = "resetvert";
|
||||
this.resetvert.Size = new System.Drawing.Size(24, 24);
|
||||
this.resetvert.TabIndex = 5;
|
||||
this.resetvert.UseVisualStyleBackColor = true;
|
||||
this.resetvert.Click += new System.EventHandler(this.resetvert_Click);
|
||||
//
|
||||
// cbfitwidth
|
||||
//
|
||||
this.cbfitwidth.AutoSize = true;
|
||||
this.cbfitwidth.Location = new System.Drawing.Point(10, 19);
|
||||
this.cbfitwidth.Name = "cbfitwidth";
|
||||
this.cbfitwidth.Size = new System.Drawing.Size(65, 17);
|
||||
this.cbfitwidth.TabIndex = 2;
|
||||
this.cbfitwidth.Text = "Fit width";
|
||||
this.cbfitwidth.UseVisualStyleBackColor = true;
|
||||
this.cbfitwidth.CheckedChanged += new System.EventHandler(this.cbfitwidth_CheckedChanged);
|
||||
//
|
||||
// accept
|
||||
//
|
||||
this.accept.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.accept.Location = new System.Drawing.Point(106, 194);
|
||||
this.accept.Name = "accept";
|
||||
this.accept.Size = new System.Drawing.Size(88, 24);
|
||||
this.accept.TabIndex = 6;
|
||||
this.accept.Text = "Apply";
|
||||
this.accept.UseVisualStyleBackColor = true;
|
||||
this.accept.Click += new System.EventHandler(this.accept_Click);
|
||||
//
|
||||
// cancel
|
||||
//
|
||||
this.cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.cancel.Location = new System.Drawing.Point(12, 194);
|
||||
this.cancel.Name = "cancel";
|
||||
this.cancel.Size = new System.Drawing.Size(88, 24);
|
||||
this.cancel.TabIndex = 7;
|
||||
this.cancel.Text = "Cancel";
|
||||
this.cancel.UseVisualStyleBackColor = true;
|
||||
this.cancel.Click += new System.EventHandler(this.cancel_Click);
|
||||
//
|
||||
// cbfitheight
|
||||
//
|
||||
this.cbfitheight.AutoSize = true;
|
||||
this.cbfitheight.Location = new System.Drawing.Point(10, 42);
|
||||
this.cbfitheight.Name = "cbfitheight";
|
||||
this.cbfitheight.Size = new System.Drawing.Size(69, 17);
|
||||
this.cbfitheight.TabIndex = 8;
|
||||
this.cbfitheight.Text = "Fit height";
|
||||
this.cbfitheight.UseVisualStyleBackColor = true;
|
||||
this.cbfitheight.CheckedChanged += new System.EventHandler(this.cbfitheight_CheckedChanged);
|
||||
//
|
||||
// cbfitconnected
|
||||
//
|
||||
this.cbfitconnected.AutoSize = true;
|
||||
this.cbfitconnected.Location = new System.Drawing.Point(10, 65);
|
||||
this.cbfitconnected.Name = "cbfitconnected";
|
||||
this.cbfitconnected.Size = new System.Drawing.Size(168, 17);
|
||||
this.cbfitconnected.TabIndex = 9;
|
||||
this.cbfitconnected.Text = "Fit across connected surfaces";
|
||||
this.cbfitconnected.UseVisualStyleBackColor = true;
|
||||
this.cbfitconnected.CheckedChanged += new System.EventHandler(this.repeat_ValueChanged);
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.cbfitwidth);
|
||||
this.groupBox2.Controls.Add(this.cbfitconnected);
|
||||
this.groupBox2.Controls.Add(this.cbfitheight);
|
||||
this.groupBox2.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(183, 89);
|
||||
this.groupBox2.TabIndex = 10;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = " Options ";
|
||||
//
|
||||
// FitTexturesForm
|
||||
//
|
||||
this.AcceptButton = this.accept;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(206, 223);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.cancel);
|
||||
this.Controls.Add(this.accept);
|
||||
this.Controls.Add(this.repeatgroup);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "FitTexturesForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Fit Textures";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FitTexturesForm_FormClosing);
|
||||
this.repeatgroup.ResumeLayout(false);
|
||||
this.repeatgroup.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.horizrepeat)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.vertrepeat)).EndInit();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label labelhorizrepeat;
|
||||
private System.Windows.Forms.GroupBox repeatgroup;
|
||||
private System.Windows.Forms.Button resethoriz;
|
||||
private System.Windows.Forms.NumericUpDown vertrepeat;
|
||||
private System.Windows.Forms.NumericUpDown horizrepeat;
|
||||
private System.Windows.Forms.Label labelvertrepeat;
|
||||
private System.Windows.Forms.Button resetvert;
|
||||
private System.Windows.Forms.CheckBox cbfitwidth;
|
||||
private System.Windows.Forms.Button accept;
|
||||
private System.Windows.Forms.Button cancel;
|
||||
private System.Windows.Forms.CheckBox cbfitheight;
|
||||
private System.Windows.Forms.CheckBox cbfitconnected;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
}
|
||||
}
|
271
Source/Plugins/BuilderModes/Interface/FitTexturesForm.cs
Normal file
|
@ -0,0 +1,271 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Forms;
|
||||
using CodeImp.DoomBuilder.Windows;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
internal struct FitTextureOptions
|
||||
{
|
||||
public int HorizontalRepeat;
|
||||
public int VerticalRepeat;
|
||||
public bool FitWidth;
|
||||
public bool FitHeight;
|
||||
public bool FitAcrossSurfaces;
|
||||
public Rectangle GlobalBounds;
|
||||
public Rectangle Bounds;
|
||||
|
||||
//Initial texture coordinats
|
||||
public float InitialOffsetX;
|
||||
public float InitialOffsetY;
|
||||
public float InitialScaleX;
|
||||
public float InitialScaleY;
|
||||
}
|
||||
|
||||
internal partial class FitTexturesForm : DelayedForm
|
||||
{
|
||||
#region ================== Event handlers
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
private static Point location = Point.Empty;
|
||||
private bool blockupdate;
|
||||
|
||||
// Settings
|
||||
private static int horizontalrepeat = 1;
|
||||
private static int verticalrepeat = 1;
|
||||
private static bool fitacrosssurfaces = true;
|
||||
private static bool fitwidth = true;
|
||||
private static bool fitheight = true;
|
||||
|
||||
//Surface stuff
|
||||
private List<SortedVisualSide> strips;
|
||||
private Rectangle bounds;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor
|
||||
|
||||
public FitTexturesForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!location.IsEmpty)
|
||||
{
|
||||
this.StartPosition = FormStartPosition.Manual;
|
||||
this.Location = location;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
public void Setup(IEnumerable<BaseVisualGeometrySidedef> sides)
|
||||
{
|
||||
// Get shapes
|
||||
strips = BuilderModesTools.SortVisualSides(sides);
|
||||
|
||||
// No dice...
|
||||
if(strips.Count == 0)
|
||||
{
|
||||
General.Interface.DisplayStatus(StatusType.Warning, "Failed to setup sidedef chains...");
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create bounds
|
||||
int minx = int.MaxValue;
|
||||
int maxx = int.MinValue;
|
||||
int miny = int.MaxValue;
|
||||
int maxy = int.MinValue;
|
||||
|
||||
foreach(SortedVisualSide side in strips)
|
||||
{
|
||||
if(side.Bounds.X < minx) minx = side.Bounds.X;
|
||||
if(side.Bounds.X + side.Bounds.Width > maxx) maxx = side.Bounds.X + side.Bounds.Width;
|
||||
if(side.Bounds.Y < miny) miny = side.Bounds.Y;
|
||||
if(side.Bounds.Y + side.Bounds.Height > maxy) maxy = side.Bounds.Y + side.Bounds.Height;
|
||||
}
|
||||
|
||||
bounds = new Rectangle(minx, miny, maxx-minx, maxy-miny);
|
||||
|
||||
// Normalize Y-offset
|
||||
foreach (SortedVisualSide side in strips) side.Bounds.Y -= bounds.Y;
|
||||
bounds.Y = 0;
|
||||
|
||||
#if DEBUG
|
||||
//debug
|
||||
DrawDebugUV();
|
||||
#endif
|
||||
|
||||
// Restore settings
|
||||
blockupdate = true;
|
||||
|
||||
horizrepeat.Value = horizontalrepeat;
|
||||
vertrepeat.Value = verticalrepeat;
|
||||
cbfitconnected.Checked = fitacrosssurfaces;
|
||||
cbfitwidth.Checked = fitwidth;
|
||||
cbfitheight.Checked = fitheight;
|
||||
UpdateRepeatGroup();
|
||||
|
||||
blockupdate = false;
|
||||
|
||||
//trigger update
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void UpdateChanges()
|
||||
{
|
||||
// Apply changes
|
||||
FitTextureOptions options = new FitTextureOptions
|
||||
{
|
||||
GlobalBounds = bounds,
|
||||
FitAcrossSurfaces = cbfitconnected.Checked,
|
||||
FitWidth = cbfitwidth.Checked,
|
||||
FitHeight = cbfitheight.Checked,
|
||||
HorizontalRepeat = (int)horizrepeat.Value,
|
||||
VerticalRepeat = (int)vertrepeat.Value
|
||||
};
|
||||
|
||||
foreach(SortedVisualSide side in strips) side.OnTextureFit(options);
|
||||
}
|
||||
|
||||
private void UpdateRepeatGroup()
|
||||
{
|
||||
// Disable whole group?
|
||||
repeatgroup.Enabled = cbfitwidth.Checked || cbfitheight.Checked;
|
||||
if(!repeatgroup.Enabled) return;
|
||||
|
||||
// Update control status
|
||||
labelhorizrepeat.Enabled = cbfitwidth.Checked;
|
||||
horizrepeat.Enabled = cbfitwidth.Checked;
|
||||
resethoriz.Enabled = cbfitwidth.Checked;
|
||||
|
||||
labelvertrepeat.Enabled = cbfitheight.Checked;
|
||||
vertrepeat.Enabled = cbfitheight.Checked;
|
||||
resetvert.Enabled = cbfitheight.Checked;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Events
|
||||
|
||||
private void FitTexturesForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
location = this.Location;
|
||||
|
||||
// Store settings
|
||||
if (this.DialogResult == DialogResult.OK)
|
||||
{
|
||||
horizontalrepeat = (int)horizrepeat.Value;
|
||||
verticalrepeat = (int)vertrepeat.Value;
|
||||
fitacrosssurfaces = cbfitwidth.Checked;
|
||||
fitwidth = cbfitwidth.Checked;
|
||||
fitheight = cbfitheight.Checked;
|
||||
}
|
||||
}
|
||||
|
||||
private void resethoriz_Click(object sender, EventArgs e)
|
||||
{
|
||||
horizrepeat.Value = 1;
|
||||
}
|
||||
|
||||
private void resetvert_Click(object sender, EventArgs e)
|
||||
{
|
||||
vertrepeat.Value = 1;
|
||||
}
|
||||
|
||||
private void repeat_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
if(blockupdate) return;
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void accept_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void cancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void cbfitwidth_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if(blockupdate) return;
|
||||
UpdateRepeatGroup();
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
private void cbfitheight_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if(blockupdate) return;
|
||||
UpdateRepeatGroup();
|
||||
UpdateChanges();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Debug
|
||||
|
||||
#if DEBUG
|
||||
private void DrawDebugUV()
|
||||
{
|
||||
const int margin = 20;
|
||||
|
||||
//find bounds
|
||||
int minx = int.MaxValue;
|
||||
int maxx = int.MinValue;
|
||||
int miny = int.MaxValue;
|
||||
int maxy = int.MinValue;
|
||||
|
||||
foreach(SortedVisualSide side in strips)
|
||||
{
|
||||
if(side.Bounds.X < minx) minx = side.Bounds.X;
|
||||
if(side.Bounds.X + side.Bounds.Width > maxx) maxx = side.Bounds.X + side.Bounds.Width;
|
||||
if(side.Bounds.Y < miny) miny = side.Bounds.Y;
|
||||
if(side.Bounds.Y + side.Bounds.Height > maxy) maxy = side.Bounds.Y + side.Bounds.Height;
|
||||
}
|
||||
|
||||
Bitmap bmp = new Bitmap(maxx - minx + margin * 2, maxy - miny + margin * 2);
|
||||
|
||||
using(Graphics g = Graphics.FromImage(bmp))
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
foreach(SortedVisualSide side in strips)
|
||||
{
|
||||
Color c = General.Colors.BrightColors[General.Random(0, General.Colors.BrightColors.Length - 1)].ToColor();
|
||||
Pen p = new Pen(c);
|
||||
Brush b = new SolidBrush(c);
|
||||
|
||||
int x = side.Bounds.X - minx + margin;
|
||||
int y = side.Bounds.Y - miny + margin;
|
||||
|
||||
g.DrawRectangle(p, x, y, side.Bounds.Width, side.Bounds.Height);
|
||||
g.DrawString(i++ + ": line " + side.Side.Sidedef.Line.Index + "; x:" + side.Bounds.X + " y:" + side.Bounds.Y, this.Font, b, x + 2, y + 2);
|
||||
}
|
||||
}
|
||||
|
||||
bmp.Save("testuv.png", ImageFormat.Png);
|
||||
|
||||
General.Interface.DisplayStatus(StatusType.Info, "Saved test image!");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
120
Source/Plugins/BuilderModes/Interface/FitTexturesForm.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?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>
|
||||
</root>
|
|
@ -908,39 +908,15 @@ visualautoaligntoselectiony
|
|||
//mxd
|
||||
visualfittextures
|
||||
{
|
||||
title = "Fit Texture";
|
||||
title = "Fit Textures";
|
||||
category = "visual";
|
||||
description = "Scales texture to match size of selected surface.";
|
||||
description = "Scales textures to match the size of selected surfaces.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
default = 393281; //Ctrl-Alt-A
|
||||
}
|
||||
|
||||
//mxd
|
||||
visualfittexturesx
|
||||
{
|
||||
title = "Fit Texture's Width";
|
||||
category = "visual";
|
||||
description = "Scales width of a texture to match width of selected surface.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
default = 262209; //Alt-A
|
||||
}
|
||||
|
||||
//mxd
|
||||
visualfittexturesy
|
||||
{
|
||||
title = "Fit Texture's Height";
|
||||
category = "visual";
|
||||
description = "Scales height of a texture to match height of selected surface.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
default = 327745; //Alt-Shift-A
|
||||
}
|
||||
|
||||
toggleupperunpegged
|
||||
{
|
||||
title = "Toggle Upper Unpegged";
|
||||
|
@ -986,7 +962,7 @@ resettexture
|
|||
{
|
||||
title = "Reset Texture Offsets";
|
||||
category = "visual";
|
||||
description = "Resets the texture offsets on the targeted or selected sidedef.";
|
||||
description = "Resets the texture offsets on targeted or selected sidedefs.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
|
@ -997,7 +973,7 @@ resettextureudmf
|
|||
{
|
||||
title = "Reset Local Texture Offsets (UDMF)";
|
||||
category = "visual";
|
||||
description = "Resets upper/middle/lower texture offsets and scale on the targeted or selected sidedef. Resets texture offsets, rotation and scale on targeted or selected floors/ceilings.";
|
||||
description = "Resets upper/middle/lower texture offsets and scale on targeted or selected sidedefs. Resets texture offsets, rotation and scale on targeted or selected floors/ceilings.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
|
|
|
@ -129,7 +129,7 @@ group sidedefs
|
|||
"Use <k>buildermodes_texturecopy</k>, <k>buildermodes_texturepaste</k> and <k>buildermodes_floodfilltextures</k> to copy, paste and flood-fill highlighted texture"
|
||||
"Use <k>buildermodes_texturecopyoffsets</k> and <k>buildermodes_texturepasteoffsets</k> to copy and paste texture offsets"
|
||||
"Use <k>buildermodes_visualautoalignx</k>, <k>buildermodes_visualautoalign</k> or <k>buildermodes_visualautoalign</k> to auto align textures on X, Y and XY axis"
|
||||
"Use <k>buildermodes_visualfittexturesx</k>, <k>buildermodes_visualfittexturesy</k> or <k>buildermodes_visualfittextures</k> to fit texture's width, height or both into it's surface (UDMF only)"
|
||||
"Use <k>buildermodes_visualfittextures</k> to fit texture's width or height to selected surfaces (UDMF only)"
|
||||
"Use <k>buildermodes_resettexture</k> to reset global texture offsets"
|
||||
"Use <k>buildermodes_resettextureudmf</k> to reset local texture offsets and scale (UDMF only)"
|
||||
"Use <k>buildermodes_toggleupperunpegged</k> or <k>buildermodes_togglelowerunpegged</k> to toggle Upper or Lower Unpegged setting"
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd
|
||||
|
||||
// This swaps triangles so that the plane faces the other way
|
||||
protected void SwapTriangleVertices(WorldVertex[] verts)
|
||||
protected static void SwapTriangleVertices(WorldVertex[] verts)
|
||||
{
|
||||
// Swap some vertices to flip all triangles
|
||||
for(int i = 0; i < verts.Length; i += 3)
|
||||
|
@ -260,7 +260,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
//do we need to align this? (and also grab texture scale while we are at it)
|
||||
float scaleX, scaleY;
|
||||
bool isFloor = (geoType == VisualGeometryType.FLOOR);
|
||||
bool isFloor = (geometrytype == VisualGeometryType.FLOOR);
|
||||
|
||||
if(mode.HighlightedTarget is VisualFloor)
|
||||
{
|
||||
|
@ -333,7 +333,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
//mxd
|
||||
protected void AlignTextureToSlopeLine(Linedef slopeSource, float slopeAngle, bool isFront, bool alignx, bool aligny)
|
||||
{
|
||||
bool isFloor = (geoType == VisualGeometryType.FLOOR);
|
||||
bool isFloor = (geometrytype == VisualGeometryType.FLOOR);
|
||||
Sector.Sector.Fields.BeforeFieldsChange();
|
||||
float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1);
|
||||
|
||||
|
@ -426,7 +426,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
// Unused
|
||||
public virtual void OnEditBegin() { }
|
||||
public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd
|
||||
public virtual void OnTextureFit(FitTextureOptions options) { } //mxd
|
||||
public virtual void OnToggleUpperUnpegged() { }
|
||||
public virtual void OnToggleLowerUnpegged() { }
|
||||
public virtual void OnResetTextureOffset() { }
|
||||
|
|
|
@ -18,16 +18,16 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Tools;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using CodeImp.DoomBuilder.Types;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
using System.Drawing;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Tools;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
protected readonly BaseVisualMode mode;
|
||||
|
||||
protected Plane top;
|
||||
protected Plane bottom;
|
||||
|
@ -236,7 +236,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
// 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)
|
||||
protected static WallPolygon SplitPoly(ref WallPolygon poly, Plane p, bool keepfront)
|
||||
{
|
||||
const float NEAR_ZERO = 0.01f;
|
||||
WallPolygon front = new WallPolygon(poly.Count);
|
||||
|
@ -312,7 +312,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
|
||||
// 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)
|
||||
protected static void CropPoly(ref WallPolygon poly, Plane p, bool keepfront)
|
||||
{
|
||||
const float NEAR_ZERO = 0.01f;
|
||||
float sideswitch = keepfront ? 1 : -1;
|
||||
|
@ -372,7 +372,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
//mxd
|
||||
protected float GetRoundedTextureOffset(float oldValue, float offset, float scale, float textureSize)
|
||||
protected static float GetRoundedTextureOffset(float oldValue, float offset, float scale, float textureSize)
|
||||
{
|
||||
if(offset == 0f) return oldValue;
|
||||
float scaledOffset = offset * scale;
|
||||
|
@ -383,7 +383,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
//mxd
|
||||
protected void OnTextureChanged()
|
||||
private void OnTextureChanged()
|
||||
{
|
||||
//check for 3d floors
|
||||
if(Sidedef.Line.Action == 160)
|
||||
|
@ -400,7 +400,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//mxd
|
||||
|
@ -408,7 +407,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
if(Sidedef.Sector == null || (!withSameTexture && !withSameHeight)) return;
|
||||
|
||||
Rectangle rect = BuilderModesTools.GetSidedefPartSize(this, geoType);
|
||||
Rectangle rect = BuilderModesTools.GetSidedefPartSize(this);
|
||||
if(rect.Height == 0) return;
|
||||
|
||||
if(select && !selected)
|
||||
|
@ -477,8 +476,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
&& line.Front.HighRequired()
|
||||
&& BuilderModesTools.GetSidedefPartSize(line.Front, VisualGeometryType.WALL_UPPER).IntersectsWith(rect));
|
||||
|
||||
addFrontMiddle = (line.Front.MiddleTexture == texture
|
||||
&& line.Front.MiddleRequired()
|
||||
addFrontMiddle = (line.Front.MiddleTexture == texture
|
||||
&& (line.Front.MiddleRequired() || line.Back != null)
|
||||
&& line.Front.GetMiddleHeight() > 0
|
||||
&& BuilderModesTools.GetSidedefPartSize(line.Front, VisualGeometryType.WALL_MIDDLE).IntersectsWith(rect));
|
||||
|
||||
|
@ -495,7 +494,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
&& BuilderModesTools.GetSidedefPartSize(line.Back, VisualGeometryType.WALL_UPPER).IntersectsWith(rect));
|
||||
|
||||
addBackMiddle = (line.Back.MiddleTexture == texture
|
||||
&& line.Back.MiddleRequired()
|
||||
&& (line.Back.MiddleRequired() || line.Front != null)
|
||||
&& line.Back.GetMiddleHeight() > 0
|
||||
&& BuilderModesTools.GetSidedefPartSize(line.Back, VisualGeometryType.WALL_MIDDLE).IntersectsWith(rect));
|
||||
|
||||
|
@ -600,6 +599,96 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
return selected;
|
||||
}
|
||||
|
||||
//mxd
|
||||
protected void FitTexture(FitTextureOptions options)
|
||||
{
|
||||
// Create undo name
|
||||
string s;
|
||||
if(options.FitWidth && options.FitHeight) s = "width and height";
|
||||
else if(options.FitWidth) s = "width";
|
||||
else s = "height";
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
// Fit width
|
||||
if(options.FitWidth)
|
||||
{
|
||||
float scalex, offsetx;
|
||||
|
||||
if(options.FitAcrossSurfaces)
|
||||
{
|
||||
scalex = Texture.ScaledWidth / (Sidedef.Line.Length * (options.GlobalBounds.Width / Sidedef.Line.Length)) * options.HorizontalRepeat;
|
||||
offsetx = (float)Math.Round((options.Bounds.X * scalex - Sidedef.OffsetX) % Texture.Width, General.Map.FormatInterface.VertexDecimals);
|
||||
}
|
||||
else
|
||||
{
|
||||
scalex = Texture.ScaledWidth / Sidedef.Line.Length * options.HorizontalRepeat;
|
||||
offsetx = -Sidedef.OffsetX;
|
||||
}
|
||||
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scalex_" + partname, (float)Math.Round(scalex, General.Map.FormatInterface.VertexDecimals), 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsetx_" + partname, offsetx, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore initial offsets
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scalex_" + partname, options.InitialScaleX, 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsetx_" + partname, options.InitialOffsetX, 0.0f);
|
||||
}
|
||||
|
||||
// Fit height
|
||||
if(options.FitHeight)
|
||||
{
|
||||
if(Sidedef.Sector != null)
|
||||
{
|
||||
float scaley, offsety;
|
||||
|
||||
if(options.FitAcrossSurfaces)
|
||||
{
|
||||
scaley = Texture.ScaledHeight / (options.Bounds.Height * ((float)options.GlobalBounds.Height / options.Bounds.Height)) * options.VerticalRepeat;
|
||||
|
||||
if(this is VisualLower) // Special cases, special cases...
|
||||
{
|
||||
offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, -Sidedef.OffsetY, scaley, true) % Texture.Height;
|
||||
}
|
||||
else if(this is VisualMiddleDouble)
|
||||
{
|
||||
if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
//offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, options.Bounds.Y * scaley - Sidedef.OffsetY, scaley, true) - (options.Bounds.Height + Sidedef.GetHighHeight()) * scaley;
|
||||
offsety = (options.Bounds.Y - /*options.Bounds.Height -*/ Sidedef.GetHighHeight()) * scaley - Sidedef.OffsetY;
|
||||
//offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, offsety, scaley, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
offsety = options.Bounds.Y * scaley - Sidedef.OffsetY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, options.Bounds.Y * scaley - Sidedef.OffsetY, scaley, true) % Texture.Height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scaley = Texture.ScaledHeight / options.Bounds.Height * options.VerticalRepeat;
|
||||
offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, -Sidedef.OffsetY, scaley, true) % Texture.Height;
|
||||
}
|
||||
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_" + partname, (float)Math.Round(scaley, General.Map.FormatInterface.VertexDecimals), 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_" + partname, (float)Math.Round(offsety, General.Map.FormatInterface.VertexDecimals), 0.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore initial offsets
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_" + partname, options.InitialScaleY, 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_" + partname, options.InitialOffsetY, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -615,7 +704,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
protected abstract void MoveTextureOffset(Point xy);
|
||||
protected abstract Point GetTextureOffset();
|
||||
public virtual void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd
|
||||
public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd
|
||||
public virtual void OnTextureFit(FitTextureOptions options) { } //mxd
|
||||
|
||||
// Insert middle texture
|
||||
public virtual void OnInsert()
|
||||
|
@ -1178,6 +1267,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
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;
|
||||
|
||||
//mxd. Modify by surface scale?
|
||||
if (General.Map.UDMF)
|
||||
{
|
||||
float sx = UDMFTools.GetFloat(Sidedef.Fields, "scalex_" + partname, 1.0f);
|
||||
float sy = UDMFTools.GetFloat(Sidedef.Fields, "scaley_" + partname, 1.0f);
|
||||
if (Math.Abs(sx) < 1) offsetx *= sx;
|
||||
if (Math.Abs(sy) < 1) offsety *= sy;
|
||||
}
|
||||
|
||||
// Apply offsets
|
||||
if(General.Interface.CtrlState && General.Interface.ShiftState)
|
||||
|
@ -1226,7 +1324,33 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Sector brightness change
|
||||
public virtual void OnChangeTargetBrightness(bool up)
|
||||
{
|
||||
if(!Sector.Changed)
|
||||
//mxd. Change UDMF wall light?
|
||||
if (General.Map.UDMF)
|
||||
{
|
||||
int light = Sidedef.Fields.GetValue("light", 0);
|
||||
bool absolute = Sidedef.Fields.GetValue("lightabsolute", false);
|
||||
int newLight;
|
||||
|
||||
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 wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
//apply changes
|
||||
Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight);
|
||||
mode.SetActionResult("Changed wall brightness to " + newLight + ".");
|
||||
Sector.Sector.UpdateCache();
|
||||
|
||||
//rebuild sector
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
else if(!Sector.Changed)
|
||||
{
|
||||
// Change brightness
|
||||
mode.CreateUndo("Change sector brightness", UndoGroup.SectorBrightnessChange, Sector.Sector.FixedIndex);
|
||||
|
@ -1279,7 +1403,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
Sidedef.OffsetX = (Sidedef.OffsetX - horizontal);
|
||||
if (Texture != null) Sidedef.OffsetX %= Texture.Width;
|
||||
Sidedef.OffsetY = (Sidedef.OffsetY - vertical);
|
||||
if(geoType != VisualGeometryType.WALL_MIDDLE && Texture != null) Sidedef.OffsetY %= Texture.Height;
|
||||
if(geometrytype != VisualGeometryType.WALL_MIDDLE && Texture != null) Sidedef.OffsetY %= Texture.Height;
|
||||
|
||||
mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
|
||||
}
|
||||
|
|
|
@ -294,8 +294,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
selectionchanged = false;
|
||||
|
||||
if(singleselection)
|
||||
ClearSelection();
|
||||
if(singleselection) ClearSelection();
|
||||
|
||||
UpdateChangedObjects();
|
||||
ShowTargetInfo();
|
||||
|
@ -2115,11 +2114,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
foreach(BaseVisualThing vt in things)
|
||||
{
|
||||
if(vt.Thing.Sector == null) continue;
|
||||
ThingTypeInfo ti = General.Map.Data.GetThingInfo(vt.Thing.Type);
|
||||
int zvalue = (int)(vt.Thing.Sector.FloorHeight + vt.Thing.Position.z);
|
||||
|
||||
if(zvalue != vt.Thing.Sector.CeilHeight - ti.Height)
|
||||
vt.OnChangeTargetHeight((int)(vt.Thing.Sector.CeilHeight - ti.Height) - zvalue);
|
||||
if (vt.Info.Hangs)
|
||||
{
|
||||
vt.OnMove(new Vector3D(vt.Thing.Position, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
vt.OnMove(new Vector3D(vt.Thing.Position, vt.Thing.Sector.CeilHeight - vt.Info.Height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2327,8 +2330,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
{
|
||||
if(vt.Thing.Sector == null) continue;
|
||||
|
||||
if(vt.Thing.Position.z != 0)
|
||||
vt.OnChangeTargetHeight((int)-vt.Thing.Position.z);
|
||||
if (vt.Info.Hangs)
|
||||
{
|
||||
vt.OnMove(new Vector3D(vt.Thing.Position, vt.Thing.Sector.CeilHeight - vt.Thing.Sector.FloorHeight - vt.Info.Height));
|
||||
}
|
||||
else
|
||||
{
|
||||
vt.OnMove(new Vector3D(vt.Thing.Position, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2770,31 +2779,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
//mxd
|
||||
[BeginAction("visualfittextures")]
|
||||
public void TextureFit()
|
||||
private void FitTextures()
|
||||
{
|
||||
PreAction(UndoGroup.None);
|
||||
|
||||
// Get selection
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnTextureFit(true, true);
|
||||
PostAction();
|
||||
}
|
||||
List<BaseVisualGeometrySidedef> sides = new List<BaseVisualGeometrySidedef>();
|
||||
foreach(IVisualEventReceiver side in objs)
|
||||
{
|
||||
if(side is BaseVisualGeometrySidedef) sides.Add(side as BaseVisualGeometrySidedef);
|
||||
}
|
||||
|
||||
//mxd
|
||||
[BeginAction("visualfittexturesx")]
|
||||
public void TextureFitX()
|
||||
{
|
||||
PreAction(UndoGroup.None);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnTextureFit(true, false);
|
||||
PostAction();
|
||||
}
|
||||
if(sides.Count == 0)
|
||||
{
|
||||
General.Interface.DisplayStatus(StatusType.Warning, "Fit Textures action requires selected sidedefs.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Show form
|
||||
FitTexturesForm form = new FitTexturesForm();
|
||||
form.Setup(sides);
|
||||
|
||||
// Undo changes?
|
||||
if(form.ShowDialog((Form)General.Interface) == DialogResult.Cancel)
|
||||
General.Map.UndoRedo.WithdrawUndo();
|
||||
|
||||
//mxd
|
||||
[BeginAction("visualfittexturesy")]
|
||||
public void TextureFitY()
|
||||
{
|
||||
PreAction(UndoGroup.None);
|
||||
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
|
||||
foreach(IVisualEventReceiver i in objs) i.OnTextureFit(false, true);
|
||||
PostAction();
|
||||
}
|
||||
|
||||
|
@ -3698,15 +3708,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
else
|
||||
{
|
||||
offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY, true);
|
||||
offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height;
|
||||
|
||||
//mxd. Clamp offset if this part is middle single or wrapped middle double
|
||||
if(j.sidedef.Other == null || j.sidedef.IsFlagSet("wrapmidtex") || j.sidedef.Line.IsFlagSet("wrapmidtex"))
|
||||
if(j.sidedef.Other != null && !j.sidedef.IsFlagSet("wrapmidtex") && !j.sidedef.Line.IsFlagSet("wrapmidtex"))
|
||||
{
|
||||
offset %= texture.Height;
|
||||
//mxd. This should be doublesided non-wrapped line. Find the nearset aligned position
|
||||
float curoffset = UDMFTools.GetFloat(j.sidedef.Fields, "offsety_mid");
|
||||
offset += texture.Height * (int)Math.Round((curoffset - offset) / texture.Height);
|
||||
|
||||
// Make sure the surface stays between floor and ceiling
|
||||
if (offset < -texture.Height)
|
||||
{
|
||||
offset += texture.Height;
|
||||
}
|
||||
else if(offset + texture.Height > j.sidedef.GetMiddleHeight())
|
||||
{
|
||||
offset -= texture.Height;
|
||||
}
|
||||
}
|
||||
|
||||
j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);//mxd
|
||||
j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset); //mxd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Variables
|
||||
|
||||
protected BaseVisualMode mode;
|
||||
private readonly BaseVisualMode mode;
|
||||
|
||||
private ThingTypeInfo info;
|
||||
private bool isloaded;
|
||||
|
@ -60,7 +60,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
#region ================== Properties
|
||||
|
||||
public bool Changed { get { return changed; } set { changed |= value; } }
|
||||
|
||||
public ThingTypeInfo Info { get { return info; } } //mxd
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Setup
|
||||
|
@ -473,7 +474,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnProcess(float deltatime) { }
|
||||
public virtual void OnTextureFloodfill() { }
|
||||
public virtual void OnInsert() { }
|
||||
public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd
|
||||
public virtual void OnTextureFit(FitTextureOptions options) { } //mxd
|
||||
public virtual void ApplyTexture(string texture) { }
|
||||
public virtual void ApplyUpperUnpegged(bool set) { }
|
||||
public virtual void ApplyLowerUnpegged(bool set) { }
|
||||
|
@ -572,7 +573,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
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, amount));
|
||||
Thing.Move(Thing.Position + new Vector3D(0.0f, 0.0f, (info.Hangs ? -amount : amount)));
|
||||
|
||||
mode.SetActionResult("Changed thing height to " + Thing.Position.z + ".");
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnCopyTextureOffsets() { }
|
||||
public virtual void OnPasteTextureOffsets() { }
|
||||
public virtual void OnTextureAlign(bool alignx, bool aligny) { }
|
||||
public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd
|
||||
public virtual void OnTextureFit(FitTextureOptions options) { } //mxd
|
||||
public virtual void OnToggleUpperUnpegged() { }
|
||||
public virtual void OnToggleLowerUnpegged() { }
|
||||
public virtual void OnResetTextureOffset() { }
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
void OnCopyProperties();
|
||||
void OnPasteProperties();
|
||||
void OnTextureAlign(bool alignx, bool aligny);
|
||||
void OnTextureFit(bool fitWidth, bool fitHeight); //mxd
|
||||
void OnTextureFit(FitTextureOptions options); //mxd
|
||||
void OnTextureFloodfill();
|
||||
void OnToggleUpperUnpegged();
|
||||
void OnToggleLowerUnpegged();
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public void OnCopyProperties() { }
|
||||
public void OnPasteProperties() { }
|
||||
public void OnTextureAlign(bool alignx, bool aligny) { }
|
||||
public void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd
|
||||
public void OnTextureFit(FitTextureOptions options) { } //mxd
|
||||
public void OnTextureFloodfill() { }
|
||||
public void OnToggleUpperUnpegged() { }
|
||||
public void OnToggleLowerUnpegged() { }
|
||||
|
|
|
@ -54,7 +54,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualCeiling(BaseVisualMode mode, VisualSector vs) : base(mode, vs)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.CEILING;
|
||||
geometrytype = VisualGeometryType.CEILING;
|
||||
partname = "ceiling";
|
||||
|
||||
//mxd
|
||||
if(mode.UseSelectionFromClassicMode && vs != null && vs.Sector.Selected && (General.Map.ViewMode == ViewMode.CeilingTextures || General.Map.ViewMode == ViewMode.Normal))
|
||||
|
|
|
@ -54,7 +54,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualFloor(BaseVisualMode mode, VisualSector vs) : base(mode, vs)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.FLOOR;
|
||||
geometrytype = VisualGeometryType.FLOOR;
|
||||
partname = "floor";
|
||||
|
||||
//mxd
|
||||
if(mode.UseSelectionFromClassicMode && vs != null && vs.Sector.Selected
|
||||
|
@ -243,7 +244,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
mode.SetActionResult("Texture offsets reset.");
|
||||
Sector.Sector.Fields.BeforeFieldsChange();
|
||||
|
||||
string[] keys = new string[] { "xpanningfloor", "ypanningfloor", "xscalefloor", "yscalefloor", "rotationfloor" };
|
||||
string[] keys = new[] { "xpanningfloor", "ypanningfloor", "xscalefloor", "yscalefloor", "rotationfloor" };
|
||||
|
||||
foreach(string key in keys)
|
||||
{
|
||||
|
|
|
@ -51,7 +51,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualLower(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_LOWER;
|
||||
geometrytype = VisualGeometryType.WALL_LOWER;
|
||||
partname = "bottom";
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -302,69 +303,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
//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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnTextureFit(bool fitWidth, bool fitHeight)
|
||||
public override void OnTextureFit(FitTextureOptions options)
|
||||
{
|
||||
if(!General.Map.UDMF) return;
|
||||
if(!Sidedef.LowRequired() || string.IsNullOrEmpty(Sidedef.LowTexture) || Sidedef.LowTexture == "-" || !Texture.IsImageLoaded) return;
|
||||
|
||||
string s;
|
||||
if(fitWidth && fitHeight) s = "width and height";
|
||||
else if(fitWidth) s = "width";
|
||||
else s = "height";
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
if(fitWidth)
|
||||
{
|
||||
float scaleX = Texture.ScaledWidth / Sidedef.Line.Length;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scalex_bottom", scaleX, 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsetx_bottom", -Sidedef.OffsetX, 0.0f);
|
||||
}
|
||||
|
||||
if(fitHeight && Sidedef.Sector != null && Sidedef.Other.Sector != null)
|
||||
{
|
||||
float scaleY = (float)Texture.Height / (Sidedef.Other.Sector.FloorHeight - Sidedef.Sector.FloorHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_bottom", scaleY, 1.0f);
|
||||
|
||||
float offsetY = Tools.GetSidedefBottomOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_bottom", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
FitTexture(options);
|
||||
Setup();
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualMiddle3D(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_MIDDLE_3D;
|
||||
geometrytype = VisualGeometryType.WALL_MIDDLE_3D;
|
||||
partname = "mid";
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
|
|
@ -29,7 +29,8 @@ namespace CodeImp.DoomBuilder.BuilderModes {
|
|||
: base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_MIDDLE;
|
||||
geometrytype = VisualGeometryType.WALL_MIDDLE;
|
||||
partname = "mid";
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -345,39 +346,6 @@ namespace CodeImp.DoomBuilder.BuilderModes {
|
|||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override Linedef GetControlLinedef()
|
||||
{
|
||||
|
|
|
@ -55,7 +55,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualMiddleDouble(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_MIDDLE;
|
||||
geometrytype = VisualGeometryType.WALL_MIDDLE;
|
||||
partname = "mid";
|
||||
|
||||
// Set render pass
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
|
@ -360,69 +361,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
//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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnTextureFit(bool fitWidth, bool fitHeight)
|
||||
public override void OnTextureFit(FitTextureOptions options)
|
||||
{
|
||||
if(!General.Map.UDMF) return;
|
||||
if(string.IsNullOrEmpty(Sidedef.MiddleTexture) || Sidedef.MiddleTexture == "-" || !Texture.IsImageLoaded) return;
|
||||
|
||||
string s;
|
||||
if(fitWidth && fitHeight) s = "width and height";
|
||||
else if(fitWidth) s = "width";
|
||||
else s = "height";
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
if(fitWidth)
|
||||
{
|
||||
float scaleX = Texture.ScaledWidth / Sidedef.Line.Length;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scalex_mid", scaleX, 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsetx_mid", -Sidedef.OffsetX, 0.0f);
|
||||
}
|
||||
|
||||
if(fitHeight && Sidedef.Sector != null)
|
||||
{
|
||||
float scaleY = Texture.ScaledHeight / (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_mid", scaleY, 1.0f);
|
||||
|
||||
float offsetY = Tools.GetSidedefMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_mid", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
FitTexture(options);
|
||||
Setup();
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualMiddleSingle(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_MIDDLE;
|
||||
geometrytype = VisualGeometryType.WALL_MIDDLE;
|
||||
partname = "mid";
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -293,69 +294,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
//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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnTextureFit(bool fitWidth, bool fitHeight)
|
||||
public override void OnTextureFit(FitTextureOptions options)
|
||||
{
|
||||
if(!General.Map.UDMF) return;
|
||||
if(string.IsNullOrEmpty(Sidedef.MiddleTexture) || Sidedef.MiddleTexture == "-" || !Texture.IsImageLoaded) return;
|
||||
|
||||
string s;
|
||||
if(fitWidth && fitHeight) s = "width and height";
|
||||
else if(fitWidth) s = "width";
|
||||
else s = "height";
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
if(fitWidth)
|
||||
{
|
||||
float scaleX = Texture.ScaledWidth / Sidedef.Line.Length;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scalex_mid", scaleX, 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsetx_mid", -Sidedef.OffsetX, 0.0f);
|
||||
}
|
||||
|
||||
if(fitHeight && Sidedef.Sector != null)
|
||||
{
|
||||
float scaleY = Texture.ScaledHeight / (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_mid", scaleY, 1.0f);
|
||||
|
||||
float offsetY = Tools.GetSidedefMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_mid", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
FitTexture(options);
|
||||
Setup();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
internal struct VisualSidedefParts
|
||||
{
|
||||
// Members
|
||||
public VisualUpper upper;
|
||||
public VisualLower lower;
|
||||
public VisualMiddleDouble middledouble;
|
||||
public VisualMiddleSingle middlesingle;
|
||||
public List<VisualMiddle3D> middle3d;
|
||||
public List<VisualMiddleBack> middleback;//mxd
|
||||
public readonly VisualUpper upper;
|
||||
public readonly VisualLower lower;
|
||||
public readonly VisualMiddleDouble middledouble;
|
||||
public readonly VisualMiddleSingle middlesingle;
|
||||
public readonly List<VisualMiddle3D> middle3d;
|
||||
public readonly List<VisualMiddleBack> middleback;//mxd
|
||||
|
||||
// Constructor
|
||||
public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m, List<VisualMiddle3D> e, List<VisualMiddleBack> eb)
|
||||
|
@ -40,7 +40,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
this.middledouble = m;
|
||||
this.middlesingle = null;
|
||||
this.middle3d = e;
|
||||
this.middleback = eb;//mxd
|
||||
this.middleback = eb; //mxd
|
||||
}
|
||||
|
||||
// Constructor
|
||||
|
@ -63,13 +63,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(upper != null) upper.Setup();
|
||||
if(middle3d != null)
|
||||
{
|
||||
foreach(VisualMiddle3D m in middle3d)
|
||||
m.Setup();
|
||||
foreach(VisualMiddle3D m in middle3d) m.Setup();
|
||||
}
|
||||
if(middleback != null)
|
||||
{
|
||||
foreach(VisualMiddleBack m in middleback)
|
||||
m.Setup();
|
||||
foreach(VisualMiddleBack m in middleback) m.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,13 +80,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(upper != null) upper.Selected = false;
|
||||
if(middle3d != null)
|
||||
{
|
||||
foreach(VisualMiddle3D m in middle3d)
|
||||
m.Selected = false;
|
||||
foreach(VisualMiddle3D m in middle3d) m.Selected = false;
|
||||
}
|
||||
if(middleback != null)
|
||||
{
|
||||
foreach(VisualMiddleBack m in middleback)
|
||||
m.Selected = false;
|
||||
foreach(VisualMiddleBack m in middleback) m.Selected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public VisualUpper(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s)
|
||||
{
|
||||
//mxd
|
||||
geoType = VisualGeometryType.WALL_UPPER;
|
||||
geometrytype = VisualGeometryType.WALL_UPPER;
|
||||
partname = "top";
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -293,69 +294,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
//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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//mxd
|
||||
public override void OnTextureFit(bool fitWidth, bool fitHeight)
|
||||
public override void OnTextureFit(FitTextureOptions options)
|
||||
{
|
||||
if(!General.Map.UDMF) return;
|
||||
if(!Sidedef.HighRequired() || string.IsNullOrEmpty(Sidedef.HighTexture) || Sidedef.HighTexture == "-" || !Texture.IsImageLoaded) return;
|
||||
|
||||
string s;
|
||||
if(fitWidth && fitHeight) s = "width and height";
|
||||
else if(fitWidth) s = "width";
|
||||
else s = "height";
|
||||
|
||||
//create undo
|
||||
mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex);
|
||||
Sidedef.Fields.BeforeFieldsChange();
|
||||
|
||||
if(fitWidth)
|
||||
{
|
||||
float scaleX = Texture.ScaledWidth / Sidedef.Line.Length;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scalex_top", scaleX, 1.0f);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsetx_top", -Sidedef.OffsetX, 0.0f);
|
||||
}
|
||||
|
||||
if(fitHeight && Sidedef.Sector != null && Sidedef.Other.Sector != null)
|
||||
{
|
||||
float scaleY = (float)Texture.Height / (Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_top", scaleY, 1.0f);
|
||||
|
||||
float offsetY = Tools.GetSidedefTopOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_top", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
FitTexture(options);
|
||||
Setup();
|
||||
}
|
||||
|
||||
|
|