Beispiel #1
0
void Font::Print(Region cliprgn, Region rgn, const unsigned char* string,
                 Palette* hicolor, unsigned char Alignment, bool anchor, Font* initials,
                 Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
    bool enablecap=false;
    int capital = 0;
    if (initials)
    {
        capital=1;
        enablecap=true;
    }
    (void)enablecap; //HACK: shut up unused-but-set warnings, until the var is reused

    unsigned int psx = PARAGRAPH_START_X;
    Palette* pal = hicolor;
    if (!pal) {
        pal = palette;
    }
    if (initials==this) {
        initials = NULL;
    }

    sprBuffer->SetPalette( pal );
    size_t len = strlen( ( char* ) string );
    char* tmp = ( char* ) malloc( len + 1 );
    memcpy( tmp, ( char * ) string, len + 1 );
    while (len > 0 && (tmp[len - 1] == '\n' || tmp[len - 1] == '\r')) {
        // ignore trailing newlines
        tmp[len - 1] = 0;
        len--;
    }

    SetupString( tmp, rgn.w, NoColor, initials, capital );
    int ystep = 0;
    if (Alignment & IE_FONT_SINGLE_LINE) {

        for (size_t i = 0; i < len; i++) {
            if (tmp[i] == 0) continue;
            int height = yPos[( unsigned char ) tmp[i] - 1];
            if (ystep < height)
                ystep = height;
        }
    } else {
        ystep = size[1].h;
    }
    if (!ystep) ystep = maxHeight;
    int x = psx, y = ystep;
    Video* video = core->GetVideoDriver();

    if (Alignment & IE_FONT_ALIGN_CENTER) {
        int w = CalcStringWidth( tmp, NoColor );
        x = ( rgn.w - w ) / 2;
    } else if (Alignment & IE_FONT_ALIGN_RIGHT) {
        int w = CalcStringWidth( tmp, NoColor );
        x = ( rgn.w - w );
    }

    if (Alignment & IE_FONT_ALIGN_MIDDLE) {
        int h = 0;
        for (size_t i = 0; i <= len; i++) {
            if (tmp[i] == 0)
                h++;
        }
        h = h * ystep;
        y += ( rgn.h - h ) / 2;
    } else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
        int h = 1;
        for (size_t i = 0; i <= len; i++) {
            if (tmp[i] == 0)
                h++;
        }
        h = h * ystep;
        y += ( rgn.h - h );
    } else if (Alignment & IE_FONT_ALIGN_TOP) {
        y += 5;
    }
    for (size_t i = 0; i < len; i++) {
        if (( ( unsigned char ) tmp[i] ) == '[' && !NoColor) {
            i++;
            char tag[256];
            tag[0]=0;
            for (int k = 0; k < 256 && i<len; k++) {
                if (tmp[i] == ']') {
                    tag[k] = 0;
                    break;
                }
                tag[k] = tmp[i++];
            }

            if (strnicmp( tag, "capital=",8)==0) {
                sscanf( tag, "capital=%d", &capital);
                if (capital) {
                    enablecap=true;
                }
                continue;
            }

            if (strnicmp( tag, "color=", 6 ) == 0) {
                unsigned int r,g,b;
                if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
                    continue;
                const Color c = {(unsigned char) r,(unsigned char) g,(unsigned char)  b, 0};
                Palette* newPal = core->CreatePalette( c, palette->back );
                sprBuffer->SetPalette( newPal );
                gamedata->FreePalette( newPal );
                continue;
            }
            if (stricmp( tag, "/color" ) == 0) {
                sprBuffer->SetPalette( pal );
                continue;
            }
            if (stricmp( "p", tag ) == 0) {
                psx = x;
                continue;
            }
            if (stricmp( "/p", tag ) == 0) {
                psx = PARAGRAPH_START_X;
                continue;
            }
            continue;
        }

        if (tmp[i] == 0) {
            y += ystep;
            x = psx;
            int w = CalcStringWidth( &tmp[i + 1], NoColor );
            if (Alignment & IE_FONT_ALIGN_CENTER) {
                x = ( rgn.w - w ) / 2;
            } else if (Alignment & IE_FONT_ALIGN_RIGHT) {
                x = ( rgn.w - w );
            }
            continue;
        }
        unsigned char currChar = ( unsigned char ) tmp[i] - 1;
        if (initials && capital) {
            x = initials->PrintInitial( x, y, rgn, currChar );
            enablecap=false;
            continue;
        }
        video->BlitSpriteRegion( sprBuffer, size[currChar],
                                 x + rgn.x, y + rgn.y - yPos[currChar],
                                 anchor, &cliprgn );
        if (cursor && ( curpos == i ))
            video->BlitSprite( cursor, x + rgn.x, y + rgn.y, anchor, &cliprgn );
        x += size[currChar].w;
    }
    if (cursor && ( curpos == len )) {
        video->BlitSprite( cursor, x + rgn.x, y + rgn.y, anchor, &cliprgn );
    }
    free( tmp );
}
Beispiel #2
0
void Font::PrintFromLine(int startrow, Region rgn, const unsigned char* string,
                         Palette* hicolor, unsigned char Alignment, Font* initials,
                         Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
    bool enablecap=false;
    int capital = 0;
    int initials_rows = 0;
    int last_initial_row = 0;
    int initials_x = 0;
    int initials_row = 0;
    unsigned char currCap = 0;
    size_t len = strlen( ( char* ) string );
    int num_empty_rows = 0;

    if (initials)
    {
        capital=1;
        enablecap=true;
        initials_rows = ((initials->maxHeight - 1) / maxHeight) - (startrow - 1);

        currCap = string[0] - 1;
        if ((startrow > 0 && initials_rows > 0) || (len > 0 && isspace(currCap))) { // we need to look back to get the cap
            while(isspace(currCap) && num_empty_rows < (int)len) { //we cant cap whitespace so keep looking
                currCap = string[++num_empty_rows] - 1;
                // WARNING: this assumes all preceeding whitespace is an empty line
            }
            last_initial_row = (startrow - 1);
            initials_rows--;
        }
    }

    unsigned int psx = PARAGRAPH_START_X;
    Palette *pal = hicolor;
    if (!pal) {
        pal = palette;
    }

    if (initials==this) {
        enablecap=false;
    }

    sprBuffer->SetPalette( pal );

    char* tmp = ( char* ) malloc( len + 1 );
    memcpy( tmp, ( char * ) string, len + 1 );
    SetupString( tmp, rgn.w, NoColor, initials, enablecap );

    if (startrow) enablecap=false;
    int ystep = 0;
    if (Alignment & IE_FONT_SINGLE_LINE) {
        for (size_t i = 0; i < len; i++) {
            int height = yPos[( unsigned char ) tmp[i] - 1];
            if (ystep < height)
                ystep = height;
        }
    } else {
        ystep = size[1].h;
    }
    if (!ystep) ystep = maxHeight;
    int x = psx, y = ystep;
    int w = CalcStringWidth( tmp, NoColor );
    if (Alignment & IE_FONT_ALIGN_CENTER) {
        x = ( rgn.w - w) / 2;
    } else if (Alignment & IE_FONT_ALIGN_RIGHT) {
        x = ( rgn.w - w );
    }
    if (Alignment & IE_FONT_ALIGN_MIDDLE) {
        int h = 0;
        for (size_t i = 0; i <= len; i++) {
            if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
                h++;
        }
        h = h * ystep;
        y += ( rgn.h - h ) / 2;
    } else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
        int h = 1;
        for (size_t i = 0; i <= len; i++) {
            if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
                h++;
        }
        h = h * ystep;
        y += ( rgn.h - h );
    } else if (Alignment & IE_FONT_ALIGN_TOP) {
        y += 5;
    }

    Video* video = core->GetVideoDriver();
    int row = 0;
    for (size_t i = 0; i < len; i++) {
        if (( ( unsigned char ) tmp[i] ) == '[' && !NoColor) {
            i++;
            char tag[256];
            tag[0]=0;

            for (int k = 0; k < 256 && i<len; k++) {
                if (tmp[i] == ']') {
                    tag[k] = 0;
                    break;
                }
                tag[k] = tmp[i++];
            }

            if (strnicmp( tag, "capital=",8)==0) {
                sscanf( tag, "capital=%d", &capital);
                if (capital && (row>=startrow) ) {
                    enablecap=true;
                }
                continue;
            }

            if (strnicmp( tag, "color=", 6 ) == 0) {
                unsigned int r,g,b;
                if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
                    continue;
                const Color c = {(unsigned char) r,(unsigned char)g, (unsigned char)b, 0};
                Palette* newPal = core->CreatePalette( c, palette->back );
                sprBuffer->SetPalette( newPal );
                gamedata->FreePalette( newPal );
                continue;
            }
            if (stricmp( tag, "/color" ) == 0) {
                sprBuffer->SetPalette( pal );
                continue;
            }
            if (stricmp( "p", tag ) == 0) {
                psx = x;
                continue;
            }
            if (stricmp( "/p", tag ) == 0) {
                psx = PARAGRAPH_START_X;
            }
            continue;
        }

        if (row < startrow) {
            if (tmp[i] == 0) {
                row++;
            }
            continue;
        }
        if (( tmp[i] == 0 ) || ( tmp[i] == '\n' )) {
            y += ystep;
            x = psx;
            int w = CalcStringWidth( &tmp[i + 1], NoColor );
            if (initials_rows > 0) {
                initials_rows--;
                x += initials_x;
                w += initials_x;
            }
            if (Alignment & IE_FONT_ALIGN_CENTER) {
                x = ( rgn.w - w ) / 2;
            } else if (Alignment & IE_FONT_ALIGN_RIGHT) {
                x = ( rgn.w - w );
            }
            continue;
        }
        unsigned char currChar = ( unsigned char ) tmp[i] - 1;
        if (initials && capital && enablecap) {
            currCap = currChar;
            x = initials->PrintInitial( x, y, rgn, currChar );
            initials_x = x;

            //how many more lines to be indented (one was already indented)
            initials_rows = (initials->maxHeight-1)/maxHeight;
            initials_row = row;
            last_initial_row = initials_row;

            enablecap = false;
            continue;
        } else if(initials && currCap && row > last_initial_row && (row - num_empty_rows - initials_row) <= ((initials->maxHeight-1)/maxHeight)) {
            // means this row doesnt have a cap, but a preceeding one did and its overlapping this row
            int initY = y;
            if (!num_empty_rows) {// num_empty_rows is for scrolling text areas
                initY = (y - (maxHeight * (row - initials_row)));
            }
            x = initials->PrintInitial( x, initY, rgn, currCap );
            initials_x = x;
            x += psx;
            last_initial_row++;
        }
        video->BlitSpriteRegion( sprBuffer, size[currChar],
                                 x + rgn.x, y + rgn.y - yPos[currChar], true, &rgn );
        if (cursor && ( i == curpos )) {
            video->BlitSprite( cursor, x + rgn.x,
                               y + rgn.y, true, &rgn );
        }
        x += size[currChar].w;
    }
    if (cursor && ( curpos == len )) {
        video->BlitSprite( cursor, x + rgn.x,
                           y + rgn.y, true, &rgn );
    }
    free( tmp );
}
static Lexer Setup(const char *string)
{
	return SetupString(String_FromC(string));
}
Beispiel #4
0
void Font::PrintFromLine(int startrow, Region rgn, const unsigned char* string,
	Palette* hicolor, unsigned char Alignment, Font* initials,
	Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
	bool enablecap=false;
	int capital = 0;
	if (initials)
	{
		capital=1;
		enablecap=true;
	}
	int initials_rows = 0;
	int initials_x = 0;

	unsigned int psx = PARAGRAPH_START_X;
	Palette *pal = hicolor;
	if (!pal) {
		pal = palette;
	}
	if (startrow) enablecap=false;

	if (initials==this) {
		enablecap=false;
	}

	sprBuffer->SetPalette( pal );
	size_t len = strlen( ( char* ) string );
	char* tmp = ( char* ) malloc( len + 1 );
	memcpy( tmp, ( char * ) string, len + 1 );
	SetupString( tmp, rgn.w, NoColor, initials, enablecap );
	int ystep = 0;
	if (Alignment & IE_FONT_SINGLE_LINE) {
		for (size_t i = 0; i < len; i++) {
			int height = yPos[( unsigned char ) tmp[i] - 1];
			if (ystep < height)
				ystep = height;
		}
	} else {
		ystep = size[1].h;
	}
	if (!ystep) ystep = maxHeight;
	int x = psx, y = ystep;
	int w = CalcStringWidth( tmp, NoColor );
	if (Alignment & IE_FONT_ALIGN_CENTER) {
		x = ( rgn.w - w) / 2;
	} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
		x = ( rgn.w - w );
	}
	if (Alignment & IE_FONT_ALIGN_MIDDLE) {
		int h = 0;
		for (size_t i = 0; i <= len; i++) {
			if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
				h++;
		}
		h = h * ystep;
		y += ( rgn.h - h ) / 2;
	} else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
		int h = 1;
		for (size_t i = 0; i <= len; i++) {
			if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
				h++;
		}
		h = h * ystep;
		y += ( rgn.h - h );
	} else if (Alignment & IE_FONT_ALIGN_TOP) {
		y += 5;
	}

	Video* video = core->GetVideoDriver();
	int row = 0;
	for (size_t i = 0; i < len; i++) {
		if (( ( unsigned char ) tmp[i] ) == '[' && !NoColor) {
			i++;
			char tag[256];
			tag[0]=0;

			for (int k = 0; k < 256 && i<len; k++) {
				if (tmp[i] == ']') {
					tag[k] = 0;
					break;
				}
				tag[k] = tmp[i++];
			}

			if (strnicmp( tag, "capital=",8)==0) {
				sscanf( tag, "capital=%d", &capital);
				if (capital && (row>=startrow) ) {
					enablecap=true;
				}
				continue;
			}

			
			if (strnicmp( tag, "color=", 6 ) == 0) {
				unsigned int r,g,b;
				if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
					continue;
				const Color c = {(unsigned char) r,(unsigned char)g, (unsigned char)b, 0};
				Palette* newPal = core->CreatePalette( c, palette->back );
				sprBuffer->SetPalette( newPal );
				gamedata->FreePalette( newPal );
				continue;
			}
			if (stricmp( tag, "/color" ) == 0) {
				sprBuffer->SetPalette( pal );
				continue;
			}
			
			if (stricmp( "p", tag ) == 0) {
				psx = x;
				continue;
			}
			if (stricmp( "/p", tag ) == 0) {
				psx = PARAGRAPH_START_X;
			}
			continue;
		}

		if (row < startrow) {
			if (tmp[i] == 0) {
				row++;
			}
			continue;
		}
		if (( tmp[i] == 0 ) || ( tmp[i] == '\n' )) {
			y += ystep;
			x = psx;
			int w = CalcStringWidth( &tmp[i + 1], NoColor );
			if (initials_rows > 0) {
				initials_rows--;
				x += initials_x;
				w += initials_x;
			}
			if (Alignment & IE_FONT_ALIGN_CENTER) {
				x = ( rgn.w - w ) / 2;
			} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
				x = ( rgn.w - w );
			}
			continue;
		}
		unsigned char currChar = ( unsigned char ) tmp[i] - 1;
		if (initials && capital && enablecap) {
			x = initials->PrintInitial( x, y, rgn, currChar );
			initials_x = x;

			//how many more lines to be indented (one was already indented)
			initials_rows = (initials->maxHeight-1)/maxHeight;
			enablecap = false;
			continue;
		}
		video->BlitSpriteRegion( sprBuffer, size[currChar],
			x + rgn.x, y + rgn.y - yPos[currChar], true, &rgn );
		if (cursor && ( i == curpos )) {
			video->BlitSprite( cursor, x + rgn.x,
				y + rgn.y, true, &rgn );
		}
		x += size[currChar].w;
	}
	if (cursor && ( curpos == len )) {
		video->BlitSprite( cursor, x + rgn.x,
			y + rgn.y, true, &rgn );
	}
	free( tmp );
}
Beispiel #5
0
void Font::PrintFromLine(int startrow, Region rgn, const unsigned char* string,
	Palette* hicolor, ieByte Alignment, Font* initials,
	Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
	bool enablecap=false;
	int capital = 0;
	int initials_rows = 0;
	int last_initial_row = 0;
	int initials_x = 0;
	int initials_row = 0;
	ieWord currCap = 0;
	ieWord* tmp = NULL;
	size_t len = GetDoubleByteString(string, tmp);

	ieWord num_empty_rows = 0;

	if (initials && initials != this)
	{
		capital=1;
		enablecap=true;
		initials_rows = 1 + ((initials->maxHeight - 1) / maxHeight); // ceiling
		currCap = string[0];
		if ((startrow > 0 && initials_rows > 0) || (len > 0 && isspace(currCap))) { // we need to look back to get the cap
			while(isspace(currCap) && num_empty_rows < len){//we cant cap whiteSpace so keep looking
				currCap = string[++num_empty_rows];
				// WARNING: this assumes all preceeding whiteSpace is an empty line
			}
			last_initial_row = startrow - 1; // always the row before current since this cannot be the first row
			initials_rows = initials_rows - (startrow + 1) + num_empty_rows; // startrow + 1 because start row is 0 based, but initials_rows is 1 based
		}
	}

	unsigned int psx = IE_FONT_PADDING;
	Palette *pal = hicolor;
	if (!pal) {
		pal = palette;
	}

	Holder<Palette> blitPalette = pal;

	SetupString( tmp, rgn.w, NoColor, initials, enablecap );

	if (startrow) enablecap=false;
	int ystep;
	if (Alignment & IE_FONT_SINGLE_LINE) {
		ystep = CalcStringHeight(tmp, len, NoColor);
		if (!ystep) ystep = maxHeight;
	} else {
		ystep = maxHeight;
	}
	int x = psx, y = ystep;
	size_t w = CalcStringWidth( tmp, NoColor );
	if (Alignment & IE_FONT_ALIGN_CENTER) {
		x = ( rgn.w - w) / 2;
	} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
		x = ( rgn.w - w ) - IE_FONT_PADDING;
	}
	if (Alignment & IE_FONT_ALIGN_MIDDLE) {
		int h = 0;
		for (size_t i = 0; i <= len; i++) {
			if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
				h++;
		}
		h = h * ystep;
		y += ( rgn.h - h ) / 2;
	} else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
		int h = 0;
		for (size_t i = 0; i <= len; i++) {
			if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
				h++;
		}
		h = h * ystep;
		y += ( rgn.h - h ) - IE_FONT_PADDING;
	} else if (Alignment & IE_FONT_ALIGN_TOP) {
		y += IE_FONT_PADDING;
	}

	Video* video = core->GetVideoDriver();
	const Sprite2D* currGlyph;
	ieWord currChar = '\0';
	int row = 0;
	for (size_t i = 0; i < len; i++) {
		if (( tmp[i] ) == '[' && !NoColor) {
			i++;
			char tag[256];
			tag[0]=0;

			for (size_t k = 0; k < 256 && i<len; k++) {
				if (tmp[i] == ']') {
					tag[k] = 0;
					break;
				}
				tag[k] = tmp[i++];
			}

			if (strnicmp( tag, "capital=",8)==0) {
				sscanf( tag, "capital=%d", &capital);
				if (capital && (row>=startrow) ) {
					enablecap=true;
				}
				continue;
			}

			if (strnicmp( tag, "color=", 6 ) == 0) {
				unsigned int r,g,b;
				if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
					continue;
				const Color c = {(unsigned char)r, (unsigned char)g, (unsigned char)b, 0};
				Palette* newPal = core->CreatePalette( c, palette->back );
				blitPalette = newPal;
				gamedata->FreePalette( newPal );
				continue;
			}
			if (stricmp( tag, "/color" ) == 0) {
				blitPalette = pal;
				continue;
			}
			if (stricmp( "p", tag ) == 0) {
				psx = x;
				continue;
			}
			if (stricmp( "/p", tag ) == 0) {
				psx = IE_FONT_PADDING;
			}
			continue;
		}

		if (row < startrow) {
			if (tmp[i] == 0) {
				row++;
			}
			continue;
		}
		if (( tmp[i] == 0 ) || ( tmp[i] == '\n' )) {
			y += ystep;
			x = psx;
			size_t w = CalcStringWidth( &tmp[i + 1], NoColor );
			if (initials_rows > 0) {
				initials_rows--;
				x += initials_x;
				w += initials_x;
			}
			if (Alignment & IE_FONT_ALIGN_CENTER) {
				x = ( rgn.w - w ) / 2;
			} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
				x = ( rgn.w - w );
			}
			continue;
		}
		currChar = tmp[i];
		if (initials && capital && enablecap) {
			currCap = currChar;
			x = initials->PrintInitial( x, y, rgn, currChar );
			initials_x = x;

			//how many more lines to be indented (one was already indented)
			initials_rows = (initials->maxHeight - 1) / maxHeight;
			initials_rows += num_empty_rows;
			initials_row = row;
			last_initial_row = initials_row;

			enablecap = false;
			continue;
		} else if (initials && currCap
				   && row > last_initial_row
				   && (row - num_empty_rows - initials_row) <= ((initials->maxHeight-1)/maxHeight)){
			// means this row doesnt have a cap, but a preceeding one did and its overlapping this row
			int initY = y;
			if (!num_empty_rows || row > num_empty_rows) {// num_empty_rows is for scrolling text areas
				initY = (y - (maxHeight * (row - initials_row - num_empty_rows)));
			}
			x = initials->PrintInitial( x, initY, rgn, currCap );
			initials_x = x;
			last_initial_row++;
			if (num_empty_rows && row <= num_empty_rows) continue;
			else x += psx;
		}
		if (i > 0) {
			// kerning
			x -= GetKerningOffset(tmp[i-1], currChar);
		}
		currGlyph = GetCharSprite(currChar);
		video->BlitSprite(currGlyph, x + rgn.x, y + rgn.y, true, &rgn, blitPalette.get());
		if (cursor && ( i == curpos )) {
			video->BlitSprite( cursor, x + rgn.x, y + rgn.y, true, &rgn );
		}
		x += currGlyph->Width;
	}
	if (cursor && ( curpos == len )) {
		video->BlitSprite( cursor, x + rgn.x, y + rgn.y, true, &rgn );
	}
	blitPalette = NULL;
	free( tmp );
}
Beispiel #6
0
void Font::Print(Region cliprgn, Region rgn, const unsigned char* string,
	Palette* hicolor, ieByte Alignment, bool anchor, Font* initials,
	Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
	int capital = (initials) ? 1 : 0;

	unsigned int psx = IE_FONT_PADDING;
	Palette* pal = hicolor;
	if (!pal) {
		pal = palette;
	}
	if (initials==this) {
		initials = NULL;
	}

	Holder<Palette> blitPalette = pal;
	ieWord* tmp = NULL;
	size_t len = GetDoubleByteString(string, tmp);
	while (len > 0 && (tmp[len - 1] == '\n' || tmp[len - 1] == '\r')) {
		// ignore trailing newlines
		tmp[len - 1] = 0;
		len--;
	}

	SetupString( tmp, rgn.w, NoColor, initials, capital );
	int ystep;
	if (Alignment & IE_FONT_SINGLE_LINE) {
		ystep = CalcStringHeight(tmp, len, NoColor);
		if (!ystep) ystep = maxHeight;
	} else {
		ystep = maxHeight;
	}
	int x = psx, y = ystep;
	Video* video = core->GetVideoDriver();

	if (Alignment & IE_FONT_ALIGN_CENTER) {
		size_t w = CalcStringWidth( tmp, NoColor );
		x = ( rgn.w - w ) / 2;
	} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
		size_t w = CalcStringWidth( tmp, NoColor );
		x = ( rgn.w - w ) - IE_FONT_PADDING;
	}

	if (Alignment & IE_FONT_ALIGN_MIDDLE) {
		int h = 0;
		for (size_t i = 0; i <= len; i++) {
			if (tmp[i] == 0)
				h++;
		}
		h = h * ystep;
		y += ( rgn.h - h ) / 2;
	} else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
		int h = 0;
		for (size_t i = 0; i <= len; i++) {
			if (tmp[i] == 0)
				h++;
		}
		h = h * ystep;
		y += ( rgn.h - h ) - IE_FONT_PADDING;
	} else if (Alignment & IE_FONT_ALIGN_TOP) {
		y += IE_FONT_PADDING;
	}

	ieWord currChar = '\0';
	const Sprite2D* currGlyph = NULL;
	for (size_t i = 0; i < len; i++) {
		if (( tmp[i] ) == '[' && !NoColor) {
			i++;
			char tag[256];
			tag[0]=0;
			for (size_t k = 0; k < 256 && i<len; k++) {
				if (tmp[i] == ']') {
					tag[k] = 0;
					break;
				}
				tag[k] = tmp[i++];
			}

			if (strnicmp( tag, "capital=",8)==0) {
				sscanf( tag, "capital=%d", &capital);
				continue;
			}

			if (strnicmp( tag, "color=", 6 ) == 0) {
				unsigned int r,g,b;
				if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
					continue;
				const Color c = {(unsigned char)r, (unsigned char)g, (unsigned char)b, 0};
				Palette* newPal = core->CreatePalette( c, palette->back );
				blitPalette = newPal;
				gamedata->FreePalette( newPal );
				continue;
			}
			if (stricmp( tag, "/color" ) == 0) {
				blitPalette = pal;
				continue;
			}
			if (stricmp( "p", tag ) == 0) {
				psx = x;
				continue;
			}
			if (stricmp( "/p", tag ) == 0) {
				psx = IE_FONT_PADDING;
				continue;
			}
			continue;
		}

		if (tmp[i] == 0) {
			y += ystep;
			x = psx;
			size_t w = CalcStringWidth( &tmp[i + 1], NoColor );
			if (Alignment & IE_FONT_ALIGN_CENTER) {
				x = ( rgn.w - w ) / 2;
			} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
				x = ( rgn.w - w );
			}
			continue;
		}
		currChar = tmp[i];
		currGlyph = GetCharSprite(currChar);
		if (initials && capital) {
			x = initials->PrintInitial( x, y, rgn, currChar );
			continue;
		}

		if (i > 0) {
			// kerning
			x -= GetKerningOffset(tmp[i-1], currChar);
		}

		video->BlitSprite(currGlyph, x + rgn.x, y + rgn.y, anchor, &cliprgn, blitPalette.get());

		if (cursor && ( curpos == i ))
			video->BlitSprite( cursor, x + rgn.x, y + rgn.y, anchor, &cliprgn );
		x += currGlyph->Width;
	}
	if (cursor && ( curpos == len )) {
		video->BlitSprite( cursor, x + rgn.x, y + rgn.y, anchor, &cliprgn );
	}
	blitPalette = NULL;
	free( tmp );
}