ddnet/src/engine/client/gfx.cpp

765 lines
22 KiB
C++
Raw Normal View History

2007-05-22 15:03:32 +00:00
#include <baselib/opengl.h>
#include <baselib/math.h>
2007-05-22 15:03:32 +00:00
#include <baselib/vmath.h>
#include <baselib/stream/file.h>
#include <engine/interface.h>
2007-05-22 15:03:32 +00:00
#include "pnglite/pnglite.h"
#include <string.h>
2007-07-21 15:48:35 +00:00
#include <engine/config.h>
2007-05-22 15:03:32 +00:00
using namespace baselib;
static opengl::context context;
struct custom_vertex
{
vec3 pos;
vec2 tex;
vec4 color;
};
2007-07-29 15:21:25 +00:00
const int vertex_buffer_size = 32*1024;
static custom_vertex *vertices = 0;
static int num_vertices = 0;
static vec4 color[4];
static vec2 texture[4];
2007-05-22 15:03:32 +00:00
static opengl::vertex_buffer vertex_buffer;
//static int screen_width = 800;
//static int screen_height = 600;
static float rotation = 0;
static int quads_drawing = 0;
2007-07-22 12:01:20 +00:00
static float screen_x0 = 0;
static float screen_y0 = 0;
static float screen_x1 = 0;
static float screen_y1 = 0;
2007-05-22 15:03:32 +00:00
struct texture_holder
{
opengl::texture tex;
int flags;
int next;
};
static const int MAX_TEXTURES = 128;
static texture_holder textures[MAX_TEXTURES];
static int first_free_texture;
2007-07-13 21:22:45 +00:00
static const unsigned char null_texture_data[] = {
2007-05-22 15:03:32 +00:00
0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff,
0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff,
0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff,
0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff,
};
static void draw_quad(bool _bflush = false)
{
if (!_bflush && ((num_vertices + 4) < vertex_buffer_size))
2007-05-22 15:03:32 +00:00
{
// Just add
num_vertices += 4;
2007-05-22 15:03:32 +00:00
}
else if (num_vertices)
2007-05-22 15:03:32 +00:00
{
if (!_bflush)
num_vertices += 4;
2007-07-21 18:54:07 +00:00
if(GLEW_ARB_vertex_buffer_object)
2007-05-22 15:03:32 +00:00
{
// set the data
vertex_buffer.data(vertices, num_vertices * sizeof(custom_vertex), GL_DYNAMIC_DRAW);
2007-05-22 15:03:32 +00:00
opengl::stream_vertex(&vertex_buffer, 3, GL_FLOAT, sizeof(custom_vertex), 0);
opengl::stream_texcoord(&vertex_buffer, 0, 2, GL_FLOAT,
sizeof(custom_vertex),
sizeof(vec3));
opengl::stream_color(&vertex_buffer, 4, GL_FLOAT,
sizeof(custom_vertex),
sizeof(vec3)+sizeof(vec2));
2007-07-29 15:21:25 +00:00
//glDrawElements(GL_TRIANGLES, num_vertices, GL_UNSIGNED_SHORT, indecies);
opengl::draw_arrays(GL_QUADS, 0, num_vertices);
2007-05-22 15:03:32 +00:00
}
else
{
glVertexPointer(3, GL_FLOAT,
sizeof(custom_vertex),
(char*)vertices);
2007-05-22 15:03:32 +00:00
glTexCoordPointer(2, GL_FLOAT,
sizeof(custom_vertex),
(char*)vertices + sizeof(vec3));
2007-05-22 15:03:32 +00:00
glColorPointer(4, GL_FLOAT,
sizeof(custom_vertex),
(char*)vertices + sizeof(vec3) + sizeof(vec2));
2007-05-22 15:03:32 +00:00
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_QUADS, 0, num_vertices);
2007-05-22 15:03:32 +00:00
}
2007-05-22 15:03:32 +00:00
// Reset pointer
num_vertices = 0;
}
}
2007-07-21 16:33:01 +00:00
bool gfx_init()
2007-05-22 15:03:32 +00:00
{
if(!context.create(config.gfx_screen_width, config.gfx_screen_height, 24, 8, 16, 0,
config.gfx_fullscreen?opengl::context::FLAG_FULLSCREEN:0))
2007-05-22 15:03:32 +00:00
{
dbg_msg("game", "failed to create gl context");
return false;
}
2007-07-22 13:42:28 +00:00
2007-05-22 15:03:32 +00:00
// Init vertices
if (vertices)
mem_free(vertices);
vertices = (custom_vertex*)mem_alloc(sizeof(custom_vertex) * vertex_buffer_size, 1);
num_vertices = 0;
2007-05-22 15:03:32 +00:00
context.set_title("---");
/*
dbg_msg("gfx", "OpenGL version %d.%d.%d", context.version_major(),
context.version_minor(),
context.version_rev());*/
gfx_mapscreen(0,0,config.gfx_screen_width, config.gfx_screen_height);
2007-05-22 15:03:32 +00:00
// TODO: make wrappers for this
glEnable(GL_BLEND);
// model
mat4 mat = mat4::identity;
opengl::matrix_modelview(&mat);
// Set all z to -5.0f
for (int i = 0; i < vertex_buffer_size; i++)
vertices[i].pos.z = -5.0f;
2007-05-22 15:03:32 +00:00
2007-07-21 18:54:07 +00:00
if(GLEW_ARB_vertex_buffer_object)
2007-05-22 15:03:32 +00:00
{
// set the streams
vertex_buffer.data(vertices, sizeof(vertex_buffer_size), GL_DYNAMIC_DRAW);
2007-05-22 15:03:32 +00:00
opengl::stream_vertex(&vertex_buffer, 3, GL_FLOAT, sizeof(custom_vertex), 0);
opengl::stream_texcoord(&vertex_buffer, 0, 2, GL_FLOAT,
sizeof(custom_vertex),
sizeof(vec3));
opengl::stream_color(&vertex_buffer, 4, GL_FLOAT,
sizeof(custom_vertex),
sizeof(vec3)+sizeof(vec2));
}
// init textures
first_free_texture = 0;
for(int i = 0; i < MAX_TEXTURES; i++)
textures[i].next = i+1;
textures[MAX_TEXTURES-1].next = -1;
2007-07-29 15:21:25 +00:00
// init indecies
/*
2007-07-29 15:21:25 +00:00
for(int i = 0; i < vertex_buffer_size; i++)
{
indecies[i*6 + 0] = i+0;
indecies[i*6 + 1] = i+1;
indecies[i*6 + 2] = i+2;
indecies[i*6 + 3] = i+1;
indecies[i*6 + 4] = i+3;
indecies[i*6 + 5] = i+2;
}*/
2007-07-29 15:21:25 +00:00
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2007-07-26 19:09:31 +00:00
2007-05-22 15:03:32 +00:00
// create null texture, will get id=0
gfx_load_texture_raw(4,4,IMG_RGBA,null_texture_data);
2007-07-22 11:46:25 +00:00
2007-07-22 13:42:28 +00:00
// set vsync as needed
gfx_set_vsync(config.gfx_vsync);
2007-07-22 13:42:28 +00:00
2007-05-22 15:03:32 +00:00
return true;
}
2007-07-26 19:09:31 +00:00
video_mode fakemodes[] = {
{320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8},
{720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8},
{1024,600,8,8,8}, {1024,768,8,8,8}, {1152,864,8,8,8},
{1280,768,8,8,8}, {1280,800,8,8,8}, {1280,960,8,8,8},
{1280,1024,8,8,8}, {1368,768,8,8,8}, {1400,1050,8,8,8},
{1440,900,8,8,8}, {1440,1050,8,8,8}, {1600,1000,8,8,8},
{1600,1200,8,8,8}, {1680,1050,8,8,8}, {1792,1344,8,8,8},
{1800,1440,8,8,8}, {1856,1392,8,8,8}, {1920,1080,8,8,8},
{1920,1200,8,8,8}, {1920,1440,8,8,8}, {1920,2400,8,8,8},
{2048,1536,8,8,8},
{320,240,5,6,5}, {400,300,5,6,5}, {640,480,5,6,5},
{720,400,5,6,5}, {768,576,5,6,5}, {800,600,5,6,5},
{1024,600,5,6,5}, {1024,768,5,6,5}, {1152,864,5,6,5},
{1280,768,5,6,5}, {1280,800,5,6,5}, {1280,960,5,6,5},
{1280,1024,5,6,5}, {1368,768,5,6,5}, {1400,1050,5,6,5},
{1440,900,5,6,5}, {1440,1050,5,6,5}, {1600,1000,5,6,5},
{1600,1200,5,6,5}, {1680,1050,5,6,5}, {1792,1344,5,6,5},
{1800,1440,5,6,5}, {1856,1392,5,6,5}, {1920,1080,5,6,5},
{1920,1200,5,6,5}, {1920,1440,5,6,5}, {1920,2400,5,6,5},
{2048,1536,5,6,5}
};
2007-07-21 12:57:36 +00:00
int gfx_get_video_modes(video_mode *list, int maxcount)
{
if(config.gfx_display_all_modes)
2007-07-26 19:09:31 +00:00
{
mem_copy(list, fakemodes, sizeof(fakemodes));
return min((int)(sizeof(fakemodes)/sizeof(video_mode)), maxcount);
}
2007-07-21 12:57:36 +00:00
return context.getvideomodes((opengl::videomode *)list, maxcount);
}
2007-07-22 13:42:28 +00:00
void gfx_set_vsync(int val)
{
context.set_vsync(val);
}
2007-05-22 15:03:32 +00:00
int gfx_unload_texture(int index)
{
textures[index].tex.clear();
textures[index].next = first_free_texture;
first_free_texture = index;
return 0;
}
void gfx_blend_normal()
{
// TODO: wrapper for this
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void gfx_blend_additive()
{
// TODO: wrapper for this
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
2007-07-29 15:38:20 +00:00
static unsigned char sample(int w, int h, const unsigned char *data, int u, int v, int offset)
{
return (data[(v*w+u)*4+offset]+
data[(v*w+u+1)*4+offset]+
data[((v+1)*w+u)*4+offset]+
data[((v+1)*w+u+1)*4+offset])/4;
}
int gfx_load_texture_raw(int w, int h, int format, const void *data)
2007-05-22 15:03:32 +00:00
{
// grab texture
int tex = first_free_texture;
first_free_texture = textures[tex].next;
textures[tex].next = -1;
2007-07-29 15:21:25 +00:00
// resample if needed
unsigned char *texdata = (unsigned char *)data;
unsigned char *tmpdata = 0;
if(config.gfx_texture_quality==0)
2007-07-29 15:21:25 +00:00
{
if(w > 16 && h > 16 && format == IMG_RGBA)
{
2007-07-29 15:38:20 +00:00
w/=2;
h/=2;
2007-07-29 15:21:25 +00:00
unsigned char *tmpdata = (unsigned char *)mem_alloc(w*h*4, 1);
int c = 0;
for(int y = 0; y < h; y++)
for(int x = 0; x < w; x++, c++)
{
2007-07-29 15:38:20 +00:00
tmpdata[c*4] = sample(w*2, h*2, texdata, x*2,y*2, 0);
tmpdata[c*4+1] = sample(w*2, h*2, texdata, x*2,y*2, 1);
tmpdata[c*4+2] = sample(w*2, h*2, texdata, x*2,y*2, 2);
tmpdata[c*4+3] = sample(w*2, h*2, texdata, x*2,y*2, 3);
2007-07-29 15:21:25 +00:00
}
texdata = tmpdata;
}
}
2007-05-22 15:03:32 +00:00
dbg_msg("gfx", "%d = %dx%d", tex, w, h);
2007-07-29 15:21:25 +00:00
// set data and return
if(config.gfx_texture_compression && GLEW_ARB_texture_compression)
2007-07-22 09:15:34 +00:00
{
2007-07-29 15:21:25 +00:00
if(format == IMG_RGB)
textures[tex].tex.data2d(w, h, GL_COMPRESSED_RGB_ARB, GL_RGB, GL_UNSIGNED_BYTE, texdata);
else if(format == IMG_RGBA)
textures[tex].tex.data2d(w, h, GL_COMPRESSED_RGBA_ARB, GL_RGBA, GL_UNSIGNED_BYTE, texdata);
2007-07-22 09:15:34 +00:00
}
2007-07-29 15:21:25 +00:00
else
{
if(format == IMG_RGB)
textures[tex].tex.data2d(w, h, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, texdata);
else if(format == IMG_RGBA)
textures[tex].tex.data2d(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, texdata);
}
mem_free(tmpdata);
2007-07-22 09:15:34 +00:00
2007-05-22 15:03:32 +00:00
return tex;
}
2007-07-22 11:46:25 +00:00
/*
int gfx_load_mip_texture_raw(int w, int h, int format, const void *data)
{
// grab texture
int tex = first_free_texture;
first_free_texture = textures[tex].next;
textures[tex].next = -1;
// set data and return
// TODO: should be RGBA, not BGRA
dbg_msg("gfx", "%d = %dx%d", tex, w, h);
dbg_assert(format == IMG_RGBA, "not an RGBA image");
2007-05-22 15:03:32 +00:00
2007-07-22 11:46:25 +00:00
unsigned mip_w = w;
unsigned mip_h = h;
unsigned level = 0;
const unsigned char *ptr = (const unsigned char*)data;
while(mip_w > 0 && mip_h > 0)
{
dbg_msg("gfx mip", "%d = %dx%d", level, mip_w, mip_h);
textures[tex].tex.data2d_mip(mip_w, mip_h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, level, ptr);
level++;
ptr = ptr + mip_w*mip_h*4;
mip_w = mip_w>>1;
mip_h = mip_h>>1;
}
return tex;
}
*/
2007-05-22 15:03:32 +00:00
// simple uncompressed RGBA loaders
int gfx_load_texture(const char *filename)
2007-05-22 15:03:32 +00:00
{
int l = strlen(filename);
if(l < 3)
return 0;
image_info img;
if(gfx_load_png(&img, filename))
2007-05-22 15:03:32 +00:00
{
int id = gfx_load_texture_raw(img.width, img.height, img.format, img.data);
mem_free(img.data);
return id;
2007-05-22 15:03:32 +00:00
}
return 0;
}
int gfx_load_png(image_info *img, const char *filename)
{
// open file for reading
png_init(0,0);
png_t png;
if(png_open_file(&png, filename) != PNG_NO_ERROR)
{
dbg_msg("game/png", "failed to open file. filename='%s'", filename);
return 0;
}
if(png.depth != 8 || (png.color_type != PNG_TRUECOLOR && png.color_type != PNG_TRUECOLOR_ALPHA))
{
dbg_msg("game/png", "invalid format. filename='%s'", filename);
png_close_file(&png);
}
unsigned char *buffer = (unsigned char *)mem_alloc(png.width * png.height * png.bpp, 1);
png_get_data(&png, buffer);
png_close_file(&png);
img->width = png.width;
img->height = png.height;
if(png.color_type == PNG_TRUECOLOR)
img->format = IMG_RGB;
else if(png.color_type == PNG_TRUECOLOR_ALPHA)
img->format = IMG_RGBA;
img->data = buffer;
return 1;
}
2007-05-22 15:03:32 +00:00
void gfx_shutdown()
{
if (vertices)
mem_free(vertices);
2007-05-22 15:03:32 +00:00
context.destroy();
}
void gfx_swap()
{
context.swap();
}
int gfx_screenwidth()
{
return config.gfx_screen_width;
2007-05-22 15:03:32 +00:00
}
int gfx_screenheight()
{
return config.gfx_screen_height;
2007-05-22 15:03:32 +00:00
}
void gfx_texture_set(int slot)
{
dbg_assert(quads_drawing == 0, "called gfx_texture_set within quads_begin");
if(slot == -1)
opengl::texture_disable(0);
else
opengl::texture_2d(0, &textures[slot].tex);
}
void gfx_clear(float r, float g, float b)
{
glClearColor(r,g,b,1.0f);
opengl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void gfx_mapscreen(float tl_x, float tl_y, float br_x, float br_y)
{
2007-07-22 12:01:20 +00:00
screen_x0 = tl_x;
screen_y0 = tl_y;
screen_x1 = br_x;
screen_y1 = br_y;
2007-05-22 15:03:32 +00:00
mat4 mat;
mat.ortho(tl_x, br_x, br_y, tl_y, 1.0f, 10.f);
opengl::matrix_projection(&mat);
}
2007-07-22 12:01:20 +00:00
void gfx_getscreen(float *tl_x, float *tl_y, float *br_x, float *br_y)
{
*tl_x = screen_x0;
*tl_y = screen_y0;
*br_x = screen_x1;
*br_y = screen_y1;
}
2007-05-22 15:03:32 +00:00
void gfx_setoffset(float x, float y)
{
//const float scale = 0.75f;
const float scale = 1.0f;
mat4 mat = mat4::identity;
mat.m[0] = scale;
mat.m[5] = scale;
mat.m[10] = scale;
mat.m[12] = x*scale;
mat.m[13] = y*scale;
opengl::matrix_modelview(&mat);
}
2007-05-22 15:03:32 +00:00
void gfx_quads_begin()
{
dbg_assert(quads_drawing == 0, "called quads_begin twice");
quads_drawing++;
gfx_quads_setsubset(0,0,1,1);
gfx_quads_setrotation(0);
gfx_quads_setcolor(1,1,1,1);
}
void gfx_quads_end()
{
dbg_assert(quads_drawing == 1, "called quads_end without quads_begin");
draw_quad(true);
quads_drawing--;
}
void gfx_quads_setrotation(float angle)
{
dbg_assert(quads_drawing == 1, "called gfx_quads_setrotation without quads_begin");
rotation = angle;
}
void gfx_quads_setcolorvertex(int i, float r, float g, float b, float a)
{
dbg_assert(quads_drawing == 1, "called gfx_quads_setcolorvertex without quads_begin");
color[i].r = r;
color[i].g = g;
color[i].b = b;
color[i].a = a;
2007-05-22 15:03:32 +00:00
}
void gfx_quads_setcolor(float r, float g, float b, float a)
{
dbg_assert(quads_drawing == 1, "called gfx_quads_setcolor without quads_begin");
color[0] = vec4(r,g,b,a);
color[1] = vec4(r,g,b,a);
color[2] = vec4(r,g,b,a);
color[3] = vec4(r,g,b,a);
2007-05-22 15:03:32 +00:00
}
void gfx_quads_setsubset(float tl_u, float tl_v, float br_u, float br_v)
{
dbg_assert(quads_drawing == 1, "called gfx_quads_setsubset without quads_begin");
texture[0].x = tl_u;
texture[0].y = tl_v;
2007-05-22 15:03:32 +00:00
//g_pVertices[g_iVertexEnd].tex.u = tl_u;
//g_pVertices[g_iVertexEnd].tex.v = tl_v;
texture[1].x = br_u;
texture[1].y = tl_v;
2007-05-22 15:03:32 +00:00
//g_pVertices[g_iVertexEnd + 2].tex.u = br_u;
//g_pVertices[g_iVertexEnd + 2].tex.v = tl_v;
texture[2].x = br_u;
texture[2].y = br_v;
2007-05-22 15:03:32 +00:00
//g_pVertices[g_iVertexEnd + 1].tex.u = tl_u;
//g_pVertices[g_iVertexEnd + 1].tex.v = br_v;
texture[3].x = tl_u;
texture[3].y = br_v;
2007-05-22 15:03:32 +00:00
//g_pVertices[g_iVertexEnd + 3].tex.u = br_u;
//g_pVertices[g_iVertexEnd + 3].tex.v = br_v;
}
static void rotate(vec3 &center, vec3 &point)
{
vec3 p = point-center;
point.x = p.x * cosf(rotation) - p.y * sinf(rotation) + center.x;
point.y = p.x * sinf(rotation) + p.y * cosf(rotation) + center.y;
}
void gfx_quads_draw(float x, float y, float w, float h)
{
gfx_quads_drawTL(x-w/2, y-h/2,w,h);
}
void gfx_quads_drawTL(float x, float y, float width, float height)
{
dbg_assert(quads_drawing == 1, "called quads_draw without quads_begin");
vec3 center;
center.x = x + width/2;
center.y = y + height/2;
center.z = 0;
vertices[num_vertices].pos.x = x;
vertices[num_vertices].pos.y = y;
vertices[num_vertices].tex.u = texture[0].x;
vertices[num_vertices].tex.v = texture[0].y;
vertices[num_vertices].color = color[0];
rotate(center, vertices[num_vertices].pos);
vertices[num_vertices + 1].pos.x = x+width;
vertices[num_vertices + 1].pos.y = y;
vertices[num_vertices + 1].tex.u = texture[1].x;
vertices[num_vertices + 1].tex.v = texture[1].y;
vertices[num_vertices + 1].color = color[1];
rotate(center, vertices[num_vertices + 1].pos);
vertices[num_vertices + 2].pos.x = x + width;
vertices[num_vertices + 2].pos.y = y+height;
vertices[num_vertices + 2].tex.u = texture[2].x;
vertices[num_vertices + 2].tex.v = texture[2].y;
vertices[num_vertices + 2].color = color[2];
rotate(center, vertices[num_vertices + 2].pos);
vertices[num_vertices + 3].pos.x = x;
vertices[num_vertices + 3].pos.y = y+height;
vertices[num_vertices + 3].tex.u = texture[3].x;
vertices[num_vertices + 3].tex.v = texture[3].y;
vertices[num_vertices + 3].color = color[3];
rotate(center, vertices[num_vertices + 3].pos);
2007-05-22 15:03:32 +00:00
draw_quad();
}
void gfx_quads_draw_freeform(
float x0, float y0,
float x1, float y1,
float x2, float y2,
float x3, float y3)
{
dbg_assert(quads_drawing == 1, "called quads_draw_freeform without quads_begin");
vertices[num_vertices].pos.x = x0;
vertices[num_vertices].pos.y = y0;
vertices[num_vertices].tex.u = texture[0].x;
vertices[num_vertices].tex.v = texture[0].y;
vertices[num_vertices].color = color[0];
vertices[num_vertices + 1].pos.x = x1;
vertices[num_vertices + 1].pos.y = y1;
vertices[num_vertices + 1].tex.u = texture[1].x;
vertices[num_vertices + 1].tex.v = texture[1].y;
vertices[num_vertices + 1].color = color[1];
vertices[num_vertices + 2].pos.x = x3;
vertices[num_vertices + 2].pos.y = y3;
vertices[num_vertices + 2].tex.u = texture[2].x;
vertices[num_vertices + 2].tex.v = texture[2].y;
vertices[num_vertices + 2].color = color[2];
vertices[num_vertices + 3].pos.x = x2;
vertices[num_vertices + 3].pos.y = y2;
vertices[num_vertices + 3].tex.u = texture[3].x;
vertices[num_vertices + 3].tex.v = texture[3].y;
vertices[num_vertices + 3].color = color[3];
2007-05-22 15:03:32 +00:00
draw_quad();
}
void gfx_quads_text(float x, float y, float size, const char *text)
{
gfx_quads_begin();
2007-07-15 13:25:10 +00:00
float startx = x;
2007-05-22 15:03:32 +00:00
while(*text)
{
char c = *text;
text++;
2007-07-15 13:25:10 +00:00
if(c == '\n')
{
x = startx;
y += size;
}
else
{
gfx_quads_setsubset(
(c%16)/16.0f,
(c/16)/16.0f,
(c%16)/16.0f+1.0f/16.0f,
(c/16)/16.0f+1.0f/16.0f);
gfx_quads_drawTL(x,y,size,size);
x += size/2;
}
2007-05-22 15:03:32 +00:00
}
gfx_quads_end();
}
struct pretty_font
{
float m_CharStartTable[256];
float m_CharEndTable[256];
int font_texture;
};
pretty_font default_font =
{
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0.421875, 0.359375, 0.265625, 0.25, 0.1875, 0.25, 0.4375, 0.390625, 0.390625, 0.34375, 0.28125, 0.421875, 0.390625, 0.4375, 0.203125,
0.265625, 0.28125, 0.28125, 0.265625, 0.25, 0.28125, 0.28125, 0.265625, 0.28125, 0.265625, 0.4375, 0.421875, 0.3125, 0.28125, 0.3125, 0.3125,
0.25, 0.234375, 0.28125, 0.265625, 0.265625, 0.296875, 0.3125, 0.25, 0.25, 0.421875, 0.28125, 0.265625, 0.328125, 0.171875, 0.234375, 0.25,
0.28125, 0.234375, 0.265625, 0.265625, 0.28125, 0.265625, 0.234375, 0.09375, 0.234375, 0.234375, 0.265625, 0.390625, 0.203125, 0.390625, 0.296875, 0.28125,
0.375, 0.3125, 0.3125, 0.3125, 0.296875, 0.3125, 0.359375, 0.296875, 0.3125, 0.4375, 0.390625, 0.328125, 0.4375, 0.203125, 0.3125, 0.296875,
0.3125, 0.296875, 0.359375, 0.3125, 0.328125, 0.3125, 0.296875, 0.203125, 0.296875, 0.296875, 0.328125, 0.375, 0.421875, 0.375, 0.28125, 0.3125,
0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125,
0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125,
0, 0.421875, 0.3125, 0.265625, 0.25, 0.25, 0.421875, 0.265625, 0.375, 0.21875, 0.375, 0.328125, 0.3125, 0, 0.21875, 0.28125,
0.359375, 0.28125, 0.34375, 0.34375, 0.421875, 0.3125, 0.265625, 0.421875, 0.421875, 0.34375, 0.375, 0.328125, 0.125, 0.125, 0.125, 0.296875,
0.234375, 0.234375, 0.234375, 0.234375, 0.234375, 0.234375, 0.109375, 0.265625, 0.296875, 0.296875, 0.296875, 0.296875, 0.375, 0.421875, 0.359375, 0.390625,
0.21875, 0.234375, 0.25, 0.25, 0.25, 0.25, 0.25, 0.296875, 0.21875, 0.265625, 0.265625, 0.265625, 0.265625, 0.234375, 0.28125, 0.3125,
0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.1875, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.375, 0.421875, 0.359375, 0.390625,
0.3125, 0.3125, 0.296875, 0.296875, 0.296875, 0.296875, 0.296875, 0.28125, 0.28125, 0.3125, 0.3125, 0.3125, 0.3125, 0.296875, 0.3125, 0.296875,
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0.2, 0.5625, 0.625, 0.71875, 0.734375, 0.796875, 0.765625, 0.546875, 0.59375, 0.59375, 0.65625, 0.703125, 0.546875, 0.59375, 0.5625, 0.6875,
0.71875, 0.609375, 0.703125, 0.703125, 0.71875, 0.703125, 0.703125, 0.6875, 0.703125, 0.703125, 0.5625, 0.546875, 0.671875, 0.703125, 0.671875, 0.671875,
0.734375, 0.75, 0.734375, 0.734375, 0.734375, 0.6875, 0.6875, 0.734375, 0.71875, 0.5625, 0.65625, 0.765625, 0.703125, 0.8125, 0.75, 0.734375,
0.734375, 0.765625, 0.71875, 0.71875, 0.703125, 0.71875, 0.75, 0.890625, 0.75, 0.75, 0.71875, 0.59375, 0.6875, 0.59375, 0.6875, 0.703125,
0.5625, 0.671875, 0.6875, 0.671875, 0.671875, 0.671875, 0.625, 0.671875, 0.671875, 0.5625, 0.546875, 0.703125, 0.5625, 0.78125, 0.671875, 0.671875,
0.6875, 0.671875, 0.65625, 0.671875, 0.65625, 0.671875, 0.6875, 0.78125, 0.6875, 0.671875, 0.65625, 0.609375, 0.546875, 0.609375, 0.703125, 0.671875,
0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875,
0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875,
0, 0.5625, 0.671875, 0.734375, 0.734375, 0.734375, 0.546875, 0.71875, 0.609375, 0.765625, 0.609375, 0.65625, 0.671875, 0, 0.765625, 0.703125,
0.625, 0.703125, 0.640625, 0.640625, 0.609375, 0.671875, 0.703125, 0.546875, 0.5625, 0.578125, 0.609375, 0.65625, 0.859375, 0.859375, 0.859375, 0.671875,
0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.84375, 0.734375, 0.6875, 0.6875, 0.6875, 0.6875, 0.5625, 0.609375, 0.640625, 0.59375,
0.734375, 0.75, 0.734375, 0.734375, 0.734375, 0.734375, 0.734375, 0.6875, 0.765625, 0.71875, 0.71875, 0.71875, 0.71875, 0.75, 0.734375, 0.6875,
0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.796875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.5625, 0.609375, 0.625, 0.59375,
0.6875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.703125, 0.703125, 0.671875, 0.671875, 0.671875, 0.671875, 0.671875, 0.6875, 0.671875,
},
0
};
2007-06-10 17:25:08 +00:00
double extra_kerning[256*256] = {0};
2007-05-22 15:03:32 +00:00
pretty_font *current_font = &default_font;
void gfx_pretty_text(float x, float y, float size, const char *text)
{
const float spacing = 0.05f;
2007-07-14 13:09:42 +00:00
gfx_texture_set(current_font->font_texture);
2007-05-22 15:03:32 +00:00
gfx_quads_begin();
2007-07-15 13:25:10 +00:00
float startx = x;
2007-05-22 15:03:32 +00:00
while (*text)
{
const int c = *text;
2007-05-22 15:03:32 +00:00
2007-07-15 13:25:10 +00:00
if(c == '\n')
{
x = startx;
y += size;
}
else
{
const float width = current_font->m_CharEndTable[c] - current_font->m_CharStartTable[c];
2007-05-22 15:03:32 +00:00
2007-07-15 13:25:10 +00:00
x -= size * current_font->m_CharStartTable[c];
gfx_quads_setsubset(
(c%16)/16.0f, // startx
(c/16)/16.0f, // starty
(c%16)/16.0f+1.0f/16.0f, // endx
(c/16)/16.0f+1.0f/16.0f); // endy
2007-05-22 15:03:32 +00:00
2007-07-15 13:25:10 +00:00
gfx_quads_drawTL(x, y, size, size);
2007-06-10 17:25:08 +00:00
2007-07-15 13:25:10 +00:00
double x_nudge = 0;
if (text[1])
x_nudge = extra_kerning[text[0] + text[1] * 256];
x += (width + current_font->m_CharStartTable[c] + spacing + x_nudge) * size;
}
2007-06-10 17:25:08 +00:00
text++;
2007-05-22 15:03:32 +00:00
}
gfx_quads_end();
}
2007-07-28 17:44:12 +00:00
float gfx_pretty_text_width(float size, const char *text, int length)
2007-05-22 15:03:32 +00:00
{
const float spacing = 0.05f;
2007-06-10 17:25:08 +00:00
float w = 0.0f;
2007-05-22 15:03:32 +00:00
2007-07-28 17:44:12 +00:00
const char *stop;
if (length == -1)
stop = text + strlen(text);
else
stop = text + length;
while (text < stop)
2007-05-22 15:03:32 +00:00
{
2007-06-10 17:25:08 +00:00
const int c = *text;
const float width = current_font->m_CharEndTable[c] - current_font->m_CharStartTable[c];
double x_nudge = 0;
if (text[1])
x_nudge = extra_kerning[text[0] + text[1] * 256];
w += (width + spacing + x_nudge) * size;
text++;
2007-05-22 15:03:32 +00:00
}
2007-06-10 17:25:08 +00:00
return w;
2007-05-22 15:03:32 +00:00
}