diff --git a/BeefLibs/Beefy2D/src/geom/Point.bf b/BeefLibs/Beefy2D/src/geom/Point.bf index 8f00c1f7..fd1cccee 100644 --- a/BeefLibs/Beefy2D/src/geom/Point.bf +++ b/BeefLibs/Beefy2D/src/geom/Point.bf @@ -14,5 +14,8 @@ namespace Beefy.geom this.x = x; this.y = y; } + + public static Point operator-(Self lhs, Self rhs) => .(lhs.x - rhs.x, lhs.y - rhs.y); + public static Point operator+(Self lhs, Self rhs) => .(lhs.x + rhs.x, lhs.y + rhs.y); } } diff --git a/BeefLibs/Beefy2D/src/gfx/Graphics.bf b/BeefLibs/Beefy2D/src/gfx/Graphics.bf index ef3dbb3d..8e092714 100644 --- a/BeefLibs/Beefy2D/src/gfx/Graphics.bf +++ b/BeefLibs/Beefy2D/src/gfx/Graphics.bf @@ -47,6 +47,7 @@ namespace Beefy.gfx public RenderState mDefaultRenderState ~ delete _; public Font mFont; public Image mWhiteDot ~ delete _; + public List mWhiteBorderedSquares = new .() ~ DeleteContainerAndItems!(_); public float ZDepth { get; set; } protected DisposeProxy mMatrixDisposeProxy ~ delete _; @@ -512,6 +513,15 @@ namespace Beefy.gfx Gfx_SetRenderState(mRenderStateStack[--mRenderStateStackIdx].mNativeRenderState); } + public Image GetBorderedWhiteSquare(int borderSize) + { + if (borderSize >= mWhiteBorderedSquares.Count) + mWhiteBorderedSquares.Count = borderSize + 1; + if (mWhiteBorderedSquares[borderSize] == null) + mWhiteBorderedSquares[borderSize] = Image.LoadFromFile(scope $"!square{borderSize}"); + return mWhiteBorderedSquares[borderSize]; + } + public void Draw(RenderCmd renderCmd) { Gfx_QueueRenderCmd(renderCmd.mNativeRenderCmd); @@ -919,7 +929,32 @@ namespace Beefy.gfx Gfx_CopyDrawVertex(4, 1); Gfx_SetDrawVertex(5, m.tx + (m.a + m.c), m.ty + (m.b + m.d), 0, 0, 0, Color.Mult(mColor, colorBotRight)); } - + + public void DrawLine(float x0, float y0, float x1, float y1, float width = 1.0f) + { + Image img = GetBorderedWhiteSquare(Math.Max((int)width, 1)); + + float ang = Math.Atan2(y1 - y0, x1 - x0); + + // Add 1 pixel to account for transparent border + float radius = (width / 2) + 1; + + float xOfs = Math.Cos(ang + Math.PI_f / 2) * radius; + float yOfs = Math.Sin(ang + Math.PI_f / 2) * radius; + + //TODO: Multiply color + + Gfx_AllocTris(img.mNativeTextureSegment, 6); + + Gfx_SetDrawVertex(0, x0 - xOfs, y0 - yOfs, 0, 0, 0.5f, mColor); + Gfx_SetDrawVertex(1, x0 + xOfs, y0 + yOfs, 0, 1.0f, 0.5f, mColor); + Gfx_SetDrawVertex(2, x1 - xOfs, y1 - yOfs, 0, 0, 0.5f, mColor); + + Gfx_CopyDrawVertex(3, 2); + Gfx_CopyDrawVertex(4, 1); + Gfx_SetDrawVertex(5, x1 + xOfs, y1 + yOfs, 0, 1.0f, 0.5f, mColor); + } + public void PolyStart(Image image, int32 vertices) { Gfx_AllocTris(image.mNativeTextureSegment, vertices); diff --git a/BeefySysLib/gfx/DrawLayer.cpp b/BeefySysLib/gfx/DrawLayer.cpp index a353506d..ea489ea0 100644 --- a/BeefySysLib/gfx/DrawLayer.cpp +++ b/BeefySysLib/gfx/DrawLayer.cpp @@ -68,11 +68,12 @@ void* DrawBatch::AllocTris(int vtxCount) { int idxCount = vtxCount; - if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (idxCount + mIdxIdx >= mAllocatedIndices)) + bool fits = (idxCount + mIdxIdx <= mAllocatedIndices) && (vtxCount + mVtxIdx <= mAllocatedVertices); + if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (!fits)) { - if (mVtxIdx > 0) + if ((mVtxIdx > 0) || (!fits)) { - DrawBatch* nextBatch = AllocateChainedBatch(0, 0); + DrawBatch* nextBatch = AllocateChainedBatch(vtxCount, idxCount); return nextBatch->AllocTris(vtxCount); } @@ -95,11 +96,12 @@ void* DrawBatch::AllocStrip(int vtxCount) { int idxCount = (vtxCount - 2) * 3; - if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (idxCount + mIdxIdx >= mAllocatedIndices)) + bool fits = (idxCount + mIdxIdx <= mAllocatedIndices) && (vtxCount + mVtxIdx <= mAllocatedVertices); + if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (!fits)) { - if (mVtxIdx > 0) + if ((mVtxIdx > 0) || (!fits)) { - DrawBatch* nextBatch = AllocateChainedBatch(0, 0); + DrawBatch* nextBatch = AllocateChainedBatch(vtxCount, idxCount); return nextBatch->AllocStrip(vtxCount); } @@ -126,9 +128,10 @@ void* DrawBatch::AllocStrip(int vtxCount) void DrawBatch::AllocIndexed(int vtxCount, int idxCount, void** verticesOut, uint16** indicesOut, uint16* idxOfsOut) { - if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (idxCount + mIdxIdx > mAllocatedIndices)) + bool fits = (idxCount + mIdxIdx <= mAllocatedIndices) && (vtxCount + mVtxIdx <= mAllocatedVertices); + if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (!fits)) { - if (mVtxIdx > 0) + if ((mVtxIdx > 0) || (!fits)) { DrawBatch* nextBatch = AllocateChainedBatch(vtxCount, idxCount); return nextBatch->AllocIndexed(vtxCount, idxCount, verticesOut, indicesOut, idxOfsOut); @@ -190,11 +193,8 @@ DrawBatch* DrawLayer::AllocateBatch(int minVtxCount, int minIdxCount) BF_ASSERT(mRenderDevice->mCurRenderState->mShader != NULL); int vtxSize = mRenderDevice->mCurRenderState->mShader->mVertexSize; - if (minIdxCount == 0) - { - minIdxCount = 512; - minVtxCount = minIdxCount; - } + minIdxCount = BF_MAX(minIdxCount, 512); + minVtxCount = BF_MAX(minIdxCount, 512); BF_ASSERT(minIdxCount * sizeof(uint16) <= DRAWBUFFER_IDXBUFFER_SIZE); BF_ASSERT(minVtxCount * vtxSize <= DRAWBUFFER_VTXBUFFER_SIZE); diff --git a/BeefySysLib/gfx/RenderDevice.cpp b/BeefySysLib/gfx/RenderDevice.cpp index e316ab2b..346177fb 100644 --- a/BeefySysLib/gfx/RenderDevice.cpp +++ b/BeefySysLib/gfx/RenderDevice.cpp @@ -120,6 +120,20 @@ Texture* RenderDevice::LoadTexture(const StringImpl& fileName, int flags) imageData->mBits[0] = 0xFFFFFFFF; handled = true; } + else if (fileName.StartsWith("!square")) + { + int squareSize = atoi(fileName.c_str() + 7); + imageData = new ImageData(); + imageData->CreateNew(squareSize + 2, squareSize + 2, true); + for (int y = 0; y < squareSize; y++) + { + for (int x = 0; x < squareSize; x++) + { + imageData->mBits[(y + 1) * (squareSize + 2) + x + 1] = 0xFFFFFFFF; + } + } + handled = true; + } else if (ext == ".tga") imageData = new TGAData(); else if (ext == ".png")