From 393b5cd1dc438872af89d334ef6e5fcc59f27d47 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 17:24:39 +1000 Subject: Added Irrlicht 1.8, but without all the Windows binaries. --- .../tools/IrrFontTool/newFontTool/CFontTool.cpp | 801 +++++++++++++++++++++ 1 file changed, 801 insertions(+) create mode 100644 libraries/irrlicht-1.8/tools/IrrFontTool/newFontTool/CFontTool.cpp (limited to 'libraries/irrlicht-1.8/tools/IrrFontTool/newFontTool/CFontTool.cpp') diff --git a/libraries/irrlicht-1.8/tools/IrrFontTool/newFontTool/CFontTool.cpp b/libraries/irrlicht-1.8/tools/IrrFontTool/newFontTool/CFontTool.cpp new file mode 100644 index 0000000..780e9b0 --- /dev/null +++ b/libraries/irrlicht-1.8/tools/IrrFontTool/newFontTool/CFontTool.cpp @@ -0,0 +1,801 @@ +#include "CFontTool.h" +#include "IXMLWriter.h" + +using namespace irr; + +const int fontsizes[] = {4,6,8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,56,68,72,0}; + +inline u32 getTextureSizeFromSurfaceSize(u32 size) +{ + u32 ts = 0x01; + while(ts < size) + ts <<= 1; + + return ts; +} + +// windows specific +#ifdef _IRR_WINDOWS_ + + const DWORD charsets[] = { ANSI_CHARSET, DEFAULT_CHARSET, OEM_CHARSET, BALTIC_CHARSET, GB2312_CHARSET, CHINESEBIG5_CHARSET, + EASTEUROPE_CHARSET, GREEK_CHARSET, HANGUL_CHARSET, MAC_CHARSET, RUSSIAN_CHARSET, + SHIFTJIS_CHARSET, SYMBOL_CHARSET, TURKISH_CHARSET, VIETNAMESE_CHARSET, JOHAB_CHARSET, + ARABIC_CHARSET, HEBREW_CHARSET, THAI_CHARSET, 0}; + + const wchar_t *setnames[] = {L"ANSI", L"All Available", L"OEM", L"Baltic", L"Chinese Simplified", L"Chinese Traditional", + L"Eastern European", L"Greek", L"Hangul", L"Macintosh", L"Russian", + L"Japanese", L"Symbol", L"Turkish", L"Vietnamese", L"Johab", + L"Arabic", L"Hebrew", L"Thai", 0}; + + // callback for adding font names + int CALLBACK EnumFontFamExProc( ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, + DWORD FontType, LPARAM lParam) + { + CFontTool* t = (CFontTool*) lParam; + t->FontNames.push_back( core::stringw(lpelfe->elfFullName)); + return 1; + } + + // + // Constructor + // + + CFontTool::CFontTool(IrrlichtDevice* device) : FontSizes(fontsizes), + Device(device), UseAlphaChannel(false), + // win specific + dc(0) + { + // init display context + dc = CreateDC(L"DISPLAY", L"DISPLAY", 0 ,0 ); + + // populate list of available character set names + for (int i=0; setnames[i] != 0; ++i) + CharSets.push_back( core::stringw(setnames[i])); + + selectCharSet(0); + } + + void CFontTool::selectCharSet(u32 currentCharSet) + { + if ( currentCharSet >= CharSets.size() ) + return; + + LOGFONTW lf; + lf.lfFaceName[0] = L'\0'; + lf.lfCharSet = (BYTE) charsets[currentCharSet]; + // HRESULT hr; // no error checking(!) + + // clear font list + FontNames.clear(); + + // create list of available fonts + EnumFontFamiliesExW( dc, (LPLOGFONTW) &lf, (FONTENUMPROCW) EnumFontFamExProc, (LPARAM) this, 0); + } + + bool CFontTool::makeBitmapFont(u32 fontIndex, u32 charsetIndex, s32 fontSize, u32 textureWidth, u32 textureHeight, bool bold, bool italic, bool aa, bool alpha) + { + if (fontIndex >= FontNames.size() || charsetIndex >= CharSets.size() ) + return false; + + UseAlphaChannel = alpha; + u32 currentImage = 0; + + // create the font + HFONT font = CreateFontW( + -MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSY), 72), 0, + 0,0, + bold ? FW_BOLD : 0, + italic, 0,0, charsets[charsetIndex], 0,0, + aa ? ANTIALIASED_QUALITY : 0, + 0, FontNames[fontIndex].c_str() ); + + if (!font) + return false; + + SelectObject(dc, font); + SetTextAlign (dc,TA_LEFT | TA_TOP | TA_NOUPDATECP); + + // get rid of the current textures/images + for (u32 i=0; idrop(); + currentTextures.clear(); + + for (u32 i=0; idrop(); + currentImages.clear(); + + // clear current image mappings + CharMap.clear(); + // clear array + Areas.clear(); + + // get information about this font's unicode ranges. + s32 size = GetFontUnicodeRanges( dc, 0); + c8 *buf = new c8[size]; + LPGLYPHSET glyphs = (LPGLYPHSET)buf; + + GetFontUnicodeRanges( dc, glyphs); + + // s32 TotalCharCount = glyphs->cGlyphsSupported; + + s32 currentx=0, currenty=0, maxy=0; + + for (u32 range=0; range < glyphs->cRanges; range++) + { + WCRANGE* current = &glyphs->ranges[range]; + + //maxy=0; + + // loop through each glyph and write its size and position + for (s32 ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++) + { + wchar_t currentchar = ch; + + if ( IsDBCSLeadByte((BYTE) ch)) + continue; // surragate pairs unsupported + + // get the dimensions + SIZE size; + ABC abc; + GetTextExtentPoint32W(dc, ¤tchar, 1, &size); + SFontArea fa; + fa.underhang = 0; + fa.overhang = 0; + + if (GetCharABCWidthsW(dc, currentchar, currentchar, &abc)) // for unicode fonts, get overhang, underhang, width + { + size.cx = abc.abcB; + fa.underhang = abc.abcA; + fa.overhang = abc.abcC; + + if (abc.abcB-abc.abcA+abc.abcC<1) + continue; // nothing of width 0 + } + if (size.cy < 1) + continue; + + //GetGlyphOutline(dc, currentchar, GGO_METRICS, &gm, 0, 0, 0); + + //size.cx++; size.cy++; + + // wrap around? + if (currentx + size.cx > (s32) textureWidth) + { + currenty += maxy; + currentx = 0; + if ((u32)(currenty + maxy) > textureHeight) + { + currentImage++; // increase Image count + currenty=0; + } + maxy = 0; + } + // add this char dimension to the current map + + fa.rectangle = core::rect(currentx, currenty, currentx + size.cx, currenty + size.cy); + fa.sourceimage = currentImage; + + CharMap.insert(currentchar, Areas.size()); + Areas.push_back( fa ); + + currentx += size.cx +1; + + if (size.cy+1 > maxy) + maxy = size.cy+1; + } + } + currenty += maxy; + + u32 lastTextureHeight = getTextureSizeFromSurfaceSize(currenty); + + // delete the glyph set + delete [] buf; + + currentImages.set_used(currentImage+1); + currentTextures.set_used(currentImage+1); + + for (currentImage=0; currentImage < currentImages.size(); ++currentImage) + { + core::stringc logmsg = "Creating image "; + logmsg += (s32) (currentImage+1); + logmsg += " of "; + logmsg += (s32) currentImages.size(); + Device->getLogger()->log(logmsg.c_str()); + // no need for a huge final texture + u32 texHeight = textureHeight; + if (currentImage == currentImages.size()-1 ) + texHeight = lastTextureHeight; + + // make a new bitmap + HBITMAP bmp = CreateCompatibleBitmap(dc, textureWidth, texHeight); + HDC bmpdc = CreateCompatibleDC(dc); + + LOGBRUSH lbrush; + lbrush.lbColor = RGB(0,0,0); + lbrush.lbHatch = 0; + lbrush.lbStyle = BS_SOLID; + + HBRUSH brush = CreateBrushIndirect(&lbrush); + HPEN pen = CreatePen(PS_NULL, 0, 0); + + HGDIOBJ oldbmp = SelectObject(bmpdc, bmp); + HGDIOBJ oldbmppen = SelectObject(bmpdc, pen); + HGDIOBJ oldbmpbrush = SelectObject(bmpdc, brush); + HGDIOBJ oldbmpfont = SelectObject(bmpdc, font); + + SetTextColor(bmpdc, RGB(255,255,255)); + + Rectangle(bmpdc, 0,0,textureWidth,texHeight); + SetBkMode(bmpdc, TRANSPARENT); + + // draw the letters... + + // iterate through the tree + core::map::Iterator it = CharMap.getIterator(); + while (!it.atEnd()) + { + s32 currentArea = (*it).getValue(); + wchar_t wch = (*it).getKey(); + // sloppy but I couldnt be bothered rewriting it + if (Areas[currentArea].sourceimage == currentImage) + { + // draw letter + s32 sx = Areas[currentArea].rectangle.UpperLeftCorner.X - Areas[currentArea].underhang; + TextOutW(bmpdc, sx, Areas[currentArea].rectangle.UpperLeftCorner.Y, &wch, 1); + + // if ascii font... + //SetPixel(bmpdc, Areas[currentArea].rectangle.UpperLeftCorner.X, Areas[currentArea].rectangle.UpperLeftCorner.Y, RGB(255,255,0));// left upper corner mark + } + it++; + } + + // copy the font bitmap into a new irrlicht image + BITMAP b; + PBITMAPINFO pbmi; + WORD cClrBits; + u32 cformat; + + // Retrieve the bitmap color format, width, and height. + GetObject(bmp, sizeof(BITMAP), (LPSTR)&b); + + // Convert the color format to a count of bits. + cClrBits = (WORD)(b.bmPlanes * b.bmBitsPixel); + + if (cClrBits <= 8) // we're not supporting these + cformat = -1; + else if (cClrBits <= 16) + cformat = video::ECF_A1R5G5B5; + else if (cClrBits <= 24) + cformat = video::ECF_R8G8B8; + else + cformat = video::ECF_A8R8G8B8; + + pbmi = (PBITMAPINFO) LocalAlloc(LPTR, + sizeof(BITMAPINFOHEADER)); + + // Initialize the fields in the BITMAPINFO structure. + + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = b.bmWidth; + pbmi->bmiHeader.biHeight = b.bmHeight; + pbmi->bmiHeader.biPlanes = b.bmPlanes; + pbmi->bmiHeader.biBitCount = b.bmBitsPixel; + + // If the bitmap is not compressed, set the BI_RGB flag. + pbmi->bmiHeader.biCompression = BI_RGB; + + // Compute the number of bytes in the array of color + // indices and store the result in biSizeImage. + // For Windows NT, the width must be DWORD aligned unless + // the bitmap is RLE compressed. This example shows this. + // For Windows 95/98/Me, the width must be WORD aligned unless the + // bitmap is RLE compressed. + pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 + * pbmi->bmiHeader.biHeight; + // Set biClrImportant to 0, indicating that all of the + // device colors are important. + pbmi->bmiHeader.biClrImportant = 0; + + LPBYTE lpBits; // memory pointer + + PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) pbmi; + lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); + + GetDIBits(dc, bmp, 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS); + + // DEBUG- copy to clipboard + //OpenClipboard(hWnd); + //EmptyClipboard(); + //SetClipboardData(CF_BITMAP, bmp); + //CloseClipboard(); + + // flip bitmap + s32 rowsize = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8; + c8 *row = new c8[rowsize]; + for (s32 i=0; i < (pbih->biHeight/2); ++i) + { + // grab a row + memcpy(row, lpBits + (rowsize * i), rowsize); + // swap row + memcpy(lpBits + (rowsize * i), lpBits + ((pbih->biHeight-1 -i) * rowsize ) , rowsize); + memcpy(lpBits + ((pbih->biHeight-1 -i) * rowsize ), row , rowsize); + } + + bool ret = false; + + if (cformat == video::ECF_A8R8G8B8) + { + // in this case the font should have an alpha channel, but since windows doesn't draw one + // we have to set one manually by going through all the pixels.. *sigh* + + u8* m; + for (m = lpBits; m < lpBits + pbih->biSizeImage; m+=4) + { + if (UseAlphaChannel) + { + if (m[0] > 0) // pixel has colour + { + m[3]=m[0]; // set alpha + m[0]=m[1]=m[2] = 255; // everything else is full + } + } + else + m[3]=255; // all pixels are full alpha + } + + } + else if (cformat == video::ECF_A1R5G5B5) + { + u8* m; + for (m = lpBits; m < lpBits + pbih->biSizeImage; m+=2) + { + WORD *p = (WORD*)m; + if (m[0] > 0 || !UseAlphaChannel) // alpha should be set + *p |= 0x8000; // set alpha bit + } + } + else + { + cformat = -1; + } + + // make a texture from the image + if (cformat != -1) + { + // turn mip-mapping off + bool b = Device->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + currentImages[currentImage] = Device->getVideoDriver()->createImageFromData((video::ECOLOR_FORMAT)cformat, core::dimension2d(textureWidth,texHeight), (void*)lpBits); + Device->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,b); + } + else + { + Device->getLogger()->log("Couldn't create font, your pixel format is unsupported."); + } + + // free memory and windows resources + // sloppy I know, but I only intended to create one image at first. + delete [] row; + LocalFree(pbmi); + GlobalFree(lpBits); + DeleteDC(bmpdc); + DeleteObject(brush); + DeleteObject(pen); + DeleteObject(bmp); + + if (currentImages[currentImage]) + { + // add texture + currentTextures[currentImage] = Device->getVideoDriver()->addTexture("GUIFontImage",currentImages[currentImage]); + currentTextures[currentImage]->grab(); + } + else + { + Device->getLogger()->log("Something went wrong, aborting."); + // drop all images + DeleteObject(font); + return false; + } + } // looping through each texture + DeleteObject(font); + return true; + } + +#else + + CFontTool::CFontTool(IrrlichtDevice *device) : FontSizes(fontsizes), Device(device), UseAlphaChannel(false) + { + if (!XftInitFtLibrary()) + { + core::stringc logmsg = "XFT not found\n"; + Device->getLogger()->log(logmsg.c_str()); + exit(EXIT_FAILURE); + } + + /* Get a list of the font foundries, storing them in a set to sort */ + std::set foundries; + Display* display = (Display*)Device->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display; + XftFontSet* fonts = XftListFonts(display, DefaultScreen(display), 0, XFT_FOUNDRY, 0); + for (int i = 0; i < fonts->nfont; i++) + { + char *foundry; + XftPatternGetString(fonts->fonts[i], XFT_FOUNDRY, 0, &foundry); + core::stringw tmp(foundry); + foundries.insert(tmp); + } + XftFontSetDestroy(fonts); + + /* Copy the sorted list into the array */ + CharSets.clear(); + for (std::set::iterator i = foundries.begin(); i != foundries.end(); i++) + CharSets.push_back((*i).c_str()); + selectCharSet(0); + } + + /* Note: There must be some trick for using strings as pattern parameters to XftListFonts because + no matter how I specify a string, I end up with an intermittent segfault. Since XftFontList is + just calling FcFontList, that's what I'll do too since that works OK */ + void CFontTool::selectCharSet(u32 currentCharSet) + { + /* Get a list of the font families, storing them in a set to sort */ + char foundry[256]; + sprintf(&foundry[0],"%ls",CharSets[currentCharSet].c_str()); + std::set families; + XftPattern *pattern = FcPatternCreate(); + XftPatternAddString(pattern, FC_FOUNDRY, &foundry[0]); + XftObjectSet *objectset = FcObjectSetCreate(); + XftObjectSetAdd(objectset, XFT_FOUNDRY); + XftObjectSetAdd(objectset, XFT_FAMILY); + FcFontSet *fonts = FcFontList(NULL, pattern, objectset); + + for (int i = 0; i < fonts->nfont; i++) + { + char* ptr; + XftPatternGetString(fonts->fonts[i], XFT_FAMILY, 0, &ptr); + core::stringw family(ptr); + families.insert(family); + } + XftPatternDestroy(pattern); + FcObjectSetDestroy(objectset); + + /* Copy the sorted list into the array */ + FontNames.clear(); + for (std::set::iterator i = families.begin(); i != families.end(); i++) + FontNames.push_back((*i).c_str()); + } + + bool CFontTool::makeBitmapFont(u32 fontIndex, u32 charsetIndex, s32 fontSize, u32 textureWidth, u32 textureHeight, bool bold, bool italic, bool aa, bool alpha) + { + if (fontIndex >= FontNames.size() || charsetIndex >= CharSets.size() ) + return false; + + Display *display = (Display*) Device->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display; + u32 screen = DefaultScreen(display); + Window win = RootWindow(display, screen); + Visual *visual = DefaultVisual(display, screen); + UseAlphaChannel = alpha; + u32 currentImage = 0; + + XftResult result; + XftPattern *request = XftPatternCreate(); + char foundry[256], family[256]; + sprintf(&foundry[0],"%ls",CharSets[charsetIndex].c_str()); + sprintf(&family[0],"%ls",FontNames[fontIndex].c_str()); + XftPatternAddString(request, XFT_FOUNDRY, &foundry[0]); + XftPatternAddString(request, XFT_FAMILY, &family[0]); + XftPatternAddInteger(request, XFT_PIXEL_SIZE, fontSize); + XftPatternAddInteger(request, XFT_WEIGHT, bold ? XFT_WEIGHT_BLACK : XFT_WEIGHT_LIGHT); + XftPatternAddInteger(request, XFT_SLANT, italic ? XFT_SLANT_ITALIC : XFT_SLANT_ROMAN); + XftPatternAddBool(request, XFT_ANTIALIAS, aa); + + /* Find the closest font that matches the user choices and open it and check if the returned + font has anti aliasing enabled by default, even if it wasn't requested */ + FcBool aaEnabled; + XftPattern *found = XftFontMatch(display, DefaultScreen(display), request, &result); + XftPatternGetBool(found, XFT_ANTIALIAS, 0, &aaEnabled); + aa = aaEnabled; + XftFont *font = XftFontOpenPattern(display, found); + + // get rid of the current textures/images + for (u32 i=0; idrop(); + currentTextures.clear(); + for (u32 i=0; idrop(); + currentImages.clear(); + CharMap.clear(); + Areas.clear(); + + /* Calculate the max height of the font. Annoyingly, it seems that the height property of the font + is the maximum height of any single character, but a string of characters, aligned along their + baselines, can exceed this figure. Because I don't know any better way of doing it, I'm going to + have to use the brute force method. + + Note: There will be a certain number of charters in a font, however they may not be grouped + consecutively, and could in fact be spread out with many gaps */ + u32 maxY = 0; + u32 charsFound = 0; + for (FT_UInt charCode = 0; charsFound < FcCharSetCount(font->charset); charCode++) + { + if (!XftCharExists(display, font, charCode)) + continue; + + charsFound++; + + XGlyphInfo extents; + XftTextExtents32(display, font, &charCode, 1, &extents); + if ((extents.xOff <= 0) && (extents.height <= 0)) + continue; + + /* Calculate the width and height, adding 1 extra pixel if anti aliasing is enabled */ + u32 chWidth = extents.xOff + (aa ? 1 : 0); + u32 chHeight = (font->ascent - extents.y + extents.height) + (aa ? 1 : 0); + if (chHeight > maxY) + maxY = chHeight; + + /* Store the character details here */ + SFontArea fontArea; + fontArea.rectangle = core::rect(0, 0, chWidth, chHeight); + CharMap.insert(charCode, Areas.size()); + Areas.push_back(fontArea); + } + core::stringc logmsg = "Found "; + logmsg += (s32) (CharMap.size() + 1); + logmsg += " characters"; + Device->getLogger()->log(logmsg.c_str()); + + /* Get the size of the chars and allocate them a position on a texture. If the next character that + is added would be outside the width or height of the texture, then a new texture is added */ + u32 currentX = 0, currentY = 0, rowY = 0; + for (core::map::Iterator it = CharMap.getIterator(); !it.atEnd(); it++) + { + s32 currentArea = (*it).getValue(); + SFontArea *fontArea = &Areas[currentArea]; + u32 chWidth = fontArea->rectangle.LowerRightCorner.X; + u32 chHeight = fontArea->rectangle.LowerRightCorner.Y; + + /* If the width of this char will exceed the textureWidth then start a new row */ + if ((currentX + chWidth) > textureWidth) + { + currentY += rowY; + currentX = 0; + + /* If the new row added to the texture exceeds the textureHeight then start a new texture */ + if ((currentY + rowY) > textureHeight) + { + currentImage++; + currentY = 0; + } + rowY = 0; + } + + /* Update the area with the current x and y and texture */ + fontArea->rectangle = core::rect(currentX, currentY, currentX + chWidth, currentY + chHeight); + fontArea->sourceimage = currentImage; + currentX += chWidth + 1; + if (chHeight + 1 > rowY) + rowY = chHeight + 1; + } + + /* The last row of chars and the last texture weren't accounted for in the loop, so add them here */ + currentY += rowY; + u32 lastTextureHeight = getTextureSizeFromSurfaceSize(currentY); + currentImages.set_used(currentImage + 1); + currentTextures.set_used(currentImage + 1); + + /* Initialise colours */ + XftColor colFore, colBack; + XRenderColor xFore = {0xffff, 0xffff, 0xffff, 0xffff}; + XRenderColor xBack = {0x0000, 0x0000, 0x0000, 0xffff}; + XftColorAllocValue(display, DefaultVisual(display, screen), DefaultColormap(display, screen), &xFore, &colFore); + XftColorAllocValue(display, DefaultVisual(display, screen), DefaultColormap(display, screen), &xBack, &colBack); + + /* Create a pixmap that is large enough to hold any character in the font */ + Pixmap pixmap = XCreatePixmap(display, win, textureWidth, maxY, DefaultDepth(display, screen)); + XftDraw *draw = XftDrawCreate(display, pixmap, visual, DefaultColormap(display, screen)); + + /* Render the chars */ + for (currentImage = 0; currentImage < currentImages.size(); ++currentImage) + { + core::stringc logmsg = "Creating image "; + logmsg += (s32) (currentImage+1); + logmsg += " of "; + logmsg += (s32) currentImages.size(); + Device->getLogger()->log(logmsg.c_str()); + + /* The last texture that is saved is vertically shrunk to fit the characters drawn on it */ + u32 texHeight = textureHeight; + if (currentImage == currentImages.size() - 1) + texHeight = lastTextureHeight; + + /* The texture that holds this "page" of characters */ + currentImages[currentImage] = Device->getVideoDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2du(textureWidth, texHeight)); + currentImages[currentImage]->fill(video::SColor(alpha ? 0 : 255,0,0,0)); + + for (core::map::Iterator it = CharMap.getIterator(); !it.atEnd(); it++) + { + FcChar32 wch = (*it).getKey(); + s32 currentArea = (*it).getValue(); + if (Areas[currentArea].sourceimage == currentImage) + { + SFontArea *fontArea = &Areas[currentArea]; + u32 chWidth = fontArea->rectangle.LowerRightCorner.X - fontArea->rectangle.UpperLeftCorner.X; + u32 chHeight = fontArea->rectangle.LowerRightCorner.Y - fontArea->rectangle.UpperLeftCorner.Y; + + /* Draw the glyph onto the pixmap */ + XGlyphInfo extents; + XftDrawRect(draw, &colBack, 0, 0, chWidth, chHeight); + XftTextExtents32(display, font, &wch, 1, &extents); + XftDrawString32(draw, &colFore, font, extents.x, extents.y, &wch, 1); + + /* Convert the pixmap into an image, then copy it onto the Irrlicht texture, pixel by pixel. + There's bound to be a faster way, but this is adequate */ + u32 xDest = fontArea->rectangle.UpperLeftCorner.X; + u32 yDest = fontArea->rectangle.UpperLeftCorner.Y + font->ascent - extents.y; + XImage *image = XGetImage(display, pixmap, 0, 0, chWidth, chHeight, 0xffffff, XYPixmap); + if (image) + { + for (u32 ySrc = 0; ySrc < chHeight; ySrc++) + for (u32 xSrc = 0; xSrc < chWidth; xSrc++) + { + /* Get the pixel colour and break it down into rgb components */ + u32 col = XGetPixel(image, xSrc, ySrc); + u32 a = 255; + u32 r = col & visual->red_mask; + u32 g = col & visual->green_mask; + u32 b = col & visual->blue_mask; + while (r > 0xff) r >>= 8; + while (g > 0xff) g >>= 8; + while (b > 0xff) b >>= 8; + + /* To make the background transparent, set the colour to 100% white and the alpha to + the average of the three rgb colour components to maintain the anti-aliasing */ + if (alpha) + { + a = (r + g + b) / 3; + r = 255; + g = 255; + b = 255; + } + currentImages[currentImage]->setPixel(xDest + xSrc,yDest + ySrc,video::SColor(a,r,g,b)); + } + image->f.destroy_image(image); + } + } + } + + /* Add the texture to the list */ + currentTextures[currentImage] = Device->getVideoDriver()->addTexture("GUIFontImage",currentImages[currentImage]); + currentTextures[currentImage]->grab(); + } + + XftColorFree (display, visual, DefaultColormap(display, screen), &colFore); + XftColorFree (display, visual, DefaultColormap(display, screen), &colBack); + XftFontClose(display,font); + XftPatternDestroy(request); + XftDrawDestroy(draw); + XFreePixmap(display, pixmap); + return true; + } +#endif + + CFontTool::~CFontTool() + { +#ifdef _IRR_WINDOWS_ + // destroy display context + if (dc) + DeleteDC(dc); +#endif + + // drop textures+images + for (u32 i=0; idrop(); + currentTextures.clear(); + + for (u32 i=0; idrop(); + currentImages.clear(); + } + +bool CFontTool::saveBitmapFont(const c8 *filename, const c8* format) +{ + if (currentImages.size() == 0) + { + Device->getLogger()->log("No image data to write, aborting."); + return false; + } + + core::stringc fn = filename; + core::stringc imagename = filename; + fn += ".xml"; + + io::IXMLWriter *writer = Device->getFileSystem()->createXMLWriter(fn.c_str()); + + // header and line breaks + writer->writeXMLHeader(); + writer->writeLineBreak(); + + // write information + writer->writeElement(L"font", false, L"type", L"bitmap"); + writer->writeLineBreak(); + writer->writeLineBreak(); + + // write images and link to them + for (u32 i=0; igetVideoDriver()->writeImageToFile(currentImages[i],imagename.c_str()); + + writer->writeElement(L"Texture", true, + L"index", core::stringw(i).c_str(), + L"filename", core::stringw(imagename.c_str()).c_str(), + L"hasAlpha", UseAlphaChannel ? L"true" : L"false"); + writer->writeLineBreak(); + } + + writer->writeLineBreak(); + + // write each character + core::map::Iterator it = CharMap.getIterator(); + while (!it.atEnd()) + { + SFontArea &fa = Areas[(*it).getValue()]; + + wchar_t c[2]; + c[0] = (*it).getKey(); + c[1] = L'\0'; + core::stringw area, under, over, image; + area = core::stringw(fa.rectangle.UpperLeftCorner.X); + area += L", "; + area += fa.rectangle.UpperLeftCorner.Y; + area += L", "; + area += fa.rectangle.LowerRightCorner.X; + area += L", "; + area += fa.rectangle.LowerRightCorner.Y; + + core::array names; + core::array values; + names.clear(); + values.clear(); + // char + names.push_back(core::stringw(L"c")); + values.push_back(core::stringw(c)); + // image number + if (fa.sourceimage != 0) + { + image = core::stringw(fa.sourceimage); + names.push_back(core::stringw(L"i")); + values.push_back(image); + } + // rectangle + names.push_back(core::stringw(L"r")); + values.push_back(area); + + if (fa.underhang != 0) + { + under = core::stringw(fa.underhang); + names.push_back(core::stringw(L"u")); + values.push_back(under); + } + if (fa.overhang != 0) + { + over = core::stringw(fa.overhang); + names.push_back(core::stringw(L"o")); + values.push_back(over); + } + writer->writeElement(L"c", true, names, values); + + writer->writeLineBreak(); + it++; + } + + writer->writeClosingTag(L"font"); + + writer->drop(); + + Device->getLogger()->log("Bitmap font saved."); + + return true; +} -- cgit v1.1