Skip to content
Merged
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
6 changes: 6 additions & 0 deletions include/cute_draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,12 @@ typedef struct CF_TextEffect
/* @member User-modifiable. The color to render this glyph with. */
CF_Color color;

/* @member User-modifiable. Per-corner colors: [0]=TL, [1]=TR, [2]=BR, [3]=BL. Only used when use_colors is true. */
CF_Color colors[4];

/* @member User-modifiable. If true, use colors[4] per-corner instead of flat color. */
bool use_colors;

/* @member User-modifiable. The opacity to render this glyph with. */
float opacity;

Expand Down
31 changes: 29 additions & 2 deletions samples/text_drawing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ static void draw_text_boxed(const char* text, v2 pos, int len = -1)

int main(int argc, char* argv[])
{
make_app("Text Drawing", 0, 0, 0, 640, 480, CF_APP_OPTIONS_WINDOW_POS_CENTERED_BIT | CF_APP_OPTIONS_RESIZABLE_BIT, argv[0]);
make_app("Text Drawing", 0, 0, 0, 960, 700, CF_APP_OPTIONS_WINDOW_POS_CENTERED_BIT | CF_APP_OPTIONS_RESIZABLE_BIT, argv[0]);

draw_push_shape_aa(1.5f);
make_font_from_memory(proggy_data, proggy_sz, "ProggyClean");
Expand Down Expand Up @@ -95,7 +95,7 @@ int main(int argc, char* argv[])
// Drawing a formatted string.
String draws = String::fmt("Draw calls: %d", draw_calls);
push_font_size(13);
draw_text_boxed(draws.c_str(), V2(-640/2.0f + 10,-480/2.0f + 20));
draw_text_boxed(draws.c_str(), V2(-960/2.0f + 10,-700/2.0f + 20));

push_font_size(26);
draw_text_boxed("Half-rendered effect <wave>groovy</wave>", V2(-230.f, 180.f), 25);
Expand All @@ -107,6 +107,33 @@ int main(int argc, char* argv[])
draw_text_boxed("Some <shake freq=35 x=2 y=2>shaking</shake> text.", round(V2(sinf((float)CF_SECONDS*0.25f)*100,cosf((float)CF_SECONDS*0.25f)*100)));


float gx = 130;

// Horizontal: left-to-right red to blue.
push_font_size(30);
draw_text_boxed("<gradient left=#ff0000 right=#0055ff>Left-to-right gradient!</gradient>", V2(gx, -80));

// Vertical: top gold to bottom purple.
push_font_size(30);
draw_text_boxed("<gradient top=#ffd700 bottom=#8b00ff>Top-to-bottom gradient!</gradient>", V2(gx, -120));

// Corners: direct per-corner control.
push_font_size(30);
draw_text_boxed("<gradient topleft=#ff0000 topright=#00ff00 bottomright=#0000ff bottomleft=#ffff00>Per-corner colors</gradient>", V2(gx, -160));

// Mix: edge + corner override.
push_font_size(30);
draw_text_boxed("<gradient left=#ff0000 right=#0000ff topleft=#00ff00>Edge + corner override</gradient>", V2(gx, -200));

// Single edge: fades from red to the glyph's current color.
push_font_size(30);
draw_text_boxed("<gradient left=#ff0000>Fade from one color</gradient>", V2(gx, -240));

// Short strings: gradient should still work on 1-2 glyphs.
push_font_size(40);
draw_text_boxed("<gradient left=#ff0000 right=#0000ff>AB</gradient>", V2(gx, -280));
draw_text_boxed("<gradient top=#ff0000 bottom=#0000ff>X</gradient>", V2(gx + 80, -280));

cf_push_text_id(1);
{
char text_buf[512];
Expand Down
67 changes: 64 additions & 3 deletions src/cute_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,28 @@ static void s_draw_report(spritebatch_sprite_t* sprites, int count, int texture_
} else {
CF_ASSERT(false);
}
out[i].color = s->geom.color;
out[i].attributes = geom.user_params;
out[i].uv_bounds[0] = s->minx;
out[i].uv_bounds[1] = s->maxy; // y-flip.
out[i].uv_bounds[2] = s->maxx;
out[i].uv_bounds[3] = s->miny; // y-flip.
}

// Per-vertex colors: text uses per-corner text_colors, sprites use flat color.
// shape[0]=TL, shape[1]=TR, shape[2]=BR, shape[3]=BL
// Triangle 1: TL(0), BL(3), TR(1) Triangle 2: TR(1), BL(3), BR(2)
if (s->geom.is_text) {
CF_Pixel *tc = s->geom.text_colors;
out[0].color = tc[0]; // TL
out[1].color = tc[3]; // BL
out[2].color = tc[1]; // TR
out[3].color = tc[1]; // TR
out[4].color = tc[3]; // BL
out[5].color = tc[2]; // BR
} else {
for (int i = 0; i < 6; ++i) out[i].color = s->geom.color;
}

out[0].posH = geom.shape[0];
out[0].uv.x = s->minx;
out[0].uv.y = s->maxy;
Expand Down Expand Up @@ -2266,12 +2280,12 @@ static CF_Color s_parse_color(CF_CodeParseState* s)
String string;
s->expect('#');
while (!s->done()) {
int cp = s->peek();
int cp = s->peek(false);
if (!s_is_hex_alphanum(cp)) {
break;
} else {
string.append(cp);
s->skip();
s->skip(false);
}
}
uint32_t rgba = 0x000000FF;
Expand Down Expand Up @@ -2458,6 +2472,39 @@ static bool s_text_fx_strike(CF_TextEffect* fx_ptr)
return true;
}

static CF_Color s_gradient_corner(TextEffect* fx, const char* corner, const char* edge_a, const char* edge_b)
{
CF_Color c = fx->color;
if (fx->has(corner)) return fx->get_color(corner, c);
bool a = fx->has(edge_a);
bool b = fx->has(edge_b);
if (a && b) return cf_color_lerp(fx->get_color(edge_a, c), fx->get_color(edge_b, c), 0.5f);
if (a) return fx->get_color(edge_a, c);
if (b) return fx->get_color(edge_b, c);
return c;
}

static bool s_text_fx_gradient(CF_TextEffect* fx_ptr)
{
TextEffect* fx = (TextEffect*)fx_ptr;

CF_Color tl = s_gradient_corner(fx, "topleft", "top", "left");
CF_Color tr = s_gradient_corner(fx, "topright", "top", "right");
CF_Color br = s_gradient_corner(fx, "bottomright", "bottom", "right");
CF_Color bl = s_gradient_corner(fx, "bottomleft", "bottom", "left");

float n = (float)fx->glyph_count;
float t_left = (float)fx->index_into_effect / n;
float t_right = (float)(fx->index_into_effect + 1) / n;

fx->use_colors = true;
fx->colors[0] = cf_color_lerp(tl, tr, t_left); // glyph TL
fx->colors[1] = cf_color_lerp(tl, tr, t_right); // glyph TR
fx->colors[2] = cf_color_lerp(bl, br, t_right); // glyph BR
fx->colors[3] = cf_color_lerp(bl, br, t_left); // glyph BL
return true;
}

static void s_parse_codes(CF_ParsedTextState* text_state, const char* text)
{
// Register built-in text effects.
Expand All @@ -2469,6 +2516,7 @@ static void s_parse_codes(CF_ParsedTextState* text_state, const char* text)
text_effect_register("fade", s_text_fx_fade);
text_effect_register("wave", s_text_fx_wave);
text_effect_register("strike", s_text_fx_strike);
text_effect_register("gradient", s_text_fx_gradient);
}

CF_CodeParseState state = { };
Expand Down Expand Up @@ -2715,6 +2763,7 @@ static v2 s_draw_text(const char* text, CF_V2 position, int text_length, bool re
v2 q1 = glyph->q1 + V2(x,y) + kern + pad;

// Apply any active custom text effects.
bool use_corner_colors = false;
for (int i = 0; i < text_state->effects.count();) {
TextEffect* effect = text_state->effects + i;
CF_TextEffectFn* fn = effect->fn;
Expand All @@ -2729,6 +2778,7 @@ static v2 s_draw_text(const char* text, CF_V2 position, int text_length, bool re
effect->w = s.w;
effect->h = s.h;
effect->color = color;
effect->use_colors = false;
effect->opacity = s.geom.alpha;
effect->xadvance = xadvance;
effect->visible = visible;
Expand All @@ -2738,6 +2788,13 @@ static v2 s_draw_text(const char* text, CF_V2 position, int text_length, bool re
q0 = effect->q0;
q1 = effect->q1;
color = effect->color;
if (effect->use_colors) {
use_corner_colors = true;
s.geom.text_colors[0] = premultiply(to_pixel(effect->colors[0]));
s.geom.text_colors[1] = premultiply(to_pixel(effect->colors[1]));
s.geom.text_colors[2] = premultiply(to_pixel(effect->colors[2]));
s.geom.text_colors[3] = premultiply(to_pixel(effect->colors[3]));
}
s.geom.alpha = effect->opacity;
xadvance = effect->xadvance;
visible = effect->visible;
Expand Down Expand Up @@ -2774,6 +2831,10 @@ static v2 s_draw_text(const char* text, CF_V2 position, int text_length, bool re
CF_MUL_M32_V2(s.geom.shape[2], m, V2(q1.x, q0.y));
CF_MUL_M32_V2(s.geom.shape[3], m, V2(q0.x, q0.y));
s.geom.color = premultiply(to_pixel(color));
if (!use_corner_colors) {
CF_Pixel flat = s.geom.color;
for (int j = 0; j < 4; ++j) s.geom.text_colors[j] = flat;
}
s.geom.is_text = true;
DRAW_PUSH_ITEM(s);
}
Expand Down
1 change: 1 addition & 0 deletions src/internal/cute_draw_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct BatchGeometry
float aa;
bool is_text;
bool is_sprite;
CF_Pixel text_colors[4]; // Per-corner: TL, TR, BR, BL (for text glyphs)
bool fill;
bool use_tri_colors; // Per-vertex colors for triangles.
bool use_tri_attributes; // Per-vertex attributes for triangles.
Expand Down
1 change: 1 addition & 0 deletions src/internal/cute_font_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct TextEffect : public CF_TextEffect
{
CF_INLINE bool on_start() const { return index_into_effect == 0; }
CF_INLINE bool on_finish() const { return index_into_effect == glyph_count - 1; }
CF_INLINE bool has(const char* key) const { return params->try_find(sintern(key)) != NULL; }

CF_INLINE double get_number(const char* key, double default_val = 0) const
{
Expand Down
Loading