diff --git a/include/c2d/text.h b/include/c2d/text.h index 53a2419..25f76ef 100755 --- a/include/c2d/text.h +++ b/include/c2d/text.h @@ -22,6 +22,7 @@ typedef struct float width; ///< Width of the text in pixels, according to 1x scale metrics. u32 lines; ///< Number of lines in the text. u32 words; ///< Number of words in the text. + u32 chars; ///< Number of characters (including whitespace) in the text C2D_Font font; ///< Font used to draw the text, or NULL for system font } C2D_Text; @@ -29,12 +30,13 @@ enum { C2D_AtBaseline = BIT(0), ///< Matches the Y coordinate with the baseline of the font. C2D_WithColor = BIT(1), ///< Draws text with color. Requires a u32 color value. - C2D_AlignLeft = 0 << 2, ///< Draws text aligned to the left. This is the default. - C2D_AlignRight = 1 << 2, ///< Draws text aligned to the right. - C2D_AlignCenter = 2 << 2, ///< Draws text centered. - C2D_AlignJustified = 3 << 2, ///< Draws text justified. When C2D_WordWrap is not specified, right edge is x + scaleX*text->width. Otherwise, right edge is x + the width specified for those values. - C2D_AlignMask = 3 << 2, ///< Bitmask for alignment values. - C2D_WordWrap = BIT(4), ///< Draws text with wrapping of full words before specified width. Requires a float value, passed after color if C2D_WithColor is specified. + C2D_MultiColor = BIT(2), ///< Draws text with multiple colors. Requires a u32* with values alternating between the index a color starts at and then the new color, and then a u32 with the length of that array. This is similar to coloredtext tables in Love2D. + C2D_AlignLeft = 0 << 3, ///< Draws text aligned to the left. This is the default. + C2D_AlignRight = 1 << 3, ///< Draws text aligned to the right. + C2D_AlignCenter = 2 << 3, ///< Draws text centered. + C2D_AlignJustified = 3 << 3, ///< Draws text justified. When C2D_WordWrap is not specified, right edge is x + scaleX*text->width. Otherwise, right edge is x + the width specified for those values. + C2D_AlignMask = 3 << 3, ///< Bitmask for alignment values. + C2D_WordWrap = BIT(5), ///< Draws text with wrapping of full words before specified width. Requires a float value, passed after color values if C2D_WithColor or C2D_MultiColor is specified. }; /** @brief Creates a new text buffer. diff --git a/source/text.c b/source/text.c index 4cb6620..bbc1fba 100644 --- a/source/text.c +++ b/source/text.c @@ -17,6 +17,7 @@ typedef struct C2Di_Glyph_s { float left, top, right, bottom; } texcoord; + u32 charNo; u32 wordNo; } C2Di_Glyph; @@ -145,9 +146,12 @@ const char* C2D_TextFontParseLine(C2D_Text* text, C2D_Font font, C2D_TextBuf buf text->begin = buf->glyphCount; text->width = 0.0f; u32 wordNum = 0; + u32 charNum = text->chars; + bool lastWasWhitespace = true; while (buf->glyphCount < buf->glyphBufSize) { + ++charNum; uint32_t code; ssize_t units = decode_utf8(&code, p); if (units == -1) @@ -175,6 +179,7 @@ const char* C2D_TextFontParseLine(C2D_Text* text, C2D_Font font, C2D_TextBuf buf glyph->xPos = text->width + glyphData.xOffset; glyph->lineNo = lineNo; glyph->wordNo = wordNum; + glyph->charNo = charNum - 1; glyph->width = glyphData.width; glyph->texcoord.left = glyphData.texcoord.left; glyph->texcoord.top = glyphData.texcoord.top; @@ -193,6 +198,7 @@ const char* C2D_TextFontParseLine(C2D_Text* text, C2D_Font font, C2D_TextBuf buf text->width *= s_textScale; text->lines = 1; text->words = wordNum; + text->chars = charNum; return (const char*)p; } @@ -208,13 +214,16 @@ const char* C2D_TextFontParse(C2D_Text* text, C2D_Font font, C2D_TextBuf buf, co text->begin = buf->glyphCount; text->width = 0.0f; text->words = 0; + text->chars = 0; text->lines = 0; for (;;) { C2D_Text temp; + temp.chars = text->chars; str = C2D_TextFontParseLine(&temp, font, buf, str, text->lines++); text->words += temp.words; + text->chars = temp.chars; if (temp.width > text->width) text->width = temp.width; if (!str || *str != '\n') @@ -337,7 +346,9 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl glyphH = scaleY*fontGetGlyphInfo(systemFont)->cellHeight; dispY = ceilf(scaleY*fontGetInfo(systemFont)->lineFeed); } - u32 color = 0xFF000000; + + + float maxWidth = scaleX*text->width; va_list va; @@ -350,8 +361,23 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl else y -= scaleY*fontGetGlyphInfo(systemFont)->baselinePos; } + + + u32 defaultColor = 0xFF000000; + if (flags & C2D_WithColor) - color = va_arg(va, u32); + defaultColor = va_arg(va, u32); + + u32 color = defaultColor; + + u32* colors = NULL; + u32 lenColors = 0; + if (flags & C2D_MultiColor) + { + colors = va_arg(va, u32*); + lenColors = va_arg(va, u32); + } + if (flags & C2D_WordWrap) maxWidth = va_arg(va, double); // Passed as float, but varargs promotes to double. @@ -384,7 +410,7 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl // And set the new line number based off the last word's words[i].newLineNumber = words[i-1].newLineNumber + 1; } - // Otherwise both X offset and new line number should be the same as the last word's + // Otherwise, both X offset and new line number should be the same as the last word's else { words[i].wrapXOffset = words[i-1].wrapXOffset; @@ -393,6 +419,7 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl } } + u32 lastColorIdx = 0; switch (flags & C2D_AlignMask) { case C2D_AlignLeft: @@ -413,6 +440,26 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl glyphY = y+dispY*cur->lineNo; } + if (colors != NULL) + { + if(cur->charNo >= colors[lastColorIdx] && (lastColorIdx + 2 >= lenColors || cur->charNo < colors[lastColorIdx+2])) + color = colors[lastColorIdx+1]; + else + { + color = defaultColor; + if (cur->charNo >= colors[0]) + { + for(size_t i = 0; i < lenColors; i += 2) { + if (cur->charNo >= colors[i] && (i + 2 >= lenColors || cur->charNo < colors[i+2])) { + color = colors[i+1]; + lastColorIdx = i; + break; + } + } + } + } + } + C2Di_SetTex(cur->sheet); C2Di_Update(); C2Di_AppendQuad(); @@ -444,6 +491,26 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl glyphY = y + dispY*cur->lineNo; } + if (colors != NULL) + { + if(cur->charNo >= colors[lastColorIdx] && (lastColorIdx + 2 >= lenColors || cur->charNo < colors[lastColorIdx+2])) + color = colors[lastColorIdx+1]; + else + { + color = defaultColor; + if (cur->charNo >= colors[0]) + { + for(size_t i = 0; i < lenColors; i += 2) { + if (cur->charNo >= colors[i] && (i + 2 >= lenColors || cur->charNo < colors[i+2])) { + color = colors[i+1]; + lastColorIdx = i; + break; + } + } + } + } + } + C2Di_SetTex(cur->sheet); C2Di_Update(); C2Di_AppendQuad(); @@ -476,6 +543,26 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl glyphY = y + dispY*cur->lineNo; } + if (colors != NULL) + { + if(cur->charNo >= colors[lastColorIdx] && (lastColorIdx + 2 >= lenColors || cur->charNo < colors[lastColorIdx+2])) + color = colors[lastColorIdx+1]; + else + { + color = defaultColor; + if (cur->charNo >= colors[0]) + { + for(size_t i = 0; i < lenColors; i += 2) { + if (cur->charNo >= colors[i] && (i + 2 >= lenColors || cur->charNo < colors[i+2])) { + color = colors[i+1]; + lastColorIdx = i; + break; + } + } + } + } + } + C2Di_SetTex(cur->sheet); C2Di_Update(); C2Di_AppendQuad(); @@ -548,6 +635,26 @@ void C2D_DrawText(const C2D_Text* text, u32 flags, float x, float y, float z, fl float glyphX = x + scaleX*wordPositions[consecutiveWordNum].xBegin + scaleX*(cur->xPos - words[consecutiveWordNum].start->xPos) + justifiedLineInfo[words[consecutiveWordNum].newLineNumber].whitespaceWidth*(consecutiveWordNum - justifiedLineInfo[words[consecutiveWordNum].newLineNumber].wordStart); float glyphY = y + dispY*words[consecutiveWordNum].newLineNumber; + if (colors != NULL) + { + if(cur->charNo >= colors[lastColorIdx] && (lastColorIdx + 2 >= lenColors || cur->charNo < colors[lastColorIdx+2])) + color = colors[lastColorIdx+1]; + else + { + color = defaultColor; + if (cur->charNo >= colors[0]) + { + for(size_t i = 0; i < lenColors; i += 2) { + if (cur->charNo >= colors[i] && (i + 2 >= lenColors || cur->charNo < colors[i+2])) { + color = colors[i+1]; + lastColorIdx = i; + break; + } + } + } + } + } + C2Di_SetTex(cur->sheet); C2Di_Update(); C2Di_AppendQuad();