Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multicolor text support #42

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions include/c2d/text.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,21 @@ 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;

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.
Expand Down
113 changes: 110 additions & 3 deletions source/text.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ typedef struct C2Di_Glyph_s
{
float left, top, right, bottom;
} texcoord;
u32 charNo;
u32 wordNo;
} C2Di_Glyph;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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')
Expand Down Expand Up @@ -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;
Expand All @@ -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.

Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down