gfx.c
changeset 5108 dc67d70b5a45
parent 4958 aaa8a92059bf
child 5155 64f930853bea
equal deleted inserted replaced
5107:8791beb0ae51 5108:dc67d70b5a45
    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;