28 : flags(0), height(0), baseline(0), interspace(0), spacewidth(0),
29 imagewidth(0), image(0), expansion(0), alpha(1), blend(
Video::BLEND_ALPHA),
30 scale(1), material(0), vset(0), polys(0), npolys(0),
31 caret_index(-1), caret_x(0), caret_y(0), tgt_bitmap(0)
33 ZeroMemory(name,
sizeof(name));
34 ZeroMemory(glyph,
sizeof(glyph));
35 ZeroMemory(kern,
sizeof(kern));
39 : flags(0), height(0), baseline(0), interspace(0), spacewidth(4),
40 imagewidth(0), image(0), expansion(0), alpha(1), blend(
Video::BLEND_ALPHA),
41 scale(1), material(0), vset(0), polys(0), npolys(0),
42 caret_index(-1), caret_x(0), caret_y(0), tgt_bitmap(0)
44 ZeroMemory(glyph,
sizeof(glyph));
45 ZeroMemory(kern,
sizeof(kern));
46 CopyMemory(name, n,
sizeof(name));
57 ZeroMemory(glyph,
sizeof(glyph));
58 ZeroMemory(kern,
sizeof(kern));
66 if (image)
delete [] image;
67 if (vset)
delete vset;
68 if (polys)
delete [] polys;
69 if (material)
delete material;
74 static char kern_tweak[256][256];
79 if (!name || !name[0])
84 wsprintf(defname,
"%s.def", name);
85 wsprintf(imgname,
"%s.pcx", name);
91 LoadDef(defname, imgname);
93 for (
int i = 0; i < 256; i++) {
94 glyph[i].
offset = GlyphOffset(i);
102 scale = bitmap.
Width() / 256;
103 imagewidth = bitmap.
Width();
104 if (height > bitmap.
Height())
108 image =
new(__FILE__,__LINE__) BYTE[imgsize];
112 CopyMemory(image, bitmap.
Pixels(), imgsize);
116 for (
int i = 0; i < imgsize; i++)
121 material =
new(__FILE__,__LINE__)
Material;
128 for (
int i = 0; i < 256; i++) {
129 glyph[i].
width = CalcWidth(i);
137 for (
int i = 0; i < 256; i++) {
138 for (
int j = 0; j < 256; j++) {
139 if (kern_tweak[i][j] < 100) {
140 kern[i][j] = kern_tweak[i][j];
149 Font::LoadDef(
char* defname,
char* imgname)
151 for (
int i = 0; i < 256; i++)
152 for (
int j = 0; j < 256; j++)
153 kern_tweak[i][j] = 111;
160 int blocklen = loader->
LoadBuffer(defname, block,
true);
162 if (!block || blocklen < 4)
165 Parser parser(
new(__FILE__,__LINE__)
BlockReader((
const char*) block, blocklen));
166 Term* term = parser.ParseTerm();
169 Print(
"WARNING: could not parse '%s'\n", defname);
174 if (!file_type || file_type->
value() !=
"FONT") {
175 Print(
"WARNING: invalid font def file '%s'\n", defname);
183 term = parser.ParseTerm();
192 else if (def->
name()->
value() ==
"height") {
196 if (h >= 0 && h <= 32)
200 else if (def->
name()->
value() ==
"baseline") {
204 if (b >= 0 && b <= 32)
208 else if (def->
name()->
value() ==
"flags") {
233 else if (def->
name()->
value() ==
"interspace") {
237 if (n >= 0 && n <= 100)
238 interspace = (BYTE) n;
241 else if (def->
name()->
value() ==
"spacewidth") {
245 if (n >= 0 && n <= 100)
246 spacewidth = (BYTE) n;
249 else if (def->
name()->
value() ==
"expansion") {
253 else if (def->
name()->
value() ==
"kern") {
277 kern_tweak[a[0]][b[0]] = k;
281 Print(
"WARNING: unknown object '%s' in '%s'\n",
286 Print(
"WARNING: term ignored in '%s'\n", defname);
299 static const int pipe_width = 16;
300 static const int char_width = 16;
301 static const int char_height = 16;
302 static const int row_items = 16;
303 static const int row_width = row_items * char_width;
304 static const int row_size = char_height * row_width;
307 Font::GlyphOffset(BYTE c)
const
313 return (c/row_items * row_size * scale * scale +
314 c%row_items * char_width * scale);
318 Font::GlyphLocationX(BYTE c)
const
320 if (flags & FONT_ALL_CAPS)
324 return c%row_items * char_width;
328 Font::GlyphLocationY(BYTE c)
const
330 if (flags & FONT_ALL_CAPS)
334 return c/row_items * char_height;
340 Font::CalcWidth(BYTE c)
const
345 if (c >= 128 || !image)
356 BYTE* src = image + GlyphOffset(c);
358 for (
int y = 0; y < h; y++) {
361 for (
int x = 0; x < w; x++) {
362 if (*pleft++ > 0 && x > result)
381 Font::FindEdges(BYTE c,
double* l,
double* r)
386 int w = glyph[c].
width;
392 BYTE* src = image + GlyphOffset(c);
394 for (
int y = 0; y < h; y++) {
396 BYTE* pright = src+w-1;
401 for (
int x = 0; x < w; x++) {
402 if (*l == -1 && *pleft != 0)
403 *l = x + 1 - (double) *pleft/255.0;
404 if (*r == -1 && *pright != 0)
405 *r = x + 1 - (double) *pright/255.0;
417 static bool nokern(
char c)
422 const char* nokernchars =
"0123456789+=<>-.,:;?'\"";
424 if (strchr(nokernchars, c))
445 for (i = 0; i < 256; i++) {
450 if ((flags & FONT_ALL_CAPS) && islower(c))
453 if (glyph[(BYTE) c].width > 0) {
454 FindEdges((BYTE) c, data[i].l, data[i].r);
462 double desired_avg = 2.5 + expansion;
463 double desired_min = 1;
465 for (i = 0; i < 256; i++) {
466 for (j = 0; j < 256; j++) {
468 if (nokern(i) || nokern(j)) {
469 kern[i][j] = (char) 0;
478 for (
int y = 0; y < h; y++) {
479 if (data[i].r[y] >= 0 && data[j].l[y] >= 0) {
480 delta = data[i].
r[y] + data[j].
l[y];
492 delta = desired_avg - avg;
494 if (delta < desired_min - min) {
495 delta = ceil(desired_min - min);
497 if (i ==
'T' && islower(j) && !(flags & FONT_ALL_CAPS))
505 kern[i][j] = (char) delta;
518 if (flags & FONT_ALL_CAPS)
527 else if (c < 0 || isspace(c))
531 result = glyph[c].
width + interspace;
545 if (flags & FONT_ALL_CAPS) {
546 if (islower(a)) a = toupper(a);
547 if (islower(b)) b = toupper(b);
556 if (k < -100 || k > 100)
559 if (flags & FONT_ALL_CAPS) {
560 if (islower(a)) a = toupper(a);
561 if (islower(b)) b = toupper(b);
564 kern[a][b] = (char) k;
581 for (
int i = 0; i < len; i++) {
582 if (isspace(*c) && (*c < PIPE_NBSP || *c >
ARROW_RIGHT))
583 result += spacewidth;
586 if (flags & FONT_ALL_CAPS)
592 k = kern[cc][str[i+1]];
594 result += glyph[cc].
width + interspace + k;
607 Rect clip_rect = text_rect;
609 if (clip_rect.
w < 1 || clip_rect.
h < 1)
614 if (text && text[0]) {
616 count = strlen(text);
619 if (flags & DT_SINGLELINE) {
620 DrawTextSingle(text, count, text_rect, clip_rect, flags);
624 else if (flags & DT_WORDBREAK) {
625 DrawTextWrap(text, count, text_rect, clip_rect, flags);
630 DrawTextMulti(text, count, text_rect, clip_rect, flags);
634 caret_x = text_rect.
x + 2;
635 caret_y = text_rect.
y + 2;
639 if (flags & DT_CALCRECT) {
640 text_rect.
h = clip_rect.
h;
641 text_rect.
w = clip_rect.
w;
645 else if (caret_index >= 0 && caret_y >= text_rect.
y && caret_y <= text_rect.
y + text_rect.
h) {
650 v[0] = (float) (caret_x + 1);
651 v[1] = (float) (caret_y);
652 v[2] = (float) (caret_x + 1);
653 v[3] = (float) (caret_y + height);
666 static int find_next_word_start(
const char* text,
int index)
669 while (text[index] && isspace(text[index]) && text[index] !=
'\n')
675 static int find_next_word_end(
const char* text,
int index)
681 if (text[index] ==
'\n')
685 while (text[index] && isspace(text[index]))
689 while (text[index] && !isspace(text[index]))
698 Font::DrawTextSingle(
const char* text,
int count,
const Rect& text_rect,
Rect& clip_rect, DWORD flags)
701 bool nodraw = (flags & DT_CALCRECT) ?
true:
false;
704 if (flags & DT_RIGHT)
706 else if (flags & DT_CENTER)
712 if (flags & DT_BOTTOM) valign = DT_BOTTOM;
713 else if (flags & DT_VCENTER) valign = DT_VCENTER;
719 if (length < text_rect.
w) {
723 case DT_RIGHT: xoffset = text_rect.
w - length;
break;
724 case DT_CENTER: xoffset = (text_rect.
w - length)/2;
break;
732 case DT_BOTTOM: yoffset = text_rect.
h -
Height();
break;
733 case DT_VCENTER: yoffset = (text_rect.
h -
Height())/2;
break;
742 clip_rect.
w = max_width;
747 int x1 = text_rect.
x + xoffset;
748 int y1 = text_rect.
y + yoffset;
753 if (caret_index >= 0 && caret_index <= count) {
754 caret_x = text_rect.
x + xoffset;
755 caret_y = text_rect.
y + yoffset;
762 caret_x = text_rect.
x + 0;
763 caret_y = text_rect.
y + 0;
770 Font::DrawTextWrap(
const char* text,
int count,
const Rect& text_rect,
Rect& clip_rect, DWORD flags)
773 bool nodraw = (flags & DT_CALCRECT) ?
true:
false;
776 if (flags & DT_RIGHT)
778 else if (flags & DT_CENTER)
786 int count_remaining = count;
787 int curr_word_end = -1;
788 int next_word_end = 0;
798 while (count_remaining > 0) {
803 next_word_end = find_next_word_end(text, curr_word_end+1);
805 if (next_word_end < 0 || next_word_end == curr_word_end)
808 if (text[next_word_end] ==
'\n') {
809 eol_index = curr_word_end = next_word_end;
813 int word_len = next_word_end - line_start + 1;
817 if (length < text_rect.
w) {
818 curr_word_end = next_word_end;
822 const char* eol = &text[curr_word_end+1];
823 while (*eol && isspace(*eol) && *eol !=
'\n')
827 eol_index = eol - text;
835 line_count = curr_word_end - line_start + 1;
837 if (line_count > 0) {
843 line_count = next_word_end - line_start + 1;
845 curr_word_end = next_word_end;
849 if (length < text_rect.
w) {
853 case DT_RIGHT: xoffset = text_rect.
w - length;
break;
854 case DT_CENTER: xoffset = (text_rect.
w - length)/2;
break;
858 if (length > max_width) max_width = length;
861 curr_word_end = eol_index;
863 int next_line_start = find_next_word_start(text, curr_word_end+1);
865 if (length > 0 && !nodraw) {
866 int x1 = text_rect.
x + xoffset;
867 int y1 = text_rect.
y + yoffset;
869 DrawString(text+line_start, line_count, x1, y1, text_rect);
871 if (caret_index == line_start) {
875 else if (caret_index > line_start && caret_index < next_line_start) {
876 caret_x = text_rect.
x + xoffset +
StringWidth(text+line_start, caret_index-line_start) - 2;
877 caret_y = text_rect.
y + yoffset;
879 else if (caret_index == count) {
880 if (text[count-1] ==
'\n') {
882 caret_y = y1 + height;
885 caret_x = text_rect.
x + xoffset +
StringWidth(text+line_start, caret_index-line_start) - 2;
886 caret_y = text_rect.
y + yoffset;
894 curr_word_end = eol_index;
895 line_start = find_next_word_start(text, curr_word_end+1);
896 count_remaining = count - line_start;
901 clip_rect.
h = nlines *
Height();
902 clip_rect.
w = max_width;
909 Font::DrawTextMulti(
const char* text,
int count,
const Rect& text_rect,
Rect& clip_rect, DWORD flags)
912 bool nodraw = (flags & DT_CALCRECT) ?
true:
false;
915 if (flags & DT_RIGHT)
917 else if (flags & DT_CENTER)
922 int count_remaining = count;
929 while (count_remaining > 0) {
934 while (line_count < count_remaining) {
935 char c = text[line_start+line_count];
942 if (line_count > 0) {
947 if (length < text_rect.
w) {
951 case DT_RIGHT: xoffset = text_rect.
w - length;
break;
952 case DT_CENTER: xoffset = (text_rect.
w - length)/2;
break;
956 if (length > max_width) max_width = length;
958 if (length && !nodraw) {
959 int x1 = text_rect.
x + xoffset;
960 int y1 = text_rect.
y + yoffset;
962 DrawString(text+line_start, line_count, x1, y1, text_rect);
968 if (line_start+line_count+1 < count) {
969 line_start = find_next_word_start(text, line_start+line_count+1);
970 count_remaining = count - line_start;
979 clip_rect.
h = nlines *
Height();
980 clip_rect.
w = max_width;
994 if (len < 1 || !video)
998 if ((y1 < clip.
y) || (y1 > clip.
y + clip.
h))
1007 for (
int i = 0; i < len; i++) {
1010 if ((flags & FONT_ALL_CAPS) && islower(c))
1013 int cw = glyph[c].
width + interspace;
1018 k = kern[c][str[i+1]];
1022 if (isspace(c) && (c < PIPE_NBSP || c >
ARROW_RIGHT)) {
1031 else if (x1+cw > clip.
x+clip.
w) {
1035 if (isspace(c) && (c < PIPE_NBSP || c >
ARROW_RIGHT)) {
1040 int sx = GlyphLocationX(c);
1041 int sy = GlyphLocationY(c);
1045 if (srcpix && dstpix) {
1046 int spitch = bitmap.
Width();
1047 int dpitch = tgt->
Width();
1049 Color* dst = dstpix + (y1*dpitch) + x1;
1050 Color* src = srcpix + (sy*spitch) + sx;
1052 for (
int i = 0; i < ch; i++) {
1056 for (
int n = 0; n < cw; n++) {
1057 DWORD alpha = ps->
Alpha();
1059 *pd = color.
dim(alpha / 240.0);
1071 tgt->
BitBlt(x1, y1, bitmap, sx, sy, cw, ch,
true);
1089 vset =
new(__FILE__,__LINE__)
VertexSet(nverts);
1096 for (
int v = 0; v < vset->
nverts; v++) {
1101 else if (vset->
nverts < nverts) {
1104 for (
int v = 0; v < vset->
nverts; v++) {
1110 if (vset->
nverts < nverts)
1114 color.
SetAlpha((BYTE) (alpha * 255.0f));
1118 for (
int i = 0; i < len; i++) {
1121 if ((flags & FONT_ALL_CAPS) && islower(c))
1124 int cw = glyph[c].
width + interspace;
1128 k = kern[c][str[i+1]];
1132 if (isspace(c) && (c < PIPE_NBSP || c >
ARROW_RIGHT)) {
1141 else if (x1+cw > clip.
x+clip.
w) {
1145 if (isspace(c) && (c < PIPE_NBSP || c >
ARROW_RIGHT)) {
1152 double char_x = GlyphLocationX(c);
1153 double char_y = GlyphLocationY(c);
1154 double char_w = glyph[c].
width;
1155 double char_h = height;
1157 if (y1 + char_h > clip.
y + clip.
h) {
1158 char_h = clip.
y + clip.
h - y1;
1161 vset->
s_loc[v+0].
x = (float) (x1 - 0.5);
1162 vset->
s_loc[v+0].
y = (float) (y1 - 0.5);
1163 vset->
tu[v+0] = (float) (char_x / 256);
1164 vset->
tv[v+0] = (float) (char_y / 256);
1167 vset->
s_loc[v+1].
x = (float) (x1 + char_w - 0.5);
1168 vset->
s_loc[v+1].
y = (float) (y1 - 0.5);
1169 vset->
tu[v+1] = (float) (char_x / 256 + char_w / 256);
1170 vset->
tv[v+1] = (float) (char_y / 256);
1173 vset->
s_loc[v+2].
x = (float) (x1 + char_w - 0.5);
1174 vset->
s_loc[v+2].
y = (float) (y1 + char_h - 0.5);
1175 vset->
tu[v+2] = (float) (char_x / 256 + char_w / 256);
1176 vset->
tv[v+2] = (float) (char_y / 256 + char_h / 256);
1179 vset->
s_loc[v+3].
x = (float) (x1 - 0.5);
1180 vset->
s_loc[v+3].
y = (float) (y1 + char_h - 0.5);
1181 vset->
tu[v+3] = (float) (char_x / 256);
1182 vset->
tv[v+3] = (float) (char_y / 256 + char_h / 256);
1197 int old_nverts = vset->
nverts;
1198 vset->
nverts = 4 * count;
1201 if (count > npolys) {
1206 polys =
new(__FILE__,__LINE__)
Poly[npolys];
1210 for (
int i = 0; i < npolys; i++) {
1214 p->
verts[0] = index++;
1215 p->
verts[1] = index++;
1216 p->
verts[2] = index++;
1217 p->
verts[3] = index++;
1226 vset->
nverts = old_nverts;