10 #include "gfx.h" |
10 #include "gfx.h" |
11 #include "table/palettes.h" |
11 #include "table/palettes.h" |
12 #include "table/sprites.h" |
12 #include "table/sprites.h" |
13 #include "hal.h" |
13 #include "hal.h" |
14 #include "variables.h" |
14 #include "variables.h" |
|
15 #include "table/control_codes.h" |
|
16 #include "fontcache.h" |
15 #include "genworld.h" |
17 #include "genworld.h" |
16 |
18 |
17 #ifdef _DEBUG |
19 #ifdef _DEBUG |
18 bool _dbg_screen_rect; |
20 bool _dbg_screen_rect; |
19 #endif |
21 #endif |
242 } |
244 } |
243 } |
245 } |
244 } |
246 } |
245 |
247 |
246 |
248 |
247 static inline SpriteID GetFontBase(FontSize size) |
|
248 { |
|
249 switch (size) { |
|
250 default: NOT_REACHED(); |
|
251 case FS_NORMAL: return SPR_ASCII_SPACE; |
|
252 case FS_SMALL: return SPR_ASCII_SPACE_SMALL; |
|
253 case FS_LARGE: return SPR_ASCII_SPACE_BIG; |
|
254 } |
|
255 } |
|
256 |
|
257 |
|
258 // ASSIGNMENT OF ASCII LETTERS < 32 |
|
259 // 0 - end of string |
|
260 // 1 - SETX <BYTE> |
|
261 // 2 - SETXY <BYTE> <BYTE> |
|
262 // 3-7 - |
|
263 // 8 - TINYFONT |
|
264 // 9 - BIGFONT |
|
265 // 10 - newline |
|
266 // 11-14 - |
|
267 // 15-31 - 17 colors |
|
268 |
|
269 |
|
270 enum { |
|
271 ASCII_SETX = 1, |
|
272 ASCII_SETXY = 2, |
|
273 |
|
274 ASCII_TINYFONT = 8, |
|
275 ASCII_BIGFONT = 9, |
|
276 ASCII_NL = 10, |
|
277 |
|
278 ASCII_COLORSTART = 15, |
|
279 }; |
|
280 |
|
281 /** Truncate a given string to a maximum width if neccessary. |
249 /** Truncate a given string to a maximum width if neccessary. |
282 * If the string is truncated, add three dots ('...') to show this. |
250 * If the string is truncated, add three dots ('...') to show this. |
283 * @param *dest string that is checked and possibly truncated |
251 * @param *dest string that is checked and possibly truncated |
284 * @param maxw maximum width in pixels of the string |
252 * @param maxw maximum width in pixels of the string |
285 * @return new width of (truncated) string */ |
253 * @return new width of (truncated) string */ |
287 { |
255 { |
288 int w = 0; |
256 int w = 0; |
289 FontSize size = _cur_fontsize; |
257 FontSize size = _cur_fontsize; |
290 int ddd, ddd_w; |
258 int ddd, ddd_w; |
291 |
259 |
292 byte c; |
260 WChar c; |
293 char *ddd_pos; |
261 char *ddd_pos; |
294 |
262 |
295 ddd_w = ddd = GetCharacterWidth(size, '.') * 3; |
263 ddd_w = ddd = GetCharacterWidth(size, '.') * 3; |
296 |
264 |
297 for (ddd_pos = str; (c = *str++) != '\0'; ) { |
265 for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) { |
298 if (c >= ASCII_LETTERSTART) { |
266 if (IsPrintable(c)) { |
299 w += GetCharacterWidth(size, c); |
267 w += GetCharacterWidth(size, c); |
300 |
268 |
301 if (w >= maxw) { |
269 if (w >= maxw) { |
302 // string got too big... insert dotdotdot |
270 // string got too big... insert dotdotdot |
303 ddd_pos[0] = ddd_pos[1] = ddd_pos[2] = '.'; |
271 ddd_pos[0] = ddd_pos[1] = ddd_pos[2] = '.'; |
304 ddd_pos[3] = 0; |
272 ddd_pos[3] = 0; |
305 return ddd_w; |
273 return ddd_w; |
306 } |
274 } |
307 } else { |
275 } else { |
308 if (c == ASCII_SETX) str++; |
276 if (c == SCC_SETX) str++; |
309 else if (c == ASCII_SETXY) str += 2; |
277 else if (c == SCC_SETXY) str += 2; |
310 else if (c == ASCII_TINYFONT) { |
278 else if (c == SCC_TINYFONT) { |
311 size = FS_SMALL; |
279 size = FS_SMALL; |
312 ddd = GetCharacterWidth(size, '.') * 3; |
280 ddd = GetCharacterWidth(size, '.') * 3; |
313 } else if (c == ASCII_BIGFONT) { |
281 } else if (c == SCC_BIGFONT) { |
314 size = FS_LARGE; |
282 size = FS_LARGE; |
315 ddd = GetCharacterWidth(size, '.') * 3; |
283 ddd = GetCharacterWidth(size, '.') * 3; |
316 } |
284 } |
317 } |
285 } |
318 |
286 |
441 for (;;) { |
409 for (;;) { |
442 char *last_space = NULL; |
410 char *last_space = NULL; |
443 int w = 0; |
411 int w = 0; |
444 |
412 |
445 for (;;) { |
413 for (;;) { |
446 byte c = *str++; |
414 WChar c = Utf8Consume((const char **)&str); |
447 /* whitespace is where we will insert the line-break */ |
415 /* whitespace is where we will insert the line-break */ |
448 if (c == ASCII_LETTERSTART) last_space = str; |
416 if (c == ' ') last_space = str; |
449 |
417 |
450 if (c >= ASCII_LETTERSTART) { |
418 if (IsPrintable(c)) { |
451 w += GetCharacterWidth(size, c); |
419 w += GetCharacterWidth(size, c); |
452 /* string is longer than maximum width so we need to decide what to |
420 /* string is longer than maximum width so we need to decide what to |
453 * do. We can do two things: |
421 * do. We can do two things: |
454 * 1. If no whitespace was found at all up until now (on this line) then |
422 * 1. If no whitespace was found at all up until now (on this line) then |
455 * we will truncate the string and bail out. |
423 * we will truncate the string and bail out. |
463 break; |
431 break; |
464 } |
432 } |
465 } else { |
433 } else { |
466 switch (c) { |
434 switch (c) { |
467 case '\0': return num + (size << 16); break; |
435 case '\0': return num + (size << 16); break; |
468 case ASCII_SETX: str++; break; |
436 case SCC_SETX: str++; break; |
469 case ASCII_SETXY: str +=2; break; |
437 case SCC_SETXY: str +=2; break; |
470 case ASCII_TINYFONT: size = FS_SMALL; break; |
438 case SCC_TINYFONT: size = FS_SMALL; break; |
471 case ASCII_BIGFONT: size = FS_LARGE; break; |
439 case SCC_BIGFONT: size = FS_LARGE; break; |
472 case ASCII_NL: goto end_of_inner_loop; |
440 case '\n': goto end_of_inner_loop; |
473 } |
441 } |
474 } |
442 } |
475 } |
443 } |
476 end_of_inner_loop: |
444 end_of_inner_loop: |
477 /* string didn't fit on line, so 'dummy' terminate and increase linecount */ |
445 /* string didn't fit on line, so 'dummy' terminate and increase linecount */ |
484 { |
452 { |
485 char buffer[512]; |
453 char buffer[512]; |
486 uint32 tmp; |
454 uint32 tmp; |
487 int num, w, mt; |
455 int num, w, mt; |
488 const char *src; |
456 const char *src; |
489 byte c; |
457 WChar c; |
490 |
458 |
491 GetString(buffer, str, lastof(buffer)); |
459 GetString(buffer, str, lastof(buffer)); |
492 |
460 |
493 tmp = FormatStringLinebreaks(buffer, maxw); |
461 tmp = FormatStringLinebreaks(buffer, maxw); |
494 num = GB(tmp, 0, 16); |
462 num = GB(tmp, 0, 16); |
503 w = GetStringBoundingBox(src).width; |
471 w = GetStringBoundingBox(src).width; |
504 DoDrawString(src, x - (w>>1), y, 0xFE); |
472 DoDrawString(src, x - (w>>1), y, 0xFE); |
505 _cur_fontsize = _last_fontsize; |
473 _cur_fontsize = _last_fontsize; |
506 |
474 |
507 for (;;) { |
475 for (;;) { |
508 c = *src++; |
476 c = Utf8Consume(&src); |
509 if (c == 0) { |
477 if (c == 0) { |
510 y += mt; |
478 y += mt; |
511 if (--num < 0) { |
479 if (--num < 0) { |
512 _cur_fontsize = FS_NORMAL; |
480 _cur_fontsize = FS_NORMAL; |
513 return; |
481 return; |
514 } |
482 } |
515 break; |
483 break; |
516 } else if (c == ASCII_SETX) { |
484 } else if (c == SCC_SETX) { |
517 src++; |
485 src++; |
518 } else if (c == ASCII_SETXY) { |
486 } else if (c == SCC_SETXY) { |
519 src+=2; |
487 src+=2; |
520 } |
488 } |
521 } |
489 } |
522 } |
490 } |
523 } |
491 } |
528 char buffer[512]; |
496 char buffer[512]; |
529 uint32 tmp; |
497 uint32 tmp; |
530 int num, mt; |
498 int num, mt; |
531 uint total_height; |
499 uint total_height; |
532 const char *src; |
500 const char *src; |
533 byte c; |
501 WChar c; |
534 |
502 |
535 GetString(buffer, str, lastof(buffer)); |
503 GetString(buffer, str, lastof(buffer)); |
536 |
504 |
537 tmp = FormatStringLinebreaks(buffer, maxw); |
505 tmp = FormatStringLinebreaks(buffer, maxw); |
538 num = GB(tmp, 0, 16); |
506 num = GB(tmp, 0, 16); |
545 for (;;) { |
513 for (;;) { |
546 DoDrawString(src, x, y, 0xFE); |
514 DoDrawString(src, x, y, 0xFE); |
547 _cur_fontsize = _last_fontsize; |
515 _cur_fontsize = _last_fontsize; |
548 |
516 |
549 for (;;) { |
517 for (;;) { |
550 c = *src++; |
518 c = Utf8Consume(&src); |
551 if (c == 0) { |
519 if (c == 0) { |
552 y += mt; |
520 y += mt; |
553 if (--num < 0) { |
521 if (--num < 0) { |
554 _cur_fontsize = FS_NORMAL; |
522 _cur_fontsize = FS_NORMAL; |
555 return total_height; |
523 return total_height; |
556 } |
524 } |
557 break; |
525 break; |
558 } else if (c == ASCII_SETX) { |
526 } else if (c == SCC_SETX) { |
559 src++; |
527 src++; |
560 } else if (c == ASCII_SETXY) { |
528 } else if (c == SCC_SETXY) { |
561 src+=2; |
529 src+=2; |
562 } |
530 } |
563 } |
531 } |
564 } |
532 } |
565 } |
533 } |
574 BoundingRect GetStringBoundingBox(const char *str) |
542 BoundingRect GetStringBoundingBox(const char *str) |
575 { |
543 { |
576 FontSize size = _cur_fontsize; |
544 FontSize size = _cur_fontsize; |
577 BoundingRect br; |
545 BoundingRect br; |
578 int max_width; |
546 int max_width; |
579 byte c; |
547 WChar c; |
580 |
548 |
581 br.width = br.height = max_width = 0; |
549 br.width = br.height = max_width = 0; |
582 for (c = *str; c != '\0'; c = *(++str)) { |
550 for (;;) { |
583 if (c >= ASCII_LETTERSTART) { |
551 c = Utf8Consume(&str); |
|
552 if (c == 0) break; |
|
553 if (IsPrintable(c)) { |
584 br.width += GetCharacterWidth(size, c); |
554 br.width += GetCharacterWidth(size, c); |
585 } else { |
555 } else { |
586 switch (c) { |
556 switch (c) { |
587 case ASCII_SETX: br.width += (byte)*++str; break; |
557 case SCC_SETX: br.width += (byte)*++str; break; |
588 case ASCII_SETXY: |
558 case SCC_SETXY: |
589 br.width += (byte)*++str; |
559 br.width += (byte)*++str; |
590 br.height += (byte)*++str; |
560 br.height += (byte)*++str; |
591 break; |
561 break; |
592 case ASCII_TINYFONT: size = FS_SMALL; break; |
562 case SCC_TINYFONT: size = FS_SMALL; break; |
593 case ASCII_BIGFONT: size = FS_LARGE; break; |
563 case SCC_BIGFONT: size = FS_LARGE; break; |
594 case ASCII_NL: |
564 case '\n': |
595 br.height += GetCharacterHeight(size); |
565 br.height += GetCharacterHeight(size); |
596 if (br.width > max_width) max_width = br.width; |
566 if (br.width > max_width) max_width = br.width; |
597 br.width = 0; |
567 br.width = 0; |
598 break; |
568 break; |
599 } |
569 } |
615 * the originally passed x-coordinate is returned */ |
585 * the originally passed x-coordinate is returned */ |
616 int DoDrawString(const char *string, int x, int y, uint16 real_color) |
586 int DoDrawString(const char *string, int x, int y, uint16 real_color) |
617 { |
587 { |
618 DrawPixelInfo *dpi = _cur_dpi; |
588 DrawPixelInfo *dpi = _cur_dpi; |
619 FontSize size = _cur_fontsize; |
589 FontSize size = _cur_fontsize; |
620 byte c; |
590 WChar c; |
621 byte color; |
591 byte color; |
622 int xo = x, yo = y; |
592 int xo = x, yo = y; |
623 |
593 |
624 color = real_color & 0xFF; |
594 color = real_color & 0xFF; |
625 |
595 |
645 |
615 |
646 check_bounds: |
616 check_bounds: |
647 if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) { |
617 if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) { |
648 skip_char:; |
618 skip_char:; |
649 for (;;) { |
619 for (;;) { |
650 c = *string++; |
620 c = Utf8Consume(&string); |
651 if (c < ASCII_LETTERSTART) goto skip_cont; |
621 if (!IsPrintable(c)) goto skip_cont; |
652 } |
622 } |
653 } |
623 } |
654 |
624 |
655 for (;;) { |
625 for (;;) { |
656 c = *string++; |
626 c = Utf8Consume(&string); |
657 skip_cont:; |
627 skip_cont:; |
658 if (c == 0) { |
628 if (c == 0) { |
659 _last_fontsize = size; |
629 _last_fontsize = size; |
660 return x; |
630 return x; |
661 } |
631 } |
662 if (c >= ASCII_LETTERSTART) { |
632 if (IsPrintable(c)) { |
663 if (x >= dpi->left + dpi->width) goto skip_char; |
633 if (x >= dpi->left + dpi->width) goto skip_char; |
664 if (x + 26 >= dpi->left) { |
634 if (x + 26 >= dpi->left) { |
665 GfxMainBlitter(GetSprite(GetFontBase(size) + c - ASCII_LETTERSTART), x, y, 1); |
635 GfxMainBlitter(GetGlyph(size, c), x, y, 1); |
666 } |
636 } |
667 x += GetCharacterWidth(size, c); |
637 x += GetCharacterWidth(size, c); |
668 } else if (c == ASCII_NL) { // newline = {} |
638 } else if (c == '\n') { // newline = {} |
669 x = xo; |
639 x = xo; |
670 y += GetCharacterHeight(size); |
640 y += GetCharacterHeight(size); |
671 goto check_bounds; |
641 goto check_bounds; |
672 } else if (c >= ASCII_COLORSTART) { // change color? |
642 } else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change color? |
673 color = (byte)(c - ASCII_COLORSTART); |
643 color = (byte)(c - SCC_BLUE); |
674 goto switch_color; |
644 goto switch_color; |
675 } else if (c == ASCII_SETX) { // {SETX} |
645 } else if (c == SCC_SETX) { // {SETX} |
676 x = xo + (byte)*string++; |
646 x = xo + (byte)*string++; |
677 } else if (c == ASCII_SETXY) {// {SETXY} |
647 } else if (c == SCC_SETXY) {// {SETXY} |
678 x = xo + (byte)*string++; |
648 x = xo + (byte)*string++; |
679 y = yo + (byte)*string++; |
649 y = yo + (byte)*string++; |
680 } else if (c == ASCII_TINYFONT) { // {TINYFONT} |
650 } else if (c == SCC_TINYFONT) { // {TINYFONT} |
681 size = FS_SMALL; |
651 size = FS_SMALL; |
682 } else if (c == ASCII_BIGFONT) { // {BIGFONT} |
652 } else if (c == SCC_BIGFONT) { // {BIGFONT} |
683 size = FS_LARGE; |
653 size = FS_LARGE; |
684 } else { |
654 } else { |
685 printf("Unknown string command character %d\n", c); |
655 printf("Unknown string command character %d\n", c); |
686 } |
656 } |
687 } |
657 } |
1639 } |
1609 } |
1640 |
1610 |
1641 |
1611 |
1642 void LoadStringWidthTable(void) |
1612 void LoadStringWidthTable(void) |
1643 { |
1613 { |
1644 SpriteID base; |
|
1645 uint i; |
1614 uint i; |
1646 |
1615 |
1647 /* Normal font */ |
1616 /* Normal font */ |
1648 base = GetFontBase(FS_NORMAL); |
|
1649 for (i = 0; i != 224; i++) { |
1617 for (i = 0; i != 224; i++) { |
1650 _stringwidth_table[FS_NORMAL][i] = SpriteExists(base + i) ? GetSprite(base + i)->width : 0; |
1618 _stringwidth_table[FS_NORMAL][i] = GetGlyphWidth(FS_NORMAL, i + 32); |
1651 } |
1619 } |
1652 |
1620 |
1653 /* Small font */ |
1621 /* Small font */ |
1654 base = GetFontBase(FS_SMALL); |
|
1655 for (i = 0; i != 224; i++) { |
1622 for (i = 0; i != 224; i++) { |
1656 _stringwidth_table[FS_SMALL][i] = SpriteExists(base + i) ? GetSprite(base + i)->width + 1 : 0; |
1623 _stringwidth_table[FS_SMALL][i] = GetGlyphWidth(FS_SMALL, i + 32); |
1657 } |
1624 } |
1658 |
1625 |
1659 /* Large font */ |
1626 /* Large font */ |
1660 base = GetFontBase(FS_LARGE); |
|
1661 for (i = 0; i != 224; i++) { |
1627 for (i = 0; i != 224; i++) { |
1662 _stringwidth_table[FS_LARGE][i] = SpriteExists(base + i) ? GetSprite(base + i)->width + 1 : 0; |
1628 _stringwidth_table[FS_LARGE][i] = GetGlyphWidth(FS_LARGE, i + 32); |
1663 } |
1629 } |
1664 } |
1630 } |
|
1631 |
|
1632 |
|
1633 byte GetCharacterWidth(FontSize size, WChar key) |
|
1634 { |
|
1635 if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32]; |
|
1636 |
|
1637 return GetGlyphWidth(size, key); |
|
1638 } |
|
1639 |
1665 |
1640 |
1666 void ScreenSizeChanged(void) |
1641 void ScreenSizeChanged(void) |
1667 { |
1642 { |
1668 // check the dirty rect |
1643 // check the dirty rect |
1669 if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width; |
1644 if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width; |