Skip to content

Commit

Permalink
Add scaling for vfnts and scale multipler to gr_string() (#6481)
Browse files Browse the repository at this point in the history
* Add scaling for vfnts and scale multipler to gr_string

* nullptr

* Add scaling to a couple other string operations

* Don't scale fonts in FRED
  • Loading branch information
MjnMixael authored Jan 14, 2025
1 parent b29e397 commit d27f735
Show file tree
Hide file tree
Showing 25 changed files with 169 additions and 198 deletions.
2 changes: 1 addition & 1 deletion code/camera/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
//Get text size
for(int i = 0; i < num_text_lines; i++)
{
gr_get_string_size(&w, &h, text_line_ptrs[i], static_cast<size_t>(text_line_lens[i]));
gr_get_string_size(&w, &h, text_line_ptrs[i], 1.0f, static_cast<size_t>(text_line_lens[i]));

if(w > tw)
tw = w;
Expand Down
2 changes: 1 addition & 1 deletion code/gamehelp/contexthelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ void help_overlay_blit(int overlay_id, int resolution_index)
font::set_font(help_overlaylist[overlay_id].fontlist.at(resolution_index));
for (idx = 0; idx < textcount; idx++) {
gr_set_color_fast(&Color_black);
gr_get_string_size(&width, &height, help_overlaylist[overlay_id].textlist.at(0).at(idx).string, strlen(help_overlaylist[overlay_id].textlist.at(0).at(idx).string));
gr_get_string_size(&width, &height, help_overlaylist[overlay_id].textlist.at(0).at(idx).string, 1.0f, strlen(help_overlaylist[overlay_id].textlist.at(0).at(idx).string));
gr_rect(help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).x_coord-2*HELP_PADDING, help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).y_coord-3*HELP_PADDING, width+4*HELP_PADDING, height+4*HELP_PADDING, GR_RESIZE_MENU);
gr_set_color_fast(&Color_bright_white);
gr_printf_menu(help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).x_coord, help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).y_coord,
Expand Down
2 changes: 1 addition & 1 deletion code/graphics/2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,7 @@ extern void gr_printf_menu_zoomed( int x, int y, const char * format, SCP_FORMAT
extern void gr_printf_no_resize( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4);

// Returns the size of the string in pixels in w and h
extern void gr_get_string_size( int *w, int *h, const char * text, size_t len = std::string::npos );
extern void gr_get_string_size( int *w, int *h, const char * text, float scaleMultiplier = 1.0f, size_t len = std::string::npos);

// Returns the height of the current font
extern int gr_get_font_height();
Expand Down
214 changes: 84 additions & 130 deletions code/graphics/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,16 +510,20 @@ extern int get_char_width_old(font* fnt, ubyte c1, ubyte c2, int* width, int* sp
}

static void gr_string_old(float sx,
float sy,
const char* s,
const char* end,
font::font* fontData,
float height,
int resize_mode) {
float sy,
const char* s,
const char* end,
font::font* fontData,
float height,
bool canScale,
int resize_mode,
float scaleMultiplier)
{
GR_DEBUG_SCOPE("Render VFNT string");

int width, spacing, letter;
float x, y;
int letter;
float x = sx;
float y = sy;
bool do_resize;
float bw, bh;
float u0, u1, v0, v1;
Expand All @@ -530,9 +534,9 @@ static void gr_string_old(float sx,
render_mat.set_depth_mode(ZBUFFER_TYPE_NONE);
render_mat.set_texture_map(TM_BASE_TYPE, fontData->bitmap_id);
render_mat.set_color(gr_screen.current_color.red,
gr_screen.current_color.green,
gr_screen.current_color.blue,
gr_screen.current_color.alpha);
gr_screen.current_color.green,
gr_screen.current_color.blue,
gr_screen.current_color.alpha);
render_mat.set_cull_mode(false);
render_mat.set_texture_type(material::TEX_TYPE_AABITMAP);

Expand All @@ -545,7 +549,6 @@ static void gr_string_old(float sx,
bw = i2fl(ibw);
bh = i2fl(ibh);

// if ( (gr_screen.custom_size && resize) || (gr_screen.rendering_to_texture != -1) ) {
if (resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1))) {
do_resize = true;
} else {
Expand All @@ -557,166 +560,116 @@ static void gr_string_old(float sx,
int clip_top = ((do_resize) ? gr_screen.clip_top_unscaled : gr_screen.clip_top);
int clip_bottom = ((do_resize) ? gr_screen.clip_bottom_unscaled : gr_screen.clip_bottom);

x = sx;
y = sy;

spacing = 0;

vertex_layout vert_def;

vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(v4), (int) offsetof(v4, x));
vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(v4), (int) offsetof(v4, u));
vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(v4), (int)offsetof(v4, x));
vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(v4), (int)offsetof(v4, u));

gr_set_2d_matrix();

// pick out letter coords, draw it, goto next letter and do the same
while (s < end) {
x += spacing;
float scale_factor = (canScale && !Fred_running) ? Font_Scale_Factor : 1.0f;
scale_factor *= scaleMultiplier;

while (s < end) {
// Handle line breaks
while (*s == '\n') {
s++;
y += height;
y += height * scale_factor;
x = sx;
}

if (*s == 0) {
break;
}

letter = font::get_char_width_old(fontData, (ubyte)s[0], (ubyte)s[1], &width, &spacing);
// Get character width and spacing
int raw_width = 0, raw_spacing = 0;
letter = font::get_char_width_old(fontData,
(ubyte)s[0],
(ubyte)s[1],
&raw_width,
&raw_spacing);
s++;

// not in font, draw as space
// Not in font, draw as space
if (letter < 0) {
x += raw_spacing * scale_factor;
continue;
}

float xd, yd, xc, yc;
float wc, hc;

// Check if this character is totally clipped
if ((x + width) < clip_left) {
continue;
}

if ((y + height) < clip_top) {
continue;
}

if (x > clip_right) {
continue;
}

if (y > clip_bottom) {
continue;
}

xd = yd = 0;

if (x < clip_left) {
xd = clip_left - x;
}

if (y < clip_top) {
yd = clip_top - y;
}

xc = x + xd;
yc = y + yd;

wc = width - xd;
hc = height - yd;

if ((xc + wc) > clip_right) {
wc = clip_right - xc;
}

if ((yc + hc) > clip_bottom) {
hc = clip_bottom - yc;
}

if ((wc < 1) || (hc < 1)) {
continue;
}

// UV coordinates
int u = fontData->bm_u[letter];
int v = fontData->bm_v[letter];
float char_width = i2fl(raw_width);
float char_height = i2fl(height);

u0 = u / bw;
v0 = v / bh;
u1 = (u + char_width) / bw;
v1 = (v + char_height) / bh;

// Scale output dimensions and positions
float xc = x; // Keep the X position unscaled
float yc = y; // Keep the Y position unscaled
float wc = char_width * scale_factor; // Scale width
float hc = char_height * scale_factor; // Scale height

// Apply offsets
x1 = xc + ((do_resize) ? gr_screen.offset_x_unscaled : gr_screen.offset_x);
y1 = yc + ((do_resize) ? gr_screen.offset_y_unscaled : gr_screen.offset_y);
x2 = x1 + wc;
y2 = y1 + hc;

// Check clipping
if ((x1 >= clip_right) || (x2 <= clip_left) || (y1 >= clip_bottom) || (y2 <= clip_top)) {
x += raw_spacing * scale_factor;
continue;
}

// Resize screen positions
if (do_resize) {
gr_resize_screen_posf(&x1, &y1, NULL, NULL, resize_mode);
gr_resize_screen_posf(&x2, &y2, NULL, NULL, resize_mode);
}

u0 = (i2fl(u + xd) / bw);
v0 = (i2fl(v + yd) / bh);

u1 = (i2fl((u + xd) + wc) / bw);
v1 = (i2fl((v + yd) + hc) / bh);
// Add vertices for the character
String_render_buff[buffer_offset++] = {x1, y1, u0, v0};
String_render_buff[buffer_offset++] = {x1, y2, u0, v1};
String_render_buff[buffer_offset++] = {x2, y1, u1, v0};
String_render_buff[buffer_offset++] = {x1, y2, u0, v1};
String_render_buff[buffer_offset++] = {x2, y1, u1, v0};
String_render_buff[buffer_offset++] = {x2, y2, u1, v1};

// If the buffer is full, render it now
if (buffer_offset == MAX_VERTS_PER_DRAW) {
gr_render_primitives_immediate(&render_mat,
PRIM_TYPE_TRIS,
&vert_def,
buffer_offset,
String_render_buff,
sizeof(v4) * buffer_offset);
PRIM_TYPE_TRIS,
&vert_def,
buffer_offset,
String_render_buff,
sizeof(v4) * buffer_offset);
buffer_offset = 0;
}

String_render_buff[buffer_offset].x = x1;
String_render_buff[buffer_offset].y = y1;
String_render_buff[buffer_offset].u = u0;
String_render_buff[buffer_offset].v = v0;
buffer_offset++;

String_render_buff[buffer_offset].x = x1;
String_render_buff[buffer_offset].y = y2;
String_render_buff[buffer_offset].u = u0;
String_render_buff[buffer_offset].v = v1;
buffer_offset++;

String_render_buff[buffer_offset].x = x2;
String_render_buff[buffer_offset].y = y1;
String_render_buff[buffer_offset].u = u1;
String_render_buff[buffer_offset].v = v0;
buffer_offset++;

String_render_buff[buffer_offset].x = x1;
String_render_buff[buffer_offset].y = y2;
String_render_buff[buffer_offset].u = u0;
String_render_buff[buffer_offset].v = v1;
buffer_offset++;

String_render_buff[buffer_offset].x = x2;
String_render_buff[buffer_offset].y = y1;
String_render_buff[buffer_offset].u = u1;
String_render_buff[buffer_offset].v = v0;
buffer_offset++;

String_render_buff[buffer_offset].x = x2;
String_render_buff[buffer_offset].y = y2;
String_render_buff[buffer_offset].u = u1;
String_render_buff[buffer_offset].v = v1;
buffer_offset++;
// Advance x for the next character
x += raw_spacing * scale_factor;
}

// Render remaining vertices in the buffer
if (buffer_offset) {
gr_render_primitives_immediate(&render_mat,
PRIM_TYPE_TRIS,
&vert_def,
buffer_offset,
String_render_buff,
sizeof(v4) * buffer_offset);
PRIM_TYPE_TRIS,
&vert_def,
buffer_offset,
String_render_buff,
sizeof(v4) * buffer_offset);
}

gr_end_2d_matrix();
}



namespace {
bool buffering_nanovg = false; //!< flag for when NanoVG buffering is enabled

Expand Down Expand Up @@ -779,7 +732,8 @@ void endDrawing(graphics::paths::PathRenderer* path) {
}
}

void gr_string(float sx, float sy, const char* s, int resize_mode, size_t in_length) {
void gr_string(float sx, float sy, const char* s, int resize_mode, float scaleMultiplier, size_t in_length)
{
if (gr_screen.mode == GR_STUB) {
return;
}
Expand Down Expand Up @@ -809,18 +763,16 @@ void gr_string(float sx, float sy, const char* s, int resize_mode, size_t in_len
VFNTFont* fnt = static_cast<VFNTFont*>(currentFont);
fo::font* fontData = fnt->getFontData();

gr_string_old(sx, sy, s, s + length, fontData, fnt->getHeight(), resize_mode);
gr_string_old(sx, sy, s, s + length, fontData, fnt->getHeight(), currentFont->getScaleBehavior(), resize_mode, scaleMultiplier);
} else if (currentFont->getType() == NVG_FONT) {
GR_DEBUG_SCOPE("Render TTF string");

auto path = beginDrawing(resize_mode);

auto nvgFont = static_cast<NVGFont*>(currentFont);

float scale_factor = Font_Scale_Factor;
if (!nvgFont->getScaleBehavior()) {
scale_factor = 1.0f;
}
float scale_factor = (nvgFont->getScaleBehavior() && !Fred_running) ? Font_Scale_Factor : 1.0f;
scale_factor *= scaleMultiplier;

float originalSize = nvgFont->getSize();
float scaledSize = originalSize * scale_factor;
Expand Down Expand Up @@ -909,7 +861,9 @@ void gr_string(float sx, float sy, const char* s, int resize_mode, size_t in_len
text + 1,
nvgFont->getSpecialCharacterFont(),
nvgFont->getHeight(),
resize_mode);
nvgFont->getScaleBehavior(),
resize_mode,
scaleMultiplier);
}

int width;
Expand Down
8 changes: 5 additions & 3 deletions code/graphics/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,22 @@ void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode =
* @param y The y-coordinate
* @param string The string to draw to the screen
* @param resize_mode The mode for translating the screen positions
* @param scaleMultiplier The scale to use to apply scaling in addition to user settings
* @param length The number of bytes in the string to render. -1 will render the whole string.
*/
void gr_string(float x, float y, const char* string, int resize_mode = GR_RESIZE_FULL, size_t length = std::string::npos);
void gr_string(float x, float y, const char* string, int resize_mode = GR_RESIZE_FULL, float scaleMultiplier = 1.0f, size_t length = std::string::npos);
/**
* @brief Renders the specified string to the screen using the current font and color
* @param x The x-coordinate
* @param y The y-coordinate
* @param string The string to draw to the screen
* @param resize_mode The mode for translating the screen positions
* @param scaleMultiplier The scale to use to apply scaling in addition to user settings
* @param length The number of bytes in the string to render. -1 will render the whole string.
*/
inline void gr_string(int x, int y, const char* string, int resize_mode = GR_RESIZE_FULL, size_t length = std::string::npos)
inline void gr_string(int x, int y, const char* string, int resize_mode = GR_RESIZE_FULL, float scaleMultiplier = 1.0f, size_t length = std::string::npos)
{
gr_string(i2fl(x), i2fl(y), string, resize_mode, length);
gr_string(i2fl(x), i2fl(y), string, resize_mode, scaleMultiplier, length);
}

/**
Expand Down
21 changes: 21 additions & 0 deletions code/graphics/software/FSFont.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
#include "graphics/software/FSFont.h"
#include "options/Option.h"

float Font_Scale_Factor = 1.0;

static auto FontScaleFactor __UNUSED = options::OptionBuilder<float>("Game.FontScaleFactor",
std::pair<const char*, int>{"Font Scale Factor", 1862},
std::pair<const char*, int>{
"Sets a multipler to scale fonts by. Only works on fonts the mod has explicitely allowed",
1863})
.category(std::make_pair("Game", 1824))
.range(0.2f, 4.0f) // Upper limit is somewhat arbitrary
.level(options::ExpertLevel::Advanced)
.default_val(1.0)
.bind_to(&Font_Scale_Factor)
.importance(55)
.finish();

void removeFontMultiplierOption()
{
options::OptionsManager::instance()->removeOption(FontScaleFactor);
}

namespace font
{
Expand Down
Loading

0 comments on commit d27f735

Please sign in to comment.