public override bool Inspect() { if (ProcessEnumerator != null) { "Running Coroutine".nl(); _processEnumerator.Inspect_AsInList(); return(false); } var changed = false; if ("CPU blit options".conditional_enter(this.TargetIsTexture2D(), ref inspectedItems, 0).nl()) { "Disable Continious Lines".toggleIcon("If you see unwanted lines appearing on the texture as you paint, enable this.", ref disableContiniousLine).nl(ref changed); "CPU blit repaint delay".edit("Delay for video memory update when painting to Texture2D", 140, ref _repaintDelay, 0.01f, 0.5f).nl(ref changed); "Don't update mipMaps".toggleIcon("May increase performance, but your changes may not disaplay if you are far from texture.", ref dontRedoMipMaps).changes(ref changed); } if ("GPU blit options".enter(ref inspectedItems, 1).nl()) { "Update Texture2D after every stroke".toggleIcon(ref updateTex2DafterStroke).nl(); } #region Processors var newWidth = Cfg.SelectedWidthForNewTexture(); //PainterDataAndConfig.SizeIndexToSize(PainterCamera.Data.selectedWidthIndex); var newHeight = Cfg.SelectedHeightForNewTexture(); if ("Texture Processors".enter(ref inspectedItems, 6).nl()) { if (errorWhileReading) { "There was en error reading texture pixels, can't process it".writeWarning(); } else { if ("Resize ({0}*{1}) => ({2}*{3})".F(width, height, newWidth, newHeight).enter(ref _inspectedProcess, 0).nl_ifFoldedOut()) { "New Width ".select(60, ref PainterCamera.Data.selectedWidthIndex, PainterDataAndConfig.NewTextureSizeOptions).nl(ref changed); "New Height ".select(60, ref PainterCamera.Data.selectedHeightIndex, PainterDataAndConfig.NewTextureSizeOptions).nl(ref changed); if (newWidth != width || newHeight != height) { bool rescale; if (newWidth <= width && newHeight <= height) { rescale = "Downscale".Click(); } else if (newWidth >= width && newHeight >= height) { rescale = "Upscale".Click(); } else { rescale = "Rescale".Click(); } if (rescale) { Resize(newWidth, newHeight); } } pegi.nl(); } if (_inspectedProcess == -1) { if ((newWidth != width || newHeight != height) && icon.Size.Click("Resize").nl(ref changed)) { Resize(newWidth, newHeight); } pegi.nl(); } if ("Clear ".enter(ref _inspectedProcess, 1, false)) { "Clear Color".edit(80, ref clearColor).nl(); if ("Clear Texture".Click().nl()) { Colorize(clearColor); SetApplyUpdateRenderTexture(); } } if (_inspectedProcess == -1 && icon.Refresh.Click("Apply color {0}".F(clearColor)).nl()) { Colorize(clearColor); SetApplyUpdateRenderTexture(); } if ("Color to Alpha".enter(ref _inspectedProcess, 2).nl()) { "Background Color".edit(80, ref clearColor).nl(); if (Pixels != null) { if ("Color to Alpha".Click("Will Convert Background Color with transparency").nl()) { bool wasRt = WasRenderTexture(); for (int i = 0; i < _pixels.Length; i++) { _pixels[i] = BlitFunctions.ColorToAlpha(_pixels[i], clearColor); } SetAndApply(); if (wasRt) { ReturnToRenderTexture(); } } if ("Color from Alpha".Click("Will subtract background color from transparency").nl()) { bool wasRt = WasRenderTexture(); for (int i = 0; i < _pixels.Length; i++) { var col = _pixels[i]; col.a = BlitFunctions.ColorToAlpha(_pixels[i], clearColor).a; _pixels[i] = col; } SetAndApply(); if (wasRt) { ReturnToRenderTexture(); } } } } if ("Signed Distance Filelds generator".enter(ref _inspectedProcess, 4).nl()) { if (texture2D.IsColorTexture()) { "Texture is a color texture, best to switch to non-color for SDF. Save any changes first, as the texture will reimport.".writeWarning(); #if UNITY_EDITOR var ai = texture2D.GetTextureImporter(); if (ai != null && "Convert to non-Color".ClickConfirm("SDFnc", "This will undo any unsaved changes. Proceed?") && ai.WasWrongIsColor(false)) { ai.SaveAndReimport(); } #endif } "Will convert black and white color to black and white signed field".nl(); "SDF Max Inside".edit(ref sdfMaxInside).nl(); "SDF Max Outside".edit(ref sdfMaxOutside).nl(); "SDF Post Process".edit(ref sdfPostProcessDistance).nl(); if ("Generate Assync".Click("Will take a bit longer but you'll be able to use Unity")) { bool wasRt = WasRenderTexture(); var p = PlaytimePainter.inspected; if (p) { p.UpdateOrSetTexTarget(TexTarget.Texture2D); } _processEnumerator = QcAsync.StartManagedCoroutine( DistanceFieldProcessor.Generate(this, sdfMaxInside, sdfMaxOutside, sdfPostProcessDistance), () => { SetAndApply(); if (wasRt) { ReturnToRenderTexture(); } }); } pegi.nl(); } if ("Curves".enter(ref _inspectedProcess, 5).nl()) { var crv = TexMGMT.InspectAnimationCurve("Channel"); if (Pixels != null) { if ("Remap Alpha".Click()) { for (int i = 0; i < _pixels.Length; i++) { var col = _pixels[i]; col.a = crv.Evaluate(col.a); _pixels[i] = col; } SetApplyUpdateRenderTexture(); } if ("Remap Color".Click()) { for (int i = 0; i < _pixels.Length; i++) { var col = _pixels[i]; col.r = crv.Evaluate(col.r); col.g = crv.Evaluate(col.g); col.b = crv.Evaluate(col.b); _pixels[i] = col; } SetApplyUpdateRenderTexture(); } } } if ("Save Textures In Game ".enter(ref _inspectedProcess, 7).nl()) { "This is intended to test playtime saving. The functions to do so are quite simple. You can find them inside ImageData.cs class." .writeHint(); pegi.nl(); "Save Name".edit(70, ref saveName); if (icon.Folder.Click("Open Folder with textures").nl()) { QcFile.Explorer.OpenPersistentFolder(SavedImagesFolder); } if ("Save Playtime".Click("Will save to {0}/{1}".F(Application.persistentDataPath, saveName)).nl()) { SaveInPlayer(); } if (Cfg && Cfg.playtimeSavedTextures.Count > 0) { "Playtime Saved Textures".write_List(Cfg.playtimeSavedTextures, LoadTexturePegi); } } if ("Fade edges".enter(ref _inspectedProcess, 8).nl()) { ("This will cahange pixels on the edges of the texture. Useful when wrap mode " + "is set to clamp.").writeHint(); if (texture2D) { #if UNITY_EDITOR var ti = texture2D.GetTextureImporter(); if (ti) { if (ti.wrapMode != TextureWrapMode.Clamp && "Change wrap mode from {0} to Clamp" .F(ti.wrapMode).Click().nl(ref changed)) { ti.wrapMode = TextureWrapMode.Clamp; ti.SaveAndReimport(); } } #endif if ("Set edges to transparent".Click().nl(ref changed)) { SetEdges(Color.clear, ColorMask.A); SetAndApply(); } if ("Set edges to Clear Black".Click().nl(ref changed)) { SetEdges(Color.clear); SetAndApply(); } } } if ("Add Background".enter(ref _inspectedProcess, 9).nl()) { "Background Color".edit(80, ref clearColor).nl(); if ("Add Background".Click("Will Add Beckground color and make everything non transparent").nl()) { bool wasRt = WasRenderTexture(); for (int i = 0; i < _pixels.Length; i++) { _pixels[i] = BlitFunctions.AddBackground(_pixels[i], clearColor); } SetAndApply(); if (wasRt) { ReturnToRenderTexture(); } } } if ("Offset".enter(ref _inspectedProcess, 10).nl()) { "X:".edit(ref _offsetByX); if ((_offsetByX != width / 2) && "{0}/{1}".F(width / 2, width).Click()) { _offsetByX = width / 2; } pegi.nl(); "Y:".edit(ref _offsetByY); if ((_offsetByY != height / 2) && "{0}/{1}".F(height / 2, height).Click()) { _offsetByY = height / 2; } pegi.nl(); if (((_offsetByX % width != 0) || (_offsetByY % height != 0)) && "Apply Offset".Click()) { OffsetPixels(); SetAndApply(); } } } } #endregion if ("Enable Undo for '{0}'".F(NameForPEGI).toggle_enter(ref enableUndoRedo, ref inspectedItems, 2, ref changed).nl()) { "UNDOs: Tex2D".edit(80, ref _numberOfTexture2DBackups).changes(ref changed); "RendTex".edit(60, ref _numberOfRenderTextureBackups).nl(ref changed); "Backup manually".toggleIcon(ref backupManually).nl(); if (_numberOfTexture2DBackups > 50 || _numberOfRenderTextureBackups > 50) { "Too big of a number will eat up lot of memory".writeWarning(); } "Creating more backups will eat more memory".writeOneTimeHint("backupIsMem"); "This are not connected to Unity's Undo/Redo because when you run out of backups you will by accident start undoing other operations.".writeOneTimeHint("noNativeUndo"); "Use Z/X to undo/redo".writeOneTimeHint("ZxUndoRedo"); } if (inspectedItems == -1) { if (isAVolumeTexture) { "Is A volume texture".toggleIcon(ref isAVolumeTexture).nl(ref changed); } } return(changed); }
public void PaintPixelsInRam(StrokeVector stroke, float brushAlpha, ImageMeta image, BrushConfig bc, PlaytimePainter painter) { var volume = image.texture2D.GetVolumeTextureData(); if (!volume) { return; } if (volume.VolumeJobIsRunning) { return; } bc.brush3DRadius = Mathf.Min(BrushScaleMaxForCpu(volume), bc.brush3DRadius); var volumeScale = volume.size; var pos = (stroke.posFrom - volume.transform.position) / volumeScale + 0.5f * Vector3.one; var height = volume.Height; var texWidth = image.width; BlitFunctions.brAlpha = brushAlpha; bc.PrepareCpuBlit(image); BlitFunctions.half = bc.Size(true) / volumeScale; var pixels = image.Pixels; var iHalf = (int)(BlitFunctions.half - 0.5f); var smooth = bc.GetBrushType(true) != BrushTypePixel.Inst; if (smooth) { iHalf += 1; } BlitFunctions.alphaMode = BlitFunctions.SphereAlpha; var sliceWidth = texWidth / volume.hSlices; var hw = sliceWidth / 2; var y = (int)pos.y; var z = (int)(pos.z + hw); var x = (int)(pos.x + hw); for (BlitFunctions.y = -iHalf; BlitFunctions.y < iHalf + 1; BlitFunctions.y++) { var h = y + BlitFunctions.y; if (h >= height) { return; } if (h < 0) { continue; } var hy = h / volume.hSlices; var hx = h % volume.hSlices; var hTexIndex = (hy * texWidth + hx) * sliceWidth; for (BlitFunctions.z = -iHalf; BlitFunctions.z < iHalf + 1; BlitFunctions.z++) { var trueZ = z + BlitFunctions.z; if (trueZ < 0 || trueZ >= sliceWidth) { continue; } var yTexIndex = hTexIndex + trueZ * texWidth; for (BlitFunctions.x = -iHalf; BlitFunctions.x < iHalf + 1; BlitFunctions.x++) { if (!BlitFunctions.alphaMode()) { continue; } var trueX = x + BlitFunctions.x; if (trueX < 0 || trueX >= sliceWidth) { continue; } var texIndex = yTexIndex + trueX; BlitFunctions.blitMode(ref pixels[texIndex]); } } } }
public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, TextureMeta image, BrushConfig bc, PlaytimePainter painter) { if (!painter.IsAtlased()) { return(false); } var uvCoords = stroke.uvFrom; var atlasedSection = GetAtlasedSection(); sectorSize = image.width / atlasRows; atlasSector.From(atlasedSection * sectorSize); BlitFunctions.brAlpha = brushAlpha; BlitFunctions.half = (bc.Size(false)) / 2; var iHalf = Mathf.FloorToInt(BlitFunctions.half - 0.5f); var smooth = bc.GetBrushType(true) != BrushTypes.Pixel.Inst; if (smooth) { BlitFunctions.alphaMode = BlitFunctions.CircleAlpha; } else { BlitFunctions.alphaMode = BlitFunctions.NoAlpha; } BlitFunctions.blitMode = bc.GetBlitMode(true).BlitFunctionTex2D(image); if (smooth) { iHalf += 1; } BlitFunctions.alpha = 1; BlitFunctions.Set(bc.mask); BlitFunctions.cSrc = bc.Color; var tmp = image.UvToPixelNumber(uvCoords); var fromX = tmp.x - iHalf; tmp.y -= iHalf; var pixels = image.Pixels; for (BlitFunctions.y = -iHalf; BlitFunctions.y < iHalf + 1; BlitFunctions.y++) { tmp.x = fromX; for (BlitFunctions.x = -iHalf; BlitFunctions.x < iHalf + 1; BlitFunctions.x++) { if (BlitFunctions.alphaMode()) { var sx = tmp.x - atlasSector.x; var sy = tmp.y - atlasSector.y; sx %= sectorSize; if (sx < 0) { sx += sectorSize; } sy %= sectorSize; if (sy < 0) { sy += sectorSize; } BlitFunctions.blitMode(ref pixels[((atlasSector.y + sy)) * image.width + (atlasSector.x + sx)]); } tmp.x += 1; } tmp.y += 1; } return(true); }