mirror of https://github.com/BOINC/boinc.git
253 lines
11 KiB
C++
253 lines
11 KiB
C++
// This file is part of BOINC.
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2010 University of California
|
|
//
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// BOINC is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
// utility functions for TrueType font OpenGL graphics
|
|
|
|
// FTGL OpenGL TrueType/FreeType font rendering
|
|
// you will need to build & link against freetype2 and ftgl
|
|
// tested using ftgl version 2.1.3 rc5 and freetype version 2.3.9
|
|
|
|
// ftgl library: http://sourceforge.net/projects/ftgl/files/FTGL%20Source/
|
|
// freetype2 library: http://www.freetype.org/
|
|
|
|
// this should basically be a drop-in for the old boinc txf_* functions i.e.
|
|
// txf_load_fonts and txf_render_string, with extra options on the latter for rotating etc
|
|
|
|
// adapted by Carl Christensen
|
|
|
|
#include "ttfont.h"
|
|
#include "filesys.h" // from boinc for file_exists
|
|
|
|
// I put in it's own namespace so call TTFont::ttf_load_fonts() etc
|
|
namespace TTFont {
|
|
|
|
// define the number of fonts required
|
|
#define NUM_FONT 2
|
|
|
|
FTFont* g_font[NUM_FONT] = {NULL, NULL};
|
|
int g_iFont = -1;
|
|
|
|
// you'll want to define a 2-d array of char as appropriate for your
|
|
// truetype font filenames (path is set in the call to ttf_load_fonts)
|
|
static const char g_cstrFont[NUM_FONT][4] = {"hvt", "cbt"};
|
|
|
|
static GLfloat g_transColor[3] = { 255, 0, 255 }; // this should be magenta - red = 255, green = 0, blue = 255
|
|
|
|
// load fonts. call once.
|
|
// pass in the font directory, and any special-scaling font name & size (i.e. I want a huge typeface for hvtb so pass in "hvtb", 3000
|
|
void ttf_load_fonts(const char* dir, const char* strScaleFont, const int& iScaleFont) {
|
|
static bool bInit = false; // flag so we don't call again, otherwise we'll have memory leaks each subsequent call to new FTTextureFont etc
|
|
if (bInit) return; // we've already been here
|
|
bInit = true; // we're in now!
|
|
ttf_cleanup();
|
|
memset(g_font, 0x00, sizeof(FTFont*) * NUM_FONT); // initialize to null's for error checking later]
|
|
char vpath[_MAX_PATH];
|
|
g_iFont = -1;
|
|
for (int i=0 ; i < NUM_FONT; i++){
|
|
sprintf(vpath, "%s/%s", dir, g_cstrFont[i]);
|
|
if (boinc_file_exists(vpath)) {
|
|
//g_font[i] = new FTBitmapFont(vpath);
|
|
//g_font[i] = new FTPixmapFont(vpath);
|
|
//g_font[i] = new FTPolygonFont(vpath);
|
|
g_font[i] = new FTTextureFont(vpath);
|
|
if(!g_font[i]->Error()) {
|
|
#ifdef _DEBUG
|
|
fprintf(stderr, "Successfully loaded '%s'...\n", vpath);
|
|
#endif
|
|
int iScale = 30;
|
|
if (strScaleFont && !strcmp(strScaleFont, g_cstrFont[i])) iScale = iScaleFont;
|
|
if(!g_font[i]->FaceSize(iScale))
|
|
{
|
|
fprintf(stderr, "Failed to set size");
|
|
}
|
|
|
|
g_font[i]->Depth(3.);
|
|
g_font[i]->Outset(-.5f, 1.5f);
|
|
|
|
g_font[i]->CharMap(ft_encoding_unicode);
|
|
g_iFont = i;
|
|
|
|
}
|
|
#ifdef _DEBUG
|
|
else {
|
|
fprintf(stderr, "Failed to load '%s'...\n", vpath);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove our objects?
|
|
void ttf_cleanup()
|
|
{
|
|
for (int i = 0; i < NUM_FONT; i++) {
|
|
if (g_font[i]) {
|
|
delete g_font[i];
|
|
g_font[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ttf_render_string(
|
|
const double& alpha_value,
|
|
// reference value to which incoming alpha values are compared.
|
|
// 0 through to 1
|
|
const double& x,
|
|
const double& y,
|
|
const double& z, // text position
|
|
const float& fscale, // scale factor
|
|
const GLfloat* col, // colour 4vf
|
|
const int& iFont, // font index
|
|
const char* s, // string ptr
|
|
const float& fRotAngle, // optional rotation angle
|
|
const float& fRotX, // optional rotation vector for X
|
|
const float& fRotY, // optional rotation vector for Y
|
|
const float& fRotZ, // optional rotation vector for Z
|
|
const float& fRadius // circular radius to draw along
|
|
)
|
|
{
|
|
// http://ftgl.sourceforge.net/docs/html/
|
|
|
|
if(iFont < 0 || iFont > NUM_FONT || !g_font[iFont]) return; //invalid font
|
|
|
|
int renderMode = FTGL::FTGL_RENDER_FRONT; //ALL; //FRONT | FTGL::FTGL_RENDER_BACK;
|
|
|
|
GLfloat color[4];
|
|
memcpy(color, col, sizeof(GLfloat) * 4);
|
|
color[3] = (GLfloat) alpha_value; // force the alpha value passed in
|
|
glColor4fv(color);
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslated(x, y, z);
|
|
glScaled(1.0f / fscale, 1.0f / fscale, 1.0f / fscale);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
if (fRotAngle != 0.0f) {
|
|
glRotatef(fRotAngle, fRotX, fRotY, fRotZ);
|
|
}
|
|
|
|
if (fRadius == 0.0f) {
|
|
g_font[iFont]->Render(s, -1, FTPoint(), FTPoint(), renderMode);
|
|
}
|
|
else {
|
|
int i = 0;
|
|
float fAdvance = 1.0f;
|
|
while ( *(s+i) ) {
|
|
fAdvance = g_font[iFont]->Advance((s+i), 1, FTPoint());
|
|
g_font[iFont]->Render((s+i), 1, FTPoint(), FTPoint(), renderMode);
|
|
glTranslated(fAdvance, 0.0f, 0.0f);
|
|
glRotatef(fRadius * fAdvance / (float) 20.0f, 0.0f, 0.0f, 1.0f);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
|
|
// based on boinc/api/gutil.cpp -- but makes an alpha map out of an RGB file for transparency
|
|
// basic pic editors such as Gimp are pretty easy to set a weird color not in the main image of course)
|
|
// or even easier -- use Gimp to set "Color to Alpha" and just embed it in the .rgb file as an RGBA (A = "alpha channel")
|
|
GLuint CreateRGBTransparentTexture(const char* strFileName, float* transColor) // default in prototype to transColor = NULL i.e. no "filter color" required
|
|
{
|
|
// transcolor is an optional (but necessary for Z=3 i.e. RGB) which will flip the alpha of an RGB color (i.e. Magenta would be 255/0/255 passed in transColor
|
|
|
|
GLuint uiTexture = 0;
|
|
int sizeX, sizeY, sizeZ;
|
|
// Load the image and store the data - this is in rgba format but the a is 255 (max)
|
|
unsigned int *pImage = read_rgb_texture(strFileName,&sizeX,&sizeY,&sizeZ); // read_rgb_texgture makes a 4channel (1 byte per R/G/B/A) anyway, so may as well use the "A"!
|
|
if(pImage == NULL) return 0;
|
|
if (sizeZ != 3 && sizeZ != 4) { // needs to be RGB i.e. z=3 or RGBA z=4
|
|
free(pImage);
|
|
return 0;
|
|
}
|
|
|
|
// need to set transparency bytes/alpha value every place in pImage using magenta 255/0/255!
|
|
// also note image needs to be flipped vertically when you save it! (at least in gimp)
|
|
if (sizeZ == 3 && transColor) { //rgb -> rgba via the RGB values in transColor[3] array, if transColor not set not much use to this so just default to the RGBA created above (A=255 for all pixels)
|
|
for(int i = 0; i < (sizeX * sizeY); i++)
|
|
{
|
|
unsigned char* bb = (unsigned char*) (pImage+i); // easy pointer to our image pixels
|
|
// just take the avg of the RGB -- as it approaches 0, the alpha goes to 0 (so basically the blacker, the more transperent)
|
|
if(*bb == g_transColor[0]
|
|
&& *(bb+1) == g_transColor[1]
|
|
&& *(bb+2) == g_transColor[2] )
|
|
{
|
|
*(bb+3) = 0x00; // If so, set alpha to fully transparent. (note this sets all 4 bytes to 0)
|
|
} // alpha already set to 255 if not transparent
|
|
|
|
//iTest = (*bb + *(bb+1) + *(bb+2)) / 3;
|
|
//*(bb+3) = iTest > 255 ? 255 : iTest;
|
|
}
|
|
}
|
|
// sizeZ == 4 is just "straight" RGBA where alpha is embedded in the file; which is already taken care of by the above load_file
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
|
|
glGenTextures( 1, &uiTexture );
|
|
glBindTexture( GL_TEXTURE_2D, uiTexture );
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // this isn't as fast supposedly, but looks pretty good
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); // also not as fast as GL_NEAREST but looks better!
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA,
|
|
sizeX, sizeY, GL_RGBA, GL_UNSIGNED_BYTE, pImage);
|
|
|
|
free(pImage); // free the mem allocated by the rgb_texture function
|
|
return uiTexture;
|
|
}
|
|
|
|
|
|
// based on boinc/api/gutil.cpp -- but makes a GL_ALPHA out of an RGB file (sums values each point to make the alpha)
|
|
// the basic idea is you can make a simple image that can translate to a complex map -- white values (1) "pass" and black values (0) "block"
|
|
GLuint CreateRGBAlpha(const char* strFileName)
|
|
{
|
|
//if(!strFileName && !boinc_file_exists(strFileName)) return 0;
|
|
GLuint uiTexture = 0;
|
|
int sizeX;
|
|
int sizeY;
|
|
int sizeZ;
|
|
// Load the image and store the data
|
|
unsigned int *pImage = read_rgb_texture(strFileName,&sizeX,&sizeY,&sizeZ);
|
|
if(pImage == NULL) return 0;
|
|
if (sizeZ > 1) { // error - just want a 1-D for alpha levels
|
|
fprintf(stderr, "Improper RGB Image for Alpha: %s needs just 1 level, this file has %d\n", strFileName, sizeZ);
|
|
free(pImage);
|
|
return 0;
|
|
}
|
|
unsigned char* pByte = new unsigned char[sizeX*sizeY*sizeZ];
|
|
memset(pByte, 0x00, sizeX*sizeY*sizeZ);
|
|
for (int i = 0 ; i < (sizeX*sizeY*sizeZ) ; i++) {
|
|
pByte[i] = (unsigned char) *(pImage+i) & ~0xffffff00; // get the final char from masking the higher bits
|
|
}
|
|
free(pImage); // don't need the image data, may as well free it
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
|
|
glGenTextures(1, &uiTexture);
|
|
glBindTexture(GL_TEXTURE_2D, uiTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, sizeX, sizeY, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pByte);
|
|
//glBindTexture(GL_TEXTURE_2D, 0);
|
|
delete [] pByte; // free the temporary byte array
|
|
return uiTexture;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|