int32_t FreeTypeFont::getTextLength(const std::u32string& text, const size_t size) { if (!face) { return -1; } int32_t textLength = 0; size_t textIndex = 0; FontCacheEntry* fontCacheEntry; while (textIndex < text.length()) { fontCacheEntry = getGlyph(text[textIndex], size); if (fontCacheEntry == nullptr) { return -1; } textLength += fontCacheEntry->advanceX; textIndex++; } return textLength; }
void CPetGlyphs::changeHighlight(int index) { if (index == _highlightIndex) return; if (_highlightIndex >= 0 && (_flags & GFLAG_4)) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) glyph->unhighlightCurrent(); } _highlightIndex = index; if (index >= 0) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) { if (_flags & GFLAG_4) { Point pt; int idx = getHighlightedIndex(_highlightIndex); if (idx >= 0) pt = getPosition(idx); glyph->highlightCurrent(pt); } glyph->updateTooltip(); } } else if (_owner) { _owner->removeText(); } }
void CPetGlyphs::enter() { if (_highlightIndex != -1) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) glyph->enter(); } }
osgText::Glyph* ScaledAltFont::getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode) { { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_glyphMapMutex); FontSizeGlyphMap::iterator itr = _sizeGlyphMap.find(fontRes); if (itr != _sizeGlyphMap.end()) { GlyphMap& glyphmap = itr->second; GlyphMap::iterator gitr = glyphmap.find(charcode); if (gitr!=glyphmap.end()) return gitr->second.get(); } } if (_implementation.valid()) { if (charcode >= 128) { unsigned int normal_code = charcode % 128; // Reload a scaled version of the glyph osgText::Glyph *normal_glyph = getGlyph(fontRes, normal_code); const osgText::FontResolution new_fontRes(fontRes.first * m_Scale, fontRes.second * m_Scale); osgText::Glyph *scaled_glyph = _implementation->getGlyph(new_fontRes, normal_code); if (m_VCenter) { osg::Vec2 hbearing = scaled_glyph->getHorizontalBearing(); hbearing.y() += 0.5f * (normal_glyph->t() - scaled_glyph->t()); scaled_glyph->setHorizontalBearing(hbearing); } addGlyph (fontRes, charcode, scaled_glyph); return scaled_glyph; } else { osgText::Glyph* g = _implementation->getGlyph(fontRes, charcode); addGlyph (fontRes, charcode, g); return g; } } return 0; }
Vector2i Font::getSize(const std::string &text) const { Vector2i size(0, getMaxVerticalBearing()); int pos = 0; for (size_t i=0; i<text.length(); i++) { char character = text[i]; if (character == '\r') continue; if (character == '\n') { size.y += (int) (getMaxVerticalBearing()*(4.0 / 3.0)); size.x = std::max(size.x, pos); pos = 0; continue; } const Font::Glyph &glyph = getGlyph(character); pos += glyph.horizontalAdvance; if (i+1 < text.length()) pos += getKerning(character, text[i+1]); } size.x = std::max(size.x, pos); return size; }
const WgUnderline * Font::getUnderline( int size ) { // Create an underline specification from the '_' character as default. // It should be possible to specify something different in the spec file later on... Glyph_p pUnder = getGlyph('_', WG_FONT_NORMAL, size); const GlyphBitmap * pSrc = pUnder->getBitmap(); m_tempUnderline.pSurf = pSrc->pSurface; m_tempUnderline.rect = pSrc->rect; m_tempUnderline.bearingX = pSrc->bearingX; m_tempUnderline.bearingY = pSrc->bearingY; if( pSrc->rect.w > 2 ) { m_tempUnderline.leftBorder = 1; m_tempUnderline.rightBorder = 1; } else { m_tempUnderline.leftBorder = 0; m_tempUnderline.rightBorder = 0; } return &m_tempUnderline; }
void Font::drawText(Bitmap *dest, Point2i pos, const std::string &text) const { int initial = pos.x; for (size_t i=0; i<text.length(); i++) { char character = text[i]; if (character == '\r') continue; if (character == '\n') { pos.x = initial; pos.y += (int) (getMaxVerticalBearing()*4.0/3.0); continue; } const Font::Glyph &glyph = getGlyph(character); Point2i targetOffset = pos + Vector2i( glyph.horizontalBearing, getMaxVerticalBearing() - glyph.verticalBearing - 1 ); Point2i sourceOffset( (int) (glyph.tx.x * m_bitmap->getWidth()), (int) (glyph.tx.y * m_bitmap->getHeight())); dest->accumulate(m_bitmap.get(), sourceOffset, targetOffset, glyph.size); pos.x += glyph.horizontalAdvance; if (i+1 < text.length()) pos.x += getKerning(character, text[i+1]); } }
VkBool32 FreeTypeFont::prepareText(const ICommandBuffersSP& cmdBuffer, const std::u32string& text, const size_t size) { if (!face || !cmdBuffer.get()) { return VK_FALSE; } size_t textIndex = 0; FontCacheEntry* fontCacheEntry; while (textIndex < text.length()) { fontCacheEntry = getGlyph(cmdBuffer, text[textIndex], size); if (fontCacheEntry == nullptr) { return VK_FALSE; } textIndex++; } return VK_TRUE; }
void CPetGlyphs::leave() { if (_highlightIndex != -1) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) glyph->leave(); } }
bool CPetGlyphs::MouseButtonDownMsg(const Point &pt) { if (_scrollLeft.contains2(pt)) { scrollLeft(); return true; } if (_scrollRight.contains2(pt)) { scrollRight(); return true; } for (int idx = 0; idx < _numVisibleGlyphs; ++idx) { Rect glyphRect = getRect(idx); if (glyphRect.contains(pt)) { int index = getItemIndex(idx); CPetGlyph *glyph = getGlyph(index); if (glyph) { if (_highlightIndex == index) { glyph->selectGlyph(glyphRect, pt); glyph->updateTooltip(); } else { changeHighlight(index); makePetDirty(); } return true; } } } if (_highlightIndex != -1) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) { if (glyph->MouseButtonDownMsg(pt)) return true; if (!(_flags & GFLAG_2)) { changeHighlight(-1); makePetDirty(); } } } return false; }
//-------------------------------------------------------------------------------------------------- /// Get the extent (width and height) of the given text with this font in pixels //-------------------------------------------------------------------------------------------------- cvf::Vec2ui Font::textExtent(const String& text) { std::vector<cvf::String> lines = text.split("\n"); float maxLineWidth = 0; uint textHeight = 0; uint lineSpacing = static_cast<uint>(this->lineSpacing()); for (size_t lineIdx = 0; lineIdx < lines.size(); ++lineIdx) { String line = lines[lineIdx]; size_t numCharacters = line.size(); float lineWidth = 0; for (size_t j = 0; j < numCharacters; ++j) { wchar_t character = line[j]; // Jump to the next character in the string, if any if (j < (numCharacters - 1)) { float advance = static_cast<float>(this->advance(character, text[j + 1])); lineWidth += advance; } else { ref<Glyph> glyph = getGlyph(character); lineWidth += static_cast<float>(glyph->width()) + static_cast<float>(glyph->horizontalBearingX()); } } maxLineWidth = CVF_MAX(lineWidth, maxLineWidth); if (lineIdx == 0) { ref<Glyph> glyph = getGlyph(L'A'); textHeight += glyph->height(); } else { textHeight += lineSpacing; } } return Vec2ui(static_cast<uint>(maxLineWidth), textHeight); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- float Font::lineSpacing() { ref<Glyph> glyph = getGlyph(L'A'); float spacing = cvf::Math::floor(static_cast<float>(glyph->height())*1.75f); return spacing; }
bool CPetGlyphs::KeyCharMsg(int key) { if (_highlightIndex >= 0) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph && glyph->KeyCharMsg(key)) return true; } return false; }
void BitmapFont::render(const ref_ptr<SpriteBatch>& spriteBatch, const vector4f& rect, vector2f& pos, const colorf& color, const string& text) { for (auto ch = text.begin(); ch != text.end(); ++ch) { char32_t id(*ch); const BitmapFontGlyph& glyph = getGlyph(id); if (glyph.page < 0 || size_t(glyph.page) >= pages.size()) throw RuntimeError("page index out of range"); const BitmapFontPage& page = pages[glyph.page]; emit(spriteBatch, rect, pos, color, glyph, page); } }
bool CPetGlyphs::MouseButtonUpMsg(const Point &pt) { if (_highlightIndex >= 0) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) { if (glyph->MouseButtonUpMsg(pt)) return true; } } return false; }
bool CPetGlyphs::highlighted14() { if (_highlightIndex != -1) { CPetGlyph *pet = getGlyph(_highlightIndex); if (pet) { pet->updateTooltip(); return true; } } return false; }
void T7GFont::drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color) const { // We ignore the color, as the font is already colored const Glyph *glyph = getGlyph(chr); const byte *src = glyph->pixels; byte *target = (byte *)dst->getBasePtr(x, y); for (int i = 0; i < glyph->height; i++) { memcpy(target, src, glyph->width); src += glyph->width; target += dst->pitch; } }
CGameObject *CPetGlyphs::getObjectAt(const Point &pt) const { for (int idx = 0; idx < _numVisibleGlyphs; ++idx) { Rect glyphRect = getRect(idx); if (glyphRect.contains(pt)) { CPetGlyph *glyph = getGlyph(getItemIndex(idx)); if (glyph) return glyph->getObjectAt(); } } return nullptr; }
void CPetGlyphs::draw(CScreenManager *screenManager) { if (_highlightIndex != -1) { int index = getHighlightedIndex(_highlightIndex); if (index != -1) { Point tempPoint; Point pt = getPosition(index); pt -= Point(12, 13); _selection.translate(pt.x, pt.y); _selection.draw(screenManager); _selection.translate(-pt.x, -pt.y); } } // Iterate through displaying glyphs on the screen int listSize = size(); for (int index = 0; index < _numVisibleGlyphs; ++index) { int itemIndex = getItemIndex(index); if (itemIndex >= 0 && itemIndex < listSize) { Point pt = getPosition(index); CPetGlyph *glyph = getGlyph(itemIndex); if (glyph) glyph->drawAt(screenManager, pt, index == _highlightIndex); } } // Draw scrolling arrows if more than a screen's worth of items are showing if (listSize > _numVisibleGlyphs || (_flags & GFLAG_16)) { _scrollLeft.draw(screenManager); _scrollRight.draw(screenManager); } // Handle secondary highlight if (_highlightIndex != -1) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) glyph->draw2(screenManager); } }
bool CPetGlyphs::MouseDragStartMsg(CMouseDragStartMsg *msg) { if (!(_flags & GFLAG_1) && _highlightIndex >= 0) { CPetGlyph *glyph = getGlyph(_highlightIndex); int index = getHighlightedIndex(_highlightIndex); Rect glyphRect = getRect(index); if (glyphRect.contains(msg->_mousePos)) return glyph->dragGlyph(glyphRect, msg); else return glyph->MouseDragStartMsg(msg); } return false; }
void TtfFont::printText(const std::string &text, int32_t x, int32_t y, float Red, float Green, float Blue, float Alpha, uint32_t fontSize) { SDL_assert_release(g_ft); if(text.empty()) return; uint32_t offsetX = 0; uint32_t offsetY = 0; const char *strIt = text.c_str(); const char *strEnd = strIt + text.size(); for(; strIt < strEnd; strIt++) { const char &cx = *strIt; UTF8 ucx = static_cast<unsigned char>(cx); switch(cx) { case '\n': offsetX = 0; offsetY += (fontSize * 1.5); continue; case '\t': //Fake tabulation offsetX += offsetX + offsetX % uint32_t(fontSize * 1.5); continue; // case ' ': // offsetX += m_spaceWidth + m_interLetterSpace / 2; // continue; } TheGlyph &glyph = getGlyph(fontSize, get_utf8_char(&cx)); GlRenderer::setTextureColor(Red, Green, Blue, Alpha); int32_t glyph_x = x + static_cast<int32_t>(offsetX); int32_t glyph_y = y + static_cast<int32_t>(offsetY + fontSize); GlRenderer::renderTexture(glyph.tx, static_cast<float>(glyph_x + glyph.left), static_cast<float>(glyph_y - glyph.top), glyph.width, glyph.height ); offsetX += uint32_t(glyph.advance>>6); strIt += static_cast<size_t>(trailingBytesForUTF8[ucx]); } }
void CPetGlyphs::setFirstVisible(int index) { if (index != _firstVisibleIndex) { _firstVisibleIndex = index; if ((_flags & GFLAG_8) && _highlightIndex != -1) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph) { int idx = getHighlightedIndex(_highlightIndex); if (idx != -1) { Point tempPt = getPosition(idx); glyph->glyphFocused(tempPt, true); } } } } }
/** Render a text * * \param qr The quad renderer used to draw * \param vText The rendered text * \param vColor The color of rendering * \param vPos The position of rendering * \param vSelection Is a selection should be drawn * \param vSelectionStart The start selection char * \param vSelectionEnd The end selection char * */ void RainbruRPG::OgreGui::Font:: render( Brush* qr, const string& vText, const ColourValue& vColor, const Vector2& vPos, bool vSelection, int vSelectionStart, int vSelectionEnd ) const{ int count = vText.size(); float currentX = vPos.x; float currentY = vPos.y; Vector2 tsize (mTexture->getWidth(), mTexture->getHeight()); Ogre::Rectangle r; int x=0; for ( x = 0; x < count; x++ ){ Glyph* g = getGlyph( vText[x] ); r.top=currentY+g->getOffsetY()+g->getHeight(); r.left=currentX; if ( vSelection == false ){ r.bottom=r.top+g->getHeight(); r.right=r.left+g->getWidth(); Ogre::Rectangle uvr = g->getGeometry(); uvr.left /= tsize.x; uvr.right /= tsize.x; uvr.top /= tsize.y; uvr.bottom /= tsize.y; qr->addGlyph( r, uvr, true ); } else{ r.right=r.left+g->getSpace(); r.bottom=r.top+mMaxGlyphHeight; if ( (x >= vSelectionStart) && (x < vSelectionEnd) ){ qr->addGlyph(r, Ogre::Rectangle()); } } currentX += g->getSpace(); } }
//-------------------------------------------------------------------------------------------------- /// Get the extent (width and height) of the given text with this font in pixels //-------------------------------------------------------------------------------------------------- cvf::Vec2ui Font::textExtent(const String& text) { Vec2ui textBB(0,0); int minHeight = std::numeric_limits<int>::max(); int maxHeight = std::numeric_limits<int>::min(); size_t numCharacters = text.size(); for (size_t j = 0; j < numCharacters; j++) { wchar_t character = text[j]; ref<Glyph> glyph = getGlyph(character); // Find bottom and top with regards to baseline (Y = 0) int minY = static_cast<int>(glyph->horizontalBearingY()) - static_cast<int>(glyph->height()); int maxY = glyph->horizontalBearingY(); if (minHeight > minY) minHeight = minY; if (maxHeight < maxY) maxHeight = maxY; uint charWidth = 0; if (j < (numCharacters - 1)) { charWidth = advance(character, text[j + 1]); } else { charWidth = glyph->width() + glyph->horizontalBearingX(); } textBB.x() += charWidth; } if (maxHeight < minHeight) { return Vec2ui(0,0); } textBB.y() = static_cast<uint>(maxHeight - minHeight); return textBB; }
void TextRenderer::draw(int x, int y, const char* str) { glEnable(GL_TEXTURE_2D); for (const char* ch = str; *ch != 0; ch++) { const Glyph& glyph = getGlyph(*ch); if (glyph.textureID() == 0) { x += glyph.width(); continue; } glBindTexture(GL_TEXTURE_2D, glyph.textureID()); int left = x + glyph.bounds().x(); int right = x + glyph.bounds().x() + glyph.bounds().width(); int bottom = y + glyph.bounds().y(); int top = y + glyph.bounds().y() + glyph.bounds().height(); float scale = 1.0 / IMAGE_SIZE; float ls = glyph.location().x() * scale; float rs = (glyph.location().x() + glyph.bounds().width()) * scale; float bt = glyph.location().y() * scale; float tt = (glyph.location().y() + glyph.bounds().height()) * scale; glBegin(GL_QUADS); glTexCoord2f(ls, bt); glVertex2f(left, bottom); glTexCoord2f(rs, bt); glVertex2f(right, bottom); glTexCoord2f(rs, tt); glVertex2f(right, top); glTexCoord2f(ls, tt); glVertex2f(left, top); glEnd(); x += glyph.width(); } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); }
ArrayList<RenderedGlyphContainer::RenderedGlyph> RenderedGlyphContainer::getRenderedGlyphs(void*fontptr, void*renderer, unsigned int size, int fontstyle, const GlyphString&txt, bool antialiasing) { mlock.lock(); ArrayList<RenderedGlyph> glyphTextures; int ttf_style = Font::styleToTTFStyle(fontstyle); TTF_SetFontStyle((TTF_Font*)fontptr, ttf_style); size_t length = txt.length(); for(size_t i=0; i<length; i++) { try { glyphTextures.add(getGlyph(txt.charAt(i), fontptr, renderer, size, fontstyle, antialiasing)); } catch(const RenderGlyphException&e) { mlock.unlock(); throw RenderGlyphException(e); } } mlock.unlock(); return glyphTextures; }
VkBool32 FreeTypeFont::renderText(const ICommandBuffersSP& cmdBuffer, const std::u32string& text, const size_t size, const glm::vec4& color) { if (!face || !cmdBuffer.get()) { return VK_FALSE; } // // TODO: Create once vertex buffer etc. like in example 3. // TODO: Create for each letter a descriptor set. // size_t textIndex = 0; FontCacheEntry* fontCacheEntry; while (textIndex < text.length()) { // Do not use the render command buffer for creation- fontCacheEntry = getGlyph(text[textIndex], size); if (fontCacheEntry == nullptr) { return VK_FALSE; } // TODO: Bind descriptor set. // TODO: Draw triangle square. textIndex++; } return VK_TRUE; }
Image* Font::getWord (const std::string &word) { Image *img = new Image; Vec2 off( 0, 0 ); const char *cword = word.c_str(); for (int c=0; cword[c] != '\0'; ++c) { if (cword[c] == '\n') { off.y -= size; off.x = 0; continue; } Object *o = getGlyph( cword[c], off ); img->addObject( o->cubicsToQuads() ); delete o; off.x += ft266ToFloat( ftFace->glyph->metrics.horiAdvance ); } return img; }
bool CPetGlyphs::VirtualKeyCharMsg(CVirtualKeyCharMsg *msg) { Common::KeyCode key = msg->_keyState.keycode; switch (key) { case Common::KEYCODE_LEFT: decSelection(); return true; case Common::KEYCODE_RIGHT: incSelection(); return true; default: break; } if (_highlightIndex >= 0) { CPetGlyph *glyph = getGlyph(_highlightIndex); if (glyph && glyph->VirtualKeyCharMsg(msg)) return true; } return false; }
void *MMSFBFont::loadFTGlyph(unsigned int character) { FT_GlyphSlot g = NULL; // load glyph but do NOT render a bitmap if (!FT_Load_Glyph((FT_Face)this->ft_face, FT_Get_Char_Index((FT_Face)this->ft_face, (FT_ULong)character), FT_LOAD_DEFAULT // FT_Get_Char_Index((FT_Face)this->ft_face, (FT_ULong)character), FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT // | FT_LOAD_TARGET_LIGHT // | FT_LOAD_TARGET_MONO // | FT_LOAD_TARGET_LCD // | FT_LOAD_TARGET_LCD_V )) { g = ((FT_Face)this->ft_face)->glyph; } else { MMSFB_SetError(0, "FT_Load_Glyph(,,FT_LOAD_DEFAULT) failed for " + this->filename); } /*TEST CODE if (!FT_Load_Glyph((FT_Face)this->ft_face, FT_Get_Char_Index((FT_Face)this->ft_face, (FT_ULong)character), FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT)) { g = ((FT_Face)this->ft_face)->glyph; } else { MMSFB_SetError(0, "FT_Load_Glyph(,,FT_LOAD_RENDER) failed for " + this->filename); } showGlyphAttributes(g); exit(0); */ if (g) { #ifdef __HAVE_OPENGL__ if (!mmsfb->bei) { #else if (1) { #endif // OpenGL is not initialized, we need a bitmap from freetype if (g->format != FT_GLYPH_FORMAT_BITMAP) { if (FT_Render_Glyph(g, FT_RENDER_MODE_NORMAL)) { // failed to load glyph MMSFB_SetError(0, "FT_Render_Glyph(,FT_RENDER_MODE_NORMAL) failed for " + this->filename); return NULL; } } if (g->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) { // failed to load glyph MMSFB_SetError(0, "glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY for " + this->filename); return NULL; } } else { #ifndef __HAVE_GLU__ // OpenGL is initialized but GLU is missing, we need a bitmap from freetype if (g->format != FT_GLYPH_FORMAT_BITMAP) { if (FT_Render_Glyph(g, FT_RENDER_MODE_NORMAL)) { // failed to load glyph MMSFB_SetError(0, "FT_Render_Glyph(,FT_RENDER_MODE_NORMAL) failed for " + this->filename); return NULL; } } if (g->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) { // failed to load glyph MMSFB_SetError(0, "glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY for " + this->filename); return NULL; } #endif } // successfully loaded return g; } else { // failed to load glyph return NULL; } } bool MMSFBFont::setupFTGlyph(unsigned int character, void *ftg, MMSFBFont_Glyph *glyph) { if (!ftg || !glyph) return false; FT_GlyphSlot g = (FT_GlyphSlot)ftg; glyph->character = character; #ifdef __HAVE_OPENGL__ if (!mmsfb->bei) { #else if (1) { #endif // OpenGL is not initialized, setup glyph for software rendering glyph->left = g->bitmap_left; glyph->top = g->bitmap_top; glyph->width = g->bitmap.width; glyph->height = g->bitmap.rows; glyph->advanceX = g->advance.x / 64; glyph->pitch = g->bitmap.pitch; #ifdef __HAVE_OPENGL__ #ifdef __HAVE_GLU__ glyph->meshes = NULL; glyph->outline = NULL; #else glyph->texture = 0; #endif #endif glyph->buffer = (unsigned char*)calloc(1, glyph->pitch * glyph->height); memcpy(glyph->buffer, g->bitmap.buffer, glyph->pitch * glyph->height); if (MMSFBBase_rotate180) { // rotate glyph by 180° rotateUCharBuffer180(glyph->buffer, glyph->pitch, glyph->width, glyph->height); } return true; } #ifndef __HAVE_GLU__ #ifdef __HAVE_OPENGL__ // OpenGL is initialized but GLU is missing, we need a bitmap from freetype glyph->left = g->bitmap_left; glyph->top = g->bitmap_top; glyph->width = g->bitmap.width; glyph->height = g->bitmap.rows; glyph->advanceX = g->advance.x / 64; /* printf("left %d width %d advanceX %d top %d height %d fonth %d - %d\n", glyph->left, glyph->width, glyph->advanceX, glyph->top, glyph->height, this->height, g->advance.y / 64); */ if (!g->bitmap.pitch) { // glyph has no bitmap (e.g. space char) glyph->pitch = 0; glyph->buffer = NULL; glyph->texture = 0; return true; } // add glyph to charmap, we use a pitch which is a multiple of 4 needed e.g. for OGL textures if(mmsfb->bei && (g->bitmap.pitch & 3)) { glyph->pitch = (g->bitmap.pitch & ~3) + 4; glyph->buffer = (unsigned char*)calloc(1, glyph->pitch * glyph->height); unsigned char *src = g->bitmap.buffer; unsigned char *dst = glyph->buffer; for(int i = 0; i < glyph->height; i++) { memcpy(dst, src, g->bitmap.pitch); src += g->bitmap.pitch; dst += glyph->pitch; } } else { glyph->pitch = g->bitmap.pitch; glyph->buffer = (unsigned char*)calloc(1, glyph->pitch * glyph->height); memcpy(glyph->buffer, g->bitmap.buffer, glyph->pitch * glyph->height); } if (MMSFBBase_rotate180) { // rotate glyph by 180° rotateUCharBuffer180(glyph->buffer, glyph->pitch, glyph->width, glyph->height); } // create a texture for this glyph glyph->texture = 0; mmsfb->bei->createAlphaTexture(&glyph->texture, glyph->buffer, glyph->pitch, glyph->height); return true; #endif #else // OpenGL is initialized and GLU is available, we create meshes based on freetype outlines bool with_outline = true; // init glyph basics glyph->buffer = NULL; glyph->pitch = 0; /* glyph->left = (float)g->metrics.horiBearingX * this->scale_coeff; if (glyph->left>= 0) glyph->left = (glyph->left + 32) / 64; else glyph->left = (glyph->left - 32) / 64; glyph->top = (float)g->metrics.horiBearingY * this->scale_coeff; if (glyph->top >= 0) glyph->top = (glyph->top + 32) / 64; else glyph->top = (glyph->top - 32) / 64; glyph->width = ((float)g->metrics.width * this->scale_coeff + 32) / 64; glyph->height = ((float)g->metrics.height * this->scale_coeff + 32) / 64; glyph->advanceX = ((float)g->advance.x * this->scale_coeff + 32) / 64; */ glyph->left = g->metrics.horiBearingX / 64; glyph->top = g->metrics.horiBearingY / 64; glyph->width = g->metrics.width / 64; glyph->height = g->metrics.height / 64; glyph->advanceX = g->advance.x / 64; /* printf("left %d width %d advanceX %d top %d height %d fonth %d - %d\n", glyph->left, glyph->width, glyph->advanceX, glyph->top, glyph->height, this->height, g->advance.y / 64); */ // init glyph mesh and outline description glyph->meshes = NULL; glyph->outline = NULL; // my mesh id unsigned int subkey_mesh = glyph->character; glyph->meshes = new MMSFBBuffer(this->font_id, subkey_mesh); if (!with_outline) { // without outline if (glyph->meshes->isInitialized()) { // meshes already initialized // printf("MMSFBFont: meshes already initialized\n"); return true; } } else { // my outline id unsigned int subkey_outline = 0x80000000 | glyph->character; glyph->outline = new MMSFBBuffer(this->font_id, subkey_outline); if (glyph->meshes->isInitialized() && glyph->outline->isInitialized()) { // meshes and outline already initialized // printf("MMSFBFont: meshes and outline already initialized\n"); return true; } } // init tesselator MMSFTTesselator *ftv = new MMSFTTesselator(g); if (!glyph->meshes->isInitialized()) { // printf("MMSFBFont: have to generate meshes\n"); ftv->generateGlyph(); const MMSFTGlyph *ftglyph = ftv->getGlyph(); if (!ftglyph) { // glyph not generated MMSFB_SetError(0, "MMSFTTesselator::generateGlyph() failed"); delete ftv; return false; } if (!ftglyph->getMeshCount()) { // no meshes available, but o.k. (e.g. space char) delete ftv; return true; } // count max meshes unsigned short int max_meshes = 0; for (unsigned int m = 0; m < ftglyph->getMeshCount(); m++) { if (!ftglyph->getMesh(m)) continue; max_meshes++; if (max_meshes >= MMSFBFONT_GLYPH_MAX_MESHES) { printf("MMSFBFONT_GLYPH_MAX_MESHES(%u) reached, %u needed\n", MMSFBFONT_GLYPH_MAX_MESHES, ftglyph->getMeshCount()); } } if (!max_meshes) { // no meshes available MMSFB_SetError(0, "no meshes available"); delete ftv; return false; } // allocate base buffer for vertices and indices // we do not need to clear because all fields will be set separately MMSFBBuffer::INDEX_BUFFER index_buffer; MMSFBBuffer::VERTEX_BUFFER vertex_buffer; index_buffer.num_arrays = 0; index_buffer.max_arrays = max_meshes; index_buffer.arrays = (MMS_INDEX_ARRAY*)malloc(sizeof(MMS_INDEX_ARRAY) * index_buffer.max_arrays); vertex_buffer.num_arrays = 0; vertex_buffer.max_arrays = max_meshes; vertex_buffer.arrays = (MMS_VERTEX_ARRAY*)malloc(sizeof(MMS_VERTEX_ARRAY) * vertex_buffer.max_arrays); // for all meshes for (unsigned int m = 0; m < ftglyph->getMeshCount(); m++) { // prepare access to vertices and indices of glyph if (index_buffer.num_arrays >= max_meshes) { printf("max_meshes(%u) reached\n", max_meshes); break; } MMS_INDEX_ARRAY *indices = &index_buffer.arrays[index_buffer.num_arrays]; MMS_VERTEX_ARRAY *vertices = &vertex_buffer.arrays[vertex_buffer.num_arrays]; // get access to polygon data const MMSFTMesh *ftmesh = ftglyph->getMesh(m); if (!ftmesh) continue; // prepare indices // note: no need to allocate index buffer, because vertices are correctly sorted switch (ftmesh->getMeshType()) { case GL_TRIANGLES: initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLES); break; case GL_TRIANGLE_STRIP: initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLE_STRIP); break; case GL_TRIANGLE_FAN: initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLE_FAN); break; default: // unsupported type printf("MMSFBFont: unsupported mesh type %u\n", ftmesh->getMeshType()); delete ftv; return false; } #ifndef __HAVE_OGL_HALF_FLOAT__ // prepare vertices using normal 32bit floating point values initVertexArray(vertices, 2, ftmesh->getVertexCount(), MMS_VERTEX_DATA_TYPE_FLOAT); #else // prepare vertices using 16bit half floating point values initVertexArray(vertices, 2, ftmesh->getVertexCount(), MMS_VERTEX_DATA_TYPE_HALF_FLOAT); #endif // for all vertices in the polygon for (unsigned int v = 0; v < ftmesh->getVertexCount(); v++) { const MMSFTVertex &vertex = ftmesh->getVertex(v); MMS_VA_SET_VERTEX_2v(vertices, v, (float)(vertex.X() - g->metrics.horiBearingX) / 64, (float)(g->metrics.horiBearingY - vertex.Y()) / 64); } // next mesh index_buffer.num_arrays++; vertex_buffer.num_arrays++; } glyph->meshes->initBuffer(index_buffer, vertex_buffer); } if (with_outline && ftv->getContourCount() > 0) { if (!glyph->outline->isInitialized()) { // printf("MMSFBFont: have to generate outline\n"); // add outline primitives unsigned short int max_outlines = ftv->getContourCount(); // allocate base buffer for vertices and indices // we do not need to clear because all fields will be set separately MMSFBBuffer::INDEX_BUFFER index_buffer; MMSFBBuffer::VERTEX_BUFFER vertex_buffer; index_buffer.num_arrays = 0; index_buffer.max_arrays = max_outlines; index_buffer.arrays = (MMS_INDEX_ARRAY*)malloc(sizeof(MMS_INDEX_ARRAY) * index_buffer.max_arrays); vertex_buffer.num_arrays = 0; vertex_buffer.max_arrays = max_outlines; vertex_buffer.arrays = (MMS_VERTEX_ARRAY*)malloc(sizeof(MMS_VERTEX_ARRAY) * vertex_buffer.max_arrays); // for all contours (outlines) for (unsigned int c = 0; c < ftv->getContourCount(); c++) { // prepare access to vertices and indices of glyph if (index_buffer.num_arrays >= max_outlines) { printf("max_outlines(%u) reached\n", max_outlines); break; } MMS_INDEX_ARRAY *indices = &index_buffer.arrays[index_buffer.num_arrays]; MMS_VERTEX_ARRAY *vertices = &vertex_buffer.arrays[vertex_buffer.num_arrays]; // get access to contour data const MMSFTContour *ftcontour = ftv->getContour(c); if (!ftcontour) continue; // prepare indices // note: no need to allocate index buffer, because vertices are correctly sorted initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_LINE_LOOP); #ifndef __HAVE_OGL_HALF_FLOAT__ // prepare vertices using normal 32bit floating point values initVertexArray(vertices, 2, ftcontour->getVertexCount(), MMS_VERTEX_DATA_TYPE_FLOAT); #else // prepare vertices using 16bit half floating point values initVertexArray(vertices, 2, ftcontour->getVertexCount(), MMS_VERTEX_DATA_TYPE_HALF_FLOAT); #endif // for all vertices in the polygon for (unsigned int v = 0; v < ftcontour->getVertexCount(); v++) { const MMSFTVertex &vertex = ftcontour->Vertex(v); MMS_VA_SET_VERTEX_2v(vertices, v, (float)(vertex.X() - g->metrics.horiBearingX) / 64, (float)(g->metrics.horiBearingY - vertex.Y()) / 64); } // next outline index_buffer.num_arrays++; vertex_buffer.num_arrays++; } glyph->outline->initBuffer(index_buffer, vertex_buffer); } } // Test mit dreiecken zieht strom!!! dazu kommt noch das Skalierungsproblem... /* if (with_outline && ftv->getContourCount() > 0) { if (!glyph->outline->isInitialized()) { glyph->top += 0; glyph->width += 2; glyph->height += 2; glyph->advanceX += 2; // add outline primitives unsigned short int max_outlines = ftv->getContourCount(); // allocate base buffer for vertices and indices // we do not need to clear because all fields will be set separately MMSFBBuffer::INDEX_BUFFER index_buffer; MMSFBBuffer::VERTEX_BUFFER vertex_buffer; index_buffer.num_arrays = 0; index_buffer.max_arrays = max_outlines; index_buffer.arrays = (MMS_INDEX_ARRAY*)malloc(sizeof(MMS_INDEX_ARRAY) * index_buffer.max_arrays); vertex_buffer.num_arrays = 0; vertex_buffer.max_arrays = max_outlines; vertex_buffer.arrays = (MMS_VERTEX_ARRAY*)malloc(sizeof(MMS_VERTEX_ARRAY) * vertex_buffer.max_arrays); // for all contours (outlines) for (unsigned int c = 0; c < ftv->getContourCount(); c++) { // prepare access to vertices and indices of glyph if (index_buffer.num_arrays >= max_outlines) { printf("max_outlines(%u) reached\n", max_outlines); break; } MMS_INDEX_ARRAY *indices = &index_buffer.arrays[index_buffer.num_arrays]; MMS_VERTEX_ARRAY *vertices = &vertex_buffer.arrays[vertex_buffer.num_arrays]; // get access to contour data const MMSFTContour *ftcontour = ftv->getContour(c); if (!ftcontour) continue; // prepare indices // note: no need to allocate index buffer, because vertices are correctly sorted initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLES); // prepare vertices using normal 32bit floating point values initVertexArray(vertices, 2, ftcontour->getVertexCount() * 6, MMS_VERTEX_DATA_TYPE_FLOAT); printf("*********************\n"); for (unsigned int v = 0; v < ftcontour->getVertexCount(); v++) { const MMSFTVertex &vertex1 = ftcontour->Vertex(v); const MMSFTVertex &outset1 = ftcontour->Outset(v); const MMSFTVertex &vertex2 = ftcontour->Vertex((v+1 < ftcontour->getVertexCount()) ? v+1 : 0); const MMSFTVertex &outset2 = ftcontour->Outset((v+1 < ftcontour->getVertexCount()) ? v+1 : 0); printf("v: %f,%f\n", vertex1.X(), vertex1.Y()); printf("o: %f,%f\n", outset1.X(), outset1.Y()); float fac=3.0f; float *vdata = (float *)vertices->data; vdata[v*6 * vertices->eSize + 0] = (float)(vertex1.X() - g->metrics.horiBearingX) / 64; vdata[v*6 * vertices->eSize + 1] = (float)(g->metrics.horiBearingY - vertex1.Y()) / 64; vdata[v*6 * vertices->eSize + 2] = (float)(vertex1.X() + outset1.X() * fac - g->metrics.horiBearingX) / 64; vdata[v*6 * vertices->eSize + 3] = (float)(g->metrics.horiBearingY - vertex1.Y() - outset1.Y() * fac) / 64; vdata[v*6 * vertices->eSize + 4] = (float)(vertex2.X() - g->metrics.horiBearingX) / 64; vdata[v*6 * vertices->eSize + 5] = (float)(g->metrics.horiBearingY - vertex2.Y()) / 64; vdata[v*6 * vertices->eSize + 6] = (float)(vertex1.X() + outset1.X() * fac - g->metrics.horiBearingX) / 64; vdata[v*6 * vertices->eSize + 7] = (float)(g->metrics.horiBearingY - vertex1.Y() - outset1.Y() * fac) / 64; vdata[v*6 * vertices->eSize + 8] = (float)(vertex2.X() + outset2.X() * fac - g->metrics.horiBearingX) / 64; vdata[v*6 * vertices->eSize + 9] = (float)(g->metrics.horiBearingY - vertex2.Y() - outset2.Y() * fac) / 64; vdata[v*6 * vertices->eSize + 10]= (float)(vertex2.X() - g->metrics.horiBearingX) / 64; vdata[v*6 * vertices->eSize + 11]= (float)(g->metrics.horiBearingY - vertex2.Y()) / 64; } // next outline index_buffer.num_arrays++; vertex_buffer.num_arrays++; } glyph->outline->initBuffer(index_buffer, vertex_buffer); } } */ // all is successfully done delete ftv; return true; #endif return false; } bool MMSFBFont::getGlyph(unsigned int character, MMSFBFont_Glyph *glyph) { if (!glyph) { return false; } if (mmsfb->backend == MMSFB_BE_DFB) { #ifdef __HAVE_DIRECTFB__ #endif } else { if(!this->ft_face) { return false; } bool ret = false; lock(); // check if requested character is already loaded std::map<unsigned int, MMSFBFont_Glyph>::iterator it; it = this->charmap.find(character); if (it == this->charmap.end()) { // no, have to load it FT_GlyphSlot g; if (!(g = (FT_GlyphSlot)loadFTGlyph(character))) { // failed to load glyph unlock(); return false; } // setup glyph values if (!setupFTGlyph(character, g, glyph)) { // failed to setup glyph unlock(); return false; } // add to charmap this->charmap.insert(std::make_pair(character, *glyph)); ret = true; } else { // already loaded *glyph = it->second; ret = true; } unlock(); return ret; } return false; } bool MMSFBFont::getStringWidth(string text, int len, int *width) { // check if initialized INITCHECK; // reset width if (!width) return false; *width = 0; // get the length of the string if (len < 0) len = text.size(); if (!len) return true; // get the width of the whole string #ifdef __HAVE_DIRECTFB__ if (this->dfbfont) { if (((IDirectFBFont*)this->dfbfont)->GetStringWidth((IDirectFBFont*)this->dfbfont, text.c_str(), len, width) != DFB_OK) return false; return true; } else #endif { MMSFBFONT_GET_UNICODE_CHAR(text, len) { MMSFBFont_Glyph glyph; if (!getGlyph(character, &glyph)) break; #if (defined(__HAVE_OPENGL__) && defined(__HAVE_GLU__)) if (mmsfb->bei) { // have to calculate advanceX because of scale coefficient (*width)+= (int)((float)glyph.advanceX * this->scale_coeff + 0.5f); } else #endif (*width)+= glyph.advanceX; } } return true; }