shithub: wipeout

ref: 6d241d506fbce2d0b6a69f19f83b34bdda0ac6af
dir: /src/wipeout/ui.c/

View raw version
#include "../render.h"
#include "../utils.h"

#include "ui.h"
#include "image.h"

typedef struct {
	vec2i_t offset;
	uint16_t width;
} glyph_t;

typedef struct {
	uint16_t texture;
	uint16_t height;
	glyph_t glyphs[40];
} char_set_t;

int ui_scale = 2;

char_set_t char_set[UI_SIZE_MAX] = {
	[UI_SIZE_16] = {
		.texture = 0,
		.height = 16,
		.glyphs = {
			{{  0,   0}, 25}, {{ 25,   0}, 24}, {{ 49,   0}, 17}, {{ 66,   0}, 24}, {{ 90,   0}, 24}, {{114,   0}, 17}, {{131,   0}, 25}, {{156,   0}, 18},
			{{174,   0},  7}, {{181,   0}, 17}, {{  0,  16}, 17}, {{ 17,  16}, 17}, {{ 34,  16}, 28}, {{ 62,  16}, 17}, {{ 79,  16}, 24}, {{103,  16}, 24},
			{{127,  16}, 26}, {{153,  16}, 24}, {{177,  16}, 18}, {{195,  16}, 17}, {{  0,  32}, 17}, {{ 17,  32}, 17}, {{ 34,  32}, 29}, {{ 63,  32}, 24},
			{{ 87,  32}, 17}, {{104,  32}, 18}, {{122,  32}, 24}, {{146,  32}, 10}, {{156,  32}, 18}, {{174,  32}, 17}, {{191,  32}, 18}, {{  0,  48}, 18},
			{{ 18,  48}, 18}, {{ 36,  48}, 18}, {{ 54,  48}, 22}, {{ 76,  48}, 25}, {{101,  48},  7}, {{108,  48},  7}, {{198,   0},  0}, {{198,   0},  0}
		}
	},
	[UI_SIZE_12] = {
		.texture = 0,
		.height = 12,
		.glyphs = {
			{{  0,   0}, 19}, {{ 19,   0}, 19}, {{ 38,   0}, 14}, {{ 52,   0}, 19}, {{ 71,   0}, 19}, {{ 90,   0}, 13}, {{103,   0}, 19}, {{122,   0}, 14},
			{{136,   0},  6}, {{142,   0}, 13}, {{155,   0}, 14}, {{169,   0}, 14}, {{  0,  12}, 22}, {{ 22,  12}, 14}, {{ 36,  12}, 19}, {{ 55,  12}, 18},
			{{ 73,  12}, 20}, {{ 93,  12}, 19}, {{112,  12}, 15}, {{127,  12}, 14}, {{141,  12}, 13}, {{154,  12}, 13}, {{167,  12}, 22}, {{  0,  24}, 19},
			{{ 19,  24}, 13}, {{ 32,  24}, 14}, {{ 46,  24}, 19}, {{ 65,  24},  8}, {{ 73,  24}, 15}, {{ 88,  24}, 13}, {{101,  24}, 14}, {{115,  24}, 15},
			{{130,  24}, 14}, {{144,  24}, 15}, {{159,  24}, 18}, {{177,  24}, 19}, {{196,  24},  5}, {{201,  24},  5}, {{183,   0},  0}, {{183,   0},  0}
		}
	},
	[UI_SIZE_8] = {
		.texture = 0,
		.height = 8,
		.glyphs = {
			{{  0,   0}, 13}, {{ 13,   0}, 13}, {{ 26,   0}, 10}, {{ 36,   0}, 13}, {{ 49,   0}, 13}, {{ 62,   0},  9}, {{ 71,   0}, 13}, {{ 84,   0}, 10},
			{{ 94,   0},  4}, {{ 98,   0},  9}, {{107,   0}, 10}, {{117,   0}, 10}, {{127,   0}, 16}, {{143,   0}, 10}, {{153,   0}, 13}, {{166,   0}, 13},
			{{179,   0}, 14}, {{  0,   8}, 13}, {{ 13,   8}, 10}, {{ 23,   8},  9}, {{ 32,   8},  9}, {{ 41,   8},  9}, {{ 50,   8}, 16}, {{ 66,   8}, 14},
			{{ 80,   8},  9}, {{ 89,   8}, 10}, {{ 99,   8}, 13}, {{112,   8},  6}, {{118,   8}, 11}, {{129,   8}, 10}, {{139,   8}, 10}, {{149,   8}, 11},
			{{160,   8}, 10}, {{170,   8}, 10}, {{180,   8}, 12}, {{192,   8}, 14}, {{206,   8},  4}, {{210,   8},  4}, {{193,   0},  0}, {{193,   0},  0}
		}
	},
};

uint16_t icon_textures[UI_ICON_MAX];

void ui_load() {
	texture_list_t tl = image_get_compressed_textures("wipeout/textures/drfonts.cmp");
	char_set[UI_SIZE_16].texture   = texture_from_list(tl, 0);
	char_set[UI_SIZE_12].texture   = texture_from_list(tl, 1);
	char_set[UI_SIZE_8 ].texture   = texture_from_list(tl, 2);
	icon_textures[UI_ICON_HAND]    = texture_from_list(tl, 3);
	icon_textures[UI_ICON_CONFIRM] = texture_from_list(tl, 5);
	icon_textures[UI_ICON_CANCEL]  = texture_from_list(tl, 6);
	icon_textures[UI_ICON_END]     = texture_from_list(tl, 7);
	icon_textures[UI_ICON_DEL]     = texture_from_list(tl, 8);
	icon_textures[UI_ICON_STAR]    = texture_from_list(tl, 9);
}

int ui_get_scale() {
	return ui_scale;
}

void ui_set_scale(int scale) {
	ui_scale = scale;
}


vec2i_t ui_scaled(vec2i_t v) {
	return vec2i(v.x * ui_scale, v.y * ui_scale);
}

vec2i_t ui_scaled_screen() {
	return vec2i_mulf(render_size(), ui_scale);
}

vec2i_t ui_scaled_pos(ui_pos_t anchor, vec2i_t offset) {
	vec2i_t pos;
	vec2i_t screen_size = render_size();

	if (flags_is(anchor, UI_POS_LEFT)) {
		pos.x = offset.x * ui_scale;
	}
	else if (flags_is(anchor, UI_POS_CENTER)) {
		pos.x = (screen_size.x >> 1) + offset.x * ui_scale;
	}
	else if (flags_is(anchor, UI_POS_RIGHT)) {
		pos.x = screen_size.x + offset.x * ui_scale;
	}

	if (flags_is(anchor, UI_POS_TOP)) {
		pos.y = offset.y * ui_scale;
	}
	else if (flags_is(anchor, UI_POS_MIDDLE)) {
		pos.y = (screen_size.y >> 1) + offset.y * ui_scale;
	}
	else if (flags_is(anchor, UI_POS_BOTTOM)) {
		pos.y = screen_size.y + offset.y * ui_scale;
	}

	return pos;
}

#define char_to_glyph_index(C) (C >= '0' && C <= '9' ? (C - '0' + 26) : C - 'A')

int ui_char_width(char c, ui_text_size_t size) {
	if (c == ' ') {
		return 8;
	}
	return char_set[size].glyphs[char_to_glyph_index(c)].width;
}

int ui_text_width(const char *text, ui_text_size_t size) {
	int width = 0;
	char_set_t *cs = &char_set[size];

	for (int i = 0; text[i] != 0; i++) {
		width += text[i] != ' '
			? cs->glyphs[char_to_glyph_index(text[i])].width
			: 8;
	}

	return width;
}

int ui_number_width(int num, ui_text_size_t size) {
	char text_buffer[16];
	text_buffer[15] = '\0';

	int i;
	for (i = 14; i > 0; i--) {
		text_buffer[i] = '0' + (num % 10);
		num = num / 10;
		if (num == 0) {
			break;
		}
	}
	return ui_text_width(text_buffer + i, size);
}

void ui_draw_time(float time, vec2i_t pos, ui_text_size_t size, rgba_t color) {
	int msec = time * 1000;
	int tenths = (msec / 100) % 10;
	int secs = (msec / 1000) % 60;
	int mins = msec / (60 * 1000);

	char text_buffer[8];
	text_buffer[0] = '0' + (mins / 10) % 10;
	text_buffer[1] = '0' + mins % 10;
	text_buffer[2] = 'e'; // ":"
	text_buffer[3] = '0' + secs / 10;
	text_buffer[4] = '0' + secs % 10;
	text_buffer[5] = 'f'; // "."
	text_buffer[6] = '0' + tenths;
	text_buffer[7] = '\0';
	ui_draw_text(text_buffer, pos, size, color);
}

void ui_draw_number(int num, vec2i_t pos, ui_text_size_t size, rgba_t color) {
	char text_buffer[16];
	text_buffer[15] = '\0';

	int i;
	for (i = 14; i > 0; i--) {
		text_buffer[i] = '0' + (num % 10);
		num = num / 10;
		if (num == 0) {
			break;
		}
	}
	ui_draw_text(text_buffer + i, pos, size, color);
}

void ui_draw_text(const char *text, vec2i_t pos, ui_text_size_t size, rgba_t color) {
	char_set_t *cs = &char_set[size];

	for (int i = 0; text[i] != 0; i++) {
		if (text[i] != ' ') {
			glyph_t *glyph = &cs->glyphs[char_to_glyph_index(text[i])];
			vec2i_t size = vec2i(glyph->width, cs->height);
			render_push_2d_tile(pos, glyph->offset, size, ui_scaled(size), color, cs->texture);
			pos.x += glyph->width * ui_scale;
		}
		else {
			pos.x += 8 * ui_scale;
		}
	}
}

void ui_draw_image(vec2i_t pos, uint16_t texture) {
	vec2i_t scaled_size = ui_scaled(render_texture_size(texture));
	render_push_2d(pos, scaled_size, rgba(128, 128, 128, 255), texture);
}

void ui_draw_icon(ui_icon_type_t icon, vec2i_t pos, rgba_t color) {
	render_push_2d(pos, ui_scaled(render_texture_size(icon_textures[icon])), color, icon_textures[icon]);
}

void ui_draw_text_centered(const char *text, vec2i_t pos, ui_text_size_t size, rgba_t color) {
	pos.x -= (ui_text_width(text, size) * ui_scale) >> 1;
	ui_draw_text(text, pos, size, color);
}