cleaning up opengl code
This commit is contained in:
parent
d04dd8879b
commit
c0bf8966eb
7
4ed.cpp
7
4ed.cpp
|
@ -2313,7 +2313,12 @@ App_Step_Sig(app_step){
|
||||||
begin_render_section(target, system);
|
begin_render_section(target, system);
|
||||||
|
|
||||||
target->clip_top = -1;
|
target->clip_top = -1;
|
||||||
draw_push_clip(target, rect_from_target(target));
|
i32_Rect target_rect = {0};
|
||||||
|
target_rect.x0 = 0;
|
||||||
|
target_rect.y0 = 0;
|
||||||
|
target_rect.x1 = target->width;
|
||||||
|
target_rect.y1 = target->height;
|
||||||
|
draw_push_clip(target, target_rect);
|
||||||
|
|
||||||
Command_Data *command = cmd;
|
Command_Data *command = cmd;
|
||||||
USE_PANEL(active_panel);
|
USE_PANEL(active_panel);
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "4ed_math.h"
|
#include "4ed_math.h"
|
||||||
#include "4ed_system.h"
|
#include "4ed_system.h"
|
||||||
|
|
||||||
// TODO(allen): set in compilation line
|
|
||||||
#define PREFERRED_ALIGNMENT 8
|
#define PREFERRED_ALIGNMENT 8
|
||||||
#define USE_DEBUG_MEMORY
|
#define USE_DEBUG_MEMORY
|
||||||
|
|
||||||
|
@ -33,7 +32,8 @@
|
||||||
# include "4ed_debug_mem.h"
|
# include "4ed_debug_mem.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "4ed_rendering.h"
|
#include "4ed_render_format.h"
|
||||||
|
#include "4ed_render_target.h"
|
||||||
#include "4ed.h"
|
#include "4ed.h"
|
||||||
#include "4ed_buffer_model.h"
|
#include "4ed_buffer_model.h"
|
||||||
|
|
||||||
|
@ -43,7 +43,9 @@
|
||||||
#include "4ed_doubly_linked_list.cpp"
|
#include "4ed_doubly_linked_list.cpp"
|
||||||
|
|
||||||
#include "4ed_translation.cpp"
|
#include "4ed_translation.cpp"
|
||||||
#include "4ed_rendering_helper.cpp"
|
|
||||||
|
#include "4ed_render_target.cpp"
|
||||||
|
#include "4ed_render_fill.cpp"
|
||||||
|
|
||||||
#include "4ed_style.h"
|
#include "4ed_style.h"
|
||||||
#include "4ed_style.cpp"
|
#include "4ed_style.cpp"
|
||||||
|
|
|
@ -5879,7 +5879,7 @@ draw_file_loaded(System_Functions *system, View *view, Models *models, i32_Rect
|
||||||
draw_rectangle_outline(target, char_rect, mark_color);
|
draw_rectangle_outline(target, char_rect, mark_color);
|
||||||
}
|
}
|
||||||
if (item->codepoint != 0){
|
if (item->codepoint != 0){
|
||||||
font_draw_glyph(target, font_id, item->codepoint, item->x0, item->y0, char_color);
|
draw_font_glyph(target, font_id, item->codepoint, item->x0, item->y0, char_color);
|
||||||
}
|
}
|
||||||
prev_ind = ind;
|
prev_ind = ind;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Mr. 4th Dimention - Allen Webster
|
* Mr. 4th Dimention - Allen Webster
|
||||||
*
|
*
|
||||||
* 12.17.2014
|
* 10.11.2017
|
||||||
*
|
*
|
||||||
* Rendering layer for project codename "4ed"
|
* Render buffer fill helpers.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,19 +11,19 @@
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
draw_push_clip(Render_Target *target, i32_Rect clip_box){
|
draw_push_clip(Render_Target *target, i32_Rect clip_box){
|
||||||
target->push_clip(target, clip_box);
|
render_push_clip(target, clip_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline i32_Rect
|
inline i32_Rect
|
||||||
draw_pop_clip(Render_Target *target){
|
draw_pop_clip(Render_Target *target){
|
||||||
i32_Rect result = target->pop_clip(target);
|
i32_Rect result = render_pop_clip(target);
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
draw_change_clip(Render_Target *target, i32_Rect clip_box){
|
draw_change_clip(Render_Target *target, i32_Rect clip_box){
|
||||||
target->pop_clip(target);
|
render_pop_clip(target);
|
||||||
target->push_clip(target, clip_box);
|
render_push_clip(target, clip_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -50,7 +50,7 @@ draw_rectangle(Render_Target *target, i32_Rect rect, u32 color){
|
||||||
piece.header.type = piece_type_rectangle;
|
piece.header.type = piece_type_rectangle;
|
||||||
piece.rectangle.rect = f32R(rect);
|
piece.rectangle.rect = f32R(rect);
|
||||||
piece.rectangle.color = color;
|
piece.rectangle.color = color;
|
||||||
target->push_piece(target, piece);
|
render_push_piece(target, piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -59,24 +59,7 @@ draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){
|
||||||
piece.header.type = piece_type_rectangle;
|
piece.header.type = piece_type_rectangle;
|
||||||
piece.rectangle.rect = rect;
|
piece.rectangle.rect = rect;
|
||||||
piece.rectangle.color = color;
|
piece.rectangle.color = color;
|
||||||
target->push_piece(target, piece);
|
render_push_piece(target, piece);
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
draw_gradient_2corner_clipped(Render_Target *target, f32_Rect rect,
|
|
||||||
Vec4 left_color, Vec4 right_color){
|
|
||||||
Render_Piece_Combined piece;
|
|
||||||
piece.header.type = piece_type_gradient;
|
|
||||||
piece.gradient.rect = rect;
|
|
||||||
piece.gradient.left_color = pack_color4(left_color);
|
|
||||||
piece.gradient.right_color = pack_color4(right_color);
|
|
||||||
target->push_piece(target, piece);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
draw_gradient_2corner_clipped(Render_Target *target, f32 l, f32 t, f32 r, f32 b,
|
|
||||||
Vec4 color_left, Vec4 color_right){
|
|
||||||
draw_gradient_2corner_clipped(target, f32R(l,t,r,b), color_left, color_right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -85,7 +68,7 @@ draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){
|
||||||
piece.header.type = piece_type_outline;
|
piece.header.type = piece_type_outline;
|
||||||
piece.rectangle.rect = rect;
|
piece.rectangle.rect = rect;
|
||||||
piece.rectangle.color = color;
|
piece.rectangle.color = color;
|
||||||
target->push_piece(target, piece);
|
render_push_piece(target, piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -107,13 +90,8 @@ draw_margin(Render_Target *target, i32_Rect outer, i32 width, u32 color){
|
||||||
draw_margin(target, outer, inner, color);
|
draw_margin(target, outer, inner, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline internal i32
|
|
||||||
font_predict_size(i32 pt_size){
|
|
||||||
return pt_size*pt_size*128;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
font_draw_glyph(Render_Target *target, Font_ID font_id, i32 type, u32 codepoint, f32 x, f32 y, u32 color){
|
draw_font_glyph(Render_Target *target, Font_ID font_id, i32 type, u32 codepoint, f32 x, f32 y, u32 color){
|
||||||
Render_Piece_Combined piece;
|
Render_Piece_Combined piece;
|
||||||
piece.header.type = type;
|
piece.header.type = type;
|
||||||
piece.glyph.pos.x = x;
|
piece.glyph.pos.x = x;
|
||||||
|
@ -121,12 +99,12 @@ font_draw_glyph(Render_Target *target, Font_ID font_id, i32 type, u32 codepoint,
|
||||||
piece.glyph.color = color;
|
piece.glyph.color = color;
|
||||||
piece.glyph.font_id = font_id;
|
piece.glyph.font_id = font_id;
|
||||||
piece.glyph.codepoint = codepoint;
|
piece.glyph.codepoint = codepoint;
|
||||||
target->push_piece(target, piece);
|
render_push_piece(target, piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
font_draw_glyph(Render_Target *target, Font_ID font_id, u32 codepoint, f32 x, f32 y, u32 color){
|
draw_font_glyph(Render_Target *target, Font_ID font_id, u32 codepoint, f32 x, f32 y, u32 color){
|
||||||
font_draw_glyph(target, font_id, piece_type_glyph, codepoint, x, y, color);
|
draw_font_glyph(target, font_id, piece_type_glyph, codepoint, x, y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
internal f32
|
||||||
|
@ -156,7 +134,7 @@ draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_i
|
||||||
if (behavior.do_codepoint_advance){
|
if (behavior.do_codepoint_advance){
|
||||||
u32 codepoint = step.value;
|
u32 codepoint = step.value;
|
||||||
if (color != 0){
|
if (color != 0){
|
||||||
font_draw_glyph(target, font_id, type, codepoint, x, y, color);
|
draw_font_glyph(target, font_id, type, codepoint, x, y, color);
|
||||||
}
|
}
|
||||||
x += font_get_glyph_advance(system, font, codepoint);
|
x += font_get_glyph_advance(system, font, codepoint);
|
||||||
}
|
}
|
||||||
|
@ -169,7 +147,7 @@ draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_i
|
||||||
|
|
||||||
f32 xx = x;
|
f32 xx = x;
|
||||||
for (u32 j = 0; j < 3; ++j){
|
for (u32 j = 0; j < 3; ++j){
|
||||||
font_draw_glyph(target, font_id, type, cs[j], xx, y, color);
|
draw_font_glyph(target, font_id, type, cs[j], xx, y, color);
|
||||||
xx += sub_advances[j];
|
xx += sub_advances[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,54 +155,6 @@ draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
for (;str < str_end;){
|
|
||||||
u8 *byte = str;
|
|
||||||
u32 codepoint = utf8_to_u32(&str, str_end);
|
|
||||||
|
|
||||||
b32 do_codepoint = false;
|
|
||||||
b32 do_numbers = false;
|
|
||||||
if (codepoint){
|
|
||||||
if (codepoint >= ' ' && codepoint <= 0xFF && codepoint != 127){
|
|
||||||
do_codepoint = true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
do_numbers = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
do_numbers = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (do_codepoint){
|
|
||||||
if (color != 0){
|
|
||||||
font_draw_glyph(target, font_id, type, (u8)codepoint, x, y, color);
|
|
||||||
}
|
|
||||||
x += font_get_glyph_advance(system, font, codepoint);
|
|
||||||
}
|
|
||||||
else if (do_numbers){
|
|
||||||
for (;byte < str; ++byte){
|
|
||||||
u8_4tech n = *byte;
|
|
||||||
if (color != 0){
|
|
||||||
u8 cs[3];
|
|
||||||
cs[0] = '\\';
|
|
||||||
byte_to_ascii(n, cs+1);
|
|
||||||
|
|
||||||
f32 *advances = font_get_byte_sub_advances(font);
|
|
||||||
|
|
||||||
f32 xx = x;
|
|
||||||
for (u32 j = 0; j < 3; ++j){
|
|
||||||
font_draw_glyph(target, font_id, type, cs[j], xx, y, color);
|
|
||||||
xx += advances[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x += byte_advance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(x);
|
return(x);
|
||||||
|
@ -243,19 +173,6 @@ draw_string(System_Functions *system, Render_Target *target, Font_ID font_id, ch
|
||||||
return(w);
|
return(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
|
||||||
draw_string_mono(System_Functions *system, Render_Target *target, Font_ID font_id, String str, i32 x, i32 y, f32 advance, u32 color){
|
|
||||||
f32 w = draw_string_base(system, target, font_id, piece_type_mono_glyph, str, x, y, color);
|
|
||||||
return(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal f32
|
|
||||||
draw_string_mono(System_Functions *system, Render_Target *target, Font_ID font_id, char *str, i32 x, i32 y, f32 advance, u32 color){
|
|
||||||
String string = make_string_slowly(str);
|
|
||||||
f32 w = draw_string_base(system, target, font_id, piece_type_mono_glyph, string, x, y, color);
|
|
||||||
return(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal f32
|
internal f32
|
||||||
font_string_width(System_Functions *system, Render_Target *target, Font_ID font_id, String str){
|
font_string_width(System_Functions *system, Render_Target *target, Font_ID font_id, String str){
|
||||||
f32 w = draw_string_base(system, target, font_id, piece_type_glyph, str, 0, 0, 0);
|
f32 w = draw_string_base(system, target, font_id, piece_type_glyph, str, 0, 0, 0);
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Mr. 4th Dimention - Allen Webster
|
||||||
|
*
|
||||||
|
* 10.11.2017
|
||||||
|
*
|
||||||
|
* Format for 4coder render commands.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
|
||||||
|
enum Render_Piece_Type{
|
||||||
|
piece_type_rectangle,
|
||||||
|
piece_type_outline,
|
||||||
|
piece_type_glyph,
|
||||||
|
piece_type_change_clip
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Header{
|
||||||
|
i32 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Rectangle{
|
||||||
|
f32_Rect rect;
|
||||||
|
u32 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Gradient{
|
||||||
|
f32_Rect rect;
|
||||||
|
u32 left_color;
|
||||||
|
u32 right_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Glyph{
|
||||||
|
Vec2 pos;
|
||||||
|
u32 color;
|
||||||
|
Font_ID font_id;
|
||||||
|
u32 codepoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Glyph_Advance{
|
||||||
|
Vec2 pos;
|
||||||
|
u32 color;
|
||||||
|
f32 advance;
|
||||||
|
Font_ID font_id;
|
||||||
|
u32 codepoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Change_Clip{
|
||||||
|
i32_Rect box;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Render_Piece_Combined{
|
||||||
|
Render_Piece_Header header;
|
||||||
|
union{
|
||||||
|
Render_Piece_Rectangle rectangle;
|
||||||
|
Render_Piece_Gradient gradient;
|
||||||
|
Render_Piece_Glyph glyph;
|
||||||
|
Render_Piece_Glyph_Advance glyph_advance;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// BOTTOM
|
||||||
|
|
|
@ -0,0 +1,419 @@
|
||||||
|
/*
|
||||||
|
* Mr. 4th Dimention - Allen Webster
|
||||||
|
*
|
||||||
|
* 10.11.2017
|
||||||
|
*
|
||||||
|
* OpenGL render implementation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
|
||||||
|
#define ExtractStruct(s) ((s*)cursor); cursor += sizeof(s)
|
||||||
|
|
||||||
|
inline void
|
||||||
|
private_draw_set_clip(Render_Target *t, i32_Rect clip_box){
|
||||||
|
glScissor(clip_box.x0, t->height - clip_box.y1, clip_box.x1 - clip_box.x0, clip_box.y1 - clip_box.y0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
private_draw_bind_texture(Render_Target *t, i32 texid){
|
||||||
|
if (t->bound_texture != texid){
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texid);
|
||||||
|
t->bound_texture = texid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
private_draw_set_color(Render_Target *t, u32 color){
|
||||||
|
if (t->color != color){
|
||||||
|
t->color = color;
|
||||||
|
Vec4 c = unpack_color4(color);
|
||||||
|
glColor4f(c.r, c.g, c.b, c.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
private_draw_rectangle(Render_Target *t, f32_Rect rect, u32 color){
|
||||||
|
private_draw_set_color(t, color);
|
||||||
|
private_draw_bind_texture(t, 0);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
{
|
||||||
|
glVertex2f(rect.x0, rect.y0);
|
||||||
|
glVertex2f(rect.x0, rect.y1);
|
||||||
|
glVertex2f(rect.x1, rect.y1);
|
||||||
|
glVertex2f(rect.x1, rect.y0);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
private_draw_rectangle_outline(Render_Target *t, f32_Rect rect, u32 color){
|
||||||
|
f32_Rect r = get_inner_rect(rect, .5f);
|
||||||
|
private_draw_set_color(t, color);
|
||||||
|
private_draw_bind_texture(t, 0);
|
||||||
|
glBegin(GL_LINE_STRIP);
|
||||||
|
{
|
||||||
|
glVertex2f(r.x0, r.y0);
|
||||||
|
glVertex2f(r.x1, r.y0);
|
||||||
|
glVertex2f(r.x1, r.y1);
|
||||||
|
glVertex2f(r.x0, r.y1);
|
||||||
|
glVertex2f(r.x0, r.y0);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Render_Quad{
|
||||||
|
f32 x0, y0, x1, y1;
|
||||||
|
f32 s0, t0, s1, t1;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Render_Quad
|
||||||
|
get_render_quad(Glyph_Bounds *b, i32 pw, i32 ph, float xpos, float ypos){
|
||||||
|
Render_Quad q;
|
||||||
|
|
||||||
|
float ipw = 1.0f / pw, iph = 1.0f / ph;
|
||||||
|
|
||||||
|
q.x0 = xpos + b->xoff;
|
||||||
|
q.y0 = ypos + b->yoff;
|
||||||
|
q.x1 = xpos + b->xoff2;
|
||||||
|
q.y1 = ypos + b->yoff2;
|
||||||
|
|
||||||
|
q.s0 = b->x0 * ipw;
|
||||||
|
q.t0 = b->y0 * iph;
|
||||||
|
q.s1 = b->x1 * ipw;
|
||||||
|
q.t1 = b->y1 * iph;
|
||||||
|
|
||||||
|
return(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
private_draw_glyph(System_Functions *system, Render_Target *t, Render_Font *font, u32 codepoint, f32 x, f32 y, u32 color){
|
||||||
|
Glyph_Data glyph = font_get_glyph(system, font, codepoint);
|
||||||
|
if (glyph.tex != 0){
|
||||||
|
Render_Quad q = get_render_quad(&glyph.bounds, glyph.tex_width, glyph.tex_height, x, y);
|
||||||
|
|
||||||
|
private_draw_set_color(t, color);
|
||||||
|
private_draw_bind_texture(t, glyph.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
interpret_render_buffer(System_Functions *system, Render_Target *t){
|
||||||
|
char *cursor = t->push_buffer;
|
||||||
|
char *cursor_end = cursor + t->size;
|
||||||
|
|
||||||
|
for (; cursor < cursor_end;){
|
||||||
|
Render_Piece_Header *header = ExtractStruct(Render_Piece_Header);
|
||||||
|
|
||||||
|
i32 type = header->type;
|
||||||
|
switch (type){
|
||||||
|
case piece_type_rectangle:
|
||||||
|
{
|
||||||
|
Render_Piece_Rectangle *rectangle = ExtractStruct(Render_Piece_Rectangle);
|
||||||
|
private_draw_rectangle(t, rectangle->rect, rectangle->color);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case piece_type_outline:
|
||||||
|
{
|
||||||
|
Render_Piece_Rectangle *rectangle = ExtractStruct(Render_Piece_Rectangle);
|
||||||
|
private_draw_rectangle_outline(t, rectangle->rect, rectangle->color);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case piece_type_glyph:
|
||||||
|
{
|
||||||
|
Render_Piece_Glyph *glyph = ExtractStruct(Render_Piece_Glyph);
|
||||||
|
|
||||||
|
Render_Font *font = system->font.get_render_data_by_id(glyph->font_id);
|
||||||
|
Assert(font != 0);
|
||||||
|
private_draw_glyph(system, t, font, glyph->codepoint, glyph->pos.x, glyph->pos.y, glyph->color);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case piece_type_change_clip:
|
||||||
|
{
|
||||||
|
Render_Piece_Change_Clip *clip = ExtractStruct(Render_Piece_Change_Clip);
|
||||||
|
private_draw_set_clip(t, clip->box);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ExtractStruct
|
||||||
|
|
||||||
|
// NOTE(allen): Thanks to insofaras. This is copy-pasted from some work he originally did to get free type working on Linux.
|
||||||
|
|
||||||
|
#undef internal
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#define internal static
|
||||||
|
|
||||||
|
internal void
|
||||||
|
font_load_page_inner(Partition *part, Render_Font *font, FT_Library ft, FT_Face face, b32 use_hinting, Glyph_Page *page, u32 page_number, i32 tab_width){
|
||||||
|
Temp_Memory temp = begin_temp_memory(part);
|
||||||
|
Assert(page != 0);
|
||||||
|
page->page_number = page_number;
|
||||||
|
|
||||||
|
// prepare to read glyphs into a temporary texture buffer
|
||||||
|
i32 max_glyph_w = face->size->metrics.x_ppem;
|
||||||
|
|
||||||
|
i32 max_glyph_h = font_get_height(font);
|
||||||
|
i32 tex_width = 64;
|
||||||
|
i32 tex_height = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
tex_width *= 2;
|
||||||
|
float glyphs_per_row = ceilf(tex_width / (float) max_glyph_w);
|
||||||
|
float rows = ceilf(ITEM_PER_FONT_PAGE / glyphs_per_row);
|
||||||
|
tex_height = ceil32(rows * (max_glyph_h + 2));
|
||||||
|
} while(tex_height > tex_width);
|
||||||
|
|
||||||
|
tex_height = round_up_pot_u32(tex_height);
|
||||||
|
|
||||||
|
i32 pen_x = 0;
|
||||||
|
i32 pen_y = 0;
|
||||||
|
|
||||||
|
u32* pixels = push_array(part, u32, tex_width * tex_height);
|
||||||
|
memset(pixels, 0, tex_width * tex_height * sizeof(u32));
|
||||||
|
|
||||||
|
u32 ft_flags = FT_LOAD_RENDER;
|
||||||
|
if (use_hinting){
|
||||||
|
// NOTE(inso): FT_LOAD_TARGET_LIGHT does hinting only vertically, which looks nicer imo
|
||||||
|
// maybe it could be exposed as an option for hinting, instead of just on/off.
|
||||||
|
ft_flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ft_flags |= (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill the texture
|
||||||
|
u32 base_codepoint = (page_number << 8);
|
||||||
|
Glyph_Bounds *glyphs = &page->glyphs[0];
|
||||||
|
Glyph_Bounds *glyph_ptr = glyphs;
|
||||||
|
|
||||||
|
f32 *advances = &page->advance[0];
|
||||||
|
f32 *advance_ptr = advances;
|
||||||
|
for(u32 i = 0; i < ITEM_PER_FONT_PAGE; ++i, ++glyph_ptr, ++advance_ptr){
|
||||||
|
u32 codepoint = i + base_codepoint;
|
||||||
|
|
||||||
|
if(FT_Load_Char(face, codepoint, ft_flags) == 0){
|
||||||
|
i32 w = face->glyph->bitmap.width;
|
||||||
|
i32 h = face->glyph->bitmap.rows;
|
||||||
|
|
||||||
|
i32 ascent = font_get_ascent(font);
|
||||||
|
|
||||||
|
// move to next line if necessary
|
||||||
|
if(pen_x + w >= tex_width){
|
||||||
|
pen_x = 0;
|
||||||
|
pen_y += (max_glyph_h + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set all this stuff the renderer needs
|
||||||
|
glyph_ptr->x0 = (f32)(pen_x);
|
||||||
|
glyph_ptr->y0 = (f32)(pen_y);
|
||||||
|
glyph_ptr->x1 = (f32)(pen_x + w);
|
||||||
|
glyph_ptr->y1 = (f32)(pen_y + h + 1);
|
||||||
|
|
||||||
|
glyph_ptr->xoff = (f32)(face->glyph->bitmap_left);
|
||||||
|
glyph_ptr->yoff = (f32)(ascent - face->glyph->bitmap_top);
|
||||||
|
glyph_ptr->xoff2 = glyph_ptr->xoff + w;
|
||||||
|
glyph_ptr->yoff2 = glyph_ptr->yoff + h + 1;
|
||||||
|
|
||||||
|
// TODO(allen): maybe advance data should be integers?
|
||||||
|
*advance_ptr = (f32)ceil32(face->glyph->advance.x / 64.0f);
|
||||||
|
|
||||||
|
// write to texture atlas
|
||||||
|
i32 pitch = face->glyph->bitmap.pitch;
|
||||||
|
for(i32 Y = 0; Y < h; ++Y){
|
||||||
|
for(i32 X = 0; X < w; ++X){
|
||||||
|
i32 x = pen_x + X;
|
||||||
|
i32 y = pen_y + Y;
|
||||||
|
|
||||||
|
pixels[y * tex_width + x] = face->glyph->bitmap.buffer[Y * pitch + X] * 0x01010101;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pen_x = ceil32(glyph_ptr->x1 + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// upload texture
|
||||||
|
tex_height = round_up_pot_u32(pen_y + max_glyph_h + 2);
|
||||||
|
|
||||||
|
page->tex_width = tex_width;
|
||||||
|
page->tex_height = tex_height;
|
||||||
|
|
||||||
|
glGenTextures(1, &page->tex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, page->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);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_INT, pixels);
|
||||||
|
|
||||||
|
end_temp_memory(temp);
|
||||||
|
|
||||||
|
// whitespace spacing stuff
|
||||||
|
if (page_number == 0){
|
||||||
|
f32 space_adv = advances[' '];
|
||||||
|
f32 backslash_adv = advances['\\'];
|
||||||
|
f32 r_adv = advances['r'];
|
||||||
|
|
||||||
|
advances['\n'] = space_adv;
|
||||||
|
advances['\r'] = backslash_adv + r_adv;
|
||||||
|
advances['\t'] = space_adv*tab_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal b32
|
||||||
|
font_load_page(System_Functions *system, Partition *part, Render_Font *font, Glyph_Page *page, u32 page_number, u32 pt_size, b32 use_hinting){
|
||||||
|
|
||||||
|
char *filename = font->filename;
|
||||||
|
|
||||||
|
// TODO(allen): Stop redoing all this init for each call.
|
||||||
|
FT_Library ft;
|
||||||
|
FT_Init_FreeType(&ft);
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
FT_New_Face(ft, filename, 0, &face);
|
||||||
|
|
||||||
|
FT_Size_RequestRec_ size = {};
|
||||||
|
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
|
||||||
|
size.height = pt_size << 6;
|
||||||
|
FT_Request_Size(face, &size);
|
||||||
|
|
||||||
|
// NOTE(allen): set texture and glyph data.
|
||||||
|
font_load_page_inner(part, font, ft, face, use_hinting, page, page_number, 4);
|
||||||
|
|
||||||
|
FT_Done_FreeType(ft);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal b32
|
||||||
|
font_load(System_Functions *system, Partition *part, Render_Font *font, i32 pt_size, b32 use_hinting){
|
||||||
|
|
||||||
|
char *filename = font->filename;
|
||||||
|
|
||||||
|
// TODO(allen): Stop redoing all this init for each call.
|
||||||
|
FT_Library ft;
|
||||||
|
FT_Init_FreeType(&ft);
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
FT_New_Face(ft, filename, 0, &face);
|
||||||
|
|
||||||
|
FT_Size_RequestRec_ size = {};
|
||||||
|
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
|
||||||
|
size.height = pt_size << 6;
|
||||||
|
FT_Request_Size(face, &size);
|
||||||
|
|
||||||
|
// set size & metrics
|
||||||
|
char *name = face->family_name;
|
||||||
|
u32 name_len = 0;
|
||||||
|
for (;name[name_len];++name_len);
|
||||||
|
name_len = clamp_top(name_len, sizeof(font->name)-1);
|
||||||
|
memcpy(font->name, name, name_len);
|
||||||
|
font->name[name_len] = 0;
|
||||||
|
font->name_len = name_len;
|
||||||
|
|
||||||
|
font->ascent = ceil32 (face->size->metrics.ascender / 64.0f);
|
||||||
|
font->descent = floor32 (face->size->metrics.descender / 64.0f);
|
||||||
|
font->advance = ceil32 (face->size->metrics.max_advance / 64.0f);
|
||||||
|
font->height = ceil32 (face->size->metrics.height / 64.0f);
|
||||||
|
font->line_skip = font->height - (font->ascent - font->descent);
|
||||||
|
|
||||||
|
font->height -= font->line_skip;
|
||||||
|
font->line_skip = 0;
|
||||||
|
|
||||||
|
// NOTE(allen): set texture and glyph data.
|
||||||
|
Glyph_Page *page = font_get_or_make_page(system, font, 0);
|
||||||
|
|
||||||
|
// NOTE(allen): Setup some basic spacing stuff.
|
||||||
|
f32 backslash_adv = page->advance['\\'];
|
||||||
|
f32 max_hex_advance = 0.f;
|
||||||
|
for (u32 i = '0'; i <= '9'; ++i){
|
||||||
|
f32 adv = page->advance[i];
|
||||||
|
max_hex_advance = Max(max_hex_advance, adv);
|
||||||
|
}
|
||||||
|
for (u32 i = 'a'; i <= 'f'; ++i){
|
||||||
|
f32 adv = page->advance[i];
|
||||||
|
max_hex_advance = Max(max_hex_advance, adv);
|
||||||
|
}
|
||||||
|
for (u32 i = 'A'; i <= 'F'; ++i){
|
||||||
|
f32 adv = page->advance[i];
|
||||||
|
max_hex_advance = Max(max_hex_advance, adv);
|
||||||
|
}
|
||||||
|
|
||||||
|
font->byte_advance = backslash_adv + max_hex_advance*2;
|
||||||
|
font->byte_sub_advances[0] = backslash_adv;
|
||||||
|
font->byte_sub_advances[1] = max_hex_advance;
|
||||||
|
font->byte_sub_advances[2] = max_hex_advance;
|
||||||
|
|
||||||
|
FT_Done_FreeType(ft);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
system_set_page(System_Functions *system, Partition *part, Render_Font *font, Glyph_Page *page, u32 page_number, u32 pt_size, b32 use_hinting){
|
||||||
|
Assert(pt_size >= 8);
|
||||||
|
|
||||||
|
memset(page, 0, sizeof(*page));
|
||||||
|
|
||||||
|
if (part->base == 0){
|
||||||
|
*part = sysshared_scratch_partition(MB(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 success = false;
|
||||||
|
for (u32 R = 0; R < 3; ++R){
|
||||||
|
success = font_load_page(system, part, font, page, page_number, pt_size, use_hinting);
|
||||||
|
if (success){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
sysshared_partition_double(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
system_set_font(System_Functions *system, Partition *part, Render_Font *font, char *filename, u32 pt_size, b32 use_hinting){
|
||||||
|
memset(font, 0, sizeof(*font));
|
||||||
|
|
||||||
|
u32 filename_len = 0;
|
||||||
|
for (;filename[filename_len];++filename_len);
|
||||||
|
|
||||||
|
if (filename_len <= sizeof(font->filename)-1){
|
||||||
|
memcpy(font->filename, filename, filename_len);
|
||||||
|
font->filename[filename_len] = 0;
|
||||||
|
font->filename_len = filename_len;
|
||||||
|
|
||||||
|
if (part->base == 0){
|
||||||
|
*part = sysshared_scratch_partition(MB(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 success = false;
|
||||||
|
for (u32 R = 0; R < 3; ++R){
|
||||||
|
success = font_load(system, part, font, pt_size, use_hinting);
|
||||||
|
if (success){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
sysshared_partition_double(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOTTOM
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Mr. 4th Dimention - Allen Webster
|
||||||
|
*
|
||||||
|
* 10.11.2017
|
||||||
|
*
|
||||||
|
* Render target function implementations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
|
||||||
|
#define Render_Push_Clip_Sig(n, t, c) void (n)(Render_Target *t, i32_Rect c)
|
||||||
|
#define Render_Pop_Clip_Sig(n, t) i32_Rect (n)(Render_Target *t)
|
||||||
|
#define Render_Push_Piece_Sig(n, t, p) void (n)(Render_Target *t, Render_Piece_Combined p)
|
||||||
|
|
||||||
|
inline void
|
||||||
|
draw_safe_push(Render_Target *t, i32 size, void *x){
|
||||||
|
if (size + t->size <= t->max){
|
||||||
|
memcpy(t->push_buffer + t->size, x, size);
|
||||||
|
t->size += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PutStruct(s,x) draw_safe_push(t, sizeof(s), &x)
|
||||||
|
|
||||||
|
internal
|
||||||
|
Render_Push_Piece_Sig(render_push_piece, t, piece){
|
||||||
|
if (!t->clip_all){
|
||||||
|
PutStruct(Render_Piece_Header, piece.header);
|
||||||
|
|
||||||
|
switch (piece.header.type){
|
||||||
|
case piece_type_rectangle: case piece_type_outline:
|
||||||
|
{
|
||||||
|
PutStruct(Render_Piece_Rectangle, piece.rectangle);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case piece_type_glyph:
|
||||||
|
{
|
||||||
|
PutStruct(Render_Piece_Glyph, piece.glyph);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(t->size <= t->max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
render_push_piece_clip(Render_Target *t, i32_Rect clip_box){
|
||||||
|
if (!t->clip_all){
|
||||||
|
// TODO(allen): optimize out if there are two clip box changes in a row
|
||||||
|
Render_Piece_Change_Clip clip = {0};
|
||||||
|
Render_Piece_Header header = {0};
|
||||||
|
|
||||||
|
header.type = piece_type_change_clip;
|
||||||
|
clip.box = clip_box;
|
||||||
|
|
||||||
|
PutStruct(Render_Piece_Header, header);
|
||||||
|
PutStruct(Render_Piece_Change_Clip, clip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal
|
||||||
|
Render_Push_Clip_Sig(render_push_clip, t, clip_box){
|
||||||
|
Assert(t->clip_top == -1 || fits_inside(clip_box, t->clip_boxes[t->clip_top]));
|
||||||
|
Assert(t->clip_top+1 < ArrayCount(t->clip_boxes));
|
||||||
|
t->clip_boxes[++t->clip_top] = clip_box;
|
||||||
|
|
||||||
|
t->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1);
|
||||||
|
render_push_piece_clip(t, clip_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal
|
||||||
|
Render_Pop_Clip_Sig(render_pop_clip, t){
|
||||||
|
Assert(t->clip_top > 0);
|
||||||
|
i32_Rect result = t->clip_boxes[t->clip_top];
|
||||||
|
--t->clip_top;
|
||||||
|
i32_Rect clip_box = t->clip_boxes[t->clip_top];
|
||||||
|
|
||||||
|
t->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1);
|
||||||
|
render_push_piece_clip(t, clip_box);
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOTTOM
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Mr. 4th Dimention - Allen Webster
|
||||||
|
*
|
||||||
|
* 10.11.2017
|
||||||
|
*
|
||||||
|
* Render target type definition
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TOP
|
||||||
|
|
||||||
|
#if !defined(FRED_RENDER_TARGET_H)
|
||||||
|
#define FRED_RENDER_TARGET_H
|
||||||
|
|
||||||
|
struct Render_Target{
|
||||||
|
void *handle;
|
||||||
|
void *context;
|
||||||
|
i32_Rect clip_boxes[5];
|
||||||
|
i32 clip_top;
|
||||||
|
b32 clip_all;
|
||||||
|
i32 width, height;
|
||||||
|
i32 bound_texture;
|
||||||
|
u32 color;
|
||||||
|
|
||||||
|
// TODO(allen): change this to a Partition
|
||||||
|
char *push_buffer;
|
||||||
|
i32 size, max;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// BOTTOM
|
||||||
|
|
122
4ed_rendering.h
122
4ed_rendering.h
|
@ -1,122 +0,0 @@
|
||||||
/*
|
|
||||||
* Mr. 4th Dimention - Allen Webster
|
|
||||||
*
|
|
||||||
* 17.12.2014
|
|
||||||
*
|
|
||||||
* Rendering layer for project codename "4ed"
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TOP
|
|
||||||
|
|
||||||
#ifndef FRED_RENDERING_H
|
|
||||||
#define FRED_RENDERING_H
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render Commands
|
|
||||||
//
|
|
||||||
|
|
||||||
enum Render_Piece_Type{
|
|
||||||
piece_type_rectangle,
|
|
||||||
piece_type_outline,
|
|
||||||
piece_type_gradient,
|
|
||||||
piece_type_glyph,
|
|
||||||
piece_type_mono_glyph,
|
|
||||||
piece_type_mono_glyph_advance,
|
|
||||||
piece_type_change_clip
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Header{
|
|
||||||
i32 type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Rectangle{
|
|
||||||
f32_Rect rect;
|
|
||||||
u32 color;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Gradient{
|
|
||||||
f32_Rect rect;
|
|
||||||
u32 left_color;
|
|
||||||
u32 right_color;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Glyph{
|
|
||||||
Vec2 pos;
|
|
||||||
u32 color;
|
|
||||||
Font_ID font_id;
|
|
||||||
u32 codepoint;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Glyph_Advance{
|
|
||||||
Vec2 pos;
|
|
||||||
u32 color;
|
|
||||||
f32 advance;
|
|
||||||
Font_ID font_id;
|
|
||||||
u32 codepoint;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Change_Clip{
|
|
||||||
i32_Rect box;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Piece_Combined{
|
|
||||||
Render_Piece_Header header;
|
|
||||||
union{
|
|
||||||
Render_Piece_Rectangle rectangle;
|
|
||||||
Render_Piece_Gradient gradient;
|
|
||||||
Render_Piece_Glyph glyph;
|
|
||||||
Render_Piece_Glyph_Advance glyph_advance;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Render_Target;
|
|
||||||
|
|
||||||
#define Draw_Push_Clip_Sig(name) void name(Render_Target *target, i32_Rect clip_box)
|
|
||||||
typedef Draw_Push_Clip_Sig(Draw_Push_Clip);
|
|
||||||
|
|
||||||
#define Draw_Pop_Clip_Sig(name) i32_Rect name(Render_Target *target)
|
|
||||||
typedef Draw_Pop_Clip_Sig(Draw_Pop_Clip);
|
|
||||||
|
|
||||||
#define Draw_Push_Piece_Sig(name) void name(Render_Target *target, Render_Piece_Combined piece)
|
|
||||||
typedef Draw_Push_Piece_Sig(Draw_Push_Piece);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render target stuff
|
|
||||||
//
|
|
||||||
|
|
||||||
struct Render_Target{
|
|
||||||
void *handle;
|
|
||||||
void *context;
|
|
||||||
i32_Rect clip_boxes[5];
|
|
||||||
i32 clip_top;
|
|
||||||
b32 clip_all;
|
|
||||||
i32 width, height;
|
|
||||||
i32 bound_texture;
|
|
||||||
u32 color;
|
|
||||||
|
|
||||||
// TODO(allen): change this to a Partition
|
|
||||||
char *push_buffer;
|
|
||||||
i32 size, max;
|
|
||||||
|
|
||||||
Draw_Push_Clip *push_clip;
|
|
||||||
Draw_Pop_Clip *pop_clip;
|
|
||||||
Draw_Push_Piece *push_piece;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DpiMultiplier(n,dpi) ((n) * (dpi) / 96)
|
|
||||||
|
|
||||||
inline i32_Rect
|
|
||||||
rect_from_target(Render_Target *target){
|
|
||||||
i32_Rect r;
|
|
||||||
r.x0 = 0;
|
|
||||||
r.y0 = 0;
|
|
||||||
r.x1 = target->width;
|
|
||||||
r.y1 = target->height;
|
|
||||||
return(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// BOTTOM
|
|
||||||
|
|
|
@ -222,598 +222,6 @@ sysshared_to_binary_path(String *out_filename, char *filename){
|
||||||
return(translate_success);
|
return(translate_success);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Rendering Interface
|
|
||||||
//
|
|
||||||
|
|
||||||
inline void
|
|
||||||
draw_safe_push(Render_Target *t, i32 size, void *x){
|
|
||||||
if (size + t->size <= t->max){
|
|
||||||
memcpy(t->push_buffer + t->size, x, size);
|
|
||||||
t->size += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PutStruct(s,x) draw_safe_push(t, sizeof(s), &x)
|
|
||||||
|
|
||||||
internal void
|
|
||||||
draw_push_piece(Render_Target *t, Render_Piece_Combined piece){
|
|
||||||
if (!t->clip_all){
|
|
||||||
PutStruct(Render_Piece_Header, piece.header);
|
|
||||||
|
|
||||||
switch (piece.header.type){
|
|
||||||
case piece_type_rectangle: case piece_type_outline:
|
|
||||||
{
|
|
||||||
PutStruct(Render_Piece_Rectangle, piece.rectangle);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_gradient:
|
|
||||||
{
|
|
||||||
PutStruct(Render_Piece_Gradient, piece.gradient);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_glyph: case piece_type_mono_glyph:
|
|
||||||
{
|
|
||||||
PutStruct(Render_Piece_Glyph, piece.glyph);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_mono_glyph_advance:
|
|
||||||
{
|
|
||||||
PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert(t->size <= t->max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
draw_push_piece_clip(Render_Target *t, i32_Rect clip_box){
|
|
||||||
if (!t->clip_all){
|
|
||||||
// TODO(allen): optimize out if there are two clip box changes in a row
|
|
||||||
Render_Piece_Change_Clip clip;
|
|
||||||
Render_Piece_Header header;
|
|
||||||
|
|
||||||
header.type = piece_type_change_clip;
|
|
||||||
clip.box = clip_box;
|
|
||||||
|
|
||||||
PutStruct(Render_Piece_Header, header);
|
|
||||||
PutStruct(Render_Piece_Change_Clip, clip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
draw_push_clip(Render_Target *t, i32_Rect clip_box){
|
|
||||||
Assert(t->clip_top == -1 || fits_inside(clip_box, t->clip_boxes[t->clip_top]));
|
|
||||||
Assert(t->clip_top+1 < ArrayCount(t->clip_boxes));
|
|
||||||
t->clip_boxes[++t->clip_top] = clip_box;
|
|
||||||
|
|
||||||
t->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1);
|
|
||||||
draw_push_piece_clip(t, clip_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal i32_Rect
|
|
||||||
draw_pop_clip(Render_Target *t){
|
|
||||||
Assert(t->clip_top > 0);
|
|
||||||
i32_Rect result = t->clip_boxes[t->clip_top];
|
|
||||||
--t->clip_top;
|
|
||||||
i32_Rect clip_box = t->clip_boxes[t->clip_top];
|
|
||||||
|
|
||||||
t->clip_all = (clip_box.x0 >= clip_box.x1 || clip_box.y0 >= clip_box.y1);
|
|
||||||
draw_push_piece_clip(t, clip_box);
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
link_rendering(){
|
|
||||||
target.push_clip = draw_push_clip;
|
|
||||||
target.pop_clip = draw_pop_clip;
|
|
||||||
target.push_piece = draw_push_piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// OpenGL
|
|
||||||
//
|
|
||||||
|
|
||||||
#define ExtractStruct(s) ((s*)cursor); cursor += sizeof(s)
|
|
||||||
|
|
||||||
inline void
|
|
||||||
draw_set_clip(Render_Target *t, i32_Rect clip_box){
|
|
||||||
glScissor(clip_box.x0, t->height - clip_box.y1, clip_box.x1 - clip_box.x0, clip_box.y1 - clip_box.y0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
draw_bind_texture(Render_Target *t, i32 texid){
|
|
||||||
if (t->bound_texture != texid){
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texid);
|
|
||||||
t->bound_texture = texid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
draw_set_color(Render_Target *t, u32 color){
|
|
||||||
if (t->color != color){
|
|
||||||
t->color = color;
|
|
||||||
Vec4 c = unpack_color4(color);
|
|
||||||
glColor4f(c.r, c.g, c.b, c.a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
private_draw_rectangle(Render_Target *t, f32_Rect rect, u32 color){
|
|
||||||
draw_set_color(t, color);
|
|
||||||
draw_bind_texture(t, 0);
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
{
|
|
||||||
glVertex2f(rect.x0, rect.y0);
|
|
||||||
glVertex2f(rect.x0, rect.y1);
|
|
||||||
glVertex2f(rect.x1, rect.y1);
|
|
||||||
glVertex2f(rect.x1, rect.y0);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
private_draw_rectangle_outline(Render_Target *t, f32_Rect rect, u32 color){
|
|
||||||
f32_Rect r = get_inner_rect(rect, .5f);
|
|
||||||
draw_set_color(t, color);
|
|
||||||
draw_bind_texture(t, 0);
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
{
|
|
||||||
glVertex2f(r.x0, r.y0);
|
|
||||||
glVertex2f(r.x1, r.y0);
|
|
||||||
glVertex2f(r.x1, r.y1);
|
|
||||||
glVertex2f(r.x0, r.y1);
|
|
||||||
glVertex2f(r.x0, r.y0);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
private_draw_gradient(Render_Target *t, f32_Rect rect, Vec4 color_left, Vec4 color_right){
|
|
||||||
Vec4 cl = color_left;
|
|
||||||
Vec4 cr = color_right;
|
|
||||||
|
|
||||||
draw_bind_texture(t, 0);
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
{
|
|
||||||
glColor4f(cl.r, cl.g, cl.b, cl.a);
|
|
||||||
glVertex2f(rect.x0, rect.y0);
|
|
||||||
glVertex2f(rect.x0, rect.y1);
|
|
||||||
|
|
||||||
glColor4f(cr.r, cr.g, cr.b, cr.a);
|
|
||||||
glVertex2f(rect.x1, rect.y1);
|
|
||||||
glVertex2f(rect.x1, rect.y0);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Render_Quad{
|
|
||||||
f32 x0, y0, x1, y1;
|
|
||||||
f32 s0, t0, s1, t1;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Render_Quad
|
|
||||||
get_render_quad(Glyph_Bounds *b, i32 pw, i32 ph, float xpos, float ypos){
|
|
||||||
Render_Quad q;
|
|
||||||
|
|
||||||
float ipw = 1.0f / pw, iph = 1.0f / ph;
|
|
||||||
|
|
||||||
q.x0 = xpos + b->xoff;
|
|
||||||
q.y0 = ypos + b->yoff;
|
|
||||||
q.x1 = xpos + b->xoff2;
|
|
||||||
q.y1 = ypos + b->yoff2;
|
|
||||||
|
|
||||||
q.s0 = b->x0 * ipw;
|
|
||||||
q.t0 = b->y0 * iph;
|
|
||||||
q.s1 = b->x1 * ipw;
|
|
||||||
q.t1 = b->y1 * iph;
|
|
||||||
|
|
||||||
return(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Render_Quad
|
|
||||||
get_exact_render_quad(Glyph_Bounds *b, i32 pw, i32 ph, float xpos, float ypos){
|
|
||||||
Render_Quad q;
|
|
||||||
|
|
||||||
float ipw = 1.0f / pw, iph = 1.0f / ph;
|
|
||||||
|
|
||||||
q.x0 = xpos;
|
|
||||||
q.y0 = ypos + b->yoff;
|
|
||||||
q.x1 = xpos + (b->xoff2 - b->xoff);
|
|
||||||
q.y1 = ypos + b->yoff2;
|
|
||||||
|
|
||||||
q.s0 = b->x0 * ipw;
|
|
||||||
q.t0 = b->y0 * iph;
|
|
||||||
q.s1 = b->x1 * ipw;
|
|
||||||
q.t1 = b->y1 * iph;
|
|
||||||
|
|
||||||
return(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
private_draw_glyph(System_Functions *system, Render_Target *t, Render_Font *font, u32 codepoint, f32 x, f32 y, u32 color){
|
|
||||||
Glyph_Data glyph = font_get_glyph(system, font, codepoint);
|
|
||||||
if (glyph.tex != 0){
|
|
||||||
Render_Quad q = get_render_quad(&glyph.bounds, glyph.tex_width, glyph.tex_height, x, y);
|
|
||||||
|
|
||||||
draw_set_color(t, color);
|
|
||||||
draw_bind_texture(t, glyph.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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
private_draw_glyph_mono(System_Functions *system, Render_Target *t, Render_Font *font, u32 codepoint, f32 x, f32 y, f32 advance, u32 color){
|
|
||||||
Glyph_Data glyph = font_get_glyph(system, font, codepoint);
|
|
||||||
if (glyph.tex != 0){
|
|
||||||
f32 left = glyph.bounds.x0;
|
|
||||||
f32 right = glyph.bounds.x1;
|
|
||||||
f32 width = (right - left);
|
|
||||||
f32 x_shift = (advance - width) * .5f;
|
|
||||||
|
|
||||||
x += x_shift;
|
|
||||||
|
|
||||||
Render_Quad q = get_exact_render_quad(&glyph.bounds, glyph.tex_width, glyph.tex_height, x, y);
|
|
||||||
|
|
||||||
draw_set_color(t, color);
|
|
||||||
draw_bind_texture(t, glyph.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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
private_draw_glyph_mono(System_Functions *system, Render_Target *t, Render_Font *font, u32 character, f32 x, f32 y, u32 color){
|
|
||||||
f32 advance = (f32)font_get_advance(font);
|
|
||||||
private_draw_glyph_mono(system, t, font, character, x, y, advance, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
launch_rendering(System_Functions *system, Render_Target *t){
|
|
||||||
char *cursor = t->push_buffer;
|
|
||||||
char *cursor_end = cursor + t->size;
|
|
||||||
|
|
||||||
for (; cursor < cursor_end;){
|
|
||||||
Render_Piece_Header *header = ExtractStruct(Render_Piece_Header);
|
|
||||||
|
|
||||||
i32 type = header->type;
|
|
||||||
switch (type){
|
|
||||||
case piece_type_rectangle:
|
|
||||||
{
|
|
||||||
Render_Piece_Rectangle *rectangle = ExtractStruct(Render_Piece_Rectangle);
|
|
||||||
private_draw_rectangle(t, rectangle->rect, rectangle->color);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_outline:
|
|
||||||
{
|
|
||||||
Render_Piece_Rectangle *rectangle = ExtractStruct(Render_Piece_Rectangle);
|
|
||||||
private_draw_rectangle_outline(t, rectangle->rect, rectangle->color);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_gradient:
|
|
||||||
{
|
|
||||||
Render_Piece_Gradient *gradient = ExtractStruct(Render_Piece_Gradient);
|
|
||||||
private_draw_gradient(t, gradient->rect, unpack_color4(gradient->left_color), unpack_color4(gradient->right_color));
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_glyph:
|
|
||||||
{
|
|
||||||
Render_Piece_Glyph *glyph = ExtractStruct(Render_Piece_Glyph);
|
|
||||||
|
|
||||||
Render_Font *font = system->font.get_render_data_by_id(glyph->font_id);
|
|
||||||
Assert(font != 0);
|
|
||||||
private_draw_glyph(system, t, font, glyph->codepoint, glyph->pos.x, glyph->pos.y, glyph->color);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_mono_glyph:
|
|
||||||
{
|
|
||||||
Render_Piece_Glyph *glyph = ExtractStruct(Render_Piece_Glyph);
|
|
||||||
|
|
||||||
Render_Font *font = system->font.get_render_data_by_id(glyph->font_id);
|
|
||||||
Assert(font != 0);
|
|
||||||
private_draw_glyph_mono(system, t, font, glyph->codepoint, glyph->pos.x, glyph->pos.y, glyph->color);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_mono_glyph_advance:
|
|
||||||
{
|
|
||||||
Render_Piece_Glyph_Advance *glyph = ExtractStruct(Render_Piece_Glyph_Advance);
|
|
||||||
|
|
||||||
Render_Font *font = system->font.get_render_data_by_id(glyph->font_id);
|
|
||||||
Assert(font != 0);
|
|
||||||
private_draw_glyph_mono(system, t, font, glyph->codepoint, glyph->pos.x, glyph->pos.y, glyph->advance, glyph->color);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case piece_type_change_clip:
|
|
||||||
{
|
|
||||||
Render_Piece_Change_Clip *clip = ExtractStruct(Render_Piece_Change_Clip);
|
|
||||||
draw_set_clip(t, clip->box);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef ExtractStruct
|
|
||||||
|
|
||||||
// NOTE(allen): Thanks to insofaras. This is copy-pasted from some work he originally did to get free type working on Linux.
|
|
||||||
|
|
||||||
#undef internal
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#define internal static
|
|
||||||
|
|
||||||
internal void
|
|
||||||
font_load_page_inner(Partition *part, Render_Font *font, FT_Library ft, FT_Face face, b32 use_hinting, Glyph_Page *page, u32 page_number, i32 tab_width){
|
|
||||||
Temp_Memory temp = begin_temp_memory(part);
|
|
||||||
Assert(page != 0);
|
|
||||||
page->page_number = page_number;
|
|
||||||
|
|
||||||
// prepare to read glyphs into a temporary texture buffer
|
|
||||||
i32 max_glyph_w = face->size->metrics.x_ppem;
|
|
||||||
|
|
||||||
i32 max_glyph_h = font_get_height(font);
|
|
||||||
i32 tex_width = 64;
|
|
||||||
i32 tex_height = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
tex_width *= 2;
|
|
||||||
float glyphs_per_row = ceilf(tex_width / (float) max_glyph_w);
|
|
||||||
float rows = ceilf(ITEM_PER_FONT_PAGE / glyphs_per_row);
|
|
||||||
tex_height = ceil32(rows * (max_glyph_h + 2));
|
|
||||||
} while(tex_height > tex_width);
|
|
||||||
|
|
||||||
tex_height = round_up_pot_u32(tex_height);
|
|
||||||
|
|
||||||
i32 pen_x = 0;
|
|
||||||
i32 pen_y = 0;
|
|
||||||
|
|
||||||
u32* pixels = push_array(part, u32, tex_width * tex_height);
|
|
||||||
memset(pixels, 0, tex_width * tex_height * sizeof(u32));
|
|
||||||
|
|
||||||
u32 ft_flags = FT_LOAD_RENDER;
|
|
||||||
if (use_hinting){
|
|
||||||
// NOTE(inso): FT_LOAD_TARGET_LIGHT does hinting only vertically, which looks nicer imo
|
|
||||||
// maybe it could be exposed as an option for hinting, instead of just on/off.
|
|
||||||
ft_flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
ft_flags |= (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill the texture
|
|
||||||
u32 base_codepoint = (page_number << 8);
|
|
||||||
Glyph_Bounds *glyphs = &page->glyphs[0];
|
|
||||||
Glyph_Bounds *glyph_ptr = glyphs;
|
|
||||||
|
|
||||||
f32 *advances = &page->advance[0];
|
|
||||||
f32 *advance_ptr = advances;
|
|
||||||
for(u32 i = 0; i < ITEM_PER_FONT_PAGE; ++i, ++glyph_ptr, ++advance_ptr){
|
|
||||||
u32 codepoint = i + base_codepoint;
|
|
||||||
|
|
||||||
if(FT_Load_Char(face, codepoint, ft_flags) == 0){
|
|
||||||
i32 w = face->glyph->bitmap.width;
|
|
||||||
i32 h = face->glyph->bitmap.rows;
|
|
||||||
|
|
||||||
i32 ascent = font_get_ascent(font);
|
|
||||||
|
|
||||||
// move to next line if necessary
|
|
||||||
if(pen_x + w >= tex_width){
|
|
||||||
pen_x = 0;
|
|
||||||
pen_y += (max_glyph_h + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set all this stuff the renderer needs
|
|
||||||
glyph_ptr->x0 = (f32)(pen_x);
|
|
||||||
glyph_ptr->y0 = (f32)(pen_y);
|
|
||||||
glyph_ptr->x1 = (f32)(pen_x + w);
|
|
||||||
glyph_ptr->y1 = (f32)(pen_y + h + 1);
|
|
||||||
|
|
||||||
glyph_ptr->xoff = (f32)(face->glyph->bitmap_left);
|
|
||||||
glyph_ptr->yoff = (f32)(ascent - face->glyph->bitmap_top);
|
|
||||||
glyph_ptr->xoff2 = glyph_ptr->xoff + w;
|
|
||||||
glyph_ptr->yoff2 = glyph_ptr->yoff + h + 1;
|
|
||||||
|
|
||||||
// TODO(allen): maybe advance data should be integers?
|
|
||||||
*advance_ptr = (f32)ceil32(face->glyph->advance.x / 64.0f);
|
|
||||||
|
|
||||||
// write to texture atlas
|
|
||||||
i32 pitch = face->glyph->bitmap.pitch;
|
|
||||||
for(i32 Y = 0; Y < h; ++Y){
|
|
||||||
for(i32 X = 0; X < w; ++X){
|
|
||||||
i32 x = pen_x + X;
|
|
||||||
i32 y = pen_y + Y;
|
|
||||||
|
|
||||||
pixels[y * tex_width + x] = face->glyph->bitmap.buffer[Y * pitch + X] * 0x01010101;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pen_x = ceil32(glyph_ptr->x1 + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// upload texture
|
|
||||||
tex_height = round_up_pot_u32(pen_y + max_glyph_h + 2);
|
|
||||||
|
|
||||||
page->tex_width = tex_width;
|
|
||||||
page->tex_height = tex_height;
|
|
||||||
|
|
||||||
glGenTextures(1, &page->tex);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, page->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);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_INT, pixels);
|
|
||||||
|
|
||||||
end_temp_memory(temp);
|
|
||||||
|
|
||||||
// whitespace spacing stuff
|
|
||||||
if (page_number == 0){
|
|
||||||
f32 space_adv = advances[' '];
|
|
||||||
f32 backslash_adv = advances['\\'];
|
|
||||||
f32 r_adv = advances['r'];
|
|
||||||
|
|
||||||
advances['\n'] = space_adv;
|
|
||||||
advances['\r'] = backslash_adv + r_adv;
|
|
||||||
advances['\t'] = space_adv*tab_width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal b32
|
|
||||||
font_load_page(System_Functions *system, Partition *part, Render_Font *font, Glyph_Page *page, u32 page_number, u32 pt_size, b32 use_hinting){
|
|
||||||
|
|
||||||
char *filename = font->filename;
|
|
||||||
|
|
||||||
// TODO(allen): Stop redoing all this init for each call.
|
|
||||||
FT_Library ft;
|
|
||||||
FT_Init_FreeType(&ft);
|
|
||||||
|
|
||||||
FT_Face face;
|
|
||||||
FT_New_Face(ft, filename, 0, &face);
|
|
||||||
|
|
||||||
FT_Size_RequestRec_ size = {};
|
|
||||||
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
|
|
||||||
size.height = pt_size << 6;
|
|
||||||
FT_Request_Size(face, &size);
|
|
||||||
|
|
||||||
// NOTE(allen): set texture and glyph data.
|
|
||||||
font_load_page_inner(part, font, ft, face, use_hinting, page, page_number, 4);
|
|
||||||
|
|
||||||
FT_Done_FreeType(ft);
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal b32
|
|
||||||
font_load(System_Functions *system, Partition *part, Render_Font *font, i32 pt_size, b32 use_hinting){
|
|
||||||
|
|
||||||
char *filename = font->filename;
|
|
||||||
|
|
||||||
// TODO(allen): Stop redoing all this init for each call.
|
|
||||||
FT_Library ft;
|
|
||||||
FT_Init_FreeType(&ft);
|
|
||||||
|
|
||||||
FT_Face face;
|
|
||||||
FT_New_Face(ft, filename, 0, &face);
|
|
||||||
|
|
||||||
FT_Size_RequestRec_ size = {};
|
|
||||||
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
|
|
||||||
size.height = pt_size << 6;
|
|
||||||
FT_Request_Size(face, &size);
|
|
||||||
|
|
||||||
// set size & metrics
|
|
||||||
char *name = face->family_name;
|
|
||||||
u32 name_len = 0;
|
|
||||||
for (;name[name_len];++name_len);
|
|
||||||
name_len = clamp_top(name_len, sizeof(font->name)-1);
|
|
||||||
memcpy(font->name, name, name_len);
|
|
||||||
font->name[name_len] = 0;
|
|
||||||
font->name_len = name_len;
|
|
||||||
|
|
||||||
font->ascent = ceil32 (face->size->metrics.ascender / 64.0f);
|
|
||||||
font->descent = floor32 (face->size->metrics.descender / 64.0f);
|
|
||||||
font->advance = ceil32 (face->size->metrics.max_advance / 64.0f);
|
|
||||||
font->height = ceil32 (face->size->metrics.height / 64.0f);
|
|
||||||
font->line_skip = font->height - (font->ascent - font->descent);
|
|
||||||
|
|
||||||
font->height -= font->line_skip;
|
|
||||||
font->line_skip = 0;
|
|
||||||
|
|
||||||
// NOTE(allen): set texture and glyph data.
|
|
||||||
Glyph_Page *page = font_get_or_make_page(system, font, 0);
|
|
||||||
|
|
||||||
// NOTE(allen): Setup some basic spacing stuff.
|
|
||||||
f32 backslash_adv = page->advance['\\'];
|
|
||||||
f32 max_hex_advance = 0.f;
|
|
||||||
for (u32 i = '0'; i <= '9'; ++i){
|
|
||||||
f32 adv = page->advance[i];
|
|
||||||
max_hex_advance = Max(max_hex_advance, adv);
|
|
||||||
}
|
|
||||||
for (u32 i = 'a'; i <= 'f'; ++i){
|
|
||||||
f32 adv = page->advance[i];
|
|
||||||
max_hex_advance = Max(max_hex_advance, adv);
|
|
||||||
}
|
|
||||||
for (u32 i = 'A'; i <= 'F'; ++i){
|
|
||||||
f32 adv = page->advance[i];
|
|
||||||
max_hex_advance = Max(max_hex_advance, adv);
|
|
||||||
}
|
|
||||||
|
|
||||||
font->byte_advance = backslash_adv + max_hex_advance*2;
|
|
||||||
font->byte_sub_advances[0] = backslash_adv;
|
|
||||||
font->byte_sub_advances[1] = max_hex_advance;
|
|
||||||
font->byte_sub_advances[2] = max_hex_advance;
|
|
||||||
|
|
||||||
FT_Done_FreeType(ft);
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
system_set_page(System_Functions *system, Partition *part, Render_Font *font, Glyph_Page *page, u32 page_number, u32 pt_size, b32 use_hinting){
|
|
||||||
Assert(pt_size >= 8);
|
|
||||||
|
|
||||||
memset(page, 0, sizeof(*page));
|
|
||||||
|
|
||||||
if (part->base == 0){
|
|
||||||
*part = sysshared_scratch_partition(MB(8));
|
|
||||||
}
|
|
||||||
|
|
||||||
b32 success = false;
|
|
||||||
for (u32 R = 0; R < 3; ++R){
|
|
||||||
success = font_load_page(system, part, font, page, page_number, pt_size, use_hinting);
|
|
||||||
if (success){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
sysshared_partition_double(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
system_set_font(System_Functions *system, Partition *part, Render_Font *font, char *filename, u32 pt_size, b32 use_hinting){
|
|
||||||
memset(font, 0, sizeof(*font));
|
|
||||||
|
|
||||||
u32 filename_len = 0;
|
|
||||||
for (;filename[filename_len];++filename_len);
|
|
||||||
|
|
||||||
if (filename_len <= sizeof(font->filename)-1){
|
|
||||||
memcpy(font->filename, filename, filename_len);
|
|
||||||
font->filename[filename_len] = 0;
|
|
||||||
font->filename_len = filename_len;
|
|
||||||
|
|
||||||
if (part->base == 0){
|
|
||||||
*part = sysshared_scratch_partition(MB(8));
|
|
||||||
}
|
|
||||||
|
|
||||||
b32 success = false;
|
|
||||||
for (u32 R = 0; R < 3; ++R){
|
|
||||||
success = font_load(system, part, font, pt_size, use_hinting);
|
|
||||||
if (success){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
sysshared_partition_double(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BOTTOM
|
// BOTTOM
|
||||||
|
|
|
@ -38,7 +38,8 @@
|
||||||
|
|
||||||
#include "4ed_system.h"
|
#include "4ed_system.h"
|
||||||
#include "4ed_log.h"
|
#include "4ed_log.h"
|
||||||
#include "4ed_rendering.h"
|
#include "4ed_render_format.h"
|
||||||
|
#include "4ed_render_target.h"
|
||||||
#include "4ed.h"
|
#include "4ed.h"
|
||||||
|
|
||||||
#include "4ed_file_track.h"
|
#include "4ed_file_track.h"
|
||||||
|
@ -431,15 +432,14 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
if (pid && waitpid(pid, &status, WNOHANG) > 0){
|
if (pid && waitpid(pid, &status, WNOHANG) > 0){
|
||||||
close_me = true;
|
|
||||||
|
|
||||||
cli->exit = WEXITSTATUS(status);
|
cli->exit = WEXITSTATUS(status);
|
||||||
|
|
||||||
|
close_me = true;
|
||||||
|
close(*(int*)&cli->out_read);
|
||||||
|
close(*(int*)&cli->out_write);
|
||||||
|
|
||||||
struct epoll_event e = {};
|
struct epoll_event e = {};
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_DEL, *(int*)&cli->out_read, &e);
|
epoll_ctl(linuxvars.epoll, EPOLL_CTL_DEL, *(int*)&cli->out_read, &e);
|
||||||
|
|
||||||
close(*(int*)&cli->out_read);
|
|
||||||
close(*(int*)&cli->out_write);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(close_me);
|
return(close_me);
|
||||||
|
@ -447,6 +447,7 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
|
|
||||||
#include "4ed_font_data.h"
|
#include "4ed_font_data.h"
|
||||||
#include "4ed_system_shared.cpp"
|
#include "4ed_system_shared.cpp"
|
||||||
|
#include "4ed_render_opengl.cpp"
|
||||||
|
|
||||||
//
|
//
|
||||||
// End of system funcs
|
// End of system funcs
|
||||||
|
@ -456,13 +457,6 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
// Renderer
|
// Renderer
|
||||||
//
|
//
|
||||||
|
|
||||||
internal void
|
|
||||||
LinuxRedrawTarget(){
|
|
||||||
launch_rendering(&sysfunc, &target);
|
|
||||||
//glFlush();
|
|
||||||
glXSwapBuffers(linuxvars.XDisplay, linuxvars.XWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
LinuxResizeTarget(i32 width, i32 height){
|
LinuxResizeTarget(i32 width, i32 height){
|
||||||
if (width > 0 && height > 0){
|
if (width > 0 && height > 0){
|
||||||
|
@ -1564,7 +1558,6 @@ main(int argc, char **argv){
|
||||||
//
|
//
|
||||||
|
|
||||||
load_app_code();
|
load_app_code();
|
||||||
link_rendering();
|
|
||||||
#if defined(FRED_SUPER)
|
#if defined(FRED_SUPER)
|
||||||
load_custom_code();
|
load_custom_code();
|
||||||
#else
|
#else
|
||||||
|
@ -1840,7 +1833,8 @@ main(int argc, char **argv){
|
||||||
system_schedule_step();
|
system_schedule_step();
|
||||||
}
|
}
|
||||||
|
|
||||||
LinuxRedrawTarget();
|
interpret_render_buffer(&sysfunc, &target);
|
||||||
|
glXSwapBuffers(linuxvars.XDisplay, linuxvars.XWindow);
|
||||||
|
|
||||||
if (result.mouse_cursor_type != linuxvars.cursor && !linuxvars.input.mouse.l){
|
if (result.mouse_cursor_type != linuxvars.cursor && !linuxvars.input.mouse.l){
|
||||||
Cursor c = xcursors[result.mouse_cursor_type];
|
Cursor c = xcursors[result.mouse_cursor_type];
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
|
|
||||||
#include "4ed_system.h"
|
#include "4ed_system.h"
|
||||||
#include "4ed_log.h"
|
#include "4ed_log.h"
|
||||||
#include "4ed_rendering.h"
|
#include "4ed_render_format.h"
|
||||||
|
#include "4ed_render_target.h"
|
||||||
#include "4ed.h"
|
#include "4ed.h"
|
||||||
|
|
||||||
#include "4ed_file_track.h"
|
#include "4ed_file_track.h"
|
||||||
|
@ -311,6 +312,7 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
|
|
||||||
#include "4ed_font_data.h"
|
#include "4ed_font_data.h"
|
||||||
#include "4ed_system_shared.cpp"
|
#include "4ed_system_shared.cpp"
|
||||||
|
#include "4ed_render_opengl.cpp"
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
|
@ -539,7 +541,7 @@ osx_step(void){
|
||||||
|
|
||||||
osx_show_cursor(0, result.mouse_cursor_type);
|
osx_show_cursor(0, result.mouse_cursor_type);
|
||||||
|
|
||||||
launch_rendering(&sysfunc, &target);
|
interpret_render_buffer(&sysfunc, &target);
|
||||||
|
|
||||||
if (result.animating || cli_count > 0){
|
if (result.animating || cli_count > 0){
|
||||||
osx_schedule_step();
|
osx_schedule_step();
|
||||||
|
@ -609,7 +611,6 @@ osx_init(){
|
||||||
|
|
||||||
DBG_POINT();
|
DBG_POINT();
|
||||||
load_app_code();
|
load_app_code();
|
||||||
link_rendering();
|
|
||||||
#if defined(FRED_SUPER)
|
#if defined(FRED_SUPER)
|
||||||
load_custom_code();
|
load_custom_code();
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -48,7 +48,8 @@
|
||||||
|
|
||||||
#include "4ed_system.h"
|
#include "4ed_system.h"
|
||||||
#include "4ed_log.h"
|
#include "4ed_log.h"
|
||||||
#include "4ed_rendering.h"
|
#include "4ed_render_format.h"
|
||||||
|
#include "4ed_render_target.h"
|
||||||
#include "4ed.h"
|
#include "4ed.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
@ -448,7 +449,7 @@ Sys_CLI_Update_Step_Sig(system_cli_update_step){
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_CLI_End_Update_Sig(system_cli_end_update){
|
Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
b32 close_me = 0;
|
b32 close_me = false;
|
||||||
HANDLE proc = *(HANDLE*)&cli->proc;
|
HANDLE proc = *(HANDLE*)&cli->proc;
|
||||||
DWORD result = 0;
|
DWORD result = 0;
|
||||||
|
|
||||||
|
@ -460,22 +461,20 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
cli->exit = (i32)result;
|
cli->exit = (i32)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
close_me = 1;
|
close_me = true;
|
||||||
CloseHandle(*(HANDLE*)&cli->proc);
|
CloseHandle(*(HANDLE*)&cli->proc);
|
||||||
CloseHandle(*(HANDLE*)&cli->out_read);
|
CloseHandle(*(HANDLE*)&cli->out_read);
|
||||||
CloseHandle(*(HANDLE*)&cli->out_write);
|
CloseHandle(*(HANDLE*)&cli->out_write);
|
||||||
|
|
||||||
--win32vars.running_cli;
|
--win32vars.running_cli;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(close_me);
|
return(close_me);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Linkage to Custom and Application
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "4ed_font_data.h"
|
#include "4ed_font_data.h"
|
||||||
#include "4ed_system_shared.cpp"
|
#include "4ed_system_shared.cpp"
|
||||||
|
#include "4ed_render_opengl.cpp"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -517,13 +516,6 @@ Win32KeycodeInit(){
|
||||||
keycode_lookup_table[VK_F16] = key_f16;
|
keycode_lookup_table[VK_F16] = key_f16;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
Win32RedrawScreen(HDC hdc){
|
|
||||||
launch_rendering(&sysfunc, &target);
|
|
||||||
glFlush();
|
|
||||||
SwapBuffers(hdc);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
Win32Resize(i32 width, i32 height){
|
Win32Resize(i32 width, i32 height){
|
||||||
if (width > 0 && height > 0){
|
if (width > 0 && height > 0){
|
||||||
|
@ -932,7 +924,8 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
||||||
win32vars.got_useful_event = true;
|
win32vars.got_useful_event = true;
|
||||||
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
||||||
HDC hdc = BeginPaint(hwnd, &ps);
|
HDC hdc = BeginPaint(hwnd, &ps);
|
||||||
Win32RedrawScreen(hdc);
|
// NOTE(allen): Do nothing?
|
||||||
|
AllowLocal(hdc);
|
||||||
EndPaint(hwnd, &ps);
|
EndPaint(hwnd, &ps);
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
|
@ -948,11 +941,6 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
||||||
win32vars.got_useful_event = true;
|
win32vars.got_useful_event = true;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case WM_CANCELMODE:
|
|
||||||
{
|
|
||||||
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
@ -1006,7 +994,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
|
||||||
//
|
//
|
||||||
|
|
||||||
load_app_code();
|
load_app_code();
|
||||||
link_rendering();
|
|
||||||
#if defined(FRED_SUPER)
|
#if defined(FRED_SUPER)
|
||||||
load_custom_code();
|
load_custom_code();
|
||||||
#else
|
#else
|
||||||
|
@ -1396,7 +1383,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
|
||||||
win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr;
|
win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr;
|
||||||
|
|
||||||
HDC hdc = GetDC(win32vars.window_handle);
|
HDC hdc = GetDC(win32vars.window_handle);
|
||||||
Win32RedrawScreen(hdc);
|
interpret_render_buffer(&sysfunc, &target);
|
||||||
|
SwapBuffers(hdc);
|
||||||
ReleaseDC(win32vars.window_handle, hdc);
|
ReleaseDC(win32vars.window_handle, hdc);
|
||||||
|
|
||||||
win32vars.first = 0;
|
win32vars.first = 0;
|
||||||
|
|
|
@ -1283,7 +1283,12 @@ replace_range_str(String *str, i32_4tech first, i32_4tech one_past_last, String
|
||||||
|
|
||||||
CPP_NAME(replace_str)
|
CPP_NAME(replace_str)
|
||||||
API_EXPORT FSTRING_LINK void
|
API_EXPORT FSTRING_LINK void
|
||||||
replace_str_ss(String *str, String replace, String with){
|
replace_str_ss(String *str, String replace, String with)/*
|
||||||
|
DOC_PARAM(str, The string to modify.)
|
||||||
|
DOC_PARAM(replace, A string matching the zero or more substring to be replaced within str.)
|
||||||
|
DOC_PARAM(with, The string to be placed into str in place of occurrences of replace.)
|
||||||
|
DOC(Modifies str so that every occurence of replace that was within str is gone and the string in with has taken their places.)
|
||||||
|
*/{
|
||||||
i32_4tech i = 0;
|
i32_4tech i = 0;
|
||||||
for (;;){
|
for (;;){
|
||||||
i = find_substr_s(*str, i, replace);
|
i = find_substr_s(*str, i, replace);
|
||||||
|
@ -1297,21 +1302,36 @@ replace_str_ss(String *str, String replace, String with){
|
||||||
|
|
||||||
CPP_NAME(replace_str)
|
CPP_NAME(replace_str)
|
||||||
API_EXPORT FSTRING_LINK void
|
API_EXPORT FSTRING_LINK void
|
||||||
replace_str_sc(String *str, String replace, char *with){
|
replace_str_sc(String *str, String replace, char *with)/*
|
||||||
|
DOC_PARAM(str, The string to modify.)
|
||||||
|
DOC_PARAM(replace, A string matching the zero or more substring to be replaced within str. Must be null terminated, and will be counted, it is always faster to use a String parameter here when possible.)
|
||||||
|
DOC_PARAM(with, The string to be placed into str in place of occurrences of replace.)
|
||||||
|
DOC(Modifies str so that every occurence of replace that was within str is gone and the string in with has taken their places.)
|
||||||
|
*/{
|
||||||
String w = make_string_slowly(with);
|
String w = make_string_slowly(with);
|
||||||
replace_str_ss(str, replace, w);
|
replace_str_ss(str, replace, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
CPP_NAME(replace_str)
|
CPP_NAME(replace_str)
|
||||||
API_EXPORT FSTRING_LINK void
|
API_EXPORT FSTRING_LINK void
|
||||||
replace_str_cs(String *str, char *replace, String with){
|
replace_str_cs(String *str, char *replace, String with)/*
|
||||||
|
DOC_PARAM(str, The string to modify.)
|
||||||
|
DOC_PARAM(replace, A string matching the zero or more substring to be replaced within str.)
|
||||||
|
DOC_PARAM(with, The string to be placed into str in place of occurrences of replace. Must be null terminated, and will be counted, it is always faster to use a String parameter here when possible.)
|
||||||
|
DOC(Modifies str so that every occurence of replace that was within str is gone and the string in with has taken their places.)
|
||||||
|
*/{
|
||||||
String r = make_string_slowly(replace);
|
String r = make_string_slowly(replace);
|
||||||
replace_str_ss(str, r, with);
|
replace_str_ss(str, r, with);
|
||||||
}
|
}
|
||||||
|
|
||||||
CPP_NAME(replace_str)
|
CPP_NAME(replace_str)
|
||||||
API_EXPORT FSTRING_LINK void
|
API_EXPORT FSTRING_LINK void
|
||||||
replace_str_cc(String *str, char *replace, char *with){
|
replace_str_cc(String *str, char *replace, char *with)/*
|
||||||
|
DOC_PARAM(str, The string to modify.)
|
||||||
|
DOC_PARAM(replace, A string matching the zero or more substring to be replaced within str. Must be null terminated, and will be counted, it is always faster to use a String parameter here when possible.)
|
||||||
|
DOC_PARAM(with, The string to be placed into str in place of occurrences of replace. Must be null terminated, and will be counted, it is always faster to use a String parameter here when possible.)
|
||||||
|
DOC(Modifies str so that every occurence of replace that was within str is gone and the string in with has taken their places.)
|
||||||
|
*/{
|
||||||
String r = make_string_slowly(replace);
|
String r = make_string_slowly(replace);
|
||||||
String w = make_string_slowly(with);
|
String w = make_string_slowly(with);
|
||||||
replace_str_ss(str, r, w);
|
replace_str_ss(str, r, w);
|
||||||
|
|
Loading…
Reference in New Issue