249 lines
7.3 KiB
C++
249 lines
7.3 KiB
C++
|
/*
|
||
|
* Overreact - Mr. 4th Dimention
|
||
|
* Allen Webster
|
||
|
* 03.21.2015 (mm.dd.yyyy)
|
||
|
*
|
||
|
* Graphics Layer.
|
||
|
*/
|
||
|
|
||
|
// TOP
|
||
|
|
||
|
internal Blit_Rect
|
||
|
rect_from_target(Game_Render_Target *target){
|
||
|
Blit_Rect result;
|
||
|
result.x_start = 0;
|
||
|
result.y_start = 0;
|
||
|
result.x_end = target->width;
|
||
|
result.y_end = target->height;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
bitmap_open_file(char *filename, Bitmap_File *bmp_file){
|
||
|
File file = system_load_file(filename);
|
||
|
if (file.data && file.size > sizeof(Bitmap_Header)){
|
||
|
*bmp_file = {};
|
||
|
bmp_file->file = file;
|
||
|
bmp_file->header = *(Bitmap_Header*)file.data;
|
||
|
bmp_file->byte_pitch =
|
||
|
bmp_file->header.image_size / bmp_file->header.h;
|
||
|
|
||
|
Assert(bmp_file->header.type == 0x4D42);
|
||
|
Assert(bmp_file->header.compression == 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal i32
|
||
|
bitmap_data_requirement(Bitmap_File *bmp_file){
|
||
|
i32 w, h;
|
||
|
w = round_up_POT(bmp_file->header.w);
|
||
|
h = round_up_POT(bmp_file->header.h);
|
||
|
|
||
|
return 4*(w * h);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
bitmap_fill_image(Bitmap_File *bmp_file, Image *image){
|
||
|
image->width = round_up_POT(bmp_file->header.w);
|
||
|
image->height = round_up_POT(bmp_file->header.h);
|
||
|
image->pitch = 4*image->width;
|
||
|
|
||
|
i32 true_width, true_height;
|
||
|
true_width = bmp_file->header.w;
|
||
|
true_height = bmp_file->header.h;
|
||
|
|
||
|
image->img_width = true_width;
|
||
|
image->img_height = true_height;
|
||
|
|
||
|
i32 byte_per_pixel = bmp_file->header.bits_per_pixel >> 3;
|
||
|
u8 *pixel_line = (u8*)bmp_file->file.data + bmp_file->header.offset;
|
||
|
u8 *dest_line = (u8*)image->data;
|
||
|
if (byte_per_pixel == 3){
|
||
|
for (i32 y = 0; y < true_height; ++y){
|
||
|
u8 *pixel = pixel_line;
|
||
|
u32 *dest = (u32*)dest_line;
|
||
|
for (i32 x = 0; x < true_width; ++x){
|
||
|
#if 0
|
||
|
*dest = (0xFF << 24) | (pixel[2] << 16) | (pixel[1] << 8) | (pixel[0]);
|
||
|
#else
|
||
|
*dest = (0xFF << 24) | (pixel[0] << 16) | (pixel[1] << 8) | (pixel[2]);
|
||
|
#endif
|
||
|
pixel += 3;
|
||
|
++dest;
|
||
|
}
|
||
|
pixel_line += bmp_file->byte_pitch;
|
||
|
dest_line += image->pitch;
|
||
|
}
|
||
|
}
|
||
|
else{
|
||
|
for (i32 y = 0; y < true_height; ++y){
|
||
|
u32 *pixel = (u32*)pixel_line;
|
||
|
u32 *dest = (u32*)dest_line;
|
||
|
for (i32 x = 0; x < true_width; ++x){
|
||
|
#if 0
|
||
|
*dest =
|
||
|
(*pixel & 0xFF00FF00) |
|
||
|
((*pixel & 0x00FF0000) >> 16) |
|
||
|
((*pixel & 0x000000FF) << 16);
|
||
|
#else
|
||
|
*dest = *pixel;
|
||
|
#endif
|
||
|
++pixel;
|
||
|
++dest;
|
||
|
}
|
||
|
pixel_line += bmp_file->byte_pitch;
|
||
|
dest_line += image->pitch;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
bitmap_free_file(Bitmap_File *bmp_file){
|
||
|
system_free_file(bmp_file->file);
|
||
|
}
|
||
|
|
||
|
// TODO(allen): eliminate this?
|
||
|
internal i32
|
||
|
font_init(){
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
inline internal i32
|
||
|
font_predict_size(i32 pt_size){
|
||
|
return pt_size*pt_size*128;
|
||
|
}
|
||
|
|
||
|
// TODO(allen): switch to 0 = FAIL, 1 = SUCCESS
|
||
|
internal i32
|
||
|
font_load(char *filename, Font *font_out, i32 pt_size,
|
||
|
void *font_block, i32 font_block_size){
|
||
|
|
||
|
i32 result = 0;
|
||
|
|
||
|
File file;
|
||
|
file = system_load_file(filename);
|
||
|
|
||
|
if (!file.data){
|
||
|
result = 1;
|
||
|
}
|
||
|
|
||
|
else{
|
||
|
stbtt_fontinfo font;
|
||
|
if (!stbtt_InitFont(&font, (u8*)file.data, 0)){
|
||
|
result = 1;
|
||
|
}
|
||
|
else{
|
||
|
i32 ascent, descent, line_gap;
|
||
|
real32 scale;
|
||
|
|
||
|
stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap);
|
||
|
scale = stbtt_ScaleForPixelHeight(&font, (real32)pt_size);
|
||
|
|
||
|
real32 scaled_ascent, scaled_descent, scaled_line_gap;
|
||
|
|
||
|
scaled_ascent = scale*ascent;
|
||
|
scaled_descent = scale*descent;
|
||
|
scaled_line_gap = scale*line_gap;
|
||
|
|
||
|
font_out->height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap);
|
||
|
font_out->ascent = (i32)(scaled_ascent);
|
||
|
font_out->descent = (i32)(scaled_descent);
|
||
|
font_out->line_skip = (i32)(scaled_line_gap);
|
||
|
|
||
|
u8 *memory_cursor = (u8*)font_block;
|
||
|
Assert(pt_size*pt_size*128 <= font_block_size);
|
||
|
|
||
|
i32 tex_width, tex_height;
|
||
|
tex_width = pt_size*128;
|
||
|
tex_height = pt_size*2;
|
||
|
|
||
|
font_out->tex_width = tex_width;
|
||
|
font_out->tex_height = tex_height;
|
||
|
|
||
|
if (stbtt_BakeFontBitmap((u8*)file.data, 0, (real32)pt_size,
|
||
|
memory_cursor, tex_width, tex_height, 0, 128, font_out->chardata) <= 0){
|
||
|
result = 0;
|
||
|
}
|
||
|
|
||
|
else{
|
||
|
GLuint font_tex;
|
||
|
glGenTextures(1, &font_tex);
|
||
|
glBindTexture(GL_TEXTURE_2D, font_tex);
|
||
|
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||
|
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, memory_cursor);
|
||
|
|
||
|
font_out->tex = font_tex;
|
||
|
}
|
||
|
|
||
|
i32 max_advance = 0;
|
||
|
|
||
|
for (u16 code_point = 0; code_point < 128; ++code_point){
|
||
|
if (stbtt_FindGlyphIndex(&font, code_point) != 0){
|
||
|
font_out->glyphs[code_point].exists = 1;
|
||
|
font_out->glyphs[code_point].advance = font_out->chardata[code_point].xadvance;
|
||
|
i32 advance = Ceil(font_out->chardata[code_point].xadvance);
|
||
|
if (max_advance < advance){
|
||
|
max_advance = advance;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
font_out->advance = max_advance;
|
||
|
|
||
|
}
|
||
|
system_free_file(file);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
font_draw_glyph_clipped(Game_Render_Target *target,
|
||
|
Font *font, u16 character,
|
||
|
real32 x, real32 y, u32 color,
|
||
|
Blit_Rect clip_box){
|
||
|
|
||
|
if (clip_box.x_start < clip_box.x_end && clip_box.y_start < clip_box.y_end){
|
||
|
real32 x_shift, y_shift;
|
||
|
x_shift = font->chardata[character].xoff;
|
||
|
y_shift = (real32)font->ascent;// + font->chardata[character].yoff;
|
||
|
|
||
|
x += x_shift;
|
||
|
y += y_shift;
|
||
|
|
||
|
glScissor(clip_box.x_start,
|
||
|
target->height - clip_box.y_end,
|
||
|
clip_box.x_end - clip_box.x_start,
|
||
|
clip_box.y_end - clip_box.y_start);
|
||
|
|
||
|
stbtt_aligned_quad q;
|
||
|
stbtt_GetBakedQuadUnrounded(font->chardata, font->tex_width, font->tex_height, character, &x, &y, &q, 1);
|
||
|
|
||
|
Vec3 c = unpack_color3(color);
|
||
|
glColor3f(c.r, c.g, c.b);
|
||
|
glBindTexture(GL_TEXTURE_2D, font->tex);
|
||
|
glBegin(GL_QUADS);
|
||
|
{
|
||
|
glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1);
|
||
|
glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1);
|
||
|
glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0);
|
||
|
glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
glScissor(0, 0, target->width, target->height);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
font_draw_glyph(Game_Render_Target *target,
|
||
|
Font *font, u16 character,
|
||
|
real32 x, real32 y, u32 color){
|
||
|
Blit_Rect screen = rect_from_target(target);
|
||
|
font_draw_glyph_clipped(target, font, character, x, y, color, screen);
|
||
|
}
|