Code:
Procedure DrawText(x, y, mx, my, trans: single; const text: string; fontn, wordwrap: integer);
var
i: integer;
b: byte;
cw: integer;
ta, tb, tc, td: single;
va, vb, vc, vd: single;
// current left edge
L: single;
// skip this much of characters from being parsed
SK: integer;
wraps: array[0..31] of word; // i dont think my game will ever need / have more than 32 word wraps
maxwrap: integer;
currwrap: integer;
lastspace: integer; // faster word wrap
procedure Vwrap(c: integer);
begin
cw:= 0;
wraps[maxwrap]:= c;
maxwrap:= maxwrap +1;
// since there is no array bounds checking this takes care for safety
if maxwrap > high(wraps) then maxwrap:= high(wraps);
end;
// this function processes the string and remembers all locations where lines should wrap (line returns, word wraps, etc..)
procedure MeasureWraps;
var
i: integer;
begin
maxwrap:= 0;
lastspace:= -1; // faster word wrap
for i:= 1 to length(text) do begin
if SK <> 0 then begin SK:= SK -1; continue; end; // skipping text coding characters
b:= byte(text[i]); // we need a integer type to use for array access,
if b = 32 then lastspace:= i; // remember last space for word wrapping
if b = 126 then begin sk:= 2; continue; end; // skip ~X~ color coding keyword
// next character would fall over the specified text width dimension, wrap at last known space character
if (wordwrap <> 0) and (cw + trunc(FontGeo[fontn, b].spacing * mx) > wordwrap) then begin
Vwrap(lastspace); continue;
end;
if b = 13 then begin Vwrap(i); continue; end; // return character - go to new line
// add character width to this line text width
cw:= cw + trunc(FontGeo[fontn, b].spacing * mx);
end;
end;
// go to next line
procedure wrap;
begin
cw:= 0;
L:= L + (FontGeo[fontn, 32].H * my);
end;
// process color codes
procedure EatColor; // changes font color depending on keyword
begin
if text[i + 1] = 'W' then glcolor4f(1, 1, 1, trans); // white
if text[i + 1] = 'N' then glcolor4f(0, 0, 0, trans); // none - black
if text[i + 1] = 'R' then glcolor4f(0.9, 0, 0, trans); // red
if text[i + 1] = 'G' then glcolor4f(0, 0.9, 0, trans); // green
if text[i + 1] = 'B' then glcolor4f(0, 0, 0.9, trans); // blue
if text[i + 1] = 'Y' then glcolor4f(1.0, 1, 0, trans); // yellow
if text[i + 1] = 'T' then glcolor4f(0, 1, 1, trans); // teal
if text[i + 1] = 'O' then glcolor4f(1, 0.7734375, 0.09765625, trans); // orange
SK:= 2; // skip 2 chars so the color coding is like '~C~' where C is color
end;
begin
if length(text) = 0 then exit; // idiot proof fuse
// ensure variables are reset for preprocessing
cw:= 0;
SK:= 0;
fillchar(wraps, sizeof(wraps), $FF);
MeasureWraps;
// ensure variables are reset for rendering
cw:= 0;
L:= 0;
SK:= 0;
currwrap:= 0;
glBindTexture(GL_TEXTURE_2D, Font.tex[fontn].GLID);
glBegin(GL_quads);
for i:= 1 to length(text) do begin
if SK <> 0 then begin SK:= SK -1; continue; end;
b:= byte(text[i]); // we need a integer type to use for array access
if b = 126 then begin eatcolor; continue; end;
// find out if we are supposed to wrap at this character
if currwrap < maxwrap then
if wraps[currwrap] = i then begin wrap; currwrap:= currwrap +1; continue; end;
// get tex coords from array
ta:= FontGeo[fontn, b].X / 256;
tb:= FontGeo[fontn, b].X / 256 + FontGeo[fontn, b].W / 256;
tc:= FontGeo[fontn, b].Y / 256;
td:= FontGeo[fontn, b].Y / 256 + FontGeo[fontn, b].H / 256;
// build vertices
va:= cw; // top left
vb:= va + (FontGeo[fontn, b].W * mx); // top right
vc:= trunc((FontGeo[fontn, b].YOFS * my) + L); // bottom left, this needs to be trunc-ed here and nowhere else!
vd:= trunc(vc + (FontGeo[fontn, b].H * my)); // bottom right, this needs to be trunc-ed here and nowhere else!
// crunch
gltexcoord2f(ta, tc); glvertex2fwin(x + va, y + vc);
gltexcoord2f(ta, td); glvertex2fwin(x + va, y + vd);
gltexcoord2f(tb, td); glvertex2fwin(x + vb, y + vd);
gltexcoord2f(tb, tc); glvertex2fwin(x + vb, y + vc);
// add character size to left edge
cw:= cw + trunc(FontGeo[fontn, b].spacing * mx);
end;
glend;
end;
function GetTextExtents(mx, my: single; const text: string; fontn, wordwrap: integer): IRect;
var
i: integer;
b: byte;
cw: integer;
// skip this much of characters from being parsed
SK: integer;
LongestLine: single;
LinesAll: single;
maxwrap: integer;
lastspace, lastwrap: integer; // faster word wrap
lastspacew: single;
procedure Vwrap(linew: single);
begin
if cw > linew then LongestLine:= linew;
cw:= 0;
lastspacew:= 0;
maxwrap:= maxwrap +1;
end;
begin
if length(text) = 0 then exit; // idiot proof fuse
// ensure variables are reset for preprocessing
cw:= 0;
SK:= 0;
LongestLine:= 0;
lastwrap:= 0;
LinesAll:= 1;
lastspacew:= 0;
maxwrap:= 0;
lastspace:= -1; // faster word wrap
for i:= 1 to length(text) do begin
if SK <> 0 then begin SK:= SK -1; continue; end; // skipping text coding characters
b:= byte(text[i]); // we need a integer type to use for array access,
if b = 32 then begin lastspace:= i; lastspacew:= cw end; // remember last space for word wrapping
if b = 126 then begin sk:= 2; continue; end; // skip ~X~ color coding keyword
// next character would fall over the specified text width dimension, wrap at last known space character
if (wordwrap <> 0) and (cw + trunc(FontGeo[fontn, b].spacing * mx) > wordwrap) then begin
Vwrap(lastspacew); continue;
end;
if b = 13 then begin Vwrap(cw); continue; end; // return character - go to new line
// add character width to this line text width
cw:= cw + trunc(FontGeo[fontn, b].spacing * mx);
end;
LinesAll:= LinesAll + maxwrap;
result.left:= 0;
result.top:= 0;
if LongestLine <> 0 then result.Right:= trunc(LongestLine) else result.Right:= cw;
result.Bottom:= trunc(LinesAll * (FontGeo[fontn, 32].H * my));
end;
Bookmarks