public override void DrawRect(PackedCol col, int x, int y, int width, int height) { RectF rec = new RectF(x, y, x + width, y + height); Paint brush = GetOrCreateBrush(col); c.DrawRect(rec, brush); }
public override void DrawRectBounds(PackedCol col, int lineWidth, int x, int y, int width, int height) { using (Pen pen = new Pen(col, lineWidth)) { pen.Alignment = PenAlignment.Inset; g.DrawRectangle(pen, x, y, width, height); } }
public override void Clear(PackedCol col, int x, int y, int width, int height) { g.SmoothingMode = SmoothingMode.None; Brush brush = GetOrCreateBrush(col); g.FillRectangle(brush, x, y, width, height); g.SmoothingMode = SmoothingMode.HighQuality; }
public override void DrawRectBounds(PackedCol col, float lineWidth, int x, int y, int width, int height) { RectF rec = new RectF(x, y, x + width, y + height); Paint brush = GetOrCreateBrush(col); brush.SetStyle(Paint.Style.Stroke); c.DrawRect(rec, brush); brush.SetStyle(Paint.Style.FillAndStroke); }
public override void Clear(PackedCol col, int x, int y, int width, int height) { RectF rec = new RectF(x, y, x + width, y + height); Paint brush = GetOrCreateBrush(col); brush.AntiAlias = false; c.DrawRect(rec, brush); brush.AntiAlias = true; }
protected override void PreStretchTiles(int x1, int y1, int z1) { base.PreStretchTiles(x1, y1, z1); for (int i = 0; i <= 4; i++) { lerp[i] = PackedCol.Lerp(env.Shadow, env.Sun, i / 4f); lerpX[i] = PackedCol.Lerp(env.ShadowXSide, env.SunXSide, i / 4f); lerpZ[i] = PackedCol.Lerp(env.ShadowZSide, env.SunZSide, i / 4f); lerpY[i] = PackedCol.Lerp(env.ShadowYBottom, env.SunYBottom, i / 4f); } }
static IsometricBlockDrawer() { PackedCol.GetShaded(PackedCol.White, out colXSide, out colZSide, out colYBottom); Matrix4 rotY, rotX; Matrix4.RotateY(out rotY, 45 * Utils.Deg2Rad); Matrix4.RotateX(out rotX, -30f * Utils.Deg2Rad); Matrix4.Mult(out transform, ref rotY, ref rotX); cosX = (float)Math.Cos(30f * Utils.Deg2Rad); sinX = (float)Math.Sin(30f * Utils.Deg2Rad); cosY = (float)Math.Cos(-45f * Utils.Deg2Rad); sinY = (float)Math.Sin(-45f * Utils.Deg2Rad); }
void DrawUnderline(FastBitmap dst, ref DrawTextArgs args, int x, int y, bool shadow) { int point = Utils.Floor(args.Font.Size), dstHeight = point, startX = x; // adjust coords to make drawn text match GDI fonts int xPadding = Utils.CeilDiv(point, 8); int yPadding = (AdjHeight(dstHeight) - dstHeight) / 2; // scale up bottom row of a cell to drawn text font int startYY = (8 - 1) * dstHeight / 8; for (int yy = startYY; yy < dstHeight; yy++) { int dstY = y + (yy + yPadding); if (dstY >= dst.Height) { return; } int *dstRow = dst.GetRowPtr(dstY); PackedCol col = Cols['f']; string text = args.Text; for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == '&' && ValidColCode(text, i + 1)) { col = GetCol(text[i + 1]); i++; continue; // Skip over the colour code. } byte cur = Utils.UnicodeToCP437(c); int dstWidth = Width(point, cur); col = shadow ? PackedCol.Black : col; int argb = col.ToArgb(); for (int xx = 0; xx < dstWidth + xPadding; xx++) { if (x >= dst.Width) { break; } dstRow[x++] = argb; } } x = startX; } }
public static void InitCols() { for (int i = 0; i < Cols.Length; i++) { Cols[i] = default(PackedCol); } for (int i = 0; i <= 9; i++) { Cols['0' + i] = PackedCol.GetHexEncodedCol(i, 191, 64); } for (int i = 10; i <= 15; i++) { Cols['a' + i - 10] = PackedCol.GetHexEncodedCol(i, 191, 64); Cols['A' + i - 10] = Cols['a' + i - 10]; } }
SolidBrush GetOrCreateBrush(PackedCol col) { int argb = col.ToArgb(); for (int i = 0; i < brushes.Count; i++) { if (brushes[i].ARGB == argb) { return(brushes[i].Brush); } } CachedBrush b; b.ARGB = argb; b.Brush = new SolidBrush(col); brushes.Add(b); return(b.Brush); }
void DrawTopFace(int count) { int texId = BlockInfo.textures[curBlock * Side.Sides + Side.Top]; int i = texId >> Atlas1D.Shift; float vOrigin = (texId & Atlas1D.Mask) * Atlas1D.invTileSize; int offset = (lightFlags >> Side.Top) & 1; float u1 = minBB.X, u2 = (count - 1) + maxBB.X * 15.99f / 16f; float v1 = vOrigin + minBB.Z * Atlas1D.invTileSize; float v2 = vOrigin + maxBB.Z * Atlas1D.invTileSize * 15.99f / 16f; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; int F = bitFlags[cIndex]; int aX0_Z0 = ((F >> xM1_yP1_zM1) & 1) + ((F >> xM1_yP1_zCC) & 1) + ((F >> xCC_yP1_zM1) & 1) + ((F >> xCC_yP1_zCC) & 1); int aX1_Z0 = ((F >> xP1_yP1_zM1) & 1) + ((F >> xP1_yP1_zCC) & 1) + ((F >> xCC_yP1_zM1) & 1) + ((F >> xCC_yP1_zCC) & 1); int aX0_Z1 = ((F >> xM1_yP1_zP1) & 1) + ((F >> xM1_yP1_zCC) & 1) + ((F >> xCC_yP1_zP1) & 1) + ((F >> xCC_yP1_zCC) & 1); int aX1_Z1 = ((F >> xP1_yP1_zP1) & 1) + ((F >> xP1_yP1_zCC) & 1) + ((F >> xCC_yP1_zP1) & 1) + ((F >> xCC_yP1_zCC) & 1); PackedCol col0_0 = fullBright ? PackedCol.White : lerp[aX0_Z0], col1_0 = fullBright ? PackedCol.White : lerp[aX1_Z0]; PackedCol col1_1 = fullBright ? PackedCol.White : lerp[aX1_Z1], col0_1 = fullBright ? PackedCol.White : lerp[aX0_Z1]; if (tinted) { PackedCol tint = BlockInfo.FogCol[curBlock]; col0_0 *= tint; col1_0 *= tint; col1_1 *= tint; col0_1 *= tint; } int index = part.vIndex[Side.Top]; if (aX0_Z0 + aX1_Z1 > aX0_Z1 + aX1_Z0) { vertices[index] = new VertexP3fT2fC4b(x2 + (count - 1), y2, z1, u2, v1, col1_0); vertices[index + 1] = new VertexP3fT2fC4b(x1, y2, z1, u1, v1, col0_0); vertices[index + 2] = new VertexP3fT2fC4b(x1, y2, z2, u1, v2, col0_1); vertices[index + 3] = new VertexP3fT2fC4b(x2 + (count - 1), y2, z2, u2, v2, col1_1); } else { vertices[index] = new VertexP3fT2fC4b(x1, y2, z1, u1, v1, col0_0); vertices[index + 1] = new VertexP3fT2fC4b(x1, y2, z2, u1, v2, col0_1); vertices[index + 2] = new VertexP3fT2fC4b(x2 + (count - 1), y2, z2, u2, v2, col1_1); vertices[index + 3] = new VertexP3fT2fC4b(x2 + (count - 1), y2, z1, u2, v1, col1_0); } part.vIndex[Side.Top] += 4; }
public void Back(int count, PackedCol col, int texLoc, VertexP3fT2fC4b[] vertices, ref int index) { float vOrigin = (texLoc & Atlas1D.Mask) * Atlas1D.invTileSize; float u1 = minBB.X, u2 = (count - 1) + maxBB.X * uv2Scale; float v1 = vOrigin + maxBB.Y * Atlas1D.invTileSize; float v2 = vOrigin + minBB.Y * Atlas1D.invTileSize * uv2Scale; if (Tinted) { col *= TintCol; } VertexP3fT2fC4b v; v.Z = z2; v.Col = col; v.X = x2 + (count - 1); v.Y = y2; v.U = u2; v.V = v1; vertices[index++] = v; v.X = x1; v.U = u1; vertices[index++] = v; v.Y = y1; v.V = v2; vertices[index++] = v; v.X = x2 + (count - 1); v.U = u2; vertices[index++] = v; }
/// <summary> Draws a 2D flat rectangle of the specified dimensions at the /// specified coordinates in the currently bound bitmap. </summary> public abstract void DrawRect(PackedCol col, int x, int y, int width, int height);
protected virtual void DrawSprite(int count) { int texId = BlockInfo.textures[curBlock * Side.Sides + Side.Right]; int i = texId >> Atlas1D.Shift; float vOrigin = (texId & Atlas1D.Mask) * Atlas1D.invTileSize; float x1 = X + 2.50f / 16, y1 = Y, z1 = Z + 2.50f / 16; float x2 = X + 13.5f / 16, y2 = Y + 1, z2 = Z + 13.5f / 16; const float u1 = 0, u2 = 15.99f / 16f; float v1 = vOrigin, v2 = vOrigin + Atlas1D.invTileSize * 15.99f / 16f; byte offsetType = BlockInfo.SpriteOffset[curBlock]; if (offsetType >= 6 && offsetType <= 7) { spriteRng.SetSeed((X + 1217 * Z) & 0x7fffffff); float valX = spriteRng.Next(-3, 3 + 1) / 16.0f; float valY = spriteRng.Next(0, 3 + 1) / 16.0f; float valZ = spriteRng.Next(-3, 3 + 1) / 16.0f; const float stretch = 1.7f / 16.0f; x1 += valX - stretch; x2 += valX + stretch; z1 += valZ - stretch; z2 += valZ + stretch; if (offsetType == 7) { y1 -= valY; y2 -= valY; } } DrawInfo part = normalParts[i]; PackedCol col = fullBright ? PackedCol.White : light.LightCol_Sprite_Fast(X, Y, Z); if (tinted) { col *= BlockInfo.FogCol[curBlock]; } VertexP3fT2fC4b v; v.Col = col; // Draw Z axis int index = part.sIndex; v.X = x1; v.Y = y1; v.Z = z1; v.U = u2; v.V = v2; vertices[index + 0] = v; v.Y = y2; v.V = v1; vertices[index + 1] = v; v.X = x2; v.Z = z2; v.U = u1; vertices[index + 2] = v; v.Y = y1; v.V = v2; vertices[index + 3] = v; // Draw Z axis mirrored index += part.sAdvance; v.X = x2; v.Y = y1; v.Z = z2; v.U = u2; vertices[index + 0] = v; v.Y = y2; v.V = v1; vertices[index + 1] = v; v.X = x1; v.Z = z1; v.U = u1; vertices[index + 2] = v; v.Y = y1; v.V = v2; vertices[index + 3] = v; // Draw X axis index += part.sAdvance; v.X = x1; v.Y = y1; v.Z = z2; v.U = u2; vertices[index + 0] = v; v.Y = y2; v.V = v1; vertices[index + 1] = v; v.X = x2; v.Z = z1; v.U = u1; vertices[index + 2] = v; v.Y = y1; v.V = v2; vertices[index + 3] = v; // Draw X axis mirrored index += part.sAdvance; v.X = x2; v.Y = y1; v.Z = z1; v.U = u2; vertices[index + 0] = v; v.Y = y2; v.V = v1; vertices[index + 1] = v; v.X = x1; v.Z = z2; v.U = u1; vertices[index + 2] = v; v.Y = y1; v.V = v2; vertices[index + 3] = v; part.sIndex += 4; }
public override void DrawRect(PackedCol col, int x, int y, int width, int height) { Brush brush = GetOrCreateBrush(col); g.FillRectangle(brush, x, y, width, height); }
void DrawCore(FastBitmap dst, ref DrawTextArgs args, int x, int y, bool shadow) { PackedCol col = Cols['f']; if (shadow) { col = BlackTextShadows ? PackedCol.Black : PackedCol.Scale(col, 0.25f); } string text = args.Text; int point = Utils.Floor(args.Font.Size), count = 0; byte * coords = stackalloc byte[256]; PackedCol *cols = stackalloc PackedCol[256]; ushort * dstWidths = stackalloc ushort[256]; for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == '&' && ValidColCode(text, i + 1)) { col = GetCol(text[i + 1]); if (shadow) { col = BlackTextShadows ? PackedCol.Black : PackedCol.Scale(col, 0.25f); } i++; continue; // Skip over the colour code. } byte cur = Utils.UnicodeToCP437(c); coords[count] = cur; cols[count] = col; dstWidths[count] = (ushort)Width(point, cur); count++; } int dstHeight = point, startX = x; // adjust coords to make drawn text match GDI fonts int xPadding = Utils.CeilDiv(point, 8); int yPadding = (AdjHeight(dstHeight) - dstHeight) / 2; for (int yy = 0; yy < dstHeight; yy++) { int dstY = y + (yy + yPadding); if (dstY >= dst.Height) { return; } int fontY = 0 + yy * boxSize / dstHeight; int *dstRow = dst.GetRowPtr(dstY); for (int i = 0; i < count; i++) { int srcX = (coords[i] & 0x0F) * boxSize; int srcY = (coords[i] >> 4) * boxSize; int *fontRow = fontPixels.GetRowPtr(fontY + srcY); int srcWidth = widths[coords[i]], dstWidth = dstWidths[i]; col = cols[i]; for (int xx = 0; xx < dstWidth; xx++) { int fontX = srcX + xx * srcWidth / dstWidth; int src = fontRow[fontX]; if ((byte)(src >> 24) == 0) { continue; } int dstX = x + xx; if (dstX >= dst.Width) { break; } int pixel = src & ~0xFFFFFF; pixel |= ((src & 0xFF) * col.B / 255); pixel |= (((src >> 8) & 0xFF) * col.G / 255) << 8; pixel |= (((src >> 16) & 0xFF) * col.R / 255) << 16; dstRow[dstX] = pixel; } x += dstWidth + xPadding; } x = startX; } }
void Stretch(int x1, int y1, int z1) { int xMax = Math.Min(width, x1 + chunkSize); int yMax = Math.Min(height, y1 + chunkSize); int zMax = Math.Min(length, z1 + chunkSize); #if OCCLUSION int flags = ComputeOcclusion(); #endif #if DEBUG_OCCLUSION PackedCol col = new PackedCol(60, 60, 60, 255); if ((flags & 1) != 0) { col.R = 255; // x } if ((flags & 4) != 0) { col.G = 255; // y } if ((flags & 2) != 0) { col.B = 255; // z } map.Sunlight = map.Shadowlight = col; map.SunlightXSide = map.ShadowlightXSide = col; map.SunlightZSide = map.ShadowlightZSide = col; map.SunlightYBottom = map.ShadowlightYBottom = col; #endif byte[] hidden = BlockInfo.hidden; for (int y = y1, yy = 0; y < yMax; y++, yy++) { for (int z = z1, zz = 0; z < zMax; z++, zz++) { int cIndex = (yy + 1) * extChunkSize2 + (zz + 1) * extChunkSize + (-1 + 1); for (int x = x1, xx = 0; x < xMax; x++, xx++) { cIndex++; BlockID b = chunk[cIndex]; if (BlockInfo.Draw[b] == DrawType.Gas) { continue; } int index = ((yy << 8) | (zz << 4) | xx) * Side.Sides; // Sprites only use one face to indicate stretching count, so we can take a shortcut here. // Note that sprites are not drawn with any of the DrawXFace, they are drawn using DrawSprite. if (BlockInfo.Draw[b] == DrawType.Sprite) { index += Side.Top; if (counts[index] != 0) { X = x; Y = y; Z = z; AddSpriteVertices(b); counts[index] = 1; } continue; } X = x; Y = y; Z = z; fullBright = BlockInfo.FullBright[b]; int tileIdx = b * BlockInfo.Count; // All of these function calls are inlined as they can be called tens of millions to hundreds of millions of times. if (counts[index] == 0 || (x == 0 && (y < sidesLevel || (b >= Block.Water && b <= Block.StillLava && y < edgeLevel))) || (x != 0 && (hidden[tileIdx + chunk[cIndex - 1]] & (1 << Side.Left)) != 0)) { counts[index] = 0; } else { int count = StretchZ(index, x, y, z, cIndex, b, Side.Left); AddVertices(b, Side.Left); counts[index] = (byte)count; } index++; if (counts[index] == 0 || (x == maxX && (y < sidesLevel || (b >= Block.Water && b <= Block.StillLava && y < edgeLevel))) || (x != maxX && (hidden[tileIdx + chunk[cIndex + 1]] & (1 << Side.Right)) != 0)) { counts[index] = 0; } else { int count = StretchZ(index, x, y, z, cIndex, b, Side.Right); AddVertices(b, Side.Right); counts[index] = (byte)count; } index++; if (counts[index] == 0 || (z == 0 && (y < sidesLevel || (b >= Block.Water && b <= Block.StillLava && y < edgeLevel))) || (z != 0 && (hidden[tileIdx + chunk[cIndex - 18]] & (1 << Side.Front)) != 0)) { counts[index] = 0; } else { int count = StretchX(index, x, y, z, cIndex, b, Side.Front); AddVertices(b, Side.Front); counts[index] = (byte)count; } index++; if (counts[index] == 0 || (z == maxZ && (y < sidesLevel || (b >= Block.Water && b <= Block.StillLava && y < edgeLevel))) || (z != maxZ && (hidden[tileIdx + chunk[cIndex + 18]] & (1 << Side.Back)) != 0)) { counts[index] = 0; } else { int count = StretchX(index, x, y, z, cIndex, b, Side.Back); AddVertices(b, Side.Back); counts[index] = (byte)count; } index++; if (counts[index] == 0 || y == 0 || (hidden[tileIdx + chunk[cIndex - 324]] & (1 << Side.Bottom)) != 0) { counts[index] = 0; } else { int count = StretchX(index, x, y, z, cIndex, b, Side.Bottom); AddVertices(b, Side.Bottom); counts[index] = (byte)count; } index++; if (counts[index] == 0 || (hidden[tileIdx + chunk[cIndex + 324]] & (1 << Side.Top)) != 0) { counts[index] = 0; } else if (b < Block.Water || b > Block.StillLava) { int count = StretchX(index, x, y, z, cIndex, b, Side.Top); AddVertices(b, Side.Top); counts[index] = (byte)count; } else { int count = StretchXLiquid(index, x, y, z, cIndex, b); if (count > 0) { AddVertices(b, Side.Top); } counts[index] = (byte)count; } } } } }
public void Render(IGraphicsApi gfx, PackedCol col) { gfx.BindTexture(ID); gfx.Draw2DTexture(ref this, col); }
public override void Clear(PackedCol col) { c.DrawColor(col); }
protected override void RenderTile(int index) { if (BlockInfo.Draw[curBlock] == DrawType.Sprite) { this.fullBright = BlockInfo.FullBright[curBlock]; this.tinted = BlockInfo.Tinted[curBlock]; int count = counts[index + Side.Top]; if (count != 0) { DrawSprite(count); } return; } int leftCount = counts[index++], rightCount = counts[index++], frontCount = counts[index++], backCount = counts[index++], bottomCount = counts[index++], topCount = counts[index++]; if (leftCount == 0 && rightCount == 0 && frontCount == 0 && backCount == 0 && bottomCount == 0 && topCount == 0) { return; } bool fullBright = BlockInfo.FullBright[curBlock]; bool isTranslucent = BlockInfo.Draw[curBlock] == DrawType.Translucent; int lightFlags = BlockInfo.LightOffset[curBlock]; drawer.minBB = BlockInfo.MinBB[curBlock]; drawer.minBB.Y = 1 - drawer.minBB.Y; drawer.maxBB = BlockInfo.MaxBB[curBlock]; drawer.maxBB.Y = 1 - drawer.maxBB.Y; Vector3 min = BlockInfo.RenderMinBB[curBlock], max = BlockInfo.RenderMaxBB[curBlock]; drawer.x1 = X + min.X; drawer.y1 = Y + min.Y; drawer.z1 = Z + min.Z; drawer.x2 = X + max.X; drawer.y2 = Y + max.Y; drawer.z2 = Z + max.Z; drawer.Tinted = BlockInfo.Tinted[curBlock]; drawer.TintCol = BlockInfo.FogCol[curBlock]; if (leftCount != 0) { int texLoc = BlockInfo.textures[curBlock * Side.Sides + Side.Left]; int i = texLoc >> Atlas1D.Shift; int offset = (lightFlags >> Side.Left) & 1; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; PackedCol col = fullBright ? PackedCol.White : X >= offset?light.LightCol_XSide_Fast(X - offset, Y, Z) : light.OutsideXSide; drawer.Left(leftCount, col, texLoc, vertices, ref part.vIndex[Side.Left]); } if (rightCount != 0) { int texLoc = BlockInfo.textures[curBlock * Side.Sides + Side.Right]; int i = texLoc >> Atlas1D.Shift; int offset = (lightFlags >> Side.Right) & 1; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; PackedCol col = fullBright ? PackedCol.White : X <= (maxX - offset) ? light.LightCol_XSide_Fast(X + offset, Y, Z) : light.OutsideXSide; drawer.Right(rightCount, col, texLoc, vertices, ref part.vIndex[Side.Right]); } if (frontCount != 0) { int texLoc = BlockInfo.textures[curBlock * Side.Sides + Side.Front]; int i = texLoc >> Atlas1D.Shift; int offset = (lightFlags >> Side.Front) & 1; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; PackedCol col = fullBright ? PackedCol.White : Z >= offset?light.LightCol_ZSide_Fast(X, Y, Z - offset) : light.OutsideZSide; drawer.Front(frontCount, col, texLoc, vertices, ref part.vIndex[Side.Front]); } if (backCount != 0) { int texLoc = BlockInfo.textures[curBlock * Side.Sides + Side.Back]; int i = texLoc >> Atlas1D.Shift; int offset = (lightFlags >> Side.Back) & 1; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; PackedCol col = fullBright ? PackedCol.White : Z <= (maxZ - offset) ? light.LightCol_ZSide_Fast(X, Y, Z + offset) : light.OutsideZSide; drawer.Back(backCount, col, texLoc, vertices, ref part.vIndex[Side.Back]); } if (bottomCount != 0) { int texLoc = BlockInfo.textures[curBlock * Side.Sides + Side.Bottom]; int i = texLoc >> Atlas1D.Shift; int offset = (lightFlags >> Side.Bottom) & 1; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; PackedCol col = fullBright ? PackedCol.White : light.LightCol_YBottom_Fast(X, Y - offset, Z); drawer.Bottom(bottomCount, col, texLoc, vertices, ref part.vIndex[Side.Bottom]); } if (topCount != 0) { int texLoc = BlockInfo.textures[curBlock * Side.Sides + Side.Top]; int i = texLoc >> Atlas1D.Shift; int offset = (lightFlags >> Side.Top) & 1; DrawInfo part = isTranslucent ? translucentParts[i] : normalParts[i]; PackedCol col = fullBright ? PackedCol.White : light.LightCol_YTop_Fast(X, (Y + 1) - offset, Z); drawer.Top(topCount, col, texLoc, vertices, ref part.vIndex[Side.Top]); } }
/// <summary> Clears the entire given area to the specified colour. </summary> public abstract void Clear(PackedCol col, int x, int y, int width, int height);
/// <summary> Draws the outline of a 2D flat rectangle of the specified dimensions /// at the specified coordinates in the currently bound bitmap. </summary> public abstract void DrawRectBounds(PackedCol col, int lineWidth, int x, int y, int width, int height);
public TextPart(string text, PackedCol col) { Text = text; Col = col; }