override protected void SetupInterface() { maxsubdivisions = 512; minsubdivisions = 3; minpointscount = 3; alwaysrendershapehints = true; // Load stored settings subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawellipsemode.subdivisions", 8), minsubdivisions, maxsubdivisions); bevelwidth = General.Settings.ReadPluginSetting("drawellipsemode.bevelwidth", 0); int angledeg = General.Settings.ReadPluginSetting("drawellipsemode.angle", 0); angle = Angle2D.DegToRad(angledeg); currentbevelwidth = bevelwidth; //Add options docker panel = new DrawEllipseOptionsPanel(); panel.MaxSubdivisions = maxsubdivisions; panel.MinSubdivisions = minsubdivisions; panel.MinSpikiness = (int)General.Map.FormatInterface.MinCoordinate; panel.MaxSpikiness = (int)General.Map.FormatInterface.MaxCoordinate; panel.Spikiness = bevelwidth; panel.Angle = angledeg; panel.Subdivisions = subdivisions; panel.OnValueChanged += OptionsPanelOnValueChanged; panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged; panel.OnShowGuidelinesChanged += OnShowGuidelinesChanged; // Needs to be set after adding the OnContinuousDrawingChanged event... panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawellipsemode.continuousdrawing", false); panel.ShowGuidelines = General.Settings.ReadPluginSetting("drawellipsemode.showguidelines", false); }
private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) { bevelwidth = panel.Spikiness; subdivisions = Math.Min(maxsubdivisions, panel.Subdivisions); angle = Angle2D.DegToRad(panel.Angle); Update(); }
//mxd public void SetPitch(int newpitch) { BeforePropsChange(); pitch = General.ClampAngle(newpitch); switch (rendermode) { case ThingRenderMode.MODEL: double pmult = General.Map.Config.BuggyModelDefPitch ? 1 : -1; ModelData md = General.Map.Data.ModeldefEntries[type]; if (md.InheritActorPitch || md.UseActorPitch) { pitchrad = Angle2D.DegToRad(pmult * (md.InheritActorPitch ? -pitch : pitch)); } else { pitchrad = 0; } break; case ThingRenderMode.FLATSPRITE: pitchrad = Angle2D.DegToRad(pitch); break; default: pitchrad = 0; break; } if (type != General.Map.Config.Start3DModeThingType) { General.Map.IsChanged = true; } }
//mxd public override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); closestline = MapSet.NearestLinedef(selectedlines, mousedownmappos); // Special cases... int distance; if(panel.FixedCurve) { if(panel.Angle > 0) { // Calculate diameter for current angle... double ma = Angle2D.DegToRad(panel.Angle); double d = (closestline.Length / Math.Tan(ma / 2f)) / 2; double D = d / Math.Cos(ma / 2f); distance = (int)Math.Round(D - d) * Math.Sign(panel.Distance); } else { distance = 0; // Special cases... } } else { distance = panel.Distance; } // Store offset between intial mouse position and curve top Vector2D perpendicular = closestline.Line.GetPerpendicular().GetNormal(); if(distance != 0) perpendicular *= distance; // Special cases... Vector2D curvetop = closestline.GetCenterPoint() - perpendicular; mousedownoffset = mousedownmappos - curvetop; }
//mxd. merged from GZDoomEditing plugin // This applies the given values on the vertices private static void SetupSurfaceVertices(FlatVertex[] vertices, Sector s, ImageData img, Vector2D offset, Vector2D scale, double rotate, int color, int light, bool absolute) { // Prepare for math! rotate = Angle2D.DegToRad(rotate); Vector2D texscale = new Vector2D(1.0f / img.ScaledWidth, 1.0f / img.ScaledHeight); if (!absolute) { light = s.Brightness + light; } PixelColor lightcolor = PixelColor.FromInt(color); PixelColor brightness = PixelColor.FromInt(General.Map.Renderer2D.CalculateBrightness(light)); PixelColor finalcolor = PixelColor.Modulate(lightcolor, brightness); color = finalcolor.WithAlpha(255).ToInt(); // Do the math for all vertices for (int i = 0; i < vertices.Length; i++) { Vector2D pos = new Vector2D(vertices[i].x, vertices[i].y); pos = pos.GetRotated(rotate); pos.y = -pos.y; pos = (pos + offset) * scale * texscale; vertices[i].u = (float)pos.x; vertices[i].v = (float)pos.y; vertices[i].c = color; } }
private void absrot_Validated(object sender, EventArgs e) { if(userinput) { float rad = Angle2D.DegToRad(absrot.GetResultFloat(this.absrotate)); mode.SetAbsRotation(rad); } }
// This performs an accurate test for object picking public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray) { u_ray = pickrayu; // Check on which side of the nearest sidedef we are Sidedef sd = MapSet.NearestSidedef(Sector.Sector.Sidedefs, pickintersect); float side = sd.Line.SideOfLine(pickintersect); //mxd. Alpha based picking. Used only on extrafloors with transparent or masked textures if ((side <= 0.0f && sd.IsFront) || (side > 0.0f && !sd.IsFront)) { if (!BuilderPlug.Me.AlphaBasedTextureHighlighting || !Texture.IsImageLoaded || extrafloor == null || RenderPass == RenderPass.Solid || (!Texture.IsTranslucent && !Texture.IsMasked)) { return(true); } // Some textures (e.g. HiResImage) may lie about their size, so use bitmap size instead Bitmap image = Texture.GetBitmap(); lock (image) { // Fetch ZDoom fields float rotate = Angle2D.DegToRad(level.sector.Fields.GetValue("rotationfloor", 0.0f)); Vector2D offset = new Vector2D(level.sector.Fields.GetValue("xpanningfloor", 0.0f), level.sector.Fields.GetValue("ypanningfloor", 0.0f)); Vector2D scale = new Vector2D(level.sector.Fields.GetValue("xscalefloor", 1.0f), level.sector.Fields.GetValue("yscalefloor", 1.0f)); Vector2D texscale = new Vector2D(1.0f / Texture.ScaledWidth, 1.0f / Texture.ScaledHeight); // Texture coordinates Vector2D o = pickintersect; o = o.GetRotated(rotate); o.y = -o.y; o = (o + offset) * scale * texscale; o.x = (o.x * image.Width) % image.Width; o.y = (o.y * image.Height) % image.Height; // Make sure coordinates are inside of texture dimensions... if (o.x < 0) { o.x += image.Width; } if (o.y < 0) { o.y += image.Height; } // Make final texture coordinates... int ox = General.Clamp((int)Math.Floor(o.x), 0, image.Width - 1); int oy = General.Clamp((int)Math.Floor(o.y), 0, image.Height - 1); // Check pixel alpha return(image.GetPixel(ox, oy).A > 0); } } return(false); }
//mxd. This checks if the thing has model override and whether pitch/roll values should be used internal void UpdateCache() { if (General.Map.Data == null) { return; } // Check if the thing has model override if (General.Map.Data.ModeldefEntries.ContainsKey(type)) { ModelData md = General.Map.Data.ModeldefEntries[type]; if ((md.LoadState == ModelLoadState.None && General.Map.Data.ProcessModel(type)) || md.LoadState != ModelLoadState.None) { rendermode = (General.Map.Data.ModeldefEntries[type].IsVoxel ? ThingRenderMode.VOXEL : ThingRenderMode.MODEL); } } else // reset rendermode if we SUDDENLY became a sprite out of a model. otherwise it crashes violently. { ThingTypeInfo ti = General.Map.Data.GetThingInfo(Type); rendermode = (ti != null) ? ti.RenderMode : ThingRenderMode.NORMAL; } // Update radian versions of pitch and roll switch (rendermode) { case ThingRenderMode.MODEL: float pmult = General.Map.Config.BuggyModelDefPitch ? 1 : -1; ModelData md = General.Map.Data.ModeldefEntries[type]; rollrad = (md.UseActorRoll ? Angle2D.DegToRad(roll) : 0); pitchrad = ((md.InheritActorPitch || md.UseActorPitch) ? Angle2D.DegToRad(pmult * (md.InheritActorPitch ? -pitch : pitch)) : 0); break; case ThingRenderMode.FLATSPRITE: rollrad = Angle2D.DegToRad(roll); pitchrad = Angle2D.DegToRad(pitch); break; case ThingRenderMode.WALLSPRITE: rollrad = Angle2D.DegToRad(roll); pitchrad = 0; break; case ThingRenderMode.NORMAL: rollrad = (rollsprite ? Angle2D.DegToRad(roll) : 0); pitchrad = 0; break; case ThingRenderMode.VOXEL: rollrad = 0; pitchrad = 0; break; default: throw new NotImplementedException("Unknown ThingRenderMode"); } }
//mxd private void ChangeAngle(int increment) { PreAction(UndoGroup.AngleChange); float incrementrad = Angle2D.DegToRad(increment); List <IVisualEventReceiver> objs = GetSelectedObjects(true, false, true); foreach (IVisualEventReceiver i in objs) { i.OnChangeTargetAngle(incrementrad); } PostAction(); }
//mxd public void SetRoll(int newroll) { BeforePropsChange(); roll = General.ClampAngle(newroll); rollrad = ((rollsprite || (rendermode == ThingRenderMode.MODEL && General.Map.Data.ModeldefEntries[type].UseActorRoll)) ? Angle2D.DegToRad(roll) : 0); if (type != General.Map.Config.Start3DModeThingType) { General.Map.IsChanged = true; } }
//mxd. This checks if the thing has model override and whether pitch/roll values should be used internal void UpdateCache() { if (General.Map.Data == null) { return; } // Check if the thing has model override if (General.Map.Data.ModeldefEntries.ContainsKey(type)) { ModelData md = General.Map.Data.ModeldefEntries[type]; if ((md.LoadState == ModelLoadState.None && General.Map.Data.ProcessModel(type)) || md.LoadState != ModelLoadState.None) { rendermode = (General.Map.Data.ModeldefEntries[type].IsVoxel ? ThingRenderMode.VOXEL : ThingRenderMode.MODEL); } } // Update radian versions of pitch and roll switch (rendermode) { case ThingRenderMode.MODEL: ModelData md = General.Map.Data.ModeldefEntries[type]; rollrad = (md.UseActorRoll ? Angle2D.DegToRad(roll) : 0); pitchrad = ((md.InheritActorPitch || md.UseActorPitch) ? Angle2D.DegToRad(md.InheritActorPitch ? -pitch : pitch) : 0); break; case ThingRenderMode.FLATSPRITE: rollrad = Angle2D.DegToRad(roll); pitchrad = Angle2D.DegToRad(pitch); break; case ThingRenderMode.WALLSPRITE: rollrad = Angle2D.DegToRad(roll); pitchrad = 0; break; case ThingRenderMode.NORMAL: rollrad = (rollsprite ? Angle2D.DegToRad(roll) : 0); pitchrad = 0; break; case ThingRenderMode.VOXEL: rollrad = 0; pitchrad = 0; break; default: throw new NotImplementedException("Unknown ThingRenderMode"); } }
// Constructor internal Renderer3D(D3DDevice graphics) : base(graphics) { // Initialize CreateProjection(); CreateMatrices2D(); SetupThingCage(); SetupTextures(); renderthingcages = true; showselection = true; showhighlight = true; // Dummy frustum frustum = new ProjectedFrustum2D(new Vector2D(), 0.0f, 0.0f, PROJ_NEAR_PLANE, General.Settings.ViewDistance, Angle2D.DegToRad(General.Settings.VisualFOV)); }
// This creates matrices for a camera view public void PositionAndLookAt(Vector3D pos, Vector3D lookat) { // Calculate delta vector cameraposition = pos; Vector3D delta = lookat - pos; float anglexy = delta.GetAngleXY(); float anglez = delta.GetAngleZ(); // Create frustum frustum = new ProjectedFrustum2D(pos, anglexy, anglez, PROJ_NEAR_PLANE, General.Settings.ViewDistance, Angle2D.DegToRad(General.Settings.VisualFOV)); // Make the view matrix view3d = Matrix.LookAtRH(D3DDevice.V3(pos), D3DDevice.V3(lookat), new Vector3(0f, 0f, 1f)); // Make the billboard matrix billboard = Matrix.RotationZ(anglexy + Angle2D.PI); }
// This creates the projection internal void CreateProjection() { // Calculate aspect float aspect = (float)General.Map.Graphics.RenderTarget.ClientSize.Width / (float)General.Map.Graphics.RenderTarget.ClientSize.Height; // The DirectX PerspectiveFovRH matrix method calculates the scaling in X and Y as follows: // yscale = 1 / tan(fovY / 2) // xscale = yscale / aspect // The fov specified in the method is the FOV over Y, but we want the user to specify the FOV // over X, so calculate what it would be over Y first; float fov = Angle2D.DegToRad((float)General.Settings.VisualFOV); float reversefov = 1.0f / (float)Math.Tan(fov / 2.0f); float reversefovy = reversefov * aspect; float fovy = (float)Math.Atan(1.0f / reversefovy) * 2.0f; // Make the projection matrix projection = Matrix.PerspectiveFovRH(fovy, aspect, PROJ_NEAR_PLANE, General.Settings.ViewDistance); // Apply matrices ApplyMatrices3D(); }
/*public DrawEllipseMode() * { * autoclosedrawing = false; * }*/ #endregion #region ================== Settings panel override protected void SetupInterface() { maxsubdivisions = 512; minsubdivisions = 3; minpointscount = 3; alwaysrendershapehints = true; // Load stored settings subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawellipsemode.subdivisions", 8), minsubdivisions, maxsubdivisions); int angledeg = General.Settings.ReadPluginSetting("drawellipsemode.angle", 0); angle = Angle2D.DegToRad(angledeg); //currentbevelwidth = bevelwidth; //Add options docker panel = new DrawEllipseOptionsPanel(); panel.MaxSubdivisions = maxsubdivisions; panel.MinSubdivisions = minsubdivisions; panel.Angle = angledeg; panel.Subdivisions = subdivisions; panel.OnValueChanged += OptionsPanelOnValueChanged; }
/// <summary> /// Updates the arch with the values currently entered in the dialog /// </summary> private void UpdateArch() { double t = theta.GetResultFloat(originaltheta); double o = offset.GetResultFloat(originaloffset); double s = scale.GetResultFloat(originalscale * 100.0) / 100.0; // Flip the scale if "down" is checked if (!up.Checked) { s *= -1.0; } slopearcher.Theta = Angle2D.DegToRad(t); slopearcher.OffsetAngle = Angle2D.DegToRad(o); slopearcher.Scale = s; slopearcher.HeightOffset = heightoffset.GetResultFloat(originalheightoffset); slopearcher.ApplySlope(); // BaseVisualMode added a event handler to the dialog, so BaseVisualMode will update the geometry when we tell it to UpdateChangedObjects?.Invoke(this, EventArgs.Empty); }
// Redraw the control private void AngleControl_Paint(object sender, PaintEventArgs e) { float rad = Angle2D.DegToRad((float)angle); e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; e.Graphics.InterpolationMode = InterpolationMode.High; e.Graphics.SmoothingMode = SmoothingMode.HighQuality; e.Graphics.Clear(this.BackColor); Pen linepen = new Pen(SystemColors.ControlText, LINE_THICKNESS); PointF start = new PointF((float)this.Size.Width * 0.5f, (float)this.Size.Height * 0.5f); float line_length = (float)this.Size.Width * 0.26f; if ((rad >= 0) && (rad < 360)) { PointF end = new PointF(start.X + (float)Math.Sin(rad + Angle2D.PIHALF) * line_length, start.Y + (float)Math.Cos(rad + Angle2D.PIHALF) * line_length); e.Graphics.DrawLine(linepen, start, end); } else { e.Graphics.DrawLine(linepen, start, start); } }
// This makes sure we are updated with the source linedef information public override void Update() { ThingData td = data.Mode.GetThingData(thing); Thing t = thing; // Floor slope thing if (t.Type == 9502) { t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { //mxd. Vertex zheight overrides this effect if (General.Map.UDMF && t.Sector.Sidedefs.Count == 3) { foreach (Sidedef side in t.Sector.Sidedefs) { if (!double.IsNaN(side.Line.Start.ZFloor) || !double.IsNaN(side.Line.End.ZFloor)) { return; } } } double angle = Angle2D.DoomToReal((int)Angle2D.RadToDeg(t.Angle)); double vangle = Angle2D.DegToRad(General.Clamp(t.Args[0], 0, 180)); //mxd. Don't underestimate user stupidity (or curiosity)! Vector2D point = new Vector2D(t.Position.x + Math.Cos(angle) * Math.Sin(vangle), t.Position.y + Math.Sin(angle) * Math.Sin(vangle)); Vector2D perpendicular = new Line2D(t.Position, point).GetPerpendicular(); Vector3D v1 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.FloorHeight); Vector3D v2 = new Vector3D( point.x + perpendicular.x, point.y + perpendicular.y, t.Position.z + t.Sector.FloorHeight + Math.Cos(vangle) ); Vector3D v3 = new Vector3D( point.x - perpendicular.x, point.y - perpendicular.y, t.Position.z + t.Sector.FloorHeight + Math.Cos(vangle) ); SectorData sd = data.Mode.GetSectorData(t.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(t.Sector, true); sd.Floor.plane = new Plane(v1, v2, v3, true); } } // Ceiling slope thing else if (t.Type == 9503) { t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { //mxd. Vertex zheight overrides this effect if (General.Map.UDMF && t.Sector.Sidedefs.Count == 3) { foreach (Sidedef side in t.Sector.Sidedefs) { if (!double.IsNaN(side.Line.Start.ZCeiling) || !double.IsNaN(side.Line.End.ZCeiling)) { return; } } } double angle = Angle2D.DoomToReal((int)Angle2D.RadToDeg(t.Angle)); double vangle = Angle2D.DegToRad(General.Clamp(t.Args[0], 0, 180)); //mxd. Don't underestimate user stupidity (or curiosity)! Vector2D point = new Vector2D(t.Position.x + Math.Cos(angle) * Math.Sin(vangle), t.Position.y + Math.Sin(angle) * Math.Sin(vangle)); Vector2D perpendicular = new Line2D(t.Position, point).GetPerpendicular(); Vector3D v1 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.CeilHeight); Vector3D v2 = new Vector3D( point.x + perpendicular.x, point.y + perpendicular.y, t.Position.z + t.Sector.CeilHeight + Math.Cos(vangle) ); Vector3D v3 = new Vector3D( point.x - perpendicular.x, point.y - perpendicular.y, t.Position.z + t.Sector.CeilHeight + Math.Cos(vangle) ); SectorData sd = data.Mode.GetSectorData(t.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(t.Sector, true); sd.Ceiling.plane = new Plane(v1, v2, v3, false); } } }
//mxd public bool Setup(SectorLevel level, Effect3DFloor extrafloor, bool innerside) { Sector s = level.sector; Vector2D texscale; this.innerside = innerside; base.Setup(level, extrafloor); // Fetch ZDoom fields float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationfloor", 0.0f)); Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f), s.Fields.GetValue("ypanningfloor", 0.0f)); Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f), s.Fields.GetValue("yscalefloor", 1.0f)); //Load floor texture if (s.LongFloorTexture != MapSet.EmptyLongName) { base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = s.LongFloorTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = s.LongFloorTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Determine texture scale if (base.Texture.IsImageLoaded) { texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight); } else { texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f); } // Determine brightness int color = PixelColor.FromInt(level.color).WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt(); //mxd. Top extrafloor level should calculate fogdensity //from the brightness of the level above it int targetbrightness; if (extrafloor != null && extrafloor.VavoomType && !level.disablelighting) { targetbrightness = 0; SectorData sd = mode.GetSectorData(this.Sector.Sector); for (int i = 0; i < sd.LightLevels.Count - 1; i++) { if (sd.LightLevels[i] == level) { targetbrightness = sd.LightLevels[i + 1].brightnessbelow; break; } } } else { targetbrightness = level.brightnessbelow; } //mxd. Determine fog density fogfactor = CalculateFogFactor(targetbrightness); // Make vertices ReadOnlyCollection <Vector2D> triverts = Sector.Sector.Triangles.Vertices; WorldVertex[] verts = new WorldVertex[triverts.Count]; for (int i = 0; i < triverts.Count; i++) { // Color shading verts[i].c = color; //mxd // Vertex coordinates verts[i].x = triverts[i].x; verts[i].y = triverts[i].y; verts[i].z = level.plane.GetZ(triverts[i]); // Texture coordinates Vector2D pos = triverts[i]; pos = pos.GetRotated(rotate); pos.y = -pos.y; pos = (pos + offset) * scale * texscale; verts[i].u = pos.x; verts[i].v = pos.y; } // The sector triangulation created clockwise triangles that // are right up for the floor. For the ceiling we must flip // the triangles upside down. if ((extrafloor != null) && !extrafloor.VavoomType && !innerside) { SwapTriangleVertices(verts); } // Determine render pass if (extrafloor != null) { if (extrafloor.Sloped3dFloor) //mxd { this.RenderPass = RenderPass.Mask; } else if (extrafloor.RenderAdditive) //mxd { this.RenderPass = RenderPass.Additive; } else if (level.alpha < 255) { this.RenderPass = RenderPass.Alpha; } else { this.RenderPass = RenderPass.Mask; } } else { this.RenderPass = RenderPass.Solid; } //mxd. Update sky render flag UpdateSkyRenderFlag(); // Apply vertices base.SetVertices(verts); return(verts.Length > 0); }
/// <summary> /// Exports the sectors to images /// </summary> public void Export() { Bitmap texturebitmap = null; Bitmap brightmapbitmap = null; Graphics gbrightmap = null; Graphics gtexture = null; Vector2D offset; Vector2D size; GetSizeAndOffset(out size, out offset); // Normal texture texturebitmap = new Bitmap((int)size.x, (int)size.y, settings.PixelFormat); gtexture = Graphics.FromImage(texturebitmap); gtexture.Clear(Color.Black); // If we don't clear to black we'll see seams where the sectors touch, due to the AA gtexture.InterpolationMode = InterpolationMode.HighQualityBilinear; gtexture.CompositingQuality = CompositingQuality.HighQuality; gtexture.PixelOffsetMode = PixelOffsetMode.HighQuality; gtexture.SmoothingMode = SmoothingMode.AntiAlias; // Without AA the sector edges will be quite rough // Brightmap if (settings.Brightmap) { brightmapbitmap = new Bitmap((int)size.x, (int)size.y, settings.PixelFormat); gbrightmap = Graphics.FromImage(brightmapbitmap); gbrightmap.Clear(Color.Black); // If we don't clear to black we'll see seams where the sectors touch, due to the AA gbrightmap.InterpolationMode = InterpolationMode.HighQualityBilinear; gbrightmap.CompositingQuality = CompositingQuality.HighQuality; gbrightmap.PixelOffsetMode = PixelOffsetMode.HighQuality; gbrightmap.SmoothingMode = SmoothingMode.AntiAlias; // Without AA the sector edges will be quite rough } foreach (Sector s in sectors) { GraphicsPath p = new GraphicsPath(); float rotation = (float)s.Fields.GetValue("rotationfloor", 0.0); // If a sector is rotated any offset is on the rotated axes. But we need to offset by // map coordinates. We'll use this vector to compute that offset Vector2D rotationvector = Vector2D.FromAngle(Angle2D.DegToRad(rotation) + Angle2D.PIHALF); // Sectors are triangulated, so draw every triangle for (int i = 0; i < s.Triangles.Vertices.Count / 3; i++) { // The GDI image has the 0/0 coordinate in the top left, so invert the y component Vector2D v1 = s.Triangles.Vertices[i * 3] - offset; v1.y *= -1.0; Vector2D v2 = s.Triangles.Vertices[i * 3 + 1] - offset; v2.y *= -1.0; Vector2D v3 = s.Triangles.Vertices[i * 3 + 2] - offset; v3.y *= -1.0; p.AddLine((float)v1.x, (float)v1.y, (float)v2.x, (float)v2.y); p.AddLine((float)v2.x, (float)v2.y, (float)v3.x, (float)v3.y); p.CloseFigure(); } Bitmap brushtexture; if (settings.Floor) { brushtexture = General.Map.Data.GetFlatImage(s.FloorTexture).ExportBitmap(); } else { brushtexture = General.Map.Data.GetFlatImage(s.CeilTexture).ExportBitmap(); } if (!settings.Fullbright) { brushtexture = AdjustBrightness(brushtexture, s.Brightness > 0 ? s.Brightness / 255.0f : 0.0f); } Vector2D textureoffset = new Vector2D(); textureoffset.x = s.Fields.GetValue("xpanningfloor", 0.0); textureoffset.y = s.Fields.GetValue("ypanningfloor", 0.0); // Create the transformation matrix Matrix matrix = new Matrix(); matrix.Rotate(rotation); matrix.Translate((float)(-offset.x * rotationvector.x), (float)(offset.x * rotationvector.y)); // Left/right offset from the map origin matrix.Translate((float)(offset.y * rotationvector.y), (float)(offset.y * rotationvector.x)); // Up/down offset from the map origin matrix.Translate(-(float)textureoffset.x, -(float)textureoffset.y); // Texture offset // Create the texture brush and apply the matrix TextureBrush tbrush = new TextureBrush(brushtexture); tbrush.Transform = matrix; // Draw the islands of the sector gtexture.FillPath(tbrush, p); // Create the brightmap based on the sector brightness if (settings.Brightmap) { SolidBrush sbrush = new SolidBrush(Color.FromArgb(255, s.Brightness, s.Brightness, s.Brightness)); gbrightmap.FillPath(sbrush, p); } } // Finally save the image(s) if (settings.Tiles) { SaveImageAsTiles(texturebitmap); if (settings.Brightmap) { SaveImageAsTiles(brightmapbitmap, "_brightmap"); } } else { texturebitmap.Save(Path.Combine(settings.Path, settings.Name) + settings.Extension, settings.ImageFormat); if (settings.Brightmap) { brightmapbitmap.Save(Path.Combine(settings.Path, settings.Name) + "_brightmap" + settings.Extension, settings.ImageFormat); } } }
/// <summary> /// This loads all nodes structures data from the lumps /// </summary> private bool LoadClassicStructures() { // Load the nodes structure MemoryStream nodesstream = General.Map.GetLumpData("NODES"); int numnodes = (int)nodesstream.Length / 28; //mxd. Boilerplate! if (numnodes < 1) { // Cancel mode MessageBox.Show("The map has only one subsector. Please add more sectors, then try running this mode again.", "THY NODETH ARETH BROKH!", MessageBoxButtons.OK, MessageBoxIcon.Error); General.Editing.CancelMode(); return(false); } BinaryReader nodesreader = new BinaryReader(nodesstream); nodes = new Node[numnodes]; for (int i = 0; i < nodes.Length; i++) { nodes[i].linestart.x = nodesreader.ReadInt16(); nodes[i].linestart.y = nodesreader.ReadInt16(); nodes[i].linedelta.x = nodesreader.ReadInt16(); nodes[i].linedelta.y = nodesreader.ReadInt16(); float top = nodesreader.ReadInt16(); float bot = nodesreader.ReadInt16(); float left = nodesreader.ReadInt16(); float right = nodesreader.ReadInt16(); nodes[i].rightbox = new RectangleF(left, top, (right - left), (bot - top)); top = nodesreader.ReadInt16(); bot = nodesreader.ReadInt16(); left = nodesreader.ReadInt16(); right = nodesreader.ReadInt16(); nodes[i].leftbox = new RectangleF(left, top, (right - left), (bot - top)); int rightindex = nodesreader.ReadInt16(); int leftindex = nodesreader.ReadInt16(); nodes[i].rightchild = rightindex & 0x7FFF; nodes[i].leftchild = leftindex & 0x7FFF; nodes[i].rightsubsector = (rightindex & 0x8000) != 0; nodes[i].leftsubsector = (leftindex & 0x8000) != 0; } nodesreader.Close(); // Add additional properties to nodes nodes[nodes.Length - 1].parent = -1; SetupNodes(); //mxd // Load the segs structure MemoryStream segsstream = General.Map.GetLumpData("SEGS"); BinaryReader segsreader = new BinaryReader(segsstream); int numsegs = (int)segsstream.Length / 12; //mxd. Boilerplate! if (numsegs < 1) { // Cancel mode MessageBox.Show("The map has empty SEGS lump. Please rebuild the nodes, then try running this mode again.", "THY SEGS HATH SINNETH!", MessageBoxButtons.OK, MessageBoxIcon.Error); General.Editing.CancelMode(); return(false); } //mxd. ZDoom SEGS overflow error if (numsegs >= ushort.MaxValue) { // Cancel mode MessageBox.Show("The map has too many SEGS (" + numsegs + "/" + ushort.MaxValue + ").\nIt won't load in Vanilla-style source ports\nand may not load in some enhanced source ports.", "THY SEGS ARETH WAAAY TOO PHAT!", MessageBoxButtons.OK, MessageBoxIcon.Error); General.Editing.CancelMode(); return(false); } //mxd. Vanilla SEGS overflow warning else if (numsegs >= short.MaxValue) { MessageBox.Show("The map has too many SEGS (" + numsegs + "/" + short.MaxValue + ").\nIt won't load in Vanilla-style source ports.", "THY SEGS ARETH TOO PHAT!", MessageBoxButtons.OK, MessageBoxIcon.Warning); } segs = new Seg[numsegs]; for (int i = 0; i < segs.Length; i++) { segs[i].startvertex = segsreader.ReadUInt16(); segs[i].endvertex = segsreader.ReadUInt16(); segs[i].angle = Angle2D.DegToRad(General.ClampAngle(segsreader.ReadInt16() / 182 + 90)); //mxd 182 == 65536 / 360; segs[i].lineindex = segsreader.ReadUInt16(); segs[i].leftside = segsreader.ReadInt16() != 0; segs[i].offset = segsreader.ReadInt16(); } segsreader.Close(); // Load the vertexes structure MemoryStream vertsstream = General.Map.GetLumpData("VERTEXES"); BinaryReader vertsreader = new BinaryReader(vertsstream); int numverts = (int)vertsstream.Length / 4; //mxd. Boilerplate! if (numverts < 1) { // Cancel mode MessageBox.Show("The map has empty VERTEXES lump. Please rebuild the nodes, then try running this mode again.", "THY VERTEXES ARETH FOUL!", MessageBoxButtons.OK, MessageBoxIcon.Error); General.Editing.CancelMode(); return(false); } verts = new Vector2D[numverts]; for (int i = 0; i < verts.Length; i++) { verts[i].x = vertsreader.ReadInt16(); verts[i].y = vertsreader.ReadInt16(); } vertsreader.Close(); // Load the subsectors structure MemoryStream ssecstream = General.Map.GetLumpData("SSECTORS"); BinaryReader ssecreader = new BinaryReader(ssecstream); int numssec = (int)ssecstream.Length / 4; //mxd. Boilerplate! if (numssec < 1) { // Cancel mode MessageBox.Show("The map has empty SSECTORS lump. Please rebuild the nodes, then try running this mode again.", "THY SSECTORS ARETH HERETYSH!", MessageBoxButtons.OK, MessageBoxIcon.Error); General.Editing.CancelMode(); return(false); } ssectors = new Subsector[numssec]; for (int i = 0; i < ssectors.Length; i++) { ssectors[i].numsegs = ssecreader.ReadUInt16(); //TECH: these are short in Doom, ushort in ZDoom/PRBoom+ ssectors[i].firstseg = ssecreader.ReadUInt16(); } ssecreader.Close(); // Link all segs to their subsectors for (int i = 0; i < ssectors.Length; i++) { int lastseg = ssectors[i].firstseg + ssectors[i].numsegs - 1; for (int sg = ssectors[i].firstseg; sg <= lastseg; sg++) { segs[sg].ssector = i; } } return(true); }
// This returns the aligned and snapped draw position public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, bool usefourcardinaldirections, IRenderer2D renderer, List <DrawnVertex> points) { DrawnVertex p = new DrawnVertex(); p.stitch = true; //mxd. Setting these to false seems to be a good way to create invalid geometry... p.stitchline = true; //mxd snaptocardinal = (snaptocardinal && points.Count > 0); //mxd. Don't snap to cardinal when there are no points //mxd. If snap to cardinal directions is enabled and we have points, modify mouse position Vector2D vm, gridoffset; if (snaptocardinal) { Vector2D offset = mousemappos - points[points.Count - 1].pos; float angle; if (usefourcardinaldirections) { angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()))) / 90 * 90 + 45); } else { angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()) + 22)) / 45 * 45); } offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle); vm = points[points.Count - 1].pos + offset; //mxd. We need to be snapped relative to initial position Vector2D prev = points[points.Count - 1].pos; gridoffset = prev - General.Map.Grid.SnappedToGrid(prev); } else { vm = mousemappos; gridoffset = new Vector2D(); } float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; // Snap to nearest? if (snaptonearest) { // Go for all drawn points foreach (DrawnVertex v in points) { if (Vector2D.DistanceSq(vm, v.pos) < (vrange * vrange)) { p.pos = v.pos; return(p); } } // Try the nearest vertex Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange); if (nv != null) { //mxd. Line angle must stay the same if (snaptocardinal) { Line2D ourline = new Line2D(points[points.Count - 1].pos, vm); if (Math.Round(ourline.GetSideOfLine(nv.Position), 1) == 0) { p.pos = nv.Position; return(p); } } else { p.pos = nv.Position; return(p); } } // Try the nearest linedef. mxd. We'll need much bigger stitch distance when snapping to cardinal directions Linedef nl = General.Map.Map.NearestLinedefRange(vm, BuilderPlug.Me.StitchRange / renderer.Scale); if (nl != null) { //mxd. Line angle must stay the same if (snaptocardinal) { Line2D ourline = new Line2D(points[points.Count - 1].pos, vm); Line2D nearestline = new Line2D(nl.Start.Position, nl.End.Position); Vector2D intersection = Line2D.GetIntersectionPoint(nearestline, ourline, false); if (!float.IsNaN(intersection.x)) { // Intersection is on nearestline? float u = Line2D.GetNearestOnLine(nearestline.v1, nearestline.v2, intersection); if (u < 0f || u > 1f) { } else { p.pos = new Vector2D((float)Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals), (float)Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals)); return(p); } } } // Snap to grid? else if (snaptogrid) { // Get grid intersection coordinates List <Vector2D> coords = nl.GetGridIntersections(General.Map.Grid.GridRotate, General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY); // Find nearest grid intersection bool found = false; float found_distance = float.MaxValue; Vector2D found_coord = new Vector2D(); foreach (Vector2D v in coords) { Vector2D delta = vm - v; if (delta.GetLengthSq() < found_distance) { found_distance = delta.GetLengthSq(); found_coord = v; found = true; } } if (found) { // Align to the closest grid intersection p.pos = found_coord; return(p); } } else { // Aligned to line p.pos = nl.NearestOnLine(vm); return(p); } } } else { // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching if (points.Count > 0) { if (Vector2D.DistanceSq(vm, points[0].pos) < (vrange * vrange)) { p.pos = points[0].pos; return(p); } } } // if the mouse cursor is outside the map bondaries check if the line between the last set point and the // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection if (points.Count > 0 && (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary || mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary)) { Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos); bool foundintersection = false; float u = 0.0f; List <Line2D> blines = new List <Line2D>(); // lines for left, top, right and bottom boundaries blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary)); blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary)); blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary)); blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary)); // check for intersections with boundaries for (int i = 0; i < blines.Count; i++) { if (!foundintersection) { // only check for intersection if the last set point is not on the // line we are checking against if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f) { foundintersection = blines[i].GetIntersection(dline, out u); } } } // if there was no intersection set the position to the last set point if (!foundintersection) { vm = points[points.Count - 1].pos; } else { vm = dline.GetCoordinatesAt(u); } } // Snap to grid? if (snaptogrid) { // Aligned to grid p.pos = General.Map.Grid.SnappedToGrid(vm - gridoffset) + gridoffset; // special handling if (p.pos.x > General.Map.Config.RightBoundary) { p.pos.x = General.Map.Config.RightBoundary; } if (p.pos.y < General.Map.Config.BottomBoundary) { p.pos.y = General.Map.Config.BottomBoundary; } return(p); } else { // Normal position p.pos.x = (float)Math.Round(vm.x); //mxd p.pos.y = (float)Math.Round(vm.y); //mxd return(p); } }
// This builds the geometry. Returns false when no geometry created. public override bool Setup(SectorLevel level, Effect3DFloor extrafloor) { WorldVertex[] verts; Sector s = level.sector; Vector2D texscale; base.Setup(level, extrafloor); // Fetch ZDoom fields float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationceiling", 0.0f)); Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f), s.Fields.GetValue("ypanningceiling", 0.0f)); Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f), s.Fields.GetValue("yscaleceiling", 1.0f)); // Load floor texture base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture); if (base.Texture == null) { base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = s.LongCeilTexture; } else { if (!base.Texture.IsImageLoaded) { setuponloadedtexture = s.LongCeilTexture; } } // Determine texture scale if (base.Texture.IsImageLoaded) { texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight); } else { texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f); } // Make vertices ReadOnlyCollection <Vector2D> triverts = base.Sector.Sector.Triangles.Vertices; verts = new WorldVertex[triverts.Count]; for (int i = 0; i < triverts.Count; i++) { // Color shading PixelColor c = PixelColor.FromInt(level.color); verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt(); // Vertex coordinates verts[i].x = triverts[i].x; verts[i].y = triverts[i].y; verts[i].z = level.plane.GetZ(triverts[i]); //(float)s.CeilHeight; // Texture coordinates Vector2D pos = triverts[i]; pos = pos.GetRotated(rotate); pos.y = -pos.y; pos = (pos + offset) * scale * texscale; verts[i].u = pos.x; verts[i].v = pos.y; } // The sector triangulation created clockwise triangles that // are right up for the floor. For the ceiling we must flip // the triangles upside down. if ((extrafloor == null) || extrafloor.VavoomType) { SwapTriangleVertices(verts); } // Determine render pass if (extrafloor != null) { if (level.alpha < 255) { this.RenderPass = RenderPass.Alpha; } else { this.RenderPass = RenderPass.Mask; } } else { this.RenderPass = RenderPass.Solid; } // Apply vertices base.SetVertices(verts); return(verts.Length > 0); }
private void DecreaseAngle() { panel.Angle = General.ClampAngle(panel.Angle - 5); angle = Angle2D.DegToRad(panel.Angle); Update(); }
// Apply clicked private void apply_Click(object sender, EventArgs e) { //mxd. Make Undo MakeUndo(); List <string> defaultflags = new List <string>(); // Verify the tag if (General.Map.FormatInterface.HasThingTag) //mxd { tagSelector.ValidateTag(); //mxd if (((tagSelector.GetTag(0) < General.Map.FormatInterface.MinTag) || (tagSelector.GetTag(0) > General.Map.FormatInterface.MaxTag))) { General.ShowWarningMessage("Thing tag must be between " + General.Map.FormatInterface.MinTag + " and " + General.Map.FormatInterface.MaxTag + ".", MessageBoxButtons.OK); return; } } // Verify the type if (!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) { General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK); return; } // Verify the action if (General.Map.FormatInterface.HasThingAction && ((action.Value < General.Map.FormatInterface.MinAction) || (action.Value > General.Map.FormatInterface.MaxAction))) { General.ShowWarningMessage("Thing action must be between " + General.Map.FormatInterface.MinAction + " and " + General.Map.FormatInterface.MaxAction + ".", MessageBoxButtons.OK); return; } // Go for all the things int offset = 0; //mxd foreach (Thing t in things) { // Coordination //mxd. Randomize rotations? if (cbrandomangle.Checked) { int newangle = General.Random(0, 359); if (General.Map.Config.DoomThingRotationAngles) { newangle = newangle / 45 * 45; } t.Rotate(newangle); } if (cbrandompitch.Checked) { t.SetPitch(General.Random(0, 359)); } if (cbrandomroll.Checked) { t.SetRoll(General.Random(0, 359)); } //mxd. Check position double px = General.Clamp(t.Position.x, General.Map.Config.LeftBoundary, General.Map.Config.RightBoundary); double py = General.Clamp(t.Position.y, General.Map.Config.BottomBoundary, General.Map.Config.TopBoundary); if (t.Position.x != px || t.Position.y != py) { t.Move(new Vector2D(px, py)); } // Action/tags t.Tag = General.Clamp(tagSelector.GetSmartTag(t.Tag, offset), General.Map.FormatInterface.MinTag, General.Map.FormatInterface.MaxTag); //mxd if (!action.Empty) { t.Action = action.Value; } //mxd. Apply args argscontrol.Apply(t, offset); //mxd. Custom fields fieldslist.Apply(t.Fields); if (!string.IsNullOrEmpty(conversationID.Text)) { UniFields.SetInteger(t.Fields, "conversation", conversationID.GetResult(t.Fields.GetValue("conversation", 0)), 0); } if (!string.IsNullOrEmpty(floatbobphase.Text)) { UniFields.SetInteger(t.Fields, "floatbobphase", General.Clamp(floatbobphase.GetResult(t.Fields.GetValue("floatbobphase", -1)), -1, 63), -1); } if (!string.IsNullOrEmpty(gravity.Text)) { UniFields.SetFloat(t.Fields, "gravity", gravity.GetResultFloat(t.Fields.GetValue("gravity", 1.0)), 1.0); } if (!string.IsNullOrEmpty(health.Text)) { UniFields.SetInteger(t.Fields, "health", health.GetResult(t.Fields.GetValue("health", 1)), 1); } if (!string.IsNullOrEmpty(score.Text)) { UniFields.SetInteger(t.Fields, "score", score.GetResult(t.Fields.GetValue("score", 0)), 0); } //mxd. User vars. Should be called after fieldslist.Apply() ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); if (ti != null && ti.Actor != null && ti.Actor.UserVars.Count > 0) { fieldslist.ApplyUserVars(ti.Actor.UserVars, t.Fields); } color.ApplyTo(t.Fields, t.Fields.GetValue("fillcolor", 0)); //mxd. Comments commenteditor.Apply(t.Fields); // Update settings t.UpdateConfiguration(); //mxd. Increase offset... offset++; } // Set as defaults foreach (CheckBox c in flags.Checkboxes) { if (c.CheckState == CheckState.Checked) { defaultflags.Add(c.Tag.ToString()); } } General.Settings.DefaultThingType = thingtype.GetResult(General.Settings.DefaultThingType); General.Settings.DefaultThingAngle = Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90); General.Settings.SetDefaultThingFlags(defaultflags); // Done General.Map.IsChanged = true; if (OnValuesChanged != null) { OnValuesChanged(this, EventArgs.Empty); //mxd } this.DialogResult = DialogResult.OK; this.Close(); }
// Apply clicked private void apply_Click(object sender, EventArgs e) { MakeUndo(); List <string> defaultflags = new List <string>(); // Verify the tag if (General.Map.FormatInterface.HasThingTag) //mxd { tagSelector.ValidateTag(); //mxd if (((tagSelector.GetTag(0) < General.Map.FormatInterface.MinTag) || (tagSelector.GetTag(0) > General.Map.FormatInterface.MaxTag))) { General.ShowWarningMessage("Thing tag must be between " + General.Map.FormatInterface.MinTag + " and " + General.Map.FormatInterface.MaxTag + ".", MessageBoxButtons.OK); return; } } // Verify the type if (!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) { General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK); return; } // Verify the action if (General.Map.FormatInterface.HasThingAction && ((action.Value < General.Map.FormatInterface.MinAction) || (action.Value > General.Map.FormatInterface.MaxAction))) { General.ShowWarningMessage("Thing action must be between " + General.Map.FormatInterface.MinAction + " and " + General.Map.FormatInterface.MaxAction + ".", MessageBoxButtons.OK); return; } // Go for all the things int offset = 0; //mxd foreach (Thing t in things) { // Coordination if (cbRandomAngle.Checked) //mxd { int newangle = General.Random(0, 359); if (General.Map.Config.DoomThingRotationAngles) { newangle = newangle / 45 * 45; } t.Rotate(newangle); } //mxd. Check position float px = General.Clamp(t.Position.x, General.Map.Config.LeftBoundary, General.Map.Config.RightBoundary); float py = General.Clamp(t.Position.y, General.Map.Config.BottomBoundary, General.Map.Config.TopBoundary); if (t.Position.x != px || t.Position.y != py) { t.Move(new Vector2D(px, py)); } // Apply all flags foreach (CheckBox c in flags.Checkboxes) { switch (c.CheckState) { case CheckState.Checked: t.SetFlag(c.Tag.ToString(), true); break; case CheckState.Unchecked: t.SetFlag(c.Tag.ToString(), false); break; } } // Action/tags t.Tag = General.Clamp(tagSelector.GetSmartTag(t.Tag, offset), General.Map.FormatInterface.MinTag, General.Map.FormatInterface.MaxTag); //mxd if (!action.Empty) { t.Action = action.Value; } //mxd. Apply args argscontrol.Apply(t, offset); // Update settings t.UpdateConfiguration(); //mxd. Increase offset... offset++; } // Set as defaults foreach (CheckBox c in flags.Checkboxes) { if (c.CheckState == CheckState.Checked) { defaultflags.Add(c.Tag.ToString()); } } General.Settings.DefaultThingType = thingtype.GetResult(General.Settings.DefaultThingType); General.Settings.DefaultThingAngle = Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90); General.Settings.SetDefaultThingFlags(defaultflags); // Done General.Map.IsChanged = true; if (OnValuesChanged != null) { OnValuesChanged(this, EventArgs.Empty); //mxd } this.DialogResult = DialogResult.OK; this.Close(); }
//mxd protected void AlignTextureToSlopeLine(Linedef slopeSource, float slopeAngle, bool isFront, bool alignx, bool aligny) { 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); if (isFloor) { if ((isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight) || (!isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight)) { sourceAngle = General.ClampAngle(sourceAngle + 180); } } else { if ((isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight) || (!isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight)) { sourceAngle = General.ClampAngle(sourceAngle + 180); } } //update angle UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f); //update scaleY string xScaleKey = (isFloor ? "xscalefloor" : "xscaleceiling"); string yScaleKey = (isFloor ? "yscalefloor" : "yscaleceiling"); float scaleX = Sector.Sector.Fields.GetValue(xScaleKey, 1.0f); float scaleY; //set scale if (aligny) { scaleY = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2); UniFields.SetFloat(Sector.Sector.Fields, yScaleKey, scaleY, 1.0f); } else { scaleY = Sector.Sector.Fields.GetValue(yScaleKey, 1.0f); } //update texture offsets Vector2D offset; if (isFloor) { if ((isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight) || (!isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight)) { offset = slopeSource.End.Position; } else { offset = slopeSource.Start.Position; } } else { if ((isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight) || (!isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight)) { offset = slopeSource.End.Position; } else { offset = slopeSource.Start.Position; } } offset = offset.GetRotated(Angle2D.DegToRad(sourceAngle)); if (alignx) { if (Texture != null && Texture.IsImageLoaded) { offset.x %= Texture.Width / scaleX; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if (aligny) { if (Texture != null && Texture.IsImageLoaded) { offset.y %= Texture.Height / scaleY; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } //update geometry Sector.UpdateSectorGeometry(false); }
//mxd protected void AlignTextureToClosestLine(bool alignx, bool aligny) { if (!(mode.HighlightedObject is BaseVisualSector)) { return; } // Do we need to align this? (and also grab texture scale while we are at it) float scaleX, scaleY; bool isFloor = (geometrytype == VisualGeometryType.FLOOR); if (mode.HighlightedTarget is VisualFloor) { VisualFloor target = (VisualFloor)mode.HighlightedTarget; // Check texture if (target.Sector.Sector.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Sector.Sector.Fields.GetValue("xscalefloor", 1.0f); scaleY = target.Sector.Sector.Fields.GetValue("yscalefloor", 1.0f); } else { VisualCeiling target = (VisualCeiling)mode.HighlightedTarget; // Check texture if (target.Sector.Sector.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Sector.Sector.Fields.GetValue("xscaleceiling", 1.0f); scaleY = target.Sector.Sector.Fields.GetValue("yscaleceiling", 1.0f); } //find a linedef to align to Vector2D hitpos = mode.GetHitPosition(); if (!hitpos.IsFinite()) { return; } //align to line of highlighted sector, which is closest to hitpos Sector highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector; List <Linedef> lines = new List <Linedef>(); foreach (Sidedef side in highlightedSector.Sidedefs) { lines.Add(side.Line); } Linedef targetLine = MapSet.NearestLinedef(lines, hitpos); if (targetLine == null) { return; } bool isFront = targetLine.SideOfLine(hitpos) > 0; Sector.Sector.Fields.BeforeFieldsChange(); //find an angle to rotate texture float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1); if (!isFront) { sourceAngle = General.ClampAngle(sourceAngle + 180); } //update angle UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f); //set scale UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f); UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f); //update offset float distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position); float distToEnd = Vector2D.Distance(hitpos, targetLine.End.Position); Vector2D offset = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle)); if (alignx) { if (Texture != null && Texture.IsImageLoaded) { offset.x %= Texture.Width / scaleX; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if (aligny) { if (Texture != null && Texture.IsImageLoaded) { offset.y %= Texture.Height / scaleY; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } //update geometry Sector.UpdateSectorGeometry(false); }
// This is called to update UV dragging protected virtual void UpdateDragUV() { float u_ray = 1.0f; // Calculate intersection position this.Level.plane.GetIntersection(General.Map.VisualCamera.Position, General.Map.VisualCamera.Target, ref u_ray); Vector3D intersect = General.Map.VisualCamera.Position + (General.Map.VisualCamera.Target - General.Map.VisualCamera.Position) * u_ray; // Calculate offsets Vector3D dragdelta = intersect - dragorigin; float offsetx = dragdelta.x; float offsety = dragdelta.y; bool lockX = General.Interface.CtrlState && !General.Interface.ShiftState; bool lockY = !General.Interface.CtrlState && General.Interface.ShiftState; if (lockX || lockY) { float camAngle = Angle2D.RadToDeg(General.Map.VisualCamera.AngleXY); if (camAngle > 315 || camAngle < 46) { if (lockX) { offsetx = 0; } if (lockY) { offsety = 0; } } else if (camAngle > 225) { if (lockX) { offsety = 0; } if (lockY) { offsetx = 0; } } else if (camAngle > 135) { if (lockX) { offsetx = 0; } if (lockY) { offsety = 0; } } else { if (lockX) { offsety = 0; } if (lockY) { offsetx = 0; } } } //mxd. Modify offsets based on surface and camera angles float angle; if (GeometryType == VisualGeometryType.CEILING) { angle = Angle2D.DegToRad(level.sector.Fields.GetValue("rotationceiling", 0f)); } else { angle = Angle2D.DegToRad(level.sector.Fields.GetValue("rotationfloor", 0f)); } Vector2D v = new Vector2D(offsetx, offsety).GetRotated(angle); offsetx = (int)Math.Round(v.x); offsety = (int)Math.Round(v.y); // Calculate deltas int deltax, deltay; if (General.Interface.CtrlState && General.Interface.ShiftState) { //mxd. Clamp to grid size? int newoffsetx = startoffsetx - (int)Math.Round(offsetx); int newoffsety = startoffsety + (int)Math.Round(offsety); deltax = prevoffsetx - newoffsetx; deltay = prevoffsety - newoffsety; if (Math.Abs(deltax) >= General.Map.Grid.GridSize) { deltax = General.Map.Grid.GridSize * Math.Sign(deltax); prevoffsetx = newoffsetx; } else { deltax = 0; } if (Math.Abs(deltay) >= General.Map.Grid.GridSize) { deltay = General.Map.Grid.GridSize * Math.Sign(deltay); prevoffsety = newoffsety; } else { deltay = 0; } } else { int newoffsetx = startoffsetx - (int)Math.Round(offsetx); int newoffsety = startoffsety + (int)Math.Round(offsety); deltax = prevoffsetx - newoffsetx; deltay = prevoffsety - newoffsety; prevoffsetx = newoffsetx; prevoffsety = newoffsety; } //mxd. Apply offset? if (deltax != 0 || deltay != 0) { mode.ApplyFlatOffsetChange(deltax, deltay); } mode.ShowTargetInfo(); }
// Apply clicked private void apply_Click(object sender, EventArgs e) { List <string> defaultflags = new List <string>(); string undodesc = "thing"; // Verify the tag if (General.Map.FormatInterface.HasThingTag && ((tag.GetResult(0) < General.Map.FormatInterface.MinTag) || (tag.GetResult(0) > General.Map.FormatInterface.MaxTag))) { General.ShowWarningMessage("Thing tag must be between " + General.Map.FormatInterface.MinTag + " and " + General.Map.FormatInterface.MaxTag + ".", MessageBoxButtons.OK); return; } // Verify the type if (((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) { General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK); return; } // Verify the action if (General.Map.FormatInterface.HasThingAction && ((action.Value < General.Map.FormatInterface.MinAction) || (action.Value > General.Map.FormatInterface.MaxAction))) { General.ShowWarningMessage("Thing action must be between " + General.Map.FormatInterface.MinAction + " and " + General.Map.FormatInterface.MaxAction + ".", MessageBoxButtons.OK); return; } // Make undo if (things.Count > 1) { undodesc = things.Count + " things"; } General.Map.UndoRedo.CreateUndo("Edit " + undodesc); // Go for all the things foreach (Thing t in things) { // Thing type index t.Type = General.Clamp(thingtype.GetResult(t.Type), General.Map.FormatInterface.MinThingType, General.Map.FormatInterface.MaxThingType); // Coordination t.Rotate(angle.GetResult(t.AngleDoom)); t.Move(t.Position.x, t.Position.y, (float)height.GetResult((int)t.Position.z)); // Apply all flags foreach (CheckBox c in flags.Checkboxes) { if (c.CheckState == CheckState.Checked) { t.SetFlag(c.Tag.ToString(), true); } else if (c.CheckState == CheckState.Unchecked) { t.SetFlag(c.Tag.ToString(), false); } } // Action/tags t.Tag = tag.GetResult(t.Tag); if (!action.Empty) { t.Action = action.Value; } t.Args[0] = arg0.GetResult(t.Args[0]); t.Args[1] = arg1.GetResult(t.Args[1]); t.Args[2] = arg2.GetResult(t.Args[2]); t.Args[3] = arg3.GetResult(t.Args[3]); t.Args[4] = arg4.GetResult(t.Args[4]); // Custom fields fieldslist.Apply(t.Fields); // Update settings t.UpdateConfiguration(); } // Set as defaults foreach (CheckBox c in flags.Checkboxes) { if (c.CheckState == CheckState.Checked) { defaultflags.Add(c.Tag.ToString()); } } General.Settings.DefaultThingType = thingtype.GetResult(General.Settings.DefaultThingType); General.Settings.DefaultThingAngle = Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90); General.Settings.SetDefaultThingFlags(defaultflags); // Done General.Map.IsChanged = true; Cleanup(); this.DialogResult = DialogResult.OK; this.Close(); }