#include "Font.h" #include "Image.h" #include "Globals.h" #include "Scroll.h" #include "Text.h" #ifdef WIN32 # include #endif #include "FrameworkMath.h" using namespace Framework; // Contents of the Character class from Font.h // Constructor Character::Character() : ReferenceCounter(), size(0, 0), alpha(0), fontSize(0) {} // Destructor Character::~Character() { if (alpha) delete[] alpha; } // non-constant void Character::NewCharacter(Point& size) // Initialization { this->size = size; if (alpha) delete[] alpha; alpha = new unsigned char[size.x * size.y]; ZeroMemory(alpha, size.x * size.y); } void Character::setPixel( Point& pos, unsigned char alpha) // sets the alpha value of the pixel { this->alpha[pos.x + pos.y * size.x] = alpha; } void Character::setPixel(int x, int y, unsigned char alpha) { this->alpha[x + y * size.x] = alpha; } void Character::setPixel(int i, unsigned char alpha) { this->alpha[i] = alpha; } void Character::setFontSize(int sg) // sets the font size of the character { fontSize = sg; } int Character::getFontSize() const { return fontSize; } // constant const Point& Character::getSize() const // returns the character image size { return size; } int Character::getWidth() const // character width { return size.x; } int Character::getHeight() const // character height { return size.y; } unsigned char* Character::getBuff() const // returns the alpha buffer { return alpha; } // Contents of the Alphabet class from Font.h // Constructor Alphabet::Alphabet() : ReferenceCounter(), zeichen(new Character*[256]), fontSize(12) { for (int i = 0; i < 256; ++i) zeichen[i] = 0; } // Destructor Alphabet::~Alphabet() { for (int i = 0; i < 256; ++i) { if (zeichen[i]) zeichen[i]->release(); } delete[] zeichen; } // non-constant void Alphabet::NeuAlphabet() // Initialization { for (int i = 0; i < 256; ++i) { if (zeichen[i]) zeichen[i]->release(); } for (int i = 0; i < 256; ++i) zeichen[i] = 0; } void Alphabet::setCharacter( unsigned char i, Character* buchstabe) // sets a character { if (zeichen[i]) zeichen[i]->release(); zeichen[i] = buchstabe; if (zeichen[i]) { zeichen[i]->setFontSize(fontSize); } } void Alphabet::setFontSize(int gr) // sets the font size { fontSize = gr; for (int i = 0; i < 256; ++i) { if (zeichen[i]) zeichen[i]->setFontSize(gr); } } // constant Character* Alphabet::getCharacter( unsigned char i) const // returns a character { if (zeichen[i]) return dynamic_cast(zeichen[i]->getThis()); return 0; } Character* Alphabet::zCharacter(unsigned char i) const { return zeichen[i]; } bool Alphabet::hasCharacter(unsigned char b) const { return zeichen[b] != 0; } int Alphabet::getFontSize() const // returns the font size { return fontSize; } // Contents of the AlphabetArray class from Font.h // Constructor AlphabetArray::AlphabetArray() { memset(alphabets, 0, sizeof(Alphabet*) * 256); } // non-constant bool AlphabetArray::addAlphabet(Alphabet* alphabet) // Adds an alphabet { if (alphabets[alphabet->getFontSize()] != 0) { alphabet->release(); return 0; } alphabets[alphabet->getFontSize()] = alphabet; return 1; } bool AlphabetArray::removeAlphabet(unsigned char sg) // removes an alphabet { if (alphabets[sg]) { alphabets[sg]->release(); alphabets[sg] = 0; return 1; } return 0; } // constant Alphabet* AlphabetArray::getAlphabet( unsigned char sg) const // returns getThis of an alphabet { if (alphabets[sg]) return dynamic_cast(alphabets[sg]->getThis()); return 0; } Alphabet* AlphabetArray::zAlphabet( unsigned char sg) const // returns an alphabet { return alphabets[sg]; } // Contents of the Font class from Font.h // Constructor Font::Font() : ReferenceCounter(), alphabetCount(0), alphabet(new AlphabetArray()) {} // Destructor Font::~Font() { delete alphabet; } bool Font::addAlphabet( Alphabet* alphabet) // Adds an alphabet to the font { if (this->alphabet->addAlphabet(alphabet)) { ++alphabetCount; return true; } return false; } void Font::removeAlphabet(unsigned char sg) // Removes an alphabet { if (alphabet->removeAlphabet(sg)) --alphabetCount; } // constant Alphabet* Font::getAlphabet(unsigned char sg) const { Alphabet* drawAlphabet = alphabet->zAlphabet(sg); if (!drawAlphabet) { for (int i = 0; i < 256; ++i) { if (sg - i > 0) { drawAlphabet = alphabet->zAlphabet((unsigned char)(sg - i)); if (drawAlphabet) break; } if (sg + i < 256) { drawAlphabet = alphabet->zAlphabet((unsigned char)(sg + i)); if (drawAlphabet) break; } } } return dynamic_cast(drawAlphabet->getThis()); } Alphabet* Font::zAlphabet(unsigned char sg) const { Alphabet* drawAlphabet = alphabet->zAlphabet(sg); if (!drawAlphabet) { for (int i = 0; i < 256; ++i) { if (sg - i > 0) { drawAlphabet = alphabet->zAlphabet((unsigned char)(sg - i)); if (drawAlphabet) break; } if (sg + i < 256) { drawAlphabet = alphabet->zAlphabet((unsigned char)(sg + i)); if (drawAlphabet) break; } } } return drawAlphabet; } unsigned char Font::getAlphabetCount() const // returns the number of alphabets contained in the font { return alphabetCount; } TextRenderer::TextRenderer() : TextRenderer(0) {} TextRenderer::TextRenderer(Font* font) : ReferenceCounter() { s = font; zeilenAbstand = 5; zeichenAbstand = 0; fontSize = 0; setFontSize(12); } TextRenderer::~TextRenderer() { if (s) s->release(); } void TextRenderer::setFontZ(Font* font) { if (s != font) { if (s) s->release(); s = font; memset(charWidths, 0, sizeof(charWidths)); memset(charHeights, 0, sizeof(charHeights)); if (s) { Alphabet* a = s->zAlphabet((unsigned char)fontSize); for (int i = 0; i < 256; i++) { Character* b = a->zCharacter((unsigned char)i); if (b) { charWidths[i] = (int)((b->getWidth() / (double)a->getFontSize()) * fontSize + 0.5); charHeights[i] = (int)((b->getHeight() / (double)a->getFontSize()) * fontSize + 0.5); } else { charWidths[i] = 0; charHeights[i] = 0; } } } } else { font->release(); } } Font* TextRenderer::getFont() { if (s) return dynamic_cast(s->getThis()); return 0; } Font* TextRenderer::zFont() { return s; } // Sets the font size to draw with. The font automatically selects the // appropriate alphabet for drawing // sg: The font size void TextRenderer::setFontSize(int sg) { if (fontSize != sg) { fontSize = sg; memset(charWidths, 0, sizeof(charWidths)); memset(charHeights, 0, sizeof(charHeights)); if (s) { Alphabet* a = s->zAlphabet((unsigned char)fontSize); for (int i = 0; i < 256; i++) { Character* b = a->zCharacter((unsigned char)i); if (b) { charWidths[i] = (int)((b->getWidth() / (double)a->getFontSize()) * fontSize + 0.5); charHeights[i] = (int)((b->getHeight() / (double)a->getFontSize()) * fontSize + 0.5); } else { charWidths[i] = 0; charHeights[i] = 0; } } } } } // Sets the line spacing to use for drawing // za: The line spacing to the bottom of the line above in pixels void TextRenderer::setLineSpacing(int za) { zeilenAbstand = za; } // Sets the character spacing to use for drawing // za: The character spacing in pixels void TextRenderer::setCharSpacing(int za) { zeichenAbstand = za; } // Inserts line breaks into the text so it is fully displayed at a given width // zText: The text to insert line breaks into // maxWidth: The width in pixels at which the text should be fully displayed void TextRenderer::formatText(Text* zTxt, int maxWidth) { int lastPos = -1; int x = 0; const char* txt = zTxt->getText(); Text result = txt; int len = zTxt->getLength(); for (int i = 0; i < len; ++i) { if (txt[i] == ' ') { lastPos = i; x += fontSize / 2 + zeichenAbstand; continue; } if (txt[i] == '\t') { lastPos = i; x += fontSize + zeichenAbstand; continue; } if (txt[i] == '\n') { x = 0; lastPos = -1; continue; } x += getCharWidth(txt[i]) + zeichenAbstand; if (x > maxWidth && lastPos > -1) { result.replace(lastPos, lastPos + 1, "\n"); x = 0; i = lastPos; lastPos = -1; } } zTxt->setText(result); } // Draws a specific text with cursor and coloring onto an image // Use (setPosition) and (setDrawFontGroesse) to change position and size // x: x position of the first character // y: y position of the first character // txt: The text to draw // zRObj: The image to draw on // cpos: The position of the cursor in the text // cf: The color of the cursor // fbeg: The position of the character in the text where coloring should begin. // The text is colored from there to the cursor position // ff: The background color of the colored text // f: A function called for each character that returns its color void TextRenderer::renderText(int x, int y, const char* txt, Image& zRObj, std::function f, int cpos, int cf, int fbeg, int ff) { if (!s) return; if (fbeg == -1) fbeg = cpos; int zRObjBr = zRObj.getWidth(); int zRObjHi = zRObj.getHeight(); const Point& zRObjOff = zRObj.getDrawOff(); int beginX = x; int zh = getRowHeight(); if (y + (zh + zeilenAbstand) * Text(txt).countOf('\n') + zh + zRObjOff.y < 0 || x + zRObjOff.x >= zRObjBr || y + zRObjOff.y >= zRObjHi) return; bool faerb = 0; int len = textLength(txt); for (int i = 0; i < len; ++i) { if (i == fbeg) faerb = !faerb; if (i == cpos) { zRObj.drawLineVAlpha(x, y, zh, cf); faerb = !faerb; } if (txt[i] == ' ') { if (faerb) zRObj.alphaRegion( x, y, fontSize / 2 + zeichenAbstand, zh, ff); x += fontSize / 2 + zeichenAbstand; continue; } if (txt[i] == '\t') { if (faerb) zRObj.alphaRegion(x, y, fontSize + zeichenAbstand, zh, ff); x += fontSize + zeichenAbstand; continue; } if (txt[i] == '\n') { y += zh + zeilenAbstand; x = beginX; continue; } renderChar(x, y, txt[i], zRObj, f(x, y, i), 0, faerb, ff); } if (textLength(txt) == cpos) zRObj.drawLineVAlpha(x, y, zh, cf); } // Draws a specific text with cursor and coloring onto an image // Use (setPosition) and (setDrawFontGroesse) to change position and size // x: x position of the first character // y: y position of the first character // txt: The text to draw // zRObj: The image to draw on // cpos: The position of the cursor in the text // cf: The color of the cursor // fbeg: The position of the character in the text where coloring should begin. // The text is colored from there to the cursor position // ff: The background color of the colored text // f: The color in which the text should be drawn void TextRenderer::renderText(int x, int y, const char* txt, Image& zRObj, int f, int cpos, int cf, int fbeg, int ff) { return renderText( x, y, txt, zRObj, [f](int a, int b, int c) { return f; }, cpos, cf, fbeg, ff); } // Draws a specific character with coloring onto an image // Use (setPosition) and (setDrawFontGroesse) to change position and size // x: x position of the first character // y: y position of the first character // txt: The text to draw // zRObj: The image to draw on // color: The color in which the text should be drawn // underlined: 1 if the text should be underlined // selected: 1 if the character should be colored // selectedBackgroundColor: The background color of the colored text void TextRenderer::renderChar(int& x, int y, char c, Image& zRObj, int color, bool underlined, bool selected, int selectedBackgroundColor) { if (!s) return; Alphabet* a = s->zAlphabet((unsigned char)fontSize); if (!a) return; Character* b = a->zCharacter(c); if (b) { if (x >= zRObj.getWidth()) return; if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c))) { if (selected) { int br = getCharWidth(c) + zeichenAbstand; zRObj.alphaRegion(x, y, br, getRowHeight() + zeilenAbstand, selectedBackgroundColor); } if (b->getBuff()) { const Point& zRObjGr = zRObj.getDrawGr(); const Point& zRObjPos = zRObj.getDrawPos(); const Point& zRObjOff = zRObj.getDrawOff(); int xp = x + zRObjOff.x, yp = y + zRObjOff.y; int xs = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0, ys = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0; int br = b->getWidth(); unsigned char a2 = (unsigned char)(255 - (color >> 24)); color &= 0x00FFFFFF; float xoff = (float)b->getFontSize() / (float)fontSize, yoff = (float)b->getFontSize() / (float)fontSize; float x = (float)xs * xoff, y = (float)ys * yoff; int maxX = getCharWidth(c), maxY = getCharHeight(c); maxX = (xp + maxX) >= zRObjGr.x ? (zRObjGr.x - xp) : maxX; maxY = (yp + maxY) >= zRObjGr.y ? (zRObjGr.y - yp) : maxY; int a, dx, ygr, ygr2; if (zRObj.hasAlpha3D()) { for (int dy = ys; dy < maxY; ++dy) { ygr2 = (yp + dy) * zRObj.getWidth() + xp; ygr = (int)y * br; for (dx = xs; dx < maxX; ++dx) { a = b->getBuff()[(int)x + ygr] - a2; zRObj.alphaPixel3D(dx + ygr2, color | (a << 24)); x += xoff; } x = (float)xs; y += yoff; } } else { for (int dy = ys; dy < maxY; ++dy) { ygr2 = (yp + dy) * zRObj.getWidth() + xp; ygr = (int)y * br; for (dx = xs; dx < maxX; ++dx) { a = b->getBuff()[(int)x + ygr] - a2; zRObj.alphaPixel2D(dx + ygr2, color | (a << 24)); x += xoff; } x = (float)xs; y += yoff; } } } if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, getCharWidth(c) + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); } x += getCharWidth(c) + zeichenAbstand; } else if (c == ' ') { if (selected) zRObj.alphaRegion(x, y, fontSize / 2 + zeichenAbstand, getRowHeight() + zeilenAbstand, selectedBackgroundColor); if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, fontSize / 2 + zeichenAbstand + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); x += fontSize / 2 + zeichenAbstand; } else if (c == '\t') { if (selected) zRObj.alphaRegion(x, y, fontSize + zeichenAbstand, getRowHeight() + zeilenAbstand, selectedBackgroundColor); if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, fontSize + zeichenAbstand + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); x += fontSize + zeichenAbstand; } } // Returns the font size used for drawing int TextRenderer::getFontSize() const { return fontSize; } // Returns the character spacing in pixels on the x axis int TextRenderer::getCharSpacing() const { return zeichenAbstand; } // Determines how many pixels are needed to fully display a specific text // txt: The text whose width in pixels should be determined int TextRenderer::getTextWidth(const char* txt) const { int ret = 0; int tmp = 0; int len = textLength(txt); for (int i = 0; i < len; ++i) { if (txt[i] == '\n') { if (tmp > ret) ret = tmp; tmp = 0; } else tmp += getCharWidth(txt[i]) + zeichenAbstand; } if (tmp > ret) ret = tmp; return ret; } // Determines how many pixels are needed to fully display a specific text // txt: The text whose height in pixels should be determined int TextRenderer::getTextHeight(const char* txt) const { int hi = getRowHeight(); return hi + ((hi + zeilenAbstand) * Text(txt).countOf('\n')); } // Determines how many pixels are needed to fully display a specific character // c: The character whose width in pixels should be determined int TextRenderer::getCharWidth(const char c) const { if (c == '\t') return fontSize; else if (c == ' ') return fontSize / 2; else return charWidths[(unsigned char)c]; } int Framework::TextRenderer::getMaxCharWidth() const { int result = 0; for (int i = 0; i < 256; i++) { result = MAX(result, getCharWidth((char)i)); } return result; } // Determines how many pixels are needed to fully display a specific character // c: The character whose height in pixels should be determined int TextRenderer::getCharHeight(const char c) const { return charHeights[(unsigned char)c]; } // Returns the line spacing in pixels to the bottom of the line above int TextRenderer::getLineSpacing() const { return zeilenAbstand; } // Returns the scaled height needed by a drawn line in pixels int TextRenderer::getRowHeight() const { int zh = 0; for (int i = 0; i < 256; ++i) { zh = maxInt(getCharHeight((char)i), zh); } return zh; } // Determines the character in the text that the mouse points to // txt: The text the mouse points to // mouseX: The X position of the mouse in pixels relative to the position of // the first character // mouseY: The Y position of the mouse in pixels relative to the position of // the first character int TextRenderer::textPos(const char* txt, int mouseX, int mouseY) const { int tx = 0; int ty = 0; int sh = getRowHeight(); if (mouseX < 0 || mouseY < 0) return -1; int len = textLength(txt); for (int i = 0; i < len; ++i) { if (txt[i] == '\n') { ty += sh + zeilenAbstand; tx = 0; if (mouseY < ty) return i; } if (txt[i] == '\t') { tx += fontSize + zeichenAbstand; } else if (txt[i] == ' ') { tx += fontSize / 2 + zeichenAbstand; } else { tx += getCharWidth(txt[i]) + zeichenAbstand; } int txpl = getCharWidth(txt[i]) / 2; if (mouseX < tx - txpl && mouseY < ty + sh + zeilenAbstand) return i; } if (mouseY < ty + sh + zeilenAbstand) return textLength(txt); return -1; } EngravedTextRenderer::EngravedTextRenderer() : EngravedTextRenderer(0) {} EngravedTextRenderer::EngravedTextRenderer(Font* font) : TextRenderer(font) {} EngravedTextRenderer::~EngravedTextRenderer() {} // Draws a specific character with coloring onto an image // Use (setPosition) and (setDrawFontGroesse) to change position and size // x: x position of the first character // y: y position of the first character // txt: The text to draw // zRObj: The image to draw on // color: The color in which the text should be drawn // underlined: 1 if the text should be underlined // selected: 1 if the character should be colored // selectedBackgroundColor: The background color of the colored text void EngravedTextRenderer::renderChar(int& x, int y, char c, Image& zRObj, int color, bool underlined, bool selected, int selectedBackgroundColor) { if (!s) return; Alphabet* a = s->zAlphabet((unsigned char)fontSize); Character* b = a->zCharacter(c); if (b) { if (x >= zRObj.getWidth()) return; if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c))) { if (selected) { int br = getCharWidth(c) + zeichenAbstand; zRObj.alphaRegion(x, y, br, getRowHeight() + zeilenAbstand, selectedBackgroundColor); } if (b->getBuff()) { const Point& zRObjGr = zRObj.getDrawGr(); const Point& zRObjPos = zRObj.getDrawPos(); const Point& zRObjOff = zRObj.getDrawOff(); int xp = x + zRObjOff.x, yp = y + zRObjOff.y; int xs = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0, ys = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0; int br = b->getWidth(), h = b->getHeight(); color &= 0x00FFFFFF; double xoff = (double)b->getFontSize() / (fontSize * 2.0), yoff = (double)b->getFontSize() / (fontSize * 2.0); double x = xs * xoff, y = ys * yoff; int maxX = getCharWidth(c), maxY = getCharHeight(c); maxX = (xp + maxX) >= zRObjGr.x ? (zRObjGr.x - xp) : maxX; maxY = (yp + maxY) >= zRObjGr.y ? (zRObjGr.y - yp) : maxY; int dx, ygr, ygr2; if (zRObj.hasAlpha3D()) { for (int dy = ys; dy < maxY; ++dy) { ygr2 = (yp + dy) * zRObj.getWidth(); ygr = (int)y * br; for (dx = xs; dx < maxX; ++dx) { int f = 0; if (b->getBuff()[(int)x + ygr]) f = 0x50000000; else if (((int)(x + xoff) < br && b->getBuff()[(int)(x + xoff) + ygr]) || ((int)(y - yoff) < h && b->getBuff()[(int)x + (int)(y - yoff) * br] > 0xF0)) f = 0xA0000000; else if (((int)(x - xoff) < br && b->getBuff()[(int)(x - xoff) + ygr]) || ((int)(y + yoff) < h && b->getBuff()[(int)x + (int)(y + yoff) * br] > 0xF0)) { f = 0xA0FFFFFF; } zRObj.alphaPixel3D(xp + dx + ygr2, f); x += xoff; } x = xs; y += yoff; } } else { for (int dy = ys; dy < maxY; ++dy) { ygr2 = (yp + dy) * zRObj.getWidth(); ygr = (int)y * br; for (dx = xs; dx < maxX; ++dx) { int f = 0; if (b->getBuff()[(int)x + ygr]) f = 0x50000000; else if (((int)(x + xoff) < br && b->getBuff()[(int)(x + xoff) + ygr]) || ((int)(y - yoff) < h && b->getBuff()[(int)x + (int)(y - yoff) * br] > 0xF0)) f = 0xA0000000; else if (((int)(x - xoff) < br && b->getBuff()[(int)(x - xoff) + ygr]) || ((int)(y + yoff) < h && b->getBuff()[(int)x + (int)(y + yoff) * br] > 0xF0)) { f = 0xA0FFFFFF; } zRObj.alphaPixel2D(xp + dx + ygr2, f); x += xoff; } x = xs; y += yoff; } } } if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, getCharWidth(c) + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); } x += getCharWidth(c) + zeichenAbstand; } else if (c == ' ') { if (selected) zRObj.alphaRegion(x, y, fontSize / 2 + zeichenAbstand, getRowHeight() + zeilenAbstand, selectedBackgroundColor); if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, fontSize / 2 + zeichenAbstand + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); x += fontSize / 2 + zeichenAbstand; } else if (c == '\t') { if (selected) zRObj.alphaRegion(x, y, fontSize + zeichenAbstand, getRowHeight() + zeilenAbstand, selectedBackgroundColor); if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, fontSize + zeichenAbstand + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); x += fontSize + zeichenAbstand; } } // Determines how many pixels are needed to fully display a specific character // c: The character whose width in pixels should be determined int EngravedTextRenderer::getCharWidth(const char c) const { if (c == '\t') return fontSize; else if (c == ' ') return fontSize / 2; else return TextRenderer::getCharWidth(c) * 2; } // Determines how many pixels are needed to fully display a specific character // c: The character whose height in pixels should be determined int EngravedTextRenderer::getCharHeight(const char c) const { return TextRenderer::getCharHeight(c) * 2; } ItalicTextRenderer::ItalicTextRenderer() : ItalicTextRenderer(0) {} ItalicTextRenderer::ItalicTextRenderer(Font* font) : TextRenderer(font) {} ItalicTextRenderer::~ItalicTextRenderer() {} // Draws a specific character with coloring onto an image // Use (setPosition) and (setDrawFontGroesse) to change position and size // x: x position of the first character // y: y position of the first character // txt: The text to draw // zRObj: The image to draw on // color: The color in which the text should be drawn // underlined: 1 if the text should be underlined // selected: 1 if the character should be colored // selectedBackgroundColor: The background color of the colored text void ItalicTextRenderer::renderChar(int& x, int y, char c, Image& zRObj, int color, bool underlined, bool selected, int selectedBackgroundColor) { if (!s) return; Alphabet* a = s->zAlphabet((unsigned char)fontSize); if (!a) return; Character* b = a->zCharacter(c); if (b) { if (x >= zRObj.getWidth()) return; if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c))) { if (selected) { int br = getCharWidth(c) + zeichenAbstand; zRObj.alphaRegion(x, y, br, getRowHeight() + zeilenAbstand, selectedBackgroundColor); } if (b->getBuff()) { const Point& zRObjGr = zRObj.getDrawGr(); const Point& zRObjPos = zRObj.getDrawPos(); const Point& zRObjOff = zRObj.getDrawOff(); int xp = x + zRObjOff.x, yp = y + zRObjOff.y; int xStartBuffer = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0, yStartBuffer = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0; int bufferWidth = b->getWidth(), bufferHeight = b->getHeight(); unsigned char colorAlpha = (unsigned char)(255 - (color >> 24)); color &= 0x00FFFFFF; double xStepBuffer = (double)b->getFontSize() / (double)fontSize, yStepBuffer = (double)b->getFontSize() / (double)fontSize; double xBuffer = xStartBuffer * xStepBuffer, yBuffer = yStartBuffer * yStepBuffer; int charHeight = getCharHeight(c); int maxXBuffer = getCharWidth(c), maxYBuffer = charHeight; maxXBuffer = (xp + maxXBuffer) >= zRObjGr.x ? (zRObjGr.x - xp) : maxXBuffer; maxYBuffer = (yp + maxYBuffer) >= zRObjGr.y ? (zRObjGr.y - yp) : maxYBuffer; std::function colorF = [charHeight, bufferWidth, bufferHeight, colorAlpha, b, color]( int xx, int yy) { xx -= (int)((float)(charHeight - yy) / 4.f + 0.5f); if (xx < 0 || xx >= bufferWidth) return 0x00FFFFFF; int a = b->getBuff()[yy * bufferWidth + xx] - colorAlpha; return color | (a << 24); }; if (zRObj.hasAlpha3D()) { for (int yS = yStartBuffer; yS < maxYBuffer; ++yS) { int ygr2 = (yp + yS) * zRObj.getWidth(); for (int xS = xStartBuffer; xS < maxXBuffer; ++xS) { zRObj.alphaPixel3D( xp + xS + ygr2, colorF((int)xS, (int)yS)); xBuffer += xStepBuffer; } xBuffer = xStartBuffer; yBuffer += yStepBuffer; } } else { for (int yS = yStartBuffer; yS < maxYBuffer; ++yS) { int ygr2 = (yp + yS) * zRObj.getWidth(); for (int xS = xStartBuffer; xS < maxXBuffer; ++xS) { zRObj.alphaPixel2D( xp + xS + ygr2, colorF((int)xS, (int)yS)); xBuffer += xStepBuffer; } xBuffer = xStartBuffer; yBuffer += yStepBuffer; } } } if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, getCharWidth(c) + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); } x += getCharWidth(c) + zeichenAbstand; } else if (c == ' ') { if (selected) zRObj.alphaRegion(x, y, fontSize / 2 + zeichenAbstand, getRowHeight() + zeilenAbstand, selectedBackgroundColor); if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, fontSize / 2 + zeichenAbstand + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); x += fontSize / 2 + zeichenAbstand; } else if (c == '\t') { if (selected) zRObj.alphaRegion(x, y, fontSize + zeichenAbstand, getRowHeight() + zeilenAbstand, selectedBackgroundColor); if (underlined) zRObj.drawLineHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5), y + getRowHeight() + getCharSpacing() / 2, fontSize + zeichenAbstand + (int)(zeichenAbstand / 2.0 + 0.5), 0xFF000000 | color); x += fontSize + zeichenAbstand; } } // Determines how many pixels are needed to fully display a specific character // c: The character whose width in pixels should be determined int ItalicTextRenderer::getCharWidth(const char c) const { if (c == '\t') return fontSize; else if (c == ' ') return fontSize / 2; else return ( int)(TextRenderer::getCharWidth(c) + getCharHeight(c) / 4.0 + 0.5); }