public static Bitmap RenderBitmapFromBlueprint(CancellationToken?worker, BlueprintPA blueprint, out int?textureSize) { // TODO: Make sure this value is saved to the render panel instance somehow or else there will be horrible issues textureSize = RenderedImagePanel.CalculateTextureSize(blueprint); if (textureSize == null) { return(null); } if (blueprint != null) { try { TaskManager.SafeReport(0, "Preparing canvas for textures"); bool isSelectiveLayerViewEnabled = Options.Get.IsEnabled(Constants.RenderedZIndexFilter, false); bool isMaterialFilterViewEnabled = Options.Get.SelectedMaterialFilter.Any(); bool isSide = Options.Get.IsSideView; double origW = blueprint.Width; double origH = blueprint.Height; //int w = (int) (origW * MainForm.PanZoomSettings.zoomLevel); //int h = (int) (origH * MainForm.PanZoomSettings.zoomLevel); //int zoom = (int) (MainForm.PanZoomSettings.zoomLevel); SolidBrush brush = new SolidBrush(Color.Black); Pen pen = new Pen(brush); bool isMaterialIncludedInFilter = true; int mWidth = blueprint.Width; int mHeight = blueprint.Height; int mDepth = Options.Get.IsMultiLayer ? 2 : 1; int calcW = mWidth * textureSize.Value; int calcH = mHeight * textureSize.Value; TaskManager.SafeReport(20, "Preparing canvas for textures"); Bitmap bm = new Bitmap( width: calcW, height: calcH, format: PixelFormat.Format32bppArgb); TaskManager.SafeReport(50, "Preparing canvas for textures"); var selectedMaterials = Options.Get.SelectedMaterialFilter.AsEnumerable().ToList(); // clone bool _IsSolidColors = Options.Get.Rendered_IsSolidColors; bool _IsColorPalette = Options.Get.Rendered_IsColorPalette; bool _IsMultiLayer = Options.Get.IsMultiLayer; bool _isSkipShadowRendering = Options.Get.IsShadowRenderingSkipped; int _RenderedZIndexToShow = Options.Get.Rendered_RenderedZIndexToShow; bool _isFrugalAesthetic = Options.Get.IsExtraShadowDepthEnabled && !selectedMaterials.Any(); using (Graphics gImg = Graphics.FromImage(bm)) { gImg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; gImg.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; gImg.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; #region Regular for (int z = 0; z < mDepth; z++) { TaskManager.SafeReport(0, "Applying textures... (Layer " + z + ")"); if (isSelectiveLayerViewEnabled) { if (z != _RenderedZIndexToShow) { continue; } } for (int x = 0; x < mWidth; x++) { TaskManager.SafeReport(100 * x / mWidth); worker?.SafeThrowIfCancellationRequested(); for (int y = 0; y < mHeight; y++) { int xi = x * textureSize.Value; int yi = y * textureSize.Value; //if (xi + MainForm.PanZoomSettings.zoomLevel >= 0 && yi + MainForm.PanZoomSettings.zoomLevel >= 0) { Material m = blueprint.GetMaterialAt(x, y, z, !_isFrugalAesthetic); if (isMaterialFilterViewEnabled) { string blockId = m.PixelStackerID; isMaterialIncludedInFilter = Options.Get.SelectedMaterialFilter.Any(xm => xm == blockId); } if (m.BlockID != 0) { if (_IsSolidColors) { if (isMaterialIncludedInFilter) { brush.Color = blueprint.GetColor(x, y); gImg.FillRectangle(brush, xi, yi, textureSize.Value, textureSize.Value); } } else if (_IsColorPalette) { if (isMaterialIncludedInFilter) { brush.Color = blueprint.GetColor(x, y); gImg.DrawImage(m.getImage(isSide), xi, yi, textureSize.Value, textureSize.Value); gImg.FillRectangle(brush, xi, yi, textureSize.Value / 2, textureSize.Value / 2); brush.Color = Color.Black; gImg.DrawRectangle(pen, xi, yi, textureSize.Value / 2, textureSize.Value / 2); } } else { if (isMaterialIncludedInFilter) { gImg .DrawImage(m.getImage(isSide), xi, yi, textureSize.Value, textureSize.Value); } } } } } } } #endregion #region SHADOW_NEW if (!_isSkipShadowRendering) { Bitmap bmShadeSprites = ShadowHelper.GetSpriteSheet(Constants.TextureSize); Bitmap bmShadow = new Bitmap( width: calcW, height: calcH, format: PixelFormat.Format32bppArgb); byte[,] shadowMap = new byte[mWidth, mHeight]; { #region Initialize shadow map (booleans basically) TaskManager.SafeReport(0, "Calculating shadow placement map"); for (int xShadeMap = 0; xShadeMap < mWidth; xShadeMap++) { TaskManager.SafeReport(100 * xShadeMap / mWidth); worker?.SafeThrowIfCancellationRequested(); for (int yShadeMap = 0; yShadeMap < mHeight; yShadeMap++) { Material mBottom = blueprint.GetMaterialAt(xShadeMap, yShadeMap, 0, true); bool isBottomShown = mBottom.BlockID != 0 && (selectedMaterials.Count == 0 || selectedMaterials.Any(xm => xm == mBottom.PixelStackerID)); Material mTop = blueprint.GetMaterialAt(xShadeMap, yShadeMap, 1, !_isFrugalAesthetic); bool isTopShown = mTop.BlockID != 0 && (selectedMaterials.Count == 0 || selectedMaterials.Any(xm => xm == mTop.PixelStackerID)); if (isTopShown && isBottomShown) { shadowMap[xShadeMap, yShadeMap] = SHOWN_TOP_AND_BOTTOM; } else if (isTopShown) { shadowMap[xShadeMap, yShadeMap] = SHOWN_TOP; } else if (isBottomShown) { shadowMap[xShadeMap, yShadeMap] = SHOWN_BOTTOM; } else { shadowMap[xShadeMap, yShadeMap] = SHOWN_NONE; } } } #endregion using (Graphics gShadow = Graphics.FromImage(bmShadow)) { gShadow.CompositingMode = CompositingMode.SourceOver; // over is slower but better... gShadow.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; gShadow.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gShadow.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; var brushTransparentCover = new SolidBrush(Color.FromArgb(40, 127, 127, 127)); { TaskManager.SafeReport(0, "Rendering shadows"); for (int x = 0; x < mWidth; x++) { TaskManager.SafeReport(100 * x / mWidth); worker?.SafeThrowIfCancellationRequested(); for (int y = 0; y < mHeight; y++) { int xi = x * textureSize.Value; int yi = y * textureSize.Value; bool isTopShown = shadowMap[x, y] == SHOWN_TOP || shadowMap[x, y] == SHOWN_TOP_AND_BOTTOM; bool isBottomShown = shadowMap[x, y] == SHOWN_BOTTOM || shadowMap[x, y] == SHOWN_TOP_AND_BOTTOM; bool isBottomCoveredByInvisibleTop = isBottomShown && !isTopShown; // The thing that makes it slightly less saturated on bottom layer if (isBottomCoveredByInvisibleTop && _IsMultiLayer) { gShadow.FillRectangle(brushTransparentCover, xi, yi, textureSize.Value, textureSize.Value); } if (isTopShown && isBottomShown) { continue; // No shade required } // AIR block (or block we aint rendering) if (!isTopShown) { ShadeFrom sFrom = ShadeFrom.EMPTY; bool isBlockTop = y > 0 && isShaded(shadowMap[x, y], shadowMap[x, y - 1]); bool isBlockLeft = x > 0 && isShaded(shadowMap[x, y], shadowMap[x - 1, y]); bool isBlockRight = x < mWidth - 1 && isShaded(shadowMap[x, y], shadowMap[x + 1, y]); bool isBlockBottom = (y < mHeight - 1 && isShaded(shadowMap[x, y], shadowMap[x, y + 1])); bool isBlockTopLeft = (y > 0 && x > 0 && isShaded(shadowMap[x, y], shadowMap[x - 1, y - 1])); bool isBlockTopRight = (y > 0 && x < mWidth - 1 && isShaded(shadowMap[x, y], shadowMap[x + 1, y - 1])); bool isBlockBottomLeft = (y < mHeight - 1 && x > 0 && isShaded(shadowMap[x, y], shadowMap[x - 1, y + 1])); bool isBlockBottomRight = (y < mHeight - 1 && x < mWidth - 1 && isShaded(shadowMap[x, y], shadowMap[x + 1, y + 1])); if (isBlockTop) { sFrom |= ShadeFrom.T; } if (isBlockLeft) { sFrom |= ShadeFrom.L; } if (isBlockRight) { sFrom |= ShadeFrom.R; } if (isBlockBottom) { sFrom |= ShadeFrom.B; } if (isBlockTopLeft) { sFrom |= ShadeFrom.TL; } if (isBlockTopRight) { sFrom |= ShadeFrom.TR; } if (isBlockBottomLeft) { sFrom |= ShadeFrom.BL; } if (isBlockBottomRight) { sFrom |= ShadeFrom.BR; } var shadeImg = ShadowHelper.GetSpriteIndividual(Constants.TextureSize, sFrom); gShadow.DrawImage(image: shadeImg, xi, yi, textureSize.Value, textureSize.Value); } } } } brushTransparentCover.Dispose(); } gImg.CompositingMode = CompositingMode.SourceOver; gImg.DrawImage(bmShadow, 0, 0, calcW, calcH); } } #endregion brush.DisposeSafely(); pen.DisposeSafely(); } return(bm); } catch (Exception ex) { Console.WriteLine(ex); blueprint = null; } } return(null); }