public Order addRectangle(ref int z, ref Rect rectangle, float?width) { Order result = new Order(-1 - rectCommands.length, z); z++; var cmd = new sDrawRectCommand() { rect = rectangle, strokeWidth = width }; rectCommands.add(ref cmd); return(result); }
void layoutBuffers(Span <sDrawCall> drawCallsSpan) { buffersLayout.clear(); for (int i = 0; i < drawCallsSpan.Length; i++) { ref var dc = ref drawCallsSpan[i]; int sn = dc.order.sn; if (sn >= 0) { buffersLayout.addMesh(i, drawMeshes.meshes[sn].mesh.meshInfo); continue; } sn = -sn - 1; if (dc.drawCall.mesh == eMesh.SpriteRectangle) { sMeshDataSize mds = new sMeshDataSize(SpriteMesh.countVertices, SpriteMesh.countTriangles); buffersLayout.addTransparent(i, ref mds); continue; } if (dc.drawCall.isText) { // Glyph runs can be either opaque or transparent, depending on text background sMeshDataSize mds = drawMeshes.textCommands[sn].meshDataSize; buffersLayout.addTransparent(i, ref mds); continue; } sDrawRectCommand cmd = drawMeshes.rectCommands[sn]; sMeshDataSize size; if (cmd.strokeWidth.HasValue) { size = RectangleMesh.sizeStroked; } else { size = RectangleMesh.sizeFilled; } buffersLayout.addOpaque(i, ref size); }
void uploadVertices(IDeviceContext ic, Span <sDrawCall> drawCallsSpan) { ReadOnlySpan <int> baseVertices = buffersLayout.baseVertices; using (var mapped = resources.getVertexBuffer().map <sVertexWithId>(ic, buffersLayout.vertexBufferSize)) { Span <sVertexWithId> span = mapped.span; for (int i = 0; i < drawCallsSpan.Length; i++) { int bv = baseVertices[i]; if (bv < 0) { continue; // Empty draw call, i.e. completely clipped out } Span <sVertexWithId> dest = span.Slice(bv); ref var dc = ref drawCallsSpan[i]; uint id = VertexID.vertex(i); int sn = dc.order.sn; if (sn >= 0) { drawMeshes.meshes[sn].mesh.mesh.copyVertices(dest, id); continue; } sn = -sn - 1; if (dc.drawCall.mesh == eMesh.SpriteRectangle) { Rect rc = drawMeshes.spriteCommands[sn].rect; SpriteMesh.writeVertices(dest, ref rc, id); continue; } if (dc.drawCall.isText) { var text = drawMeshes.textCommands[sn]; sMeshDataSize mds; if (text.consoleWidth.HasValue) { mds = text.font.renderConsole(dest, id, text.text, text.rectangle.topLeft, text.textRendering, text.consoleWidth.Value); } else { mds = text.font.renderBlock(dest, id, text.text, ref text.rectangle, text.textRendering); } Debug.Assert(mds.vertices <= text.meshDataSize.vertices && mds.triangles <= text.meshDataSize.triangles); // Store the actual count of triangles written. // uploadIndices function needs it later, to fill unused portion of the index buffer with UINT_MAX (32 bit IB) or 0xFFFF (16 bit IB) discarding the data. // Technically that's wasted GPU bandwidth, however: // (a) Not much of it, as normal text only contains a few of these soft hyphens and ligatures. // (b) Saves substantial amount of resources allowing to generate the complete mesh with a single pass over the glyphs. // With exact-sized buffers, we would have to build the complete text mesh in managed memory, then copy to GPU. // Current implementation only buffers 1 word for left aligned blocks, or 1 line for middle or right aligned blocks, or nothing at all for single-line text. The vertices go straight to mapped GPU verftex buffer. text.actualTriangles = mds.triangles; drawMeshes.textCommands[sn] = text; // dbgPrintGlyphVertices( dest ); continue; } sDrawRectCommand cmd = drawMeshes.rectCommands[sn]; if (cmd.strokeWidth.HasValue) { RectangleMesh.strokedVertices(dest, id, ref cmd.rect, cmd.strokeWidth.Value); } else { RectangleMesh.filledVertices(dest, id, ref cmd.rect); } } }