/* Copyright (c) 2022 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #include "uitoolkit/UIDrawingInterface2DTexture.h" #include "uitoolkit/UIToolkitDrawing.h" #define stemobject_implementation UIDrawingInterface2DTexture stemobject_vtable_begin(); stemobject_vtable_entry(dispose); stemobject_vtable_entry(drawQuad); stemobject_vtable_entry(drawQuadWithTransform); stemobject_vtable_entry(drawQuadWithSeparateColors); stemobject_vtable_entry(drawSlicedQuad3x3); stemobject_vtable_entry(drawSlicedQuad3x1); stemobject_vtable_entry(drawSlicedQuad1x3); stemobject_vtable_entry(drawSlicedQuad3x3WithAlternatingRowColors); stemobject_vtable_entry(drawIndexedVertices_p2f_t2f_c4f); stemobject_vtable_entry(drawString); stemobject_vtable_entry(drawTextLayout); stemobject_vtable_end(); UIDrawingInterface2DTexture * UIDrawingInterface2DTexture_create(void) { stemobject_create_implementation(init) } bool UIDrawingInterface2DTexture_init(UIDrawingInterface2DTexture * self) { call_super(init, self); return true; } void UIDrawingInterface2DTexture_dispose(UIDrawingInterface2DTexture * self) { call_super_virtual(dispose, self); } void UIDrawingInterface2DTexture_drawQuad(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, Color4f color, VertexIO * vertexIO) { writeQuad2DTexture(vertexBounds, textureBounds, color, vertexIO); } void UIDrawingInterface2DTexture_drawQuadWithTransform(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, quadTransformBits transformBits, Color4f color, VertexIO * vertexIO) { writeQuad2DTextureWithTransform(vertexBounds, textureBounds, color, transformBits, vertexIO); } void UIDrawingInterface2DTexture_drawQuadWithSeparateColors(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, Color4f colorBottomLeft, Color4f colorBottomRight, Color4f colorTopLeft, Color4f colorTopRight, VertexIO * vertexIO) { struct vertex_p2f_t2f_c4f vertices[4], vertex; vertex.position[0] = vertexBounds.xMin; vertex.position[1] = vertexBounds.yMin; vertex.texCoords[0] = textureBounds.xMin; vertex.texCoords[1] = textureBounds.yMin; vertex.color[0] = colorBottomLeft.red; vertex.color[1] = colorBottomLeft.green; vertex.color[2] = colorBottomLeft.blue; vertex.color[3] = colorBottomLeft.alpha; vertices[0] = vertex; vertex.position[0] = vertexBounds.xMax; vertex.texCoords[0] = textureBounds.xMax; vertex.color[0] = colorBottomRight.red; vertex.color[1] = colorBottomRight.green; vertex.color[2] = colorBottomRight.blue; vertex.color[3] = colorBottomRight.alpha; vertices[1] = vertex; vertex.position[1] = vertexBounds.yMax; vertex.texCoords[1] = textureBounds.yMax; vertex.color[0] = colorTopRight.red; vertex.color[1] = colorTopRight.green; vertex.color[2] = colorTopRight.blue; vertex.color[3] = colorTopRight.alpha; vertices[2] = vertex; vertex.position[0] = vertexBounds.xMin; vertex.texCoords[0] = textureBounds.xMin; vertex.color[0] = colorTopLeft.red; vertex.color[1] = colorTopLeft.green; vertex.color[2] = colorTopLeft.blue; vertex.color[3] = colorTopLeft.alpha; vertices[3] = vertex; uint32_t indexes[6] = {0, 1, 2, 2, 3, 0}; VertexIO_writeIndexedVertices(vertexIO, 4, vertices, 6, indexes); } #define copySlicedVertices(count) \ for (unsigned int vertexIndex = 0; vertexIndex < count; vertexIndex++) { \ vertices[vertexIndex].position[0] = sliceVertices[vertexIndex].position.x; \ vertices[vertexIndex].position[1] = sliceVertices[vertexIndex].position.y; \ vertices[vertexIndex].texCoords[0] = sliceVertices[vertexIndex].texCoords.x; \ vertices[vertexIndex].texCoords[1] = sliceVertices[vertexIndex].texCoords.y; \ vertices[vertexIndex].color[0] = color.red; \ vertices[vertexIndex].color[1] = color.green; \ vertices[vertexIndex].color[2] = color.blue; \ vertices[vertexIndex].color[3] = color.alpha; \ } void UIDrawingInterface2DTexture_drawSlicedQuad3x3(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, UISliceGrid3x3 slices, Color4f color, VertexIO * vertexIO) { struct vertex_p2f_t2f_c4f vertices[UI_SLICE_VERTEX_COUNT_3x3]; UIToolkit_sliceVertex sliceVertices[UI_SLICE_VERTEX_COUNT_3x3]; uint32_t indexes[UI_SLICE_INDEX_COUNT_3x3]; UIToolkit_sliceQuad3x3(vertexBounds, textureBounds, slices, sliceVertices, indexes); copySlicedVertices(UI_SLICE_VERTEX_COUNT_3x3); VertexIO_writeIndexedVertices(vertexIO, UI_SLICE_VERTEX_COUNT_3x3, vertices, UI_SLICE_INDEX_COUNT_3x3, indexes); } void UIDrawingInterface2DTexture_drawSlicedQuad3x1(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, UISliceGrid3x1 slices, Color4f color, VertexIO * vertexIO) { struct vertex_p2f_t2f_c4f vertices[UI_SLICE_VERTEX_COUNT_3x1]; UIToolkit_sliceVertex sliceVertices[UI_SLICE_VERTEX_COUNT_3x1]; uint32_t indexes[UI_SLICE_INDEX_COUNT_3x1]; UIToolkit_sliceQuad3x1(vertexBounds, textureBounds, slices, sliceVertices, indexes); copySlicedVertices(UI_SLICE_VERTEX_COUNT_3x1); VertexIO_writeIndexedVertices(vertexIO, UI_SLICE_VERTEX_COUNT_3x1, vertices, UI_SLICE_INDEX_COUNT_3x1, indexes); } void UIDrawingInterface2DTexture_drawSlicedQuad1x3(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, UISliceGrid1x3 slices, Color4f color, VertexIO * vertexIO) { struct vertex_p2f_t2f_c4f vertices[UI_SLICE_VERTEX_COUNT_1x3]; UIToolkit_sliceVertex sliceVertices[UI_SLICE_VERTEX_COUNT_1x3]; uint32_t indexes[UI_SLICE_INDEX_COUNT_1x3]; UIToolkit_sliceQuad1x3(vertexBounds, textureBounds, slices, sliceVertices, indexes); copySlicedVertices(UI_SLICE_VERTEX_COUNT_1x3); VertexIO_writeIndexedVertices(vertexIO, UI_SLICE_VERTEX_COUNT_1x3, vertices, UI_SLICE_INDEX_COUNT_1x3, indexes); } void UIDrawingInterface2DTexture_drawSlicedQuad3x3WithAlternatingRowColors(UIDrawingInterface2DTexture * self, Rect4f vertexBounds, Rect4f textureBounds, UISliceGrid3x3 slices, float inset, float rowHeight, Color4f evenColor, Color4f oddColor, VertexIO * vertexIO) { unsigned int vertexCount, indexCount; UIToolkit_getCountsForSlicedQuad3x3WithRows(vertexBounds, slices, inset, rowHeight, &vertexCount, &indexCount); struct vertex_p2f_t2f_c4f vertices[vertexCount]; UIToolkit_sliceVertexWithRow sliceVertices[vertexCount]; uint32_t indexes[indexCount]; UIToolkit_sliceQuad3x3WithRows(vertexBounds, textureBounds, slices, inset, rowHeight, sliceVertices, indexes); Color4f colors[2] = {evenColor, oddColor}; for (unsigned int vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) { vertices[vertexIndex].position[0] = sliceVertices[vertexIndex].position.x; vertices[vertexIndex].position[1] = sliceVertices[vertexIndex].position.y; vertices[vertexIndex].texCoords[0] = sliceVertices[vertexIndex].texCoords.x; vertices[vertexIndex].texCoords[1] = sliceVertices[vertexIndex].texCoords.y; Color4f color = colors[sliceVertices[vertexIndex].rowIndex & 0x1]; vertices[vertexIndex].color[0] = color.red; vertices[vertexIndex].color[1] = color.green; vertices[vertexIndex].color[2] = color.blue; vertices[vertexIndex].color[3] = color.alpha; } VertexIO_writeIndexedVertices(vertexIO, vertexCount, vertices, indexCount, indexes); } void UIDrawingInterface2DTexture_drawIndexedVertices_p2f_t2f_c4f(UIDrawingInterface2DTexture * self, unsigned int vertexCount, const struct vertex_p2f_t2f_c4f * vertices, unsigned int indexCount, const uint32_t * indexes, VertexIO * vertexIO) { VertexIO_writeIndexedVertices(vertexIO, vertexCount, vertices, indexCount, indexes); } struct drawStringContext { Color4f color; Color4f fixedColor; VertexIO * vertexIO; }; static void glyphCallback(Rect4f vertexBounds, Rect4f textureBounds, bool fixedColor, void * context) { struct drawStringContext * contextStruct = context; Color4f color = fixedColor ? contextStruct->fixedColor : contextStruct->color; struct vertex_p2f_t2f_c4f vertices[4], vertex = {{vertexBounds.xMin, vertexBounds.yMin}, {textureBounds.xMin, textureBounds.yMin}, {color.red, color.green, color.blue, color.alpha}}; vertices[0] = vertex; vertex.position[0] = vertexBounds.xMax; vertex.texCoords[0] = textureBounds.xMax; vertices[1] = vertex; vertex.position[1] = vertexBounds.yMax; vertex.texCoords[1] = textureBounds.yMax; vertices[2] = vertex; vertex.position[0] = vertexBounds.xMin; vertex.texCoords[0] = textureBounds.xMin; vertices[3] = vertex; uint32_t indexes[6] = {0, 1, 2, 2, 3, 0}; VertexIO_writeIndexedVertices(contextStruct->vertexIO, 4, vertices, 6, indexes); } void UIDrawingInterface2DTexture_drawString(UIDrawingInterface2DTexture * self, compat_type(UITypeface *) typefaceUntyped, String string, Vector2f offset, Vector2f relativeOrigin, float textScale, Color4f color, VertexIO * vertexIO) { struct drawStringContext contextStruct = {.color = color, .vertexIO = vertexIO}; if (self->alphaPremultiplied) { contextStruct.fixedColor = COLOR4f(color.alpha, color.alpha, color.alpha, color.alpha); } else { contextStruct.fixedColor = COLOR4f(1.0f, 1.0f, 1.0f, color.alpha); } UITypeface * typeface = typefaceUntyped; if (relativeOrigin.x != 0.0f) { offset.x -= call_virtual(measureString, typeface, string) * relativeOrigin.x * textScale; } if (relativeOrigin.y != 1.0f) { offset.y += call_virtual(getLineHeight, typeface) * (1.0f - relativeOrigin.y) * textScale; } call_virtual(writeGlyphsWithCallback, typeface, string, offset, textScale, glyphCallback, &contextStruct); } void UIDrawingInterface2DTexture_drawTextLayout(UIDrawingInterface2DTexture * self, compat_type(UITextLayout *) textLayoutUntyped, Vector2f offset, Vector2f relativeOrigin, float textScale, Color4f color, VertexIO * vertexIO) { struct drawStringContext contextStruct = {.color = color, .vertexIO = vertexIO}; if (self->alphaPremultiplied) { contextStruct.fixedColor = COLOR4f(color.alpha, color.alpha, color.alpha, color.alpha); } else { contextStruct.fixedColor = COLOR4f(1.0f, 1.0f, 1.0f, color.alpha); } UITextLayout * textLayout = textLayoutUntyped; if (relativeOrigin.x != 0.0f || relativeOrigin.y != 1.0f) { Vector2f size = call_virtual(measureString, textLayout); offset.x -= size.x * relativeOrigin.x * textScale; offset.y += size.y * (1.0f - relativeOrigin.y) * textScale; } call_virtual(writeGlyphsWithCallback, textLayout, offset, textScale, glyphCallback, &contextStruct); }