#include "Schrift.h" #include "Bild.h" #include "Text.h" #include "Scroll.h" #include "Globals.h" #ifdef WIN32 #include #endif #include "FrameworkMath.h" using namespace Framework; // Inhalt der Buchstabe Klasse aus Schrift.h // Konstruktor Buchstabe::Buchstabe() : ReferenceCounter(), size( 0, 0 ), alpha( 0 ), schriftSize( 0 ) {} // Destruktor Buchstabe::~Buchstabe() { if( alpha ) delete[]alpha; } // nicht constant void Buchstabe::NeuBuchstabe( Punkt &size ) // Initialisierung { this->size = size; if( alpha ) delete[]alpha; alpha = new unsigned char[ size.x * size.y ]; ZeroMemory( alpha, size.x * size.y ); } void Buchstabe::setPixel( Punkt &pos, unsigned char alpha ) // setzt den alphawert des Pixels { this->alpha[ pos.x + pos.y * size.x ] = alpha; } void Buchstabe::setPixel( int x, int y, unsigned char alpha ) { this->alpha[ x + y * size.x ] = alpha; } void Buchstabe::setPixel( int i, unsigned char alpha ) { this->alpha[ i ] = alpha; } void Buchstabe::setSchriftSize( int sg ) // setzt die Schriftgröße des Buchstaben { schriftSize = sg; } int Buchstabe::getSchriftSize() const { return schriftSize; } // constant const Punkt &Buchstabe::getSize() const // gibt die Buchstabenbildgröße zurück { return size; } int Buchstabe::getBreite() const // Buchstabenbreite { return size.x; } int Buchstabe::getHeight() const // Buchstabenhöhe { return size.y; } unsigned char *Buchstabe::getBuff() const // gibt den Alphabuffer zurück { return alpha; } // Inhalt der Alphabet Klasse aus Schrift.h // Konstruktor Alphabet::Alphabet() : ReferenceCounter(), zeichen( new Buchstabe *[ 256 ] ), schriftSize( 12 ) { for( int i = 0; i < 256; ++i ) zeichen[ i ] = 0; } // Destruktor Alphabet::~Alphabet() { for( int i = 0; i < 256; ++i ) { if( zeichen[ i ] ) zeichen[ i ]->release(); } delete[]zeichen; } // nicht constant void Alphabet::NeuAlphabet() // Initialisierung { 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::setBuchstabe( unsigned char i, Buchstabe *buchstabe ) // setzt einen Buchstaben { if( zeichen[ i ] ) zeichen[ i ]->release(); zeichen[ i ] = buchstabe; if( zeichen[ i ] ) { zeichen[ i ]->setSchriftSize( schriftSize ); } } void Alphabet::setSchriftSize( int gr ) // setzt die Schriftgröße { schriftSize = gr; for( int i = 0; i < 256; ++i ) { if( zeichen[ i ] ) zeichen[ i ]->setSchriftSize( gr ); } } // constant Buchstabe *Alphabet::getBuchstabe( unsigned char i ) const // gibt einen Buchstaben zurück { if( zeichen[ i ] ) return (Buchstabe *)zeichen[ i ]->getThis(); return 0; } Buchstabe *Alphabet::zBuchstabe( unsigned char i ) const { return zeichen[ i ]; } bool Alphabet::hatBuchstabe( unsigned char b ) const { return zeichen[ b ] != 0; } int Alphabet::getSchriftSize() const // gibt die Schriftgröße zurück { return schriftSize; } // Inhalt der AlphabetArray Klasse aus Schrift.h // Konstruktor AlphabetArray::AlphabetArray() : next( 0 ), This( 0 ) {} // Destruktor AlphabetArray::~AlphabetArray() { if( This ) This->release(); delete next; } // nicht constant bool AlphabetArray::addAlphabet( Alphabet *alphabet ) // Fügt ein Alphabet hinzu { if( This ) { if( This->getSchriftSize() == alphabet->getSchriftSize() ) { alphabet->release(); return false; } } else { This = alphabet; return true; } if( !next ) next = new AlphabetArray(); return next->addAlphabet( alphabet ); } bool AlphabetArray::removeAlphabet( int sg ) // entfernt ein Alphabet { if( This ) { if( This->getSchriftSize() == sg ) This = (Alphabet *)This->release(); return 1; } if( !next ) return 0; if( next->removeAlphabet( sg ) ) { AlphabetArray *tmp = next->getNext(); next->setNext0(); delete next; next = tmp; } return 0; } void AlphabetArray::setNext0() // setzt den next Zeiger zu 0 { next = 0; } // constant Alphabet *AlphabetArray::getAlphabet( unsigned char sg ) const // gibt getThis von einem Alphabet zurück { if( !This ) return 0; if( This->getSchriftSize() == sg ) return (Alphabet *)This->getThis(); if( next ) return next->getAlphabet( sg ); return 0; } Alphabet *AlphabetArray::zAlphabet( unsigned char sg ) const // gibt ein Alphabet zurück { if( !This ) return 0; if( This->getSchriftSize() == sg ) return This; if( next ) return next->zAlphabet( sg ); return 0; } Alphabet *AlphabetArray::getAlphabetI( int index, int count ) const { if( count == index ) return (Alphabet *)This->getThis(); if( next ) return next->getAlphabetI( index, count + 1 ); return 0; } Alphabet *AlphabetArray::zAlphabetI( int index, int count ) const { if( count == index ) return This; if( next ) return next->zAlphabetI( index, count + 1 ); return 0; } AlphabetArray *AlphabetArray::getNext() const // gibt das nächste Alphabet zurück { return next; } // Inhalt der Schrift Klasse aus Schrift.h // Konstruktor Schrift::Schrift() : ReferenceCounter(), alphabetAnzahl( 0 ), alphabet( new AlphabetArray() ) {} // Destruktor Schrift::~Schrift() { delete alphabet; } bool Schrift::addAlphabet( Alphabet *alphabet ) // Fügt der Schrift ein Alphabet hinzu { if( this->alphabet->addAlphabet( alphabet ) ) { ++alphabetAnzahl; return true; } return false; } void Schrift::removeAlphabet( int sg ) // Entfernt ein Alphabet { if( alphabet->removeAlphabet( sg ) ) --alphabetAnzahl; } // constant Alphabet *Schrift::getAlphabet( int sg ) const { Alphabet *drawAlphabet = alphabet->zAlphabet( (unsigned char)sg ); if( !drawAlphabet ) { for( int i = 0; i < 256; ++i ) { drawAlphabet = alphabet->zAlphabet( (unsigned char)( sg - i ) ); if( drawAlphabet ) break; drawAlphabet = alphabet->zAlphabet( (unsigned char)( sg + i ) ); if( drawAlphabet ) break; } } return (Alphabet *)drawAlphabet->getThis(); } Alphabet *Schrift::zAlphabet( int sg ) const { Alphabet *drawAlphabet = alphabet->zAlphabet( (unsigned char)sg ); if( !drawAlphabet ) { for( int i = 0; i < 256; ++i ) { drawAlphabet = alphabet->zAlphabet( (unsigned char)( sg - i ) ); if( drawAlphabet ) break; drawAlphabet = alphabet->zAlphabet( (unsigned char)( sg + i ) ); if( drawAlphabet ) break; } } return drawAlphabet; } Alphabet *Schrift::getAlphabetI( int index ) const { return alphabet->getAlphabetI( index, 0 ); } Alphabet *Schrift::zAlphabetI( int index ) const { return alphabet->zAlphabetI( index, 0 ); } unsigned char Schrift::getAlphabetAnzahl() const // gibt die anzahl von in der Schrift enthaltenen Alphabeten zurück { return alphabetAnzahl; } TextRenderer::TextRenderer() : TextRenderer( 0 ) {} TextRenderer::TextRenderer( Schrift *schrift ) : ReferenceCounter() { s = schrift; schriftSize = 12; zeilenAbstand = 5; zeichenAbstand = 0; } TextRenderer::~TextRenderer() { if( s ) s->release(); } void TextRenderer::setSchriftZ( Schrift *schrift ) { if( s ) s->release(); s = schrift; } Schrift *TextRenderer::getSchrift() { if( s ) return (Schrift *)s->getThis(); return 0; } Schrift *TextRenderer::zSchrift() { return s; } // Setzt die Schriftgröße, in der gezeichnet werden soll. Die Schrift wählt automatisch das passende Alphabet zum Zeichnen // sg: Die Schriftgröße void TextRenderer::setSchriftSize( int sg ) { schriftSize = sg; } // Setzt den Zeilenabstand, der zum zeichnen verwendet werden soll // za: Der Zeilenabstand zum unteren Ende der darüber liegenden zeile in Pixeln void TextRenderer::setZeilenAbstand( int za ) { zeilenAbstand = za; } // Setzt den Zeichenabstand, der zum zeichnen verwendet werden soll // za: Der Zeichenabstand zum unteren Ende der darüber liegenden zeile in Pixeln void TextRenderer::setZeichenAbstand( int za ) { zeichenAbstand = za; } // Fügt Zeilenumbrüche in den Text ein, so dass er bei einer vorgegebenen Breite follständig angezeigt wird // zText: Der text, in den die Zeilenumbrüche eingefügt werden sollen // maxBreite: Die Breite in Pixeln auf der der Text follständig angezeigt werden soll void TextRenderer::textFormatieren( Text *zTxt, int maxBreite ) { 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 += schriftSize / 2 + zeichenAbstand; continue; } if( txt[ i ] == '\t' ) { lastPos = i; x += schriftSize + zeichenAbstand; continue; } if( txt[ i ] == '\n' ) { x = 0; lastPos = -1; continue; } x += getCharWidth( txt[ i ] ) + zeichenAbstand; if( x > maxBreite && lastPos > -1 ) { result.ersetzen( lastPos, lastPos + 1, "\n" ); x = 0; i = lastPos; lastPos = -1; } } zTxt->setText( result ); } // Zeichnet einen Bestimmten Text mit Cursor und einfärbung auf ein Bild // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe zu verändern // x: x position des ersten zeichens // y: y position des ersten zeichens // txt: Der Text, der gezeichnet werden soll // zRObj: Das Bild, auf das gezeichnet werden soll // cpos: Die position des Cursors im Text // cf: Die Farbe des Cursors // fbeg: Die Position des Zeichens im Text, wo die Einfärbung beginnen soll. Der Text wird von dort bis zur Cursorposition eingefärbt // ff: Die Hintergrund Farbe des eingefärbten Textes // f: Eine Funktion die für jeden Buchstaben aufgerufen wird und seine Farbe zurückgibt void TextRenderer::renderText( int x, int y, const char *txt, Bild &zRObj, std::function< int( int, int, int ) > f, int cpos, int cf, int fbeg, int ff ) { if( !s ) return; if( fbeg == -1 ) fbeg = cpos; int zRObjBr = zRObj.getBreite(); int zRObjHi = zRObj.getHeight(); const Punkt &zRObjOff = zRObj.getDrawOff(); int beginX = x; int zh = getZeilenHeight(); if( y + ( zh + zeilenAbstand ) * Text( txt ).anzahlVon( '\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.drawLinieVAlpha( x, y, zh, cf ); faerb = !faerb; } if( txt[ i ] == ' ' ) { if( faerb ) zRObj.alphaRegion( x, y, schriftSize / 2 + zeichenAbstand, zh, ff ); x += schriftSize / 2 + zeichenAbstand; continue; } if( txt[ i ] == '\t' ) { if( faerb ) zRObj.alphaRegion( x, y, schriftSize + zeichenAbstand, zh, ff ); x += schriftSize + 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.drawLinieVAlpha( x, y, zh, cf ); } // Zeichnet einen Bestimmten Text mit Cursor und einfärbung auf ein Bild // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe zu verändern // x: x position des ersten zeichens // y: y position des ersten zeichens // txt: Der Text, der gezeichnet werden soll // zRObj: Das Bild, auf das gezeichnet werden soll // cpos: Die position des Cursors im Text // cf: Die Farbe des Cursors // fbeg: Die Position des Zeichens im Text, wo die Einfärbung beginnen soll. Der Text wird von dort bis zur Cursorposition eingefärbt // ff: Die Hintergrund Farbe des eingefärbten Textes // f: Die Farbe, in der der Text gezeichnet werden soll void TextRenderer::renderText( int x, int y, const char *txt, Bild &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 ); } // Zeichnet einen Bestimmten Buchstaben mit einfärbung auf ein Bild // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe zu verändern // x: x position des ersten zeichens // y: y position des ersten zeichens // txt: Der Text, der gezeichnet werden soll // zRObj: Das Bild, auf das gezeichnet werden soll // color: Die Farbe, in der der Text gezeichnet werden soll // underlined: 1, falls der Text unterstrichen sein soll // selected: 1, falls das zeichen eingefärbt sein soll // selectedBackgroundColor: Die Hintergrund Farbe des eingefärbten Textes void TextRenderer::renderChar( int &x, int y, char c, Bild &zRObj, int color, bool underlined, bool selected, int selectedBackgroundColor ) { if( !s ) return; Alphabet *a = s->zAlphabet( schriftSize ); if( !a ) return; Buchstabe *b = a->zBuchstabe( c ); if( b ) { if( x >= zRObj.getBreite() ) return; if( zRObj.isAreaDrawable( x, y, getCharWidth( c ), getCharHeight( c ) ) ) { if( selected ) { int br = getCharWidth( c ) + zeichenAbstand; zRObj.alphaRegion( x, y, br, getZeilenHeight(), selectedBackgroundColor ); } if( b->getBuff() ) { const Punkt &zRObjGr = zRObj.getDrawGr(); const Punkt &zRObjPos = zRObj.getDrawPos(); const Punkt &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->getBreite(); unsigned char a2 = (unsigned char)( 255 - ( color >> 24 ) ); color &= 0x00FFFFFF; float xoff = (float)b->getSchriftSize() / (float)schriftSize, yoff = (float)b->getSchriftSize() / (float)schriftSize; 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.getBreite() + 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.getBreite() + 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.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, getCharWidth( c ) + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); } x += getCharWidth( c ) + zeichenAbstand; } else if( c == ' ' ) { if( selected ) zRObj.alphaRegion( x, y, schriftSize / 2 + zeichenAbstand, getZeilenHeight(), selectedBackgroundColor ); if( underlined ) zRObj.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, schriftSize / 2 + zeichenAbstand + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); x += schriftSize / 2 + zeichenAbstand; } else if( c == '\t' ) { if( selected ) zRObj.alphaRegion( x, y, schriftSize + zeichenAbstand, getZeilenHeight(), selectedBackgroundColor ); if( underlined ) zRObj.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, schriftSize + zeichenAbstand + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); x += schriftSize + zeichenAbstand; } } // Gibt die Schriftgröße zurück, die zum Zeichnen verwendet wird int TextRenderer::getSchriftSize() const { return schriftSize; } // Gibt den Abstand in Pixeln zum unteren Ende der darüber ligenden Zeile zurück int TextRenderer::getZeilenabstand() const { return zeilenAbstand; } // Gibt den Abstand in Pixeln zum zwischen zwei zeichen auf der x Achse zurück int TextRenderer::getZeichenAbstand() const { return zeichenAbstand; } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text vollständig darzustellen // txt: Der Text, von dem die Breite in Pixeln ermitelt werden soll int TextRenderer::getTextBreite( 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 if( txt[ i ] == '\t' ) tmp += schriftSize + zeichenAbstand; else if( txt[ i ] == ' ' ) tmp += schriftSize / 2 + zeichenAbstand; else tmp += getCharWidth( txt[ i ] ) + zeichenAbstand; } if( tmp > ret ) ret = tmp; return ret; } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text vollständig darzustellen // txt: Der Text, von dem die Höhe in Pixeln ermitelt werden soll int TextRenderer::getTextHeight( const char *txt ) const { int hi = getZeilenHeight(); return hi + ( ( hi + zeilenAbstand ) * Text( txt ).anzahlVon( '\n' ) ); } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Buchstaben vollständig darzustellen // c: Der Buchstabe, von dem die Breite in Pixeln ermitelt werden soll int TextRenderer::getCharWidth( const char c ) const { if( !s ) return 0; Alphabet *a = s->zAlphabet( schriftSize ); if( !a ) return 0; Buchstabe *b = a->zBuchstabe( c ); if( b ) return (int)( ( (double)b->getBreite() / (double)b->getSchriftSize() ) * (double)schriftSize + 0.5 ); return 0; } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text vollständig darzustellen // c: Der Buchstabe, von dem die Höhe in Pixeln ermitelt werden soll int TextRenderer::getCharHeight( const char c ) const { if( !s ) return 0; Alphabet *a = s->zAlphabet( schriftSize ); if( !a ) return 0; Buchstabe *b = a->zBuchstabe( c ); if( b ) return (int)( ( (double)b->getHeight() / (double)b->getSchriftSize() ) * (double)schriftSize + 0.5 ); return 0; } // Gibt den Abstand in Pixeln zum unteren Ende der darüber ligenden Zeile zurück int TextRenderer::getZeilenAbstand() const { return zeilenAbstand; } // Gibt die skallierte Höhe zurück, die eine gezeichnete Zeile in Pixeln benötigt int TextRenderer::getZeilenHeight() const { int zh = 0; for( int i = 0; i < 256; ++i ) { zh = maxInt( getCharHeight( (char)i ), zh ); } return zh; } // Ermittelt das Zeichen im Text, auf das die Maus zeigt // txt: Der Text, auf den die Maus Zeigt // mausX: Die X Position der Maus in Pixeln Relativ zur Position des ersten Zeichens // mausY: Die Y Position der Maus in Pixeln Relativ zur Position des ersten Zeichens int TextRenderer::textPos( const char *txt, int mausX, int mausY ) const { int tx = 0; int ty = 0; int sh = getZeilenHeight(); if( mausX < 0 || mausY < 0 ) return -1; int len = textLength( txt ); for( int i = 0; i < len; ++i ) { if( txt[ i ] == '\n' ) { ty += sh + zeilenAbstand; tx = 0; if( mausY < ty ) return i; } if( txt[ i ] == '\t' ) tx += schriftSize + zeichenAbstand; if( txt[ i ] == ' ' ) tx += schriftSize / 2 + zeichenAbstand; tx += getCharWidth( txt[ i ] ); int txpl = getCharWidth( txt[ i + 1 ] ) / 2; if( mausX < tx - txpl && mausY < ty + sh + zeilenAbstand ) return i; } if( mausY < ty + sh + zeilenAbstand ) return textLength( txt ); return -1; } GravurTextRenderer::GravurTextRenderer() : GravurTextRenderer( 0 ) {} GravurTextRenderer::GravurTextRenderer( Schrift *schrift ) : TextRenderer( schrift ) {} GravurTextRenderer::~GravurTextRenderer() {} // Zeichnet einen Bestimmten Buchstaben mit einfärbung auf ein Bild // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe zu verändern // x: x position des ersten zeichens // y: y position des ersten zeichens // txt: Der Text, der gezeichnet werden soll // zRObj: Das Bild, auf das gezeichnet werden soll // color: Die Farbe, in der der Text gezeichnet werden soll // underlined: 1, falls der Text unterstrichen sein soll // selected: 1, falls das zeichen eingefärbt sein soll // selectedBackgroundColor: Die Hintergrund Farbe des eingefärbten Textes void GravurTextRenderer::renderChar( int &x, int y, char c, Bild &zRObj, int color, bool underlined, bool selected, int selectedBackgroundColor ) { if( !s ) return; Alphabet *a = s->zAlphabet( schriftSize ); Buchstabe *b = a->zBuchstabe( c ); if( b ) { if( x >= zRObj.getBreite() ) return; if( zRObj.isAreaDrawable( x, y, getCharWidth( c ), getCharHeight( c ) ) ) { if( selected ) { int br = getCharWidth( c ) + zeichenAbstand; zRObj.alphaRegion( x, y, br, getZeilenHeight(), selectedBackgroundColor ); } if( b->getBuff() ) { const Punkt &zRObjGr = zRObj.getDrawGr(); const Punkt &zRObjPos = zRObj.getDrawPos(); const Punkt &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->getBreite(), h = b->getHeight(); color &= 0x00FFFFFF; double xoff = (double)b->getSchriftSize() / ( schriftSize * 2.0 ), yoff = (double)b->getSchriftSize() / ( schriftSize * 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.getBreite(); 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.getBreite(); 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.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, getCharWidth( c ) + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); } x += getCharWidth( c ) + zeichenAbstand; } else if( c == ' ' ) { if( selected ) zRObj.alphaRegion( x, y, schriftSize / 2 + zeichenAbstand, getZeilenHeight(), selectedBackgroundColor ); if( underlined ) zRObj.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, schriftSize / 2 + zeichenAbstand + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); x += schriftSize / 2 + zeichenAbstand; } else if( c == '\t' ) { if( selected ) zRObj.alphaRegion( x, y, schriftSize + zeichenAbstand, getZeilenHeight(), selectedBackgroundColor ); if( underlined ) zRObj.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, schriftSize + zeichenAbstand + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); x += schriftSize + zeichenAbstand; } } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Buchstaben vollständig darzustellen // c: Der Buchstabe, von dem die Breite in Pixeln ermitelt werden soll int GravurTextRenderer::getCharWidth( const char c ) const { if( !s ) return 0; Alphabet *a = s->zAlphabet( schriftSize ); Buchstabe *b = a->zBuchstabe( c ); if( b ) return (int)( ( (double)b->getBreite() / (double)b->getSchriftSize() ) * (double)schriftSize * 2 + 0.5 ); return 0; } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text vollständig darzustellen // c: Der Buchstabe, von dem die Höhe in Pixeln ermitelt werden soll int GravurTextRenderer::getCharHeight( const char c ) const { if( !s ) return 0; Alphabet *a = s->zAlphabet( schriftSize ); Buchstabe *b = a->zBuchstabe( c ); if( b ) return (int)( ( (double)b->getHeight() / (double)b->getSchriftSize() ) * (double)schriftSize * 2 + 0.5 ); return 0; } KursivTextRenderer::KursivTextRenderer() : KursivTextRenderer( 0 ) {} KursivTextRenderer::KursivTextRenderer( Schrift *schrift ) : TextRenderer( schrift ) {} KursivTextRenderer::~KursivTextRenderer() {} // Zeichnet einen Bestimmten Buchstaben mit einfärbung auf ein Bild // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe zu verändern // x: x position des ersten zeichens // y: y position des ersten zeichens // txt: Der Text, der gezeichnet werden soll // zRObj: Das Bild, auf das gezeichnet werden soll // color: Die Farbe, in der der Text gezeichnet werden soll // underlined: 1, falls der Text unterstrichen sein soll // selected: 1, falls das zeichen eingefärbt sein soll // selectedBackgroundColor: Die Hintergrund Farbe des eingefärbten Textes void KursivTextRenderer::renderChar( int &x, int y, char c, Bild &zRObj, int color, bool underlined, bool selected, int selectedBackgroundColor ) { if( !s ) return; Alphabet *a = s->zAlphabet( schriftSize ); if( !a ) return; Buchstabe *b = a->zBuchstabe( c ); if( b ) { if( x >= zRObj.getBreite() ) return; if( zRObj.isAreaDrawable( x, y, getCharWidth( c ), getCharHeight( c ) ) ) { if( selected ) { int br = getCharWidth( c ) + zeichenAbstand; zRObj.alphaRegion( x, y, br, getZeilenHeight(), selectedBackgroundColor ); } if( b->getBuff() ) { const Punkt &zRObjGr = zRObj.getDrawGr(); const Punkt &zRObjPos = zRObj.getDrawPos(); const Punkt &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 bufferBreite = b->getBreite(), bufferHeight = b->getHeight(); unsigned char colorAlpha = (unsigned char)( 255 - ( color >> 24 ) ); color &= 0x00FFFFFF; double xStepBuffer = (double)b->getSchriftSize() / (double)schriftSize, yStepBuffer = (double)b->getSchriftSize() / (double)schriftSize; 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< int( int x, int y ) > colorF = [charHeight, bufferBreite, bufferHeight, colorAlpha, b, color]( int x, int y ) { x -= (int)( (float)( charHeight - y ) / 4.f + 0.5f ); if( x < 0 || x >= bufferBreite ) return 0x00FFFFFF; int a = b->getBuff()[ y * bufferBreite + x ] - colorAlpha; return color | ( a << 24 ); }; if( zRObj.hasAlpha3D() ) { for( int yS = yStartBuffer; yS < maxYBuffer; ++yS ) { int ygr2 = ( yp + yS ) * zRObj.getBreite(); 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.getBreite(); 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.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, getCharWidth( c ) + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); } x += getCharWidth( c ) + zeichenAbstand; } else if( c == ' ' ) { if( selected ) zRObj.alphaRegion( x, y, schriftSize / 2 + zeichenAbstand, getZeilenHeight(), selectedBackgroundColor ); if( underlined ) zRObj.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, schriftSize / 2 + zeichenAbstand + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); x += schriftSize / 2 + zeichenAbstand; } else if( c == '\t' ) { if( selected ) zRObj.alphaRegion( x, y, schriftSize + zeichenAbstand, getZeilenHeight(), selectedBackgroundColor ); if( underlined ) zRObj.drawLinieHAlpha( x - (int)( zeichenAbstand / 2.0 + 0.5 ), y + getZeilenHeight() + getZeichenAbstand() / 2, schriftSize + zeichenAbstand + (int)( zeichenAbstand / 2.0 + 0.5 ), 0xFF000000 | color ); x += schriftSize + zeichenAbstand; } } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Buchstaben vollständig darzustellen // c: Der Buchstabe, von dem die Breite in Pixeln ermitelt werden soll int KursivTextRenderer::getCharWidth( const char c ) const { if( !s ) return 0; Alphabet *a = s->zAlphabet( schriftSize ); Buchstabe *b = a->zBuchstabe( c ); if( b ) return (int)( ( (double)b->getBreite() / (double)b->getSchriftSize() ) * (double)schriftSize + getCharHeight( c ) / 4.0 + 0.5 ); return 0; } // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text vollständig darzustellen // c: Der Buchstabe, von dem die Höhe in Pixeln ermitelt werden soll int KursivTextRenderer::getCharHeight( const char c ) const { if( !s ) return 0; Alphabet *a = s->zAlphabet( schriftSize ); Buchstabe *b = a->zBuchstabe( c ); if( b ) return (int)( ( (double)b->getHeight() / (double)b->getSchriftSize() ) * (double)schriftSize + 0.5 ); return 0; }