void HandleTool_ColorPickFromPlayer(bool trigger, IMyPlayer targetPlayer) { PlayerInfo pi = Main.Palette.GetPlayerInfo(targetPlayer.SteamUserId); if (pi == null) { Log.Error($"{GetType().Name} :: PlayerInfo for {targetPlayer.DisplayName} ({targetPlayer.SteamUserId.ToString()}) not found!", Log.PRINT_MESSAGE); return; } AimedPlayer = targetPlayer; AimedPlayersPaint = pi.GetPaintMaterial(); if (trigger) { Main.Palette.ColorPickMode = false; Main.Palette.GrabPaletteFromPaint(AimedPlayersPaint, changeApply: true); return; } if (!ToolPreviewPaint.HasValue || !ToolPreviewPaint.Value.PaintEquals(AimedPlayersPaint)) { ToolPreviewPaint = AimedPlayersPaint; Main.HUDSounds.PlayItem(); } Main.SelectionGUI.SetGUIStatus(0, "Click to get engineer's selected color."); Main.SelectionGUI.SetGUIStatus(1, null); return; }
void HandleTool_ColorPickModeFromBlock(PaintMaterial paintMaterial, BlockMaterial blockMaterial, bool trigger) { if (trigger) { Main.Palette.ColorPickMode = false; Main.Palette.GrabPaletteFromPaint(new PaintMaterial(blockMaterial.ColorMask, blockMaterial.Skin)); return; } if (!ToolPreviewPaint.HasValue || !ToolPreviewPaint.Value.PaintEquals(blockMaterial)) { ToolPreviewPaint = new PaintMaterial(blockMaterial.ColorMask, blockMaterial.Skin); Main.HUDSounds.PlayItem(); } if (paintMaterial.ColorMask.HasValue && !paintMaterial.Skin.HasValue) { Main.SelectionGUI.SetGUIStatus(0, "Click to get this color.", "lime"); } else if (!paintMaterial.ColorMask.HasValue && paintMaterial.Skin.HasValue) { Main.SelectionGUI.SetGUIStatus(0, "Click to select this skin.", "lime"); } else { Main.SelectionGUI.SetGUIStatus(0, "Click to get this material.", "lime"); } Main.SelectionGUI.SetGUIStatus(1, null); }
/// <summary> /// Fill to buffer base rows data information using non-zero rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> protected override void OnFillingNonZero( PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex) { if (!(paint.Paint is LinearGradient)) { NotMatchPaintTypeException.Publish(typeof(LinearGradient), paint.Paint.GetType()); return; } LinearGradient linearGradient = paint.Paint as LinearGradient; switch (linearGradient.Mode) { case LinearGradientMode.Horizontal: OnFillingHorizontalNonZero(linearGradient, paint.ScaledOpacity, rows, startRowIndex, endRowIndex); break; case LinearGradientMode.Vertical: OnFillingVerticalNonZero(linearGradient, paint.ScaledOpacity, rows, startRowIndex, endRowIndex); break; case LinearGradientMode.ForwardDiagonal: OnFillingDiagonalNonZero(linearGradient, paint.ScaledOpacity, rows, startRowIndex, endRowIndex, true); break; case LinearGradientMode.BackwardDiagonal: OnFillingDiagonalNonZero(linearGradient, paint.ScaledOpacity, rows, startRowIndex, endRowIndex, false); break; } }
/// <summary> /// Filling method including prepare material and perform filling /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> protected void Filling(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { //this.CurrentPaint = paint; PrepareMaterial(paint, CurrentStartXIndex, startYIndex, CurrentEndXIndex, endYIndex); OnFilling(paint, rows, startYIndex, endYIndex); OnFinishFilling(); }
public override void Execute(MyCommandLine parser) { bool rgb = (parser.Argument(1) == "rgb"); float[] values = new float[3]; if (rgb && parser.Argument(2).StartsWith("#", COMPARE_TYPE)) { string hexText = parser.Argument(2); if (hexText.Length < 7) { Utils.ShowColoredChatMessage(PaintGunMod.MOD_NAME, "Invalid HEX color, needs 6 characters after #.", MyFontEnum.Red); return; } int c = 0; for (int i = 1; i < 7; i += 2) { values[c++] = Convert.ToInt32(hexText[i].ToString() + hexText[i + 1].ToString(), 16); } } else { if (parser.ArgumentCount != 5) { Utils.ShowColoredChatMessage(PaintGunMod.MOD_NAME, "Need to specify 3 numbers separated by spaces.", MyFontEnum.Red); return; } for (int i = 0; i < 3; i++) { string arg = parser.Argument(i + 2); if (!float.TryParse(arg, out values[i])) { Utils.ShowColoredChatMessage(PaintGunMod.MOD_NAME, $"'{arg}' is not a valid number!", MyFontEnum.Red); return; } } } Vector3 colorMask; if (rgb) { colorMask = Utils.RGBToColorMask(new Color(MathHelper.Clamp((int)values[0], 0, 255), MathHelper.Clamp((int)values[1], 0, 255), MathHelper.Clamp((int)values[2], 0, 255))); } else { colorMask = Utils.HSVToColorMask(new Vector3(MathHelper.Clamp(values[0], 0f, 360f) / 360.0f, MathHelper.Clamp(values[1], 0f, 100f) / 100.0f, MathHelper.Clamp(values[2], 0f, 100f) / 100.0f)); } PaintMaterial material = new PaintMaterial(colorMask, Main.Palette.GetLocalPaintMaterial().Skin); Main.Palette.GrabPaletteFromPaint(material); }
public override void Received(ref RelayMode relay) { // no way to check if creative tools is enabled for sender but it's enough to check their access level. if (Main.IsServer && MyAPIGateway.Session.GetUserPromoteLevel(OriginalSenderSteamId) < MyPromoteLevel.SpaceMaster) { MyLog.Default.WriteLineAndConsole($"{PaintGunMod.MOD_NAME} Warning: Player {Utils.PrintPlayerName(OriginalSenderSteamId)} tried to use replace paint while not being at least SpaceMaster promote level."); Main.NetworkLibHandler.PacketWarningMessage.Send(OriginalSenderSteamId, "Failed to replace paint server side, access denied."); return; } bool modified = false; if (!Main.Palette.ValidateSkinOwnership(NewPaint.Skin, OriginalSenderSteamId)) { NewPaint = new SerializedPaintMaterial(NewPaint.ColorMaskPacked, null); modified = true; } MyCubeGrid grid = Utils.GetEntityOrError <MyCubeGrid>(this, GridEntId, Constants.NETWORK_DESYNC_ERROR_LOGGING); if (grid == null) { if (Main.IsServer) { Main.NetworkLibHandler.PacketWarningMessage.Send(OriginalSenderSteamId, "Failed to replace paint server side, grid no longer exists."); } return; } if (Main.IsServer) { // ensure server side if safezone permissions are respected if (!Utils.SafeZoneCanPaint(grid, OriginalSenderSteamId)) { Main.NetworkLibHandler.PacketWarningMessage.Send(OriginalSenderSteamId, "Failed to replace paint server side, denied by safe zone."); return; } long identity = MyAPIGateway.Players.TryGetIdentityId(OriginalSenderSteamId); if (!Utils.AllowedToPaintGrid(grid, identity)) { Main.NetworkLibHandler.PacketWarningMessage.Send(OriginalSenderSteamId, "Failed to replace paint server side, ship not allied."); return; } } PaintMaterial newPaint = new PaintMaterial(NewPaint); BlockMaterial oldPaint = new BlockMaterial(OldPaint); Main.Painting.ReplaceColorInGrid(false, grid, oldPaint, newPaint, IncludeSubgrids, OriginalSenderSteamId); if (Main.IsServer) { relay = modified ? RelayMode.RelayWithChanges : RelayMode.RelayOriginal; } }
Vector3I?MirrorHighlight(IMyCubeGrid grid, int axis, Vector3I originalPosition, List <Vector3I> alreadyMirrored) { Vector3I?mirrorPosition = null; switch (axis) { case 0: if (grid.XSymmetryPlane.HasValue) { mirrorPosition = originalPosition + new Vector3I(((grid.XSymmetryPlane.Value.X - originalPosition.X) * 2) - (grid.XSymmetryOdd ? 1 : 0), 0, 0); } break; case 1: if (grid.YSymmetryPlane.HasValue) { mirrorPosition = originalPosition + new Vector3I(0, ((grid.YSymmetryPlane.Value.Y - originalPosition.Y) * 2) - (grid.YSymmetryOdd ? 1 : 0), 0); } break; case 2: if (grid.ZSymmetryPlane.HasValue) { mirrorPosition = originalPosition + new Vector3I(0, 0, ((grid.ZSymmetryPlane.Value.Z - originalPosition.Z) * 2) + (grid.ZSymmetryOdd ? 1 : 0)); // reversed on odd } break; } if (mirrorPosition.HasValue && mirrorPosition.Value != originalPosition && !alreadyMirrored.Contains(mirrorPosition.Value)) { alreadyMirrored.Add(mirrorPosition.Value); IMySlimBlock block = grid.GetCubeBlock(mirrorPosition.Value); if (block != null) { mirroredValidTotal++; PaintMaterial paintMaterial = Main.Palette.GetLocalPaintMaterial(); bool validSelection = Main.LocalToolHandler.IsMirrorBlockValid(block, paintMaterial); if (validSelection) { mirroredValid++; } DrawBlockSelection(block, (validSelection ? SelectionState.Valid : SelectionState.Invalid)); } } return(mirrorPosition); // this must be returned regardless if block exists or not }
} // Empty constructor required for deserialization public void Send(IMyCubeGrid grid, BlockMaterial oldPaint, PaintMaterial newPaint, bool includeSubgrids) { GridEntId = grid.EntityId; OldPaint = new SerializedBlockMaterial(oldPaint); NewPaint = new SerializedPaintMaterial(newPaint); IncludeSubgrids = includeSubgrids; Network.SendToServer(this); // do the action for local client too if (!MyAPIGateway.Session.IsServer) { Main.Painting.ReplaceColorInGrid(false, grid, oldPaint, newPaint, includeSubgrids, OriginalSenderSteamId); } }
} // Empty constructor required for deserialization public void Send(IMyCubeGrid grid, Vector3I blockPosition, PaintMaterial paint, bool useMirroring) { GridEntId = grid.EntityId; BlockPosition = blockPosition; Paint = new SerializedPaintMaterial(paint); MirrorData = (useMirroring ? new MirrorData(grid) : default(MirrorData)); Network.SendToServer(this); // do the action for local client too if (!MyAPIGateway.Session.IsServer) { DoAction(grid); } }
public bool IsMirrorBlockValid(IMySlimBlock block, PaintMaterial paintMaterial) { if (block == null) { return(false); } if (Main.Palette.ColorPickMode) { return(false); } if (!paintMaterial.ColorMask.HasValue && !paintMaterial.Skin.HasValue) { return(false); } if (!Utils.AllowedToPaintGrid(block.CubeGrid, MyAPIGateway.Session.Player.IdentityId)) { return(false); } if (!Utils.SafeZoneCanPaint(block, MyAPIGateway.Multiplayer.MyId)) { return(false); } BlockMaterial blockMaterial = new BlockMaterial(block); bool materialEquals = paintMaterial.PaintEquals(blockMaterial); if (Main.Palette.ReplaceMode) { return(!materialEquals); } if (!Main.InstantPaintAccess) { MyCubeBlockDefinition def = (MyCubeBlockDefinition)block.BlockDefinition; bool built = (block.BuildLevelRatio >= def.CriticalIntegrityRatio); if (!built || block.CurrentDamage > (block.MaxIntegrity / 10.0f)) { return(false); } } return(!materialEquals); }
protected override void OnFilling(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { //outside of box, no need to fill if (IsClipBoxOutSideBound) { return; } if (!IsTransformed) { base.OnFilling(paint, rows, startYIndex, endYIndex); } else { // when gamma function is assigned and gamma function need to apply //if ((mGamma != null) && (mGamma.IsAppliedGamma)) if (mGamma != null) { if (paint.FillingRule == FillingRule.NonZero) { // fill non-zero including gamma OnFillingTransformedNonZero(paint, rows, startYIndex, endYIndex, mGamma.GetLookupTableRed(), mGamma.GetLookupTableGreen(), mGamma.GetLookupTableBlue()); } else { // fill Even-Odd including gamma OnFillingTransformedEvenOdd(paint, rows, startYIndex, endYIndex, mGamma.GetLookupTableRed(), mGamma.GetLookupTableGreen(), mGamma.GetLookupTableBlue()); } } else { //Cross.Log.Debug("Filling without gamma"); if (paint.FillingRule == FillingRule.NonZero) { OnFillingTransformedNonZero(paint, rows, startYIndex, endYIndex); } else { OnFillingTransformedEvenOdd(paint, rows, startYIndex, endYIndex); } } } }
bool DoAction(IMyCubeGrid grid) { if (!Main.Palette.ValidateSkinOwnership(Paint.Skin, OriginalSenderSteamId)) { //Paint = new SerializedPaintMaterial(Paint.ColorMaskPacked, null); return(false); } PaintMaterial paint = new PaintMaterial(Paint); if (MirrorData.HasMirroring) { Main.Painting.PaintBlockSymmetry(false, grid, BlockPosition, paint, MirrorData, OriginalSenderSteamId); } else { Main.Painting.PaintBlock(false, grid, BlockPosition, paint, OriginalSenderSteamId); } return(true); }
void UpdatePaintCanMaterial() { PaintMaterial material = PaintPreviewMaterial ?? OwnerInfo.GetPaintMaterial(); MyDefinitionManager.MyAssetModifiers skinRender = default(MyDefinitionManager.MyAssetModifiers); Vector3?skinColorOverride = null; if (material.Skin.HasValue) { skinRender = MyDefinitionManager.Static.GetAssetModifierDefinitionForRender(material.Skin.Value); MyAssetModifierDefinition skinDef = MyDefinitionManager.Static.GetAssetModifierDefinition(new MyDefinitionId(typeof(MyObjectBuilder_AssetModifierDefinition), material.Skin.Value)); if (skinDef != null && skinDef.DefaultColor.HasValue) { skinColorOverride = skinDef.DefaultColor.Value.ColorToHSVDX11(); } } Vector3 colorMask = skinColorOverride ?? material.ColorMask ?? Main.Palette.DefaultColorMask; IMyEntity paintEntity = (MagazineSubpart as IMyEntity) ?? Rifle; paintEntity.Render.MetalnessColorable = skinRender.MetalnessColorable; paintEntity.Render.TextureChanges = skinRender.SkinTextureChanges; // required to properly update skin (like glamour not being recolorable paintEntity.Render.RemoveRenderObjects(); paintEntity.Render.AddRenderObjects(); if (!paintEntity.Render.EnableColorMaskHsv) { paintEntity.Render.EnableColorMaskHsv = true; } paintEntity.Render.ColorMaskHsv = colorMask; ParticleColor = Utils.ColorMaskToRGB(colorMask); }
/// <summary> /// Rasterize and fill the polygon directly in one pass. This approach is slightly faster than the normal renderation process (Begin, Addxxx, Finish) /// </summary> /// <param name="paint">The paint material used for filling</param> /// <param name="data">raw data array in format [x1,y1, x2,y2, ...]</param> /// <param name="pointCount">Number of points contained within data</param> /// <param name="startOffset">Index of the first point in data </param> /// <param name="offsetX">offseted X</param> /// <param name="offsetY">offseted Y</param> public void FillPolygon(PaintMaterial paint, double[] data, int pointCount, int startOffset, double offsetX, double offsetY) { if (IsClipBoxOutSideBound) { return; } double calculatedX = 0, calculatedY = 0; int endIndex = startOffset + pointCount * 2; #region determine the startY,endY // Start,end y for drawing int endRowPosition = int.MinValue; int startRowPosition = int.MaxValue; CurrentStartXIndex = int.MaxValue; CurrentEndXIndex = int.MinValue; for (int i = startOffset; i < endIndex; i += 2) { calculatedX = data[i] + offsetX; calculatedY = data[i + 1] + offsetY; if (calculatedX > CurrentEndXIndex) { CurrentEndXIndex = (int)calculatedX + 1; } if (calculatedX < CurrentStartXIndex) { CurrentStartXIndex = (int)calculatedX; } if (calculatedY > endRowPosition) { endRowPosition = (int)calculatedY + 1; } if (calculatedY < startRowPosition) { startRowPosition = (int)calculatedY; } } #endregion #region prepare Rows array startRowPosition--; endRowPosition++; if (startRowPosition < ClippingBoxYMin) { startRowPosition = (int)ClippingBoxYMin; } if (endRowPosition > ClippingBoxYMax + 1) { endRowPosition = (int)ClippingBoxYMax + 1; } for (int rowIndex = startRowPosition; rowIndex <= endRowPosition; rowIndex++) { Rows[rowIndex] = new RowData(); } #endregion #region draw lines CurrentXPosition = data[startOffset] + offsetX; CurrentYPosition = data[startOffset + 1] + offsetY; CurrentPositionFlag = ((CurrentXPosition > ClippingBoxXMax) ? XMaxClippingFlag : (CurrentXPosition < ClippingBoxXMin) ? XMinClippingFlag : 0) | ((CurrentYPosition > ClippingBoxYMax) ? YMaxClippingFlag : (CurrentYPosition < ClippingBoxYMin) ? YMinClippingFlag : 0); for (int i = startOffset + 2; i < endIndex; i += 2) { if (CurrentYPosition != data[i + 1] + offsetY) { DrawAndClippedLine(data[i] + offsetX, data[i + 1] + offsetY); } else { // just move to and calculate the flag CurrentXPosition = data[i] + offsetX; CurrentYPosition = data[i + 1] + offsetY; CurrentPositionFlag = ((CurrentXPosition > ClippingBoxXMax) ? XMaxClippingFlag : (CurrentXPosition < ClippingBoxXMin) ? XMinClippingFlag : 0) | ((CurrentYPosition > ClippingBoxYMax) ? YMaxClippingFlag : (CurrentYPosition < ClippingBoxYMin) ? YMinClippingFlag : 0); } } if (CurrentYPosition != data[startOffset + 1] + offsetY) { DrawAndClippedLine(data[startOffset] + offsetX, data[startOffset + 1] + offsetY); } #endregion #region fill BuildMask(Rows, startRowPosition, endRowPosition); //Filling(paint, Rows, startRowPosition, endRowPosition); #endregion }
/// <summary> /// Fill to buffer base rows data information using even odd rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> protected abstract void OnFillingEvenOdd(PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex);
/// <summary> /// Prepare material for paint,including define the bounding box of drawing /// </summary> /// <param name="paint">paint</param> /// <param name="startXIndex">start x index</param> /// <param name="startYIndex">start y index</param> /// <param name="endXIndex">end x index</param> /// <param name="endYIndex">end y index</param> protected virtual void PrepareMaterial(PaintMaterial paint, int startXIndex, int startYIndex, int endXIndex, int endYIndex) { }
/// <summary> /// Rasterize and fill the polygon directly in one pass. This approach is slightly faster than the normal renderation process (Begin, Addxxx, Finish) /// </summary> /// <param name="paint">The paint material used for filling</param> /// <param name="data">raw data array in format [x1,y1, x2,y2, ...]</param> /// <param name="pointCount">Number of points contained within data</param> /// <param name="startOffset">Index of the first point in data </param> /// <param name="offsetX">offseted X</param> /// <param name="offsetY">offseted Y</param> public void FillPolygon(PaintMaterial paint, double[] data, int pointCount, int startOffset, double offsetX, double offsetY) { if (IsClipBoxOutSideBound) { return; } double calculatedX = 0, calculatedY = 0; int endIndex = startOffset + pointCount * 2; #region determine the startY,endY // Start,end y for drawing int endRowPosition = int.MinValue; int startRowPosition = int.MaxValue; CurrentStartXIndex = int.MaxValue; CurrentEndXIndex = int.MinValue; for (int i = startOffset; i < endIndex; i += 2) { calculatedX = data[i] + offsetX; calculatedY = data[i + 1] + offsetY; if (calculatedX > CurrentEndXIndex) { CurrentEndXIndex = (int)calculatedX + 1; } if (calculatedX < CurrentStartXIndex) { CurrentStartXIndex = (int)calculatedX; } if (calculatedY > endRowPosition) { endRowPosition = (int)calculatedY + 1; } if (calculatedY < startRowPosition) { startRowPosition = (int)calculatedY; } } #endregion #region prepare Rows array startRowPosition--; endRowPosition++; if (startRowPosition < ClippingBoxYMin) { startRowPosition = (int)ClippingBoxYMin; } if (endRowPosition > ClippingBoxYMax + 1) { endRowPosition = (int)ClippingBoxYMax + 1; } for (int rowIndex = startRowPosition; rowIndex <= endRowPosition; rowIndex++) { Rows[rowIndex] = new RowData(); } #endregion #region draw lines CurrentXPosition = data[startOffset] + offsetX; CurrentYPosition = data[startOffset + 1] + offsetY; CurrentPositionFlag = ((CurrentXPosition > ClippingBoxXMax) ? XMaxClippingFlag : (CurrentXPosition < ClippingBoxXMin) ? XMinClippingFlag : 0) | ((CurrentYPosition > ClippingBoxYMax) ? YMaxClippingFlag : (CurrentYPosition < ClippingBoxYMin) ? YMinClippingFlag : 0); for (int i = startOffset + 2; i < endIndex; i += 2) { if (CurrentYPosition != data[i + 1] + offsetY) { DrawAndClippedLine(data[i] + offsetX, data[i + 1] + offsetY); } else { // just move to and calculate the flag CurrentXPosition = data[i] + offsetX; CurrentYPosition = data[i + 1] + offsetY; CurrentPositionFlag = ((CurrentXPosition > ClippingBoxXMax) ? XMaxClippingFlag : (CurrentXPosition < ClippingBoxXMin) ? XMinClippingFlag : 0) | ((CurrentYPosition > ClippingBoxYMax) ? YMaxClippingFlag : (CurrentYPosition < ClippingBoxYMin) ? YMinClippingFlag : 0); } } if (CurrentYPosition != data[startOffset + 1] + offsetY) { DrawAndClippedLine(data[startOffset] + offsetX, data[startOffset + 1] + offsetY); } #endregion #region fill Filling(paint, Rows, startRowPosition, endRowPosition); #endregion }
/// <summary> /// Filling row data result from start y index to end y index including transformation /// <para>While filling can use CurrentTransformMatrix, or InverterMatrix... to calculate /// or access transformation information</para> /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> protected override void OnFillingTransformedNonZero( PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { if (!(paint.Paint is LinearGradient)) { //throw new NotImplementedException("Support color paint only"); NotMatchPaintTypeException.Publish(typeof(LinearGradient), paint.Paint.GetType()); return; } LinearGradient linearGradient = paint.Paint as LinearGradient; switch (linearGradient.Mode) { case LinearGradientMode.Horizontal: OnFillingTransformedHorizontalNonZero(linearGradient, paint.ScaledOpacity, rows, startYIndex, endYIndex); break; case LinearGradientMode.Vertical: OnFillingTransformedVerticalNonZero(linearGradient, paint.ScaledOpacity, rows, startYIndex, endYIndex); break; case LinearGradientMode.ForwardDiagonal: OnFillingTransformedDiagonalNonZero(linearGradient, paint.ScaledOpacity, rows, startYIndex, endYIndex, true); break; case LinearGradientMode.BackwardDiagonal: OnFillingTransformedDiagonalNonZero(linearGradient, paint.ScaledOpacity, rows, startYIndex, endYIndex, false); break; } }
/// <summary> /// Filling row data result from start y index to end y index including transformation /// <para>While filling can use CurrentTransformMatrix, or InverterMatrix... to calculate /// or access transformation information</para> /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> protected abstract void OnFillingTransformedNonZero(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue);
/// <summary> /// Filling row data result from start y index to end y index including transformation /// <para>While filling can use CurrentTransformMatrix, or InverterMatrix... to calculate /// or access transformation information</para> /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> protected override void OnFillingTransformedNonZero(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue) { throw new NotImplementedException(); }
/// <summary> /// Returns True if tool has painted. /// </summary> void HandleTool(bool trigger) { AimedPlayer = null; AimedBlock = null; AimedState = SelectionState.Invalid; SymmetryInputAvailable = false; IMyCharacter character = MyAPIGateway.Session.Player.Character; IMyCubeGrid targetGrid; IMySlimBlock targetBlock; IMyPlayer targetPlayer; Vector3D aimPoint; GetTarget(character, out targetGrid, out targetBlock, out targetPlayer, out aimPoint); if (targetPlayer != null && Main.Palette.ColorPickMode) { HandleTool_ColorPickFromPlayer(trigger, targetPlayer); return; } if (targetBlock == null) { if (Main.Palette.ColorPickMode) { Main.Notifications.Show(0, "Aim at a block or player and click to pick color.", MyFontEnum.Blue); } else if (!Utils.SafeZoneCanPaint(aimPoint, MyAPIGateway.Multiplayer.MyId)) { // sound likely already played by the shoot restriction in the safe zone //HUDSounds.PlayUnable(); if (trigger) { Main.Notifications.Show(0, "Can't paint in this safe zone.", MyFontEnum.Red); } } else if (Main.Palette.ReplaceMode) { Main.Notifications.Show(0, $"Aim at a block to replace its color on {(Main.Palette.ReplaceShipWide ? "the entire ship" : "this grid")}.", MyFontEnum.Blue); } else if (trigger) { //Main.HUDSounds.PlayUnable(); if (!Main.IgnoreAmmoConsumption && LocalTool.Ammo == 0) { Main.Notifications.Show(0, "No ammo and no target.", MyFontEnum.Red); } else { Main.Notifications.Show(0, "Aim at a block to paint it.", MyFontEnum.Red); } } return; } Main.SelectionGUI.UpdateSymmetryStatus(targetBlock); PaintMaterial paintMaterial = Main.Palette.GetLocalPaintMaterial(); BlockMaterial blockMaterial = new BlockMaterial(targetBlock); AimedBlock = targetBlock; if (Main.Palette.ColorPickMode) { HandleTool_ColorPickModeFromBlock(paintMaterial, blockMaterial, trigger); return; } if (!ValidateMainBlock(targetBlock, paintMaterial, blockMaterial, trigger)) { return; } string blockName = Utils.GetBlockName(targetBlock); if (!Main.IgnoreAmmoConsumption && LocalTool.Ammo == 0) { if (trigger) { //Main.HUDSounds.PlayUnable(); Main.Notifications.Show(1, "No ammo.", MyFontEnum.Red); } Main.SelectionGUI.SetGUIStatus(0, "No ammo!", "red"); return; } AimedState = SelectionState.Valid; if (trigger) { float paintSpeed = (1.0f / Utils.GetBlockSurface(targetBlock)); PaintMaterial finalMaterial = HandleTool_PaintProcess(paintMaterial, blockMaterial, paintSpeed, blockName); if (Main.Palette.ReplaceMode && Main.ReplaceColorAccess) { Main.Painting.ToolReplacePaint(targetGrid, blockMaterial, finalMaterial, Main.Palette.ReplaceShipWide); } else { bool useMirroring = (Main.SymmetryAccess && MyAPIGateway.CubeBuilder.UseSymmetry); Main.Painting.ToolPaintBlock(targetGrid, targetBlock.Position, finalMaterial, useMirroring); } } }
/// <summary> /// Fill to buffer base rows data information using non zero rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> protected override void OnFillingNonZero(PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex) { throw new NotImplementedException(); }
/// <summary> /// Filling row data result from start y index to end y index including transformation /// <para>While filling can use CurrentTransformMatrix, or InverterMatrix... to calculate /// or access transformation information</para> /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> protected override void OnFillingTransformedEvenOdd(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { throw new NotImplementedException(); }
/// <summary> /// Fill to buffer base rows data information using even odd rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> protected override void OnFillingEvenOdd(PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue) { throw new NotImplementedException(); }
/// <summary> /// Fill to buffer base rows data information using even odd rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> protected override void OnFillingEvenOdd(PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue) { // this base on paint to filling if (!(paint.Paint is RadialGradient)) { //throw new NotImplementedException("Support color paint only"); NotMatchPaintTypeException.Publish(typeof(RadialGradient), paint.Paint.GetType()); return; } RadialGradient radial = paint.Paint as RadialGradient; if (radial.RadiusX == radial.RadiusY) { if ((radial.FocusX == radial.CenterX) && (radial.FocusY == radial.CenterY)) { // when normal radial gradient FillingRadialEvenOdd(radial, paint.ScaledOpacity, rows, startRowIndex, endRowIndex, gammaLutRed, gammaLutGreen, gammaLutBlue); } else { // circle and focus gradient FillingRadialFocalEvenOdd(radial, paint.ScaledOpacity, rows, startRowIndex, endRowIndex, gammaLutRed, gammaLutGreen, gammaLutBlue); } } else { if ((radial.FocusX == radial.CenterX) && (radial.FocusY == radial.CenterY)) { // when normal ellipse gradient FillingEllipseEvenOdd(radial, paint.ScaledOpacity, rows, startRowIndex, endRowIndex, gammaLutRed, gammaLutGreen, gammaLutBlue); } else { // ellipse and focus gradient FillingEllipseFocalEvenOdd(radial, paint.ScaledOpacity, rows, startRowIndex, endRowIndex, gammaLutRed, gammaLutGreen, gammaLutBlue); } } }
/// <summary> /// Filling row data result from start y index to end y index including transformation /// <para>While filling can use CurrentTransformMatrix, or InverterMatrix... to calculate /// or access transformation information</para> /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> protected override void OnFillingTransformedNonZero(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { throw new NotImplementedException(); }
/// <summary> /// Filling row data result from start y index to end y index including transformation /// <para>While filling can use CurrentTransformMatrix, or InverterMatrix... to calculate /// or access transformation information</para> /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> protected abstract void OnFillingTransformedNonZero(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex);
void UpdateGUI() { if (!Main.TextAPI.IsEnabled || !Main.CheckPlayerField.Ready) { return; } if (uiTitle == null) { const int MAX_EXPECTED_CHARACTERS_TITLE = 64; const int MAX_EXPECTED_CHARACTERS_TEXT = 512; // NOTE: this creation order is needed to have background elements stay in background when everything uses PostPP (or SDR) at once. int i = 0; ui[i++] = uiTextBg = new HudAPIv2.BillBoardHUDMessage(Main.PaletteHUD.MATERIAL_PALETTE_BACKGROUND, uiPosition, UI_TEXT_BG_COLOR, Width: UI_BOX_WIDTH, Height: UI_TEXT_BG_HEIGHT, Blend: UI_BG_BLENDTYPE); ui[i++] = uiTitleBg = new HudAPIv2.BillBoardHUDMessage(Main.PaletteHUD.MATERIAL_PALETTE_BACKGROUND, uiPosition, UI_TITLE_BG_COLOR, Width: UI_BOX_WIDTH, Height: UI_TITLE_BG_HEIGHT, Blend: UI_BG_BLENDTYPE); ui[i++] = uiTitle = new HudAPIv2.HUDMessage(new StringBuilder(MAX_EXPECTED_CHARACTERS_TITLE), uiPosition, Scale: UI_TITLE_SCALE, Blend: UI_FG_BLENDTYPE); ui[i++] = uiText = new HudAPIv2.HUDMessage(new StringBuilder(MAX_EXPECTED_CHARACTERS_TEXT), uiPosition, Scale: UI_TEXT_SCALE, Blend: UI_FG_BLENDTYPE); ui[i++] = uiTargetColor = new HudAPIv2.BillBoardHUDMessage(MATERIAL_ICON_GENERIC_BLOCK, uiPosition, Color.White, Width: UI_COLORBOX_WIDTH, Height: UI_COLORBOX_HEIGHT, Blend: UI_FG_BLENDTYPE); ui[i++] = uiPaintColor = new HudAPIv2.BillBoardHUDMessage(MATERIAL_ICON_PAINT_AMMO, uiPosition, Color.White, Width: UI_COLORBOX_WIDTH, Height: UI_COLORBOX_HEIGHT, Blend: UI_FG_BLENDTYPE); ui[i++] = uiProgressBarBg = new HudAPIv2.BillBoardHUDMessage(Main.PaletteHUD.MATERIAL_PALETTE_BACKGROUND, uiPosition, UI_PROGRESSBAR_BG_COLOR, Width: UI_PROGRESSBAR_WIDTH, Height: UI_PROGRESSBAR_HEIGHT, Blend: UI_BG_BLENDTYPE); ui[i++] = uiProgressBar = new HudAPIv2.BillBoardHUDMessage(Main.PaletteHUD.MATERIAL_PALETTE_BACKGROUND, uiPosition, UI_PROGRESSBAR_COLOR, Width: UI_PROGRESSBAR_WIDTH, Height: UI_PROGRESSBAR_HEIGHT, Blend: UI_FG_BLENDTYPE); UpdateUISettings(); } bool targetCharacter = (Main.Palette.ColorPickMode && Main.LocalToolHandler.AimedPlayer != null); bool visible = (!MyAPIGateway.Gui.IsCursorVisible && Main.Palette.LocalInfo != null && (targetCharacter || Main.LocalToolHandler.AimedBlock != null)); SetGUIVisible(visible); if (!visible) { return; } PaintMaterial targetMaterial; PaintMaterial paint = Main.Palette.GetLocalPaintMaterial(); int ammo = (Main.LocalToolHandler.LocalTool != null ? Main.LocalToolHandler.LocalTool.Ammo : 0); StringBuilder title = uiTitle.Message.Clear().Append("<color=220,244,252>"); float progress = 0f; if (targetCharacter) { uiTargetColor.Material = MATERIAL_ICON_GENERIC_CHARACTER; targetMaterial = Main.LocalToolHandler.AimedPlayersPaint; uiTargetColor.BillBoardColor = (targetMaterial.ColorMask.HasValue ? Utils.ColorMaskToRGB(targetMaterial.ColorMask.Value) : Color.Gray); title.AppendLimitedChars(Main.LocalToolHandler.AimedPlayer.DisplayName, GUI_TITLE_MAX_CHARS); } else { uiTargetColor.Material = MATERIAL_ICON_GENERIC_BLOCK; IMySlimBlock block = Main.LocalToolHandler.AimedBlock; targetMaterial = new PaintMaterial(block.ColorMaskHSV, block.SkinSubtypeId); uiTargetColor.BillBoardColor = Utils.ColorMaskToRGB(targetMaterial.ColorMask.Value); if (paint.ColorMask.HasValue) { progress = Utils.ColorScalar(targetMaterial.ColorMask.Value, paint.ColorMask.Value); } else { progress = 1f; } progress *= 0.75f; if (paint.Skin.HasValue && targetMaterial.Skin == paint.Skin.Value) { progress += 0.25f; } progress = MathHelper.Clamp(progress, 0, 1f); MyCubeBlockDefinition selectedDef = (MyCubeBlockDefinition)block.BlockDefinition; title.AppendLimitedChars(selectedDef.DisplayNameText, GUI_TITLE_MAX_CHARS); } uiPaintColor.BillBoardColor = (paint.ColorMask.HasValue ? Utils.ColorMaskToRGB(paint.ColorMask.Value) : Color.Gray); float height = UI_PROGRESSBAR_HEIGHT * progress; uiProgressBar.Height = height; uiProgressBar.Offset = new Vector2D(uiProgressBar.Width * 0.5, -UI_PROGRESSBAR_HEIGHT + uiProgressBar.Height * 0.5) + uiProgressBarPosition; StringBuilder text = uiText.Message; text.Clear().Append(blockInfoStatus[0]); text.Append('\n'); text.Append('\n'); { text.Append("<color=220,244,252>"); if (Main.Palette.ColorPickMode && Main.LocalToolHandler.AimedPlayer != null) { text.Append("Engineer's selected paint:"); } else { text.Append("Block's material:"); } text.Append('\n').Append(" HSV: "); if (targetMaterial.ColorMask.HasValue) { if (Main.Palette.IsColorMaskInPalette(targetMaterial.ColorMask.Value)) { text.Append("<color=55,255,55>"); } else { text.Append("<color=255,200,25>"); } text.Append(Utils.ColorMaskToString(targetMaterial.ColorMask.Value)); } else { text.Append("(N/A)"); } text.Append('\n'); text.Append("<color=white> Skin: "); if (targetMaterial.Skin.HasValue) { SkinInfo targetSkin = Main.Palette.GetSkinInfo(targetMaterial.Skin.Value); if (targetSkin != null) { if (!targetSkin.LocallyOwned) { text.Append("<color=red>"); } else if (targetSkin.SubtypeId == MyStringHash.NullOrEmpty) { text.Append("<color=gray>"); } text.Append(targetSkin.Name); } else { text.Append("<color=gray>").Append(targetMaterial.Skin.Value.ToString()).Append(" <color=red>(uninstalled)"); } } else { text.Append("(N/A)"); } text.Append('\n'); } text.Append('\n'); { text.Append("<color=220,244,252>"); if (Main.Palette.ColorPickMode) { text.Append("Replace slot: ").Append(Main.Palette.LocalInfo.SelectedColorSlot + 1); } else { text.Append("Paint: "); if (Main.IgnoreAmmoConsumption) { text.Append("Inf."); } else { text.Append(ammo); } } text.Append('\n'); } { text.Append(" "); if (paint.ColorMask.HasValue) { text.Append("<color=white>HSV: ").Append(Utils.ColorMaskToString(paint.ColorMask.Value)).Append('\n'); } else { text.Append('\n'); } } { if (paint.Skin.HasValue) { text.Append(" <color=white>Skin: "); SkinInfo skin = Main.Palette.GetSkinInfo(paint.Skin.Value); if (skin != null) { if (skin.SubtypeId == MyStringHash.NullOrEmpty) { text.Append("<color=gray>"); } text.Append(skin.Name); } else { text.Append("<color=gray>").Append(paint.Skin.Value.ToString()).Append(" <color=red>(uninstalled)"); } } text.Append('\n'); } text.Append("<color=white>"); if (blockInfoStatus[1] != null) { text.Append('\n').Append(blockInfoStatus[1]); } if (blockInfoStatus[2] != null) { text.Append('\n').Append(blockInfoStatus[2]); } }
/// <summary> /// Fill to buffer base rows data information using even odd rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> /// <param name="gammaLutRed">gamma look up table for red</param> /// <param name="gammaLutGreen">gamma look up table for green</param> /// <param name="gammaLutBlue">gamma look up table for blue</param> protected abstract void OnFillingEvenOdd(PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex, byte[] gammaLutRed, byte[] gammaLutGreen, byte[] gammaLutBlue);
bool ValidateMainBlock(IMySlimBlock block, PaintMaterial paintMaterial, BlockMaterial blockMaterial, bool trigger) { if (!paintMaterial.ColorMask.HasValue && !paintMaterial.Skin.HasValue) { string assigned = InputHandler.GetFriendlyStringForControl(MyAPIGateway.Input.GetGameControl(MyControlsSpace.CUBE_COLOR_CHANGE)); Main.Notifications.Show(0, "No paint or skin enabled.", MyFontEnum.Red); Main.Notifications.Show(1, $"Press [{assigned}] to toggle color or combined with [Shift] to toggle skin.", MyFontEnum.Debug); Main.SelectionGUI.SetGUIStatus(0, "No paint or skin enabled.", "red"); Main.SelectionGUI.SetGUIStatus(1, null); return(false); } if (!Utils.AllowedToPaintGrid(block.CubeGrid, MyAPIGateway.Session.Player.IdentityId)) { if (trigger) { Main.HUDSounds.PlayUnable(); Main.Notifications.Show(0, "Can't paint enemy ships.", MyFontEnum.Red, 2000); } Main.SelectionGUI.SetGUIStatus(0, "Not allied ship.", "red"); Main.SelectionGUI.SetGUIStatus(1, null); return(false); } if (!Utils.SafeZoneCanPaint(block, MyAPIGateway.Multiplayer.MyId)) { if (trigger) { Main.HUDSounds.PlayUnable(); Main.Notifications.Show(0, "Can't paint in this safe zone.", MyFontEnum.Red, 2000); } Main.SelectionGUI.SetGUIStatus(0, "Protected by safe zone", "red"); Main.SelectionGUI.SetGUIStatus(1, null); return(false); } bool materialEquals = paintMaterial.PaintEquals(blockMaterial); if (Main.Palette.ReplaceMode) { AimedState = (materialEquals ? SelectionState.Invalid : SelectionState.Valid); string assigned = InputHandler.GetFriendlyStringForControl(MyAPIGateway.Input.GetGameControl(MyControlsSpace.USE_SYMMETRY)); if (AimedState == SelectionState.Invalid) { Main.SelectionGUI.SetGUIStatus(0, "Already this material.", "red"); } else { Main.SelectionGUI.SetGUIStatus(0, "Click to replace material.", "lime"); } Main.SelectionGUI.SetGUIStatus(1, $"[{assigned}] {(Main.Palette.ReplaceShipWide ? "<color=yellow>" : "")}Replace mode: {(Main.Palette.ReplaceShipWide ? "Ship-wide" : "Grid")}"); return(AimedState == SelectionState.Valid); } if (!Main.InstantPaintAccess) { MyCubeBlockDefinition def = (MyCubeBlockDefinition)block.BlockDefinition; bool built = (block.BuildLevelRatio >= def.CriticalIntegrityRatio); if (!built || block.CurrentDamage > (block.MaxIntegrity / 10.0f)) { AimedState = SelectionState.Invalid; if (trigger) { Main.HUDSounds.PlayUnable(); Main.Notifications.Show(0, "Unfinished blocks can't be painted!", MyFontEnum.Red); } Main.SelectionGUI.SetGUIStatus(0, (!built ? "Block not built" : "Block damaged"), "red"); Main.SelectionGUI.SetGUIStatus(1, null); return(false); } } MyCubeGrid grid = (MyCubeGrid)block.CubeGrid; bool symmetry = Main.SymmetryAccess && MyCubeBuilder.Static.UseSymmetry && (grid.XSymmetryPlane.HasValue || grid.YSymmetryPlane.HasValue || grid.ZSymmetryPlane.HasValue); bool symmetrySameColor = true; if (materialEquals) { AimedState = SelectionState.Invalid; if (symmetry) { Vector3I?mirrorX = null; Vector3I?mirrorY = null; Vector3I?mirrorZ = null; Vector3I?mirrorYZ = null; // NOTE: do not optimize, all methods must be called if (!MirrorCheckSameColor(grid, 0, block.Position, paintMaterial, out mirrorX)) { symmetrySameColor = false; } if (!MirrorCheckSameColor(grid, 1, block.Position, paintMaterial, out mirrorY)) { symmetrySameColor = false; } if (!MirrorCheckSameColor(grid, 2, block.Position, paintMaterial, out mirrorZ)) { symmetrySameColor = false; } if (mirrorX.HasValue && grid.YSymmetryPlane.HasValue) // XY { if (!MirrorCheckSameColor(grid, 1, mirrorX.Value, paintMaterial, out mirrorX)) { symmetrySameColor = false; } } if (mirrorX.HasValue && grid.ZSymmetryPlane.HasValue) // XZ { if (!MirrorCheckSameColor(grid, 2, mirrorX.Value, paintMaterial, out mirrorX)) { symmetrySameColor = false; } } if (mirrorY.HasValue && grid.ZSymmetryPlane.HasValue) // YZ { if (!MirrorCheckSameColor(grid, 2, mirrorY.Value, paintMaterial, out mirrorYZ)) { symmetrySameColor = false; } } if (grid.XSymmetryPlane.HasValue && mirrorYZ.HasValue) // XYZ { if (!MirrorCheckSameColor(grid, 0, mirrorYZ.Value, paintMaterial, out mirrorX)) { symmetrySameColor = false; } } if (!symmetrySameColor) { AimedState = SelectionState.InvalidButMirrorValid; } } if (!symmetry || symmetrySameColor) { AimedState = SelectionState.Invalid; if (symmetry) { Main.SelectionGUI.SetGUIStatus(0, "All materials match.", "lime"); } else { Main.SelectionGUI.SetGUIStatus(0, "Materials match.", "lime"); } Main.SelectionGUI.SetGUIStatus(1, Main.SelectionGUI.SymmetryStatusText); return(false); } } if (!trigger) { if (symmetry && !symmetrySameColor) { Main.SelectionGUI.SetGUIStatus(0, "Click to update symmetry paint."); } else if (Main.InstantPaintAccess) { Main.SelectionGUI.SetGUIStatus(0, "Click to paint."); } else { Main.SelectionGUI.SetGUIStatus(0, "Hold click to paint."); } Main.SelectionGUI.SetGUIStatus(1, Main.SelectionGUI.SymmetryStatusText); } return(true); }
bool MirrorCheckSameColor(IMyCubeGrid grid, int axis, Vector3I originalPosition, PaintMaterial paintMaterial, out Vector3I?mirrorPosition) { mirrorPosition = null; switch (axis) { case 0: if (grid.XSymmetryPlane.HasValue) { mirrorPosition = originalPosition + new Vector3I(((grid.XSymmetryPlane.Value.X - originalPosition.X) * 2) - (grid.XSymmetryOdd ? 1 : 0), 0, 0); } break; case 1: if (grid.YSymmetryPlane.HasValue) { mirrorPosition = originalPosition + new Vector3I(0, ((grid.YSymmetryPlane.Value.Y - originalPosition.Y) * 2) - (grid.YSymmetryOdd ? 1 : 0), 0); } break; case 2: if (grid.ZSymmetryPlane.HasValue) { mirrorPosition = originalPosition + new Vector3I(0, 0, ((grid.ZSymmetryPlane.Value.Z - originalPosition.Z) * 2) + (grid.ZSymmetryOdd ? 1 : 0)); // reversed on odd } break; } if (mirrorPosition.HasValue) { IMySlimBlock slim = grid.GetCubeBlock(mirrorPosition.Value); if (slim != null) { return(paintMaterial.PaintEquals(slim)); } } return(true); }
/// <summary> /// Perform filling into rasterized result /// </summary> /// <param name="paint">paint</param> /// <param name="rows">rows</param> /// <param name="startYIndex">start y index</param> /// <param name="endYIndex">end y index</param> protected virtual void OnFilling(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { //outside of box, no need to fill if (IsClipBoxOutSideBound) return; //Cross.Log.Debug("Start row {0}, end rows {1}",startYIndex,endYIndex); // when gamma function is assigned and gamma function need to apply //if ((mGamma != null) &&(mGamma.IsAppliedGamma)) if ((mGamma != null)) { if (paint.FillingRule == FillingRule.NonZero) { // fill non-zero including gamma OnFillingNonZero(paint, Rows, startYIndex, endYIndex, mGamma.GetLookupTableRed(), mGamma.GetLookupTableGreen(), mGamma.GetLookupTableBlue()); } else { // fill Even-Odd including gamma OnFillingEvenOdd(paint, Rows, startYIndex, endYIndex, mGamma.GetLookupTableRed(), mGamma.GetLookupTableGreen(), mGamma.GetLookupTableBlue()); } } else { //Cross.Log.Debug("Filling without gamma"); if (paint.FillingRule == FillingRule.NonZero) { OnFillingNonZero(paint, Rows, startYIndex, endYIndex); } else { OnFillingEvenOdd(paint, Rows, startYIndex, endYIndex); } } }
/// <summary> /// Fill to buffer base rows data information using even odd rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startRowIndex">start row index in row array need to draw</param> /// <param name="endRowIndex">end row index in end row array need to draw</param> protected override void OnFillingEvenOdd(PaintMaterial paint, RowData[] rows, int startRowIndex, int endRowIndex) { throw new NotImplementedException(); }
/// <summary> /// Fill to buffer base rows data information using EvenOdd rule /// </summary> /// <param name="paint">paint using for fill</param> /// <param name="rows">row data information</param> /// <param name="startYIndex">start row index in row array need to draw</param> /// <param name="endYIndex">end row index in end row array need to draw</param> protected override void OnFillingEvenOdd(PaintMaterial paint, RowData[] rows, int startYIndex, int endYIndex) { if (!(paint.Paint is ColorPaint)) { //throw new NotImplementedException("Support color paint only"); NotMatchPaintTypeException.Publish(typeof(ColorPaint), paint.Paint.GetType()); return; } Color currentColor = ((ColorPaint)paint.Paint).Color; #region private variable for filling int currentCoverage, scLastCoverage, scLastX = 0; int tempCover = 0; int currentArea = 0; int lastXPosition = 0; int startXPosition = 0; CellData currentCellData = null; byte calculatedCoverage = 0; uint colorData = currentColor.Data; uint colorAlpha = (currentColor.A * paint.ScaledOpacity) >> 8; if (paint.ScaledOpacity < 256) { colorData = (colorAlpha << 24) | (colorAlpha & 0x00FFFFFF); } uint colorG = currentColor.Green; uint colorRB = currentColor.RB; uint dst, dstRB, dstG; #endregion if (mOpacityMask != null) { #region check the y of mask if (startYIndex < MaskStartY) startYIndex = MaskStartY; if (endYIndex > MaskEndY - 1) endYIndex = MaskEndY - 1; #endregion #region variable using opacity mask int currentMaskY = startYIndex - MaskStartY; int currentMaskIndex = 0; #endregion #region PERFORM FILLING startYIndex--; while (++startYIndex <= endYIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startYIndex] != null) { // get first cell in current row currentCellData = rows[startYIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1) && (scLastCoverage != 0)) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region even odd change scLastCoverage &= 511; if (scLastCoverage >= 256) { scLastCoverage = 512 - scLastCoverage - 1; } #endregion //fill from currentX position to last x position scLastCoverage = (byte)((scLastCoverage * colorAlpha) >> 8); if (scLastCoverage > 0) { #region BLEND HORIZONTAL LINE // calculate start and end position #region modifi for start ,end X position if (scLastX + 1 < MaskStartX) { startXPosition = BufferStartOffset + startYIndex * BufferStride + MaskStartX; currentMaskIndex = currentMaskY * MaskStride + MaskStartOffset; } else { startXPosition = BufferStartOffset + startYIndex * BufferStride + scLastX + 1; currentMaskIndex = currentMaskY * MaskStride + MaskStartOffset + scLastX + 1 - MaskStartX; } if (currentCellData.X > MaskEndX) { lastXPosition = BufferStartOffset + startYIndex * BufferStride + MaskEndX; } else { lastXPosition = BufferStartOffset + startYIndex * BufferStride + currentCellData.X; } #endregion while (startXPosition < lastXPosition) { if (MaskData[currentMaskIndex] > 0) { calculatedCoverage = (byte)((scLastCoverage * (MaskData[currentMaskIndex] + 1)) >> 8); #region blend here // because scLastCoverage about 255 when multiply with 255 will have value about 254 if (calculatedCoverage >= 254) { // draw only BufferData[startXPosition] = colorData; } else // != 255 { //calculatedCoverage = (byte)scLastCoverage; //blending here dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); } #endregion } // go next cell startXPosition++; currentMaskIndex++; } #endregion } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // calculate tempcover tempCover = ((currentCoverage << 9) - currentArea) >> 9; if (tempCover != 0) { // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); #region even odd change tempCover &= 511; if (tempCover >= 256) { tempCover = 512 - tempCover - 1; } #endregion tempCover = (int)((tempCover * colorAlpha) >> 8); #region blend pixel if ((currentCellData.X >= MaskStartX) && (currentCellData.X < MaskEndX)) { #region mask chage currentMaskIndex = currentMaskY * MaskStride + MaskStartOffset + currentCellData.X - MaskStartX; #endregion if (MaskData[currentMaskIndex] > 0) { calculatedCoverage = (byte)((tempCover * (MaskData[currentMaskIndex] + 1)) >> 8); startXPosition = BufferStartOffset + startYIndex * BufferStride + currentCellData.X; dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); } } #endregion } #endregion scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } // increase current mask y currentMaskY++; } #endregion } else { startYIndex--; while (++startYIndex <= endYIndex) { currentCoverage = scLastCoverage = scLastX = 0; if (rows[startYIndex] != null) { // get first cell in current row currentCellData = rows[startYIndex].First; if (currentCellData != null) { #region fill current row do { currentArea = currentCellData.Area; #region blend horizontal line if ((currentCellData.X > scLastX + 1) && (scLastCoverage != 0)) { // fast bit absolute scLastCoverage = (scLastCoverage ^ (scLastCoverage >> 31)) - (scLastCoverage >> 31); #region even odd change //scLastCoverage &= 511; //if (scLastCoverage > 256) //{ // scLastCoverage = 512 - scLastCoverage; //} scLastCoverage &= 511; if (scLastCoverage >= 256) { scLastCoverage = 512 - scLastCoverage - 1; } #endregion if (scLastCoverage != 0) { #region BLEND HORIZONTAL LINE // calculate start and end position startXPosition = BufferStartOffset + startYIndex * BufferStride + scLastX + 1; lastXPosition = BufferStartOffset + startYIndex * BufferStride + currentCellData.X; //fill from currentX position to last x position scLastCoverage = (byte)((scLastCoverage * colorAlpha) >> 8); if (scLastCoverage >= 254) { // draw only while (startXPosition < lastXPosition) { BufferData[startXPosition++] = colorData; } } else // != 255 { calculatedCoverage = (byte)scLastCoverage; //blending here while (startXPosition < lastXPosition) { dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition++] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); } } #endregion } } #endregion currentCoverage += currentCellData.Coverage; #region blend the current cell // fast absolute tempCover = ((currentCoverage << 9) - currentArea) >> 9; // fast bit absolute tempCover = (tempCover ^ (tempCover >> 31)) - (tempCover >> 31); //tempCover &= 511; //if (tempCover >= 256) //{ // tempCover = 512 - tempCover; //} #region even odd change tempCover &= 511; if (tempCover >= 256) { tempCover = 512 - tempCover - 1; } #endregion if (tempCover != 0) { #region blend pixel tempCover = (int)((tempCover * colorAlpha) >> 8); //if (tempCover > 255) tempCover = 255; calculatedCoverage = (byte)tempCover; startXPosition = BufferStartOffset + startYIndex * BufferStride + currentCellData.X; dst = BufferData[startXPosition]; dstRB = dst & 0x00FF00FF; dstG = (dst >> 8) & 0xFF; BufferData[startXPosition] = (uint)(AlphaCache[(((dst >> 24) & 0xFF) << 8) + calculatedCoverage]) | (uint)((((((colorG - dstG) * calculatedCoverage) >> 8) + dstG) << 8) & 0x0000FF00) | (uint)(((((colorRB - dstRB) * calculatedCoverage) >> 8) + dstRB) & 0x00FF00FF); #endregion } #endregion scLastCoverage = currentCoverage; scLastX = currentCellData.X; // move to next cell currentCellData = currentCellData.Next; } while (currentCellData != null); #endregion } } } } }
PaintMaterial HandleTool_PaintProcess(PaintMaterial paintMaterial, BlockMaterial blockMaterial, float paintSpeed, string blockName) { if (Main.Palette.ReplaceMode) { // notification for this is done in the ReceivedPacket method to avoid re-iterating blocks return(paintMaterial); } if (!paintMaterial.ColorMask.HasValue && !paintMaterial.Skin.HasValue) { return(paintMaterial); } if (Main.InstantPaintAccess) { Main.SelectionGUI.SetGUIStatus(0, "Painted!", "lime"); Main.SelectionGUI.SetGUIStatus(1, Main.SelectionGUI.SymmetryStatusText); return(paintMaterial); } if (!paintMaterial.ColorMask.HasValue && paintMaterial.Skin.HasValue) { Main.SelectionGUI.SetGUIStatus(0, "Skinned!", "lime"); Main.SelectionGUI.SetGUIStatus(1, Main.SelectionGUI.SymmetryStatusText); return(paintMaterial); } Vector3 paintColorMask = (paintMaterial.ColorMask.HasValue ? paintMaterial.ColorMask.Value : blockMaterial.ColorMask); Vector3 blockColorMask = blockMaterial.ColorMask; // If hue is within reason change saturation and value directly. if (Math.Abs(blockColorMask.X - paintColorMask.X) < PAINT_HUE_TOLERANCE) { paintSpeed *= PAINT_SPEED * PAINT_UPDATE_TICKS; paintSpeed *= MyAPIGateway.Session.WelderSpeedMultiplier; for (int i = 0; i < 3; i++) { if (blockColorMask.GetDim(i) > paintColorMask.GetDim(i)) { blockColorMask.SetDim(i, Math.Max(blockColorMask.GetDim(i) - paintSpeed, paintColorMask.GetDim(i))); } else { blockColorMask.SetDim(i, Math.Min(blockColorMask.GetDim(i) + paintSpeed, paintColorMask.GetDim(i))); } } if (Utils.ColorMaskEquals(blockColorMask, paintColorMask)) { blockColorMask = paintColorMask; Main.SelectionGUI.SetGUIStatus(0, "Painting done!", "lime"); Main.HUDSounds.PlayColor(); } else { int percent = Utils.ColorPercent(blockColorMask, paintColorMask); Main.SelectionGUI.SetGUIStatus(0, $"Painting {percent.ToString()}%..."); } } else // if hue is too far off, first "remove" the paint. { Vector3 defaultColorMask = Main.Palette.DefaultColorMask; paintSpeed *= DEPAINT_SPEED * PAINT_UPDATE_TICKS; paintSpeed *= MyAPIGateway.Session.GrinderSpeedMultiplier; blockColorMask.Y = Math.Max(blockColorMask.Y - paintSpeed, defaultColorMask.Y); blockColorMask.Z = (blockColorMask.Z > 0 ? Math.Max(blockColorMask.Z - paintSpeed, defaultColorMask.Z) : Math.Min(blockColorMask.Z + paintSpeed, defaultColorMask.Z)); // when saturation and value reach the default color, change hue and begin painting if (Math.Abs(blockColorMask.Y - defaultColorMask.Y) < COLOR_EPSILON && Math.Abs(blockColorMask.Z - defaultColorMask.Z) < COLOR_EPSILON) { blockColorMask.X = paintColorMask.X; } // block was stripped of color if (Utils.ColorMaskEquals(blockColorMask, defaultColorMask)) { // set the X (hue) to the paint's hue so that the other condition starts painting it saturation&value. blockColorMask = new Vector3(paintColorMask.X, defaultColorMask.Y, defaultColorMask.Z); if (Utils.ColorMaskEquals(paintColorMask, defaultColorMask)) { blockColorMask = paintColorMask; Main.SelectionGUI.SetGUIStatus(0, "Removing paint done!"); } else { Main.SelectionGUI.SetGUIStatus(0, "Removing paint 100%..."); } } else { int percent = Utils.ColorPercent(blockColorMask, defaultColorMask); Main.SelectionGUI.SetGUIStatus(0, $"Removing paint {percent.ToString()}%..."); } } return(new PaintMaterial(blockColorMask, paintMaterial.Skin)); }