1303 lines
35 KiB
C++
1303 lines
35 KiB
C++
#include "CKAll.h"
|
|
#include "CKTextureFont.h"
|
|
#include "CKFontManager.h"
|
|
#include "CKRasterizer.h"
|
|
|
|
#define ROUND(a) (((a)<0)?(int)((a)-0.5):(int)((a)+0.5))
|
|
|
|
CKTextureFont::CKTextureFont(CKFontManager* fm,CKContext* ctx,char* name)
|
|
{
|
|
///
|
|
// Font Visual Properties
|
|
m_Leading.Set(0.0f,0.0f);
|
|
m_Scale.Set(1.0f,1.0f);
|
|
m_ShadowOffset.Set(4.0f,4.0f);
|
|
m_ShadowScale.Set(1.0f,1.0f);
|
|
m_ItalicOffset = 0.0f;
|
|
m_StartColor = RGBAITOCOLOR(255,255,255,255);
|
|
m_EndColor = RGBAITOCOLOR(0,0,0,255);
|
|
m_ShadowColor = RGBAITOCOLOR(0,0,0,128);
|
|
m_Material = 0;
|
|
m_Properties = 0;
|
|
m_FontTexture = 0;
|
|
m_FirstCharacter = 0;
|
|
m_ParagraphIndentation = 0.0f;
|
|
m_SpacingProperties = 0;
|
|
m_CaretMaterial = 0;
|
|
m_CaretSize = 0.0f;
|
|
m_SpacePercentage = 0.3f;
|
|
|
|
m_FontName = CKStrdup(name);
|
|
m_Context = ctx;
|
|
m_FontManager = fm;
|
|
}
|
|
|
|
CKTextureFont::~CKTextureFont()
|
|
{
|
|
CKStrdelete(m_FontName);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// NEW FUNCTIONS
|
|
|
|
// Font Access
|
|
char*
|
|
CKTextureFont::GetFontName()
|
|
{
|
|
return m_FontName;
|
|
}
|
|
|
|
CKBOOL
|
|
CKTextureFont::IsFontSimilar(CKTexture* fonttexture,Vx2DVector& charnumber,CKBOOL fixed)
|
|
{
|
|
if(fixed) {
|
|
if(!(m_SpacingProperties & FIXED)) return FALSE;
|
|
} else {
|
|
if (m_SpacingProperties & FIXED) return FALSE;
|
|
}
|
|
if(m_FontTexture != CKOBJID(fonttexture)) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
CKTextureFont::CreateCKFont(CKTexture* fonttexture,VxRect& tzone,Vx2DVector& charnumber,CKBOOL fixed,int firstcharacter,float iSpaceSize)
|
|
{
|
|
if(!fonttexture) return;
|
|
|
|
m_CharNumber = charnumber;
|
|
m_SpacingProperties = (fixed)?FIXED:0;
|
|
m_FirstCharacter = firstcharacter;
|
|
|
|
// save the font texture id
|
|
m_FontTexture = CKOBJID(fonttexture);
|
|
|
|
float twidth = (float)fonttexture->GetWidth();
|
|
float theight = (float)fonttexture->GetHeight();
|
|
|
|
m_ScreenExtents.Set(twidth,theight);
|
|
|
|
if (!tzone.GetWidth() || !tzone.GetHeight()) {
|
|
tzone.SetDimension(0,0,twidth,theight);
|
|
}
|
|
|
|
m_FontZone = tzone;
|
|
m_SpacePercentage = iSpaceSize;
|
|
|
|
// the Creation
|
|
CreateFromTexture();
|
|
}
|
|
|
|
void
|
|
CKTextureFont::CreateFromTexture()
|
|
{
|
|
if (m_SpacingProperties&CREATED) return;
|
|
|
|
CKTexture* fonttexture = (CKTexture*)m_Context->GetObject(m_FontTexture);
|
|
if(!fonttexture) return;
|
|
|
|
|
|
int iWidth = fonttexture->GetWidth();
|
|
|
|
float twidth = (float)iWidth;
|
|
float theight = (float)fonttexture->GetHeight();
|
|
|
|
m_ScreenExtents.Set(twidth,theight);
|
|
|
|
float ustep = m_FontZone.GetWidth()/(twidth*m_CharNumber.x);
|
|
float vstep = m_FontZone.GetHeight()/(theight*m_CharNumber.y);
|
|
|
|
Vx2DVector v2 = m_FontZone.GetTopLeft();
|
|
float u = v2.x/twidth;
|
|
float v = v2.y/theight;
|
|
|
|
int c = m_FirstCharacter;
|
|
|
|
// Initialisation of the characters
|
|
for(int k=0; k<256; ++k) {
|
|
m_FontCoordinates[k].ustart = u;
|
|
m_FontCoordinates[k].vstart = v;
|
|
m_FontCoordinates[k].uwidth = ustep;
|
|
m_FontCoordinates[k].uprewidth = 0;
|
|
m_FontCoordinates[k].upostwidth = 0;
|
|
m_FontCoordinates[k].vwidth = vstep;
|
|
}
|
|
|
|
if (m_SpacingProperties & FIXED) { // The font must be fixed
|
|
|
|
// fill the uvs of the characters
|
|
for(int i=0;i<m_CharNumber.y;++i) {
|
|
for(int j=0;j<m_CharNumber.x;++j) {
|
|
m_FontCoordinates[c].ustart = u;
|
|
m_FontCoordinates[c].vstart = v;
|
|
|
|
m_FontCoordinates[c].uwidth = ustep;
|
|
m_FontCoordinates[c].vwidth = vstep;
|
|
|
|
u += ustep;
|
|
c++;
|
|
}
|
|
u = 0.0f;
|
|
v += vstep;
|
|
}
|
|
} else { // The font must be proportionnal
|
|
CKDWORD transcolor = 0;
|
|
CKBOOL alpha = TRUE;
|
|
if(fonttexture->IsTransparent()) {
|
|
alpha = FALSE;
|
|
transcolor = fonttexture->GetTransparentColor();
|
|
}
|
|
|
|
float width = (float)fonttexture->GetWidth();
|
|
float height= (float)fonttexture->GetHeight();
|
|
|
|
float upixel = 1.0f / width;
|
|
float vpixel = 1.0f / height;
|
|
|
|
int xpixel = 0;
|
|
int ypixel = 0;
|
|
|
|
int xwidth = (int)(width*ustep);
|
|
int ywidth = (int)(height*vstep);
|
|
|
|
#ifndef FONTMANAGER_NOSYSFONT
|
|
// Give the priority to the user defined font texture
|
|
// If we give the same name to a texture than a system font, we use the texture
|
|
// with self calculated dimensions
|
|
|
|
// Mark the font as to be saved
|
|
m_SpacingProperties |= SPACINGTOBESAVED;
|
|
|
|
// Select the font
|
|
CKTexture* texture = (CKTexture*)m_Context->GetObject(m_FontTexture);
|
|
CKSTRING textureName = (texture)?texture->GetName():NULL;
|
|
if(textureName)
|
|
if (m_FontManager->SelectFont(textureName)) {
|
|
if(m_FontManager->IsTrueTypeFont()) {
|
|
FONT_ABC fontABC[256];
|
|
if(m_FontManager->GetCharABCWidths(0, 255, fontABC)) {
|
|
for(int i = 0 ; i < m_CharNumber.y ; i++) {
|
|
for(int j = 0 ; j < m_CharNumber.x ; j++) {
|
|
m_FontCoordinates[c].ustart = u+fontABC[c].abcA*upixel;
|
|
m_FontCoordinates[c].vstart = v;
|
|
m_FontCoordinates[c].uprewidth = fontABC[c].abcA*upixel;
|
|
m_FontCoordinates[c].uwidth = fontABC[c].abcB*upixel;
|
|
m_FontCoordinates[c].upostwidth = fontABC[c].abcC*upixel;
|
|
m_FontCoordinates[c].vwidth = vstep;
|
|
|
|
u += ustep;
|
|
c++;
|
|
}
|
|
u = 0.0f;
|
|
v += vstep;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
int widths[256];
|
|
if(m_FontManager->GetCharWidths(0, 255, widths)) {
|
|
for(int i = 0 ; i < m_CharNumber.y ; i++) {
|
|
for(int j = 0 ; j < m_CharNumber.x ; j++) {
|
|
m_FontCoordinates[c].ustart = u;
|
|
m_FontCoordinates[c].vstart = v;
|
|
m_FontCoordinates[c].uprewidth = 0;
|
|
m_FontCoordinates[c].uwidth = widths[c]*upixel;
|
|
m_FontCoordinates[c].upostwidth = 0;
|
|
m_FontCoordinates[c].vwidth = vstep;
|
|
|
|
u += ustep;
|
|
c++;
|
|
}
|
|
u = 0.0f;
|
|
v += vstep;
|
|
}
|
|
}
|
|
}
|
|
m_FontManager->SelectFont(NULL);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
CKDWORD* pixelMap = (CKDWORD*)fonttexture->LockSurfacePtr();
|
|
|
|
// fill the uvs of the characters
|
|
for(int i=0;i<m_CharNumber.y;++i) {
|
|
for(int j=0;j<m_CharNumber.x;++j) {
|
|
m_FontCoordinates[c].ustart = u;
|
|
m_FontCoordinates[c].vstart = v;
|
|
|
|
m_FontCoordinates[c].uwidth = ustep;
|
|
m_FontCoordinates[c].vwidth = vstep;
|
|
|
|
// We now try to narrow the character
|
|
|
|
// left
|
|
int k;
|
|
for(k=0;k<xwidth;k++) {
|
|
CKDWORD color;
|
|
int y;
|
|
if(alpha) {
|
|
for (y=0;y<ywidth;y++) {
|
|
// color = fonttexture->GetPixel(xpixel+k,ypixel+y);
|
|
color = pixelMap[xpixel+k+iWidth*(ypixel+y)];
|
|
if(ColorGetAlpha(color)) break;
|
|
}
|
|
} else {
|
|
for (y=0;y<ywidth;y++) {
|
|
// color = fonttexture->GetPixel(xpixel+k,ypixel+y);
|
|
color = pixelMap[xpixel+k+iWidth*(ypixel+y)];
|
|
if(color != transcolor) break;
|
|
}
|
|
}
|
|
if(y < ywidth) break;
|
|
}
|
|
|
|
if (k == xwidth) { // the whole character is empty
|
|
m_FontCoordinates[c].uwidth *= m_SpacePercentage; // Changed from 0.5 to 0.3 coz was too big
|
|
u += ustep;
|
|
xpixel += xwidth;
|
|
|
|
c++;
|
|
// We go on to the next character
|
|
continue;
|
|
} else {
|
|
m_FontCoordinates[c].ustart += k*upixel;
|
|
m_FontCoordinates[c].uwidth -= k*upixel;
|
|
}
|
|
|
|
// right
|
|
for(k=0;k<xwidth;k++) {
|
|
int y;
|
|
for(y=0;y<ywidth;y++) {
|
|
//CKDWORD color = fonttexture->GetPixel(xpixel+xwidth-1-k,ypixel+y);
|
|
CKDWORD color = pixelMap[xpixel+xwidth-1-k+iWidth*(ypixel+y)];
|
|
if(alpha) {
|
|
if(ColorGetAlpha(color)) break;
|
|
} else {
|
|
if(color != transcolor) break;
|
|
}
|
|
}
|
|
if(y < ywidth) break;
|
|
}
|
|
|
|
m_FontCoordinates[c].uwidth -= k*upixel;
|
|
if(m_FontCoordinates[c].uwidth < 0.0f) m_FontCoordinates[c].uwidth = 0.0f;
|
|
|
|
u += ustep;
|
|
xpixel += xwidth;
|
|
|
|
c++;
|
|
}
|
|
|
|
u = 0.0f;
|
|
xpixel = 0;
|
|
|
|
v += vstep;
|
|
ypixel += ywidth;
|
|
}
|
|
|
|
fonttexture->ReleaseSurfacePtr();
|
|
}
|
|
}
|
|
|
|
if (m_FirstCharacter) {
|
|
m_FontCoordinates[0].vwidth = vstep;
|
|
}
|
|
|
|
// The font is now officialy created
|
|
m_SpacingProperties |= CREATED;
|
|
}
|
|
|
|
/////////////////////////
|
|
// The leading must be in relative of the texture too (for example leading = leadinginpixels/texturewidth or leadinginpixels/devicewidth)
|
|
// Warning : Is /texturewidth working ok ?
|
|
////////////////////////////
|
|
float
|
|
CKTextureFont::GetStringWidth(CKSTRING string)
|
|
{
|
|
if(!string) return 0.0f;
|
|
|
|
// TODO : optimize this
|
|
float scale = m_Scale.x*m_ScreenExtents.x;
|
|
float leading = m_Leading.x/scale;
|
|
float italic = m_ItalicOffset/scale;
|
|
|
|
float sw = 0.0f;
|
|
while((*string>0) && *string != '\n') {
|
|
// We add the character width (relative to the texture)
|
|
CharacterTextureCoordinates* ctc = &m_FontCoordinates[(unsigned char)*string];
|
|
sw += (ctc->uprewidth+ctc->uwidth+ctc->upostwidth);
|
|
// We add the leading
|
|
sw += leading;
|
|
|
|
string++;
|
|
}
|
|
|
|
// No space after last character of the line
|
|
sw -= leading;
|
|
// Italic offset at the end
|
|
sw += italic;
|
|
|
|
return sw*scale;
|
|
}
|
|
|
|
int
|
|
CKTextureFont::GetTextExtents(float &width,float& height)
|
|
{
|
|
int linecount = m_FontManager->GetLineCount();
|
|
|
|
float vspace = m_FontCoordinates[0].vwidth*(m_Scale.y*m_ScreenExtents.y)+m_Leading.y;
|
|
for(int i=0;i<linecount;++i) {
|
|
// currrent line
|
|
LineData* data = m_FontManager->GetLine(i);
|
|
|
|
if(data->stringwidth > width) {
|
|
width = data->stringwidth;
|
|
}
|
|
|
|
// Paragraph Indentation
|
|
if((data->len < 0) && (i != 0)) {
|
|
height += m_ParagraphIndentation.y*m_FontCoordinates[0].vwidth*(m_Scale.y*m_ScreenExtents.y);
|
|
}
|
|
|
|
// We add the Y space
|
|
height += vspace;
|
|
}
|
|
|
|
return linecount;
|
|
}
|
|
|
|
void
|
|
DrawFillRectangle(CKRenderContext *dev,CKMaterial* mat,VxRect& rect,BOOL lighted,BOOL transform)
|
|
{
|
|
if(!mat) return;
|
|
|
|
VxDrawPrimitiveData* data;
|
|
if(transform && lighted) data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VNT,4);
|
|
else
|
|
if(transform) data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VCT,4);
|
|
else
|
|
if(lighted) data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VNT&~CKRST_DP_TRANSFORM),4);
|
|
else data = dev->GetDrawPrimitiveStructure(CKRST_DP_CL_VCT,4);
|
|
|
|
CKWORD* indices = dev->GetDrawPrimitiveIndices(4);
|
|
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<VxVector> normals(data->Normals);
|
|
XPtrStrided<CKDWORD> colors(data->Colors);
|
|
|
|
// TODO handle the multi lines
|
|
mat->SetAsCurrent(dev);
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE);
|
|
|
|
if(lighted) {
|
|
/////////////////
|
|
// Normals
|
|
|
|
// Normal 0
|
|
normals->x = 0;
|
|
normals->y = 0;
|
|
normals->z = 1.0f;
|
|
++normals;
|
|
// Normal 1
|
|
normals->x = 0;
|
|
normals->y = 0;
|
|
normals->z = 1.0f;
|
|
++normals;
|
|
// Normal 2
|
|
normals->x = 0;
|
|
normals->y = 0;
|
|
normals->z = 1.0f;
|
|
++normals;
|
|
// Normal 3
|
|
normals->x = 0;
|
|
normals->y = 0;
|
|
normals->z = 1.0f;
|
|
++normals;
|
|
|
|
} else {
|
|
/////////////////
|
|
// Colors
|
|
|
|
VxColor vxcol = mat->GetDiffuse();
|
|
CKDWORD col = RGBAFTOCOLOR(&vxcol);
|
|
// Vertex 0
|
|
*colors = col;
|
|
++colors;
|
|
// Vertex 1
|
|
*colors = col;
|
|
++colors;
|
|
// Vertex 2
|
|
*colors = col;
|
|
++colors;
|
|
// Vertex 3
|
|
*colors = col;
|
|
++colors;
|
|
}
|
|
|
|
/////////////////
|
|
// UVs
|
|
|
|
// Vertex 0
|
|
uvs->u = 0.0f;
|
|
uvs->v = 0.0f;
|
|
++uvs;
|
|
// Vertex 1
|
|
uvs->u = 1.0f;
|
|
uvs->v = 0.0f;
|
|
++uvs;
|
|
// Vertex 2
|
|
uvs->u = 1.0f;
|
|
uvs->v = 1.0f;
|
|
++uvs;
|
|
// Vertex 3
|
|
uvs->u = 0.0f;
|
|
uvs->v = 1.0f;
|
|
++uvs;
|
|
|
|
/////////////////
|
|
// Positions
|
|
|
|
// Vertex 0
|
|
positions->Set( rect.left , rect.top , 0.0f , 1.0f);
|
|
++positions;
|
|
// Vertex 1
|
|
positions->Set( rect.right , rect.top , 0.0f , 1.0f);
|
|
++positions;
|
|
// Vertex 2
|
|
positions->Set( rect.right , rect.bottom , 0.0f , 1.0f);
|
|
++positions;
|
|
// Vertex 3
|
|
positions->Set( rect.left , rect.bottom , 0.0f , 1.0f);
|
|
++positions;
|
|
|
|
indices[0] = 0;
|
|
indices[1] = 1;
|
|
indices[2] = 2;
|
|
indices[3] = 3;
|
|
|
|
// the drawing itself
|
|
dev->DrawPrimitive( VX_TRIANGLEFAN, indices, 4, data );
|
|
}
|
|
|
|
void
|
|
CKTextureFont::DrawString(CKRenderContext *dev,CKSTRING string,int slen,VxVector position,VxRect& Textzone,CKDWORD textoptions,CompiledTextData* ctdata)
|
|
{
|
|
if(!slen) return;
|
|
int len = slen;
|
|
|
|
// We check if we are in Text Compilation
|
|
if (!(textoptions & TEXT_COMPILED)) ctdata = NULL;
|
|
|
|
// Screen Clipping
|
|
VxRect textzone = Textzone;
|
|
if (textoptions & TEXT_SCREENCLIP) {
|
|
if (!textzone.Clip(m_ClippingRect)) return;
|
|
}
|
|
|
|
///
|
|
// Creation of the DrawPrim Data
|
|
VxDrawPrimitiveData* data = NULL;
|
|
CKWORD* IndicesPtr = NULL;
|
|
if (ctdata) {
|
|
if (textoptions&TEXT_3D) { // 3D
|
|
if (m_Properties&FONT_LIGHTING) { // Lighting
|
|
data = ctdata->GetStructure(CKRST_DP_TR_CL_VNT,len*4);
|
|
} else {
|
|
data = ctdata->GetStructure(CKRST_DP_TR_CL_VCT,len*4);
|
|
}
|
|
} else { // 2D
|
|
data = ctdata->GetStructure(CKRST_DP_CL_VCST,len*4);
|
|
}
|
|
|
|
// Indices
|
|
IndicesPtr = ctdata->GetIndices(len*6);
|
|
} else {
|
|
// Draw Prim Data
|
|
if (textoptions&TEXT_3D) { // 3D
|
|
if (m_Properties&FONT_LIGHTING) { // Lighting
|
|
data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VNT,len*4);
|
|
} else {
|
|
data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VCT,len*4);
|
|
}
|
|
} else { // 2D
|
|
data = dev->GetDrawPrimitiveStructure(CKRST_DP_CL_VCST,len*4);
|
|
}
|
|
|
|
// Indices
|
|
IndicesPtr = dev->GetDrawPrimitiveIndices(len*6);
|
|
}
|
|
|
|
VxVector pos = position;
|
|
VxVector scale(m_Scale.x*m_ScreenExtents.x,m_Scale.y*m_ScreenExtents.y,0);
|
|
float width = scale.x;
|
|
float height= scale.y;
|
|
float italic = m_ItalicOffset*width;
|
|
|
|
CKTexture* tex = GetFontTexture();
|
|
if(!tex) {
|
|
return;
|
|
}
|
|
|
|
// Multiplication by scale removed because big fonts were cropped !
|
|
float texelwidth = /*m_Scale.x */ 0.25f/tex->GetWidth();
|
|
float texelheight= /*m_Scale.y */ 0.25f/tex->GetHeight();
|
|
|
|
WORD* indices = IndicesPtr;
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
|
|
int index = 0;
|
|
|
|
int oldlen = len;
|
|
// We reset the counter
|
|
len = 0;
|
|
|
|
// int conversion for proper rendering
|
|
if (!(textoptions&TEXT_3D)) {
|
|
pos.x = (float)(int)(pos.x+0.5f);
|
|
pos.y = (float)(int)(pos.y+0.5f);
|
|
|
|
if (!(textoptions&TEXT_JUSTIFIED)) {
|
|
m_HLeading = (float)ROUND(m_HLeading);
|
|
}
|
|
}
|
|
|
|
float lineheight = m_FontCoordinates[0].vwidth*height;
|
|
|
|
BOOL seeCaret = FALSE;
|
|
// Clipping Y
|
|
float starty = pos.y;
|
|
float endy = pos.y+lineheight;
|
|
float cutup = 0.0f;
|
|
float cutdown = 1.0f;
|
|
|
|
if (textoptions & TEXT_CLIP) {
|
|
// Bottom of the zone
|
|
if(pos.y > textzone.bottom) return;
|
|
// Top of the zone
|
|
if(endy < textzone.top) return;
|
|
// Right of the zone
|
|
if(pos.x > textzone.right) return;
|
|
// Left of the zone
|
|
if(pos.x+m_LineWidth < textzone.left) return;
|
|
|
|
// Cut on top
|
|
if(starty < textzone.top) {
|
|
cutup = (textzone.top-starty)/lineheight;
|
|
starty = textzone.top;
|
|
}
|
|
// Cut on bottom
|
|
if(endy > textzone.bottom) {
|
|
cutdown = 1.0f - (endy-textzone.bottom)/lineheight;
|
|
endy = textzone.bottom;
|
|
}
|
|
}
|
|
|
|
// Temporary Variables
|
|
float startx = -1.0f;
|
|
float endx = -1.0f;
|
|
float startu = -1.0f;
|
|
float endu = -1.0f;
|
|
|
|
while(slen--) {
|
|
// Skipping irrelevant character
|
|
if((*string == ' ')) { // Here comes a space or a null character
|
|
if (seeCaret) {
|
|
if (textoptions & TEXT_SHOWCARET) {
|
|
DrawCaret(dev,pos.x,starty,m_SpaceSize,endy-starty,data->Flags);
|
|
SetRenderStates(dev,textoptions);
|
|
}
|
|
seeCaret = FALSE;
|
|
}
|
|
pos.x += m_SpaceSize;
|
|
|
|
++string;
|
|
continue;
|
|
}
|
|
|
|
if((*string == '\b')) { // Caret character
|
|
if (!slen) { // end of string, we have to draw the caret now
|
|
if (textoptions & TEXT_SHOWCARET) {
|
|
DrawCaret(dev,pos.x,starty,m_SpaceSize,endy-starty,data->Flags);
|
|
SetRenderStates(dev,textoptions);
|
|
}
|
|
}
|
|
seeCaret = TRUE;
|
|
|
|
++string;
|
|
continue;
|
|
}
|
|
|
|
CharacterTextureCoordinates* ctc = &m_FontCoordinates[(unsigned char)*string];
|
|
|
|
// If the character is empty, we skip it
|
|
if(ctc->vwidth == 0.0f) {
|
|
string++;
|
|
continue;
|
|
}
|
|
|
|
/////////////////
|
|
// Positions
|
|
|
|
startx = pos.x+ctc->uprewidth*width;
|
|
endx = startx + width*ctc->uwidth;
|
|
startu = ctc->ustart;
|
|
endu = ctc->ustart+ctc->uwidth;
|
|
|
|
////////////////////
|
|
// Clipping
|
|
|
|
if (textoptions & TEXT_CLIP) {
|
|
if(startx > textzone.right) break; // letter totally Right of the zone : we can stop writing
|
|
|
|
if(endx < textzone.left) { // letter totally Left of the zone : skip tio the next one
|
|
pos.x = endx + m_HLeading + ctc->upostwidth*width;
|
|
++string;
|
|
continue;
|
|
}
|
|
|
|
if (pos.x < textzone.left) { // Letter partially left of the zone
|
|
startu += (textzone.left-startx)/width;
|
|
startx = textzone.left;
|
|
}
|
|
|
|
if(endx > textzone.right) { // Letter partially left of the zone
|
|
endu -= (endx-textzone.right)/width;
|
|
endx = textzone.right;
|
|
}
|
|
}
|
|
|
|
// Vertices 0 1 2 3
|
|
if (!(textoptions&TEXT_3D)) {
|
|
positions->Set((int)(startx+italic+0.5f)-0.25f, starty, 0.01f,1.0f);++positions;
|
|
positions->Set((int)(endx+italic+0.5f)-0.25f, starty, 0.01f,1.0f);++positions;
|
|
positions->Set((int)(endx+0.5f)-0.25f, endy, 0.01f,1.0f);++positions;
|
|
positions->Set((int)(startx+0.5f)-0.25f, endy, 0.01f,1.0f);++positions;
|
|
} else {
|
|
positions->Set(startx+italic, starty, 0.01f,1.0f);++positions;
|
|
positions->Set(endx+italic, starty, 0.01f,1.0f);++positions;
|
|
positions->Set(endx, endy, 0.01f,1.0f);++positions;
|
|
positions->Set(startx, endy, 0.01f,1.0f);++positions;
|
|
}
|
|
|
|
if (seeCaret) {
|
|
if (textoptions & TEXT_SHOWCARET) {
|
|
DrawCaret(dev,startx,starty,endx-startx,endy-starty,data->Flags);
|
|
SetRenderStates(dev,textoptions);
|
|
}
|
|
seeCaret = FALSE;
|
|
}
|
|
|
|
// advance to next character
|
|
pos.x = endx + ctc->upostwidth*width + m_HLeading;
|
|
|
|
/////////////////
|
|
// UVs
|
|
|
|
float topv = ctc->vstart+cutup*ctc->vwidth;
|
|
float botv = ctc->vstart+cutdown*ctc->vwidth;
|
|
|
|
startu += texelwidth;
|
|
topv += texelheight;
|
|
|
|
// Vertex 0 1 2 3
|
|
uvs->u = startu; uvs->v = topv; ++uvs;
|
|
uvs->u = endu; uvs->v = topv; ++uvs;
|
|
uvs->u = endu; uvs->v = botv; ++uvs;
|
|
uvs->u = startu; uvs->v = botv; ++uvs;
|
|
|
|
/////////////////////
|
|
// Indices
|
|
|
|
indices[0] = index;
|
|
indices[1] = index+1;
|
|
indices[2] = index+2;
|
|
indices[3] = index;
|
|
indices[4] = index+2;
|
|
indices[5] = index+3;
|
|
indices += 6;
|
|
index += 4;
|
|
|
|
// String advance
|
|
++string;
|
|
// One more face couple
|
|
++len;
|
|
}
|
|
|
|
if (!len) return;
|
|
|
|
///
|
|
// Colors & Normals
|
|
|
|
if(m_Properties&FONT_LIGHTING) {
|
|
/////////////////
|
|
// Normals
|
|
|
|
VxVector norm(0,0,1.0f);
|
|
VxFillStructure(len*4,data->Normals,sizeof(VxVector),&norm);
|
|
} else {
|
|
/////////////////
|
|
// Colors
|
|
|
|
CKDWORD cols[4];
|
|
if (m_Properties & FONT_GRADIENT) {
|
|
CKDWORD scolor = m_StartColor;
|
|
CKDWORD ecolor = m_EndColor;
|
|
if(cutup!=0.0f || cutdown!=0.0f) {
|
|
cutdown = 1.0f - cutdown;
|
|
|
|
VxColor scol(scolor);
|
|
VxColor ecol(ecolor);
|
|
VxColor delta(ecol.r-scol.r,ecol.g-scol.g,ecol.b-scol.b,ecol.a-scol.a);
|
|
scol.r += (delta.r)*cutup;
|
|
scol.g += (delta.g)*cutup;
|
|
scol.b += (delta.b)*cutup;
|
|
scol.a += (delta.a)*cutup;
|
|
ecol.r -= (delta.r)*cutdown;
|
|
ecol.g -= (delta.g)*cutdown;
|
|
ecol.b -= (delta.b)*cutdown;
|
|
ecol.a -= (delta.a)*cutdown;
|
|
scolor = RGBAFTOCOLOR(&scol);
|
|
ecolor = RGBAFTOCOLOR(&ecol);
|
|
}
|
|
|
|
cols[0] = scolor;
|
|
cols[1] = scolor;
|
|
cols[2] = ecolor;
|
|
cols[3] = ecolor;
|
|
} else {
|
|
cols[0] = m_StartColor;
|
|
cols[1] = m_StartColor;
|
|
cols[2] = m_StartColor;
|
|
cols[3] = m_StartColor;
|
|
}
|
|
|
|
// WARNING : this works only because all the colors are contiguous...
|
|
VxFillStructure(len,data->Colors.Ptr,4*data->Colors.Stride,4*sizeof(CKDWORD),&cols);
|
|
}
|
|
|
|
if (ctdata) ctdata->PatchIndices(oldlen*6,len*6);
|
|
|
|
// the drawing itself
|
|
data->VertexCount = index;
|
|
dev->DrawPrimitive( VX_TRIANGLELIST, IndicesPtr, len*6, data );
|
|
}
|
|
|
|
|
|
void
|
|
CKTextureFont::DrawCaret(CKRenderContext* context,float posx,float posy,float dimx,float dimy,CKDWORD flags)
|
|
{
|
|
VxDrawPrimitiveData data;
|
|
data.VertexCount = 4;
|
|
if(m_CaretMaterial) m_CaretMaterial->SetAsCurrent(context);
|
|
VxVector4 positions[4];
|
|
float uvs[8] = {0.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f,1.0f};
|
|
positions[0].Set(posx,posy+dimy,0.0f,1.0f);
|
|
positions[1].Set(posx,posy+dimy*(1.0f-m_CaretSize),0.0f,1.0f);
|
|
positions[2].Set(posx+dimx,posy+dimy*(1.0f-m_CaretSize),0.0f,1.0f);
|
|
positions[3].Set(posx+dimx,posy+dimy,0.0f,1.0f);
|
|
VxColor diffuse(1.0f,1.0f,1.0f,0.5f);
|
|
if(m_CaretMaterial) diffuse = m_CaretMaterial->GetDiffuse();
|
|
CKDWORD col = RGBAFTOCOLOR(&diffuse);
|
|
CKDWORD colors[4] = {col,col,col,col};
|
|
data.Flags = flags;
|
|
data.Positions.Set(&positions,sizeof(VxVector4));
|
|
data.TexCoord.Set(&uvs,2*sizeof(float));
|
|
data.Colors.Set(&colors,sizeof(CKDWORD));
|
|
data.Normals.Set(0,0);
|
|
context->DrawPrimitive(VX_TRIANGLEFAN,(WORD*)0,4,&data);
|
|
}
|
|
|
|
|
|
void
|
|
CKTextureFont::DrawStringShadowed(CKRenderContext *dev,CKSTRING string,int slen,VxVector position,VxRect& textzone,CKDWORD textoptions,CompiledTextData* ctdata)
|
|
{
|
|
VxVector shadowoffset(m_ShadowOffset.x,m_ShadowOffset.y,0);
|
|
VxVector shadowpos = position + shadowoffset;
|
|
|
|
CKDWORD oldproperties = m_Properties;
|
|
m_Properties &= ~FONT_GRADIENT;
|
|
|
|
CKDWORD oldstartcolor = m_StartColor;
|
|
m_StartColor = m_ShadowColor;
|
|
|
|
Vx2DVector oldscale = m_Scale;
|
|
m_Scale = m_ShadowScale;
|
|
|
|
// We draw the shadow
|
|
if (ColorGetAlpha(m_ShadowColor)) DrawString(dev,string,slen,shadowpos,textzone,textoptions,ctdata);
|
|
|
|
// We restore the normal states
|
|
m_StartColor = oldstartcolor;
|
|
m_Properties = oldproperties;
|
|
m_Scale = oldscale;
|
|
|
|
// We draw the real string
|
|
DrawString(dev,string,slen,position,textzone,textoptions,ctdata);
|
|
}
|
|
|
|
void
|
|
CKTextureFont::SetRenderStates(CKRenderContext* dev,int options)
|
|
{
|
|
///
|
|
// STATES
|
|
|
|
// Render in solid
|
|
dev->SetState(VXRENDERSTATE_FILLMODE, VXFILL_SOLID);
|
|
|
|
dev->SetState(VXRENDERSTATE_SPECULARENABLE, FALSE);
|
|
|
|
if(m_Properties & FONT_LIGHTING) {
|
|
CKMaterial* mat = (CKMaterial*)m_Context->GetObject(m_Material);
|
|
if(mat) mat->SetAsCurrent(dev);
|
|
} else {
|
|
dev->SetState(VXRENDERSTATE_CULLMODE, VXCULL_NONE);
|
|
dev->SetState(VXRENDERSTATE_WRAP0 , 0);
|
|
dev->SetState(VXRENDERSTATE_SRCBLEND, VXBLEND_SRCALPHA);
|
|
dev->SetState(VXRENDERSTATE_DESTBLEND, VXBLEND_INVSRCALPHA);
|
|
}
|
|
|
|
CKTexture* fonttexture = (CKTexture*)m_Context->GetObject(m_FontTexture);
|
|
if (!CKIsChildClassOf(fonttexture,CKCID_TEXTURE)) {
|
|
return;
|
|
}
|
|
dev->SetTexture(fonttexture);
|
|
|
|
// TODO : move these in the TExt3D and 2D Callback
|
|
dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
|
|
|
|
|
if(options & TEXT_3D) {
|
|
dev->SetState(VXRENDERSTATE_ZENABLE , TRUE);
|
|
if(options & TEXT_RESPECTZORDER)
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
else
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE);
|
|
} else {
|
|
dev->SetState(VXRENDERSTATE_ZENABLE , FALSE);
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE);
|
|
}
|
|
|
|
if(m_Properties & FONT_GRADIENT) {
|
|
dev->SetState(VXRENDERSTATE_SHADEMODE, VXSHADE_GOURAUD);
|
|
} else {
|
|
dev->SetState(VXRENDERSTATE_SHADEMODE, VXSHADE_FLAT);
|
|
}
|
|
|
|
dev->SetTextureStageState(CKRST_TSS_ADDRESS,VXTEXTURE_ADDRESSCLAMP);
|
|
dev->SetTextureStageState(CKRST_TSS_TEXTUREMAPBLEND, VXTEXTUREBLEND_MODULATEALPHA);
|
|
|
|
dev->SetTextureStageState(CKRST_TSS_STAGEBLEND,0,1);
|
|
|
|
CKRasterizerContext* rst = (CKRasterizerContext*) dev->GetRasterizerContext();
|
|
rst->SetTransformMatrix(VXMATRIX_TEXTURE0,VxMatrix::Identity());
|
|
|
|
if(m_Properties & FONT_DISABLEFILTER) {
|
|
dev->SetTextureStageState(CKRST_TSS_MINFILTER,VXTEXTUREFILTER_NEAREST);
|
|
dev->SetTextureStageState(CKRST_TSS_MAGFILTER,VXTEXTUREFILTER_NEAREST);
|
|
} else {
|
|
if (fonttexture && ( (fonttexture->GetMipmapCount() > 1) || (fonttexture->GetMipmapCount() == -1)))
|
|
dev->SetTextureStageState(CKRST_TSS_MINFILTER,VXTEXTUREFILTER_LINEARMIPLINEAR);
|
|
else
|
|
dev->SetTextureStageState(CKRST_TSS_MINFILTER,VXTEXTUREFILTER_LINEAR);
|
|
dev->SetTextureStageState(CKRST_TSS_MAGFILTER,VXTEXTUREFILTER_LINEAR);
|
|
}
|
|
}
|
|
|
|
void
|
|
CKTextureFont::DrawCKText(CKRenderContext *dev,CKBeObject* obj, CKSTRING string,int align,VxRect& textzone,CKMaterial* mat,int options, CKBOOL reallyDraw)
|
|
{
|
|
CK_ID objID = obj->GetID();
|
|
|
|
CompiledTextData* ctdata = NULL;
|
|
if (options & TEXT_COMPILED) { // The user asked for text compilation
|
|
if (reallyDraw && (ctdata = m_FontManager->GetCompiledText(objID))) {
|
|
if(options & TEXT_BACKGROUND) {
|
|
// Rendering of the rectangle
|
|
DrawFillRectangle(dev,mat,ctdata->m_DrawZone,m_Properties&FONT_LIGHTING,options&TEXT_3D);
|
|
}
|
|
|
|
// set the render states
|
|
SetRenderStates(dev,options);
|
|
|
|
// Do the rendering
|
|
ctdata->Render(dev);
|
|
|
|
return;
|
|
} else {
|
|
// we have to add the compiled data
|
|
ctdata = m_FontManager->AddCompiledText(objID);
|
|
}
|
|
} else {
|
|
// we clear the data
|
|
m_FontManager->RemoveCompiledText(objID);
|
|
}
|
|
|
|
VxRect drawzone = textzone;
|
|
textzone.left += m_Margins.left;
|
|
textzone.right -= m_Margins.right;
|
|
textzone.top += m_Margins.top;
|
|
textzone.bottom -= m_Margins.bottom;
|
|
|
|
// If the textzone is smaller than a character maxwidth, we do not write anything
|
|
float inv32f = 1.0f;
|
|
if(options & TEXT_3D) inv32f = 1.0f / 32.0f;
|
|
|
|
///
|
|
// We choose the relative coordinates (screen(same size,peu importe la resolution) or textures(looks better, original fontsize)....)
|
|
if (options & TEXT_SCREEN) {
|
|
m_ScreenExtents.Set(dev->GetWidth()*inv32f,dev->GetHeight()*inv32f);
|
|
} else {
|
|
CKTexture* fonttexture = GetFontTexture();
|
|
if (fonttexture) m_ScreenExtents.Set(fonttexture->GetWidth()*inv32f,fonttexture->GetHeight()*inv32f);
|
|
}
|
|
|
|
if(options & (TEXT_JUSTIFIED|TEXT_WORDWRAP)) {
|
|
// TODO : check this cull test becaus it's buggy on wordwrap on very small font
|
|
// if(textzone.GetWidth() < inv32f*m_FontZone.GetWidth()/(m_Scale.x*m_ScreenExtents.x*m_CharNumber.x)) return;
|
|
}
|
|
|
|
// Dimensions variables
|
|
float width = m_Scale.x*m_ScreenExtents.x;
|
|
float hlead = m_Leading.x;
|
|
|
|
|
|
if (m_FontManager->m_VersionUpdate) {
|
|
hlead = 0.1f*width*(m_FontCoordinates[' '].uprewidth+m_FontCoordinates[' '].uwidth+m_FontCoordinates[' '].upostwidth)*m_Leading.x;
|
|
}
|
|
if (!(options&TEXT_3D)) {
|
|
if (!(options&TEXT_JUSTIFIED)) {
|
|
hlead = (float)ROUND(hlead);
|
|
}
|
|
}
|
|
|
|
float spacesize = width*(m_FontCoordinates[' '].uprewidth+m_FontCoordinates[' '].uwidth+m_FontCoordinates[' '].upostwidth)+hlead;
|
|
float zonewidth = textzone.GetWidth();
|
|
|
|
// We clear the line array
|
|
m_FontManager->ClearLines();
|
|
|
|
// Line Data Variables
|
|
LineData ldata;
|
|
|
|
// Wrapping variables
|
|
char* lastword = "\n";
|
|
int lastlen = 0;
|
|
float lastwidth = 0.0f;
|
|
BOOL lastcharacterwasspace = TRUE;
|
|
BOOL paragraphstart = TRUE;
|
|
|
|
// String cutting, LineData Array filling
|
|
while(*string) {
|
|
ldata.string = string;
|
|
ldata.len = 0;
|
|
ldata.nbspace = 0;
|
|
if(paragraphstart) {
|
|
ldata.stringwidth = m_ParagraphIndentation.x*m_FontCoordinates[0].uwidth*(m_Scale.x*m_ScreenExtents.x);
|
|
} else ldata.stringwidth = 0.0f;
|
|
|
|
// we iterate line by line
|
|
while(*string && *string != '\n') {
|
|
// We encounter a space
|
|
if(*string == ' ') {
|
|
if(lastcharacterwasspace) { // we already encounter a space
|
|
|
|
} else lastcharacterwasspace = TRUE;
|
|
|
|
lastlen = ldata.len;
|
|
lastword = string+1;
|
|
lastwidth = ldata.stringwidth;
|
|
|
|
ldata.nbspace++;
|
|
ldata.stringwidth += spacesize;
|
|
} else { // we encounter a character
|
|
if(lastcharacterwasspace) { // Is it a word start ?
|
|
lastcharacterwasspace = FALSE;
|
|
lastlen = ldata.len-1;
|
|
lastword = string;
|
|
lastwidth = ldata.stringwidth-spacesize;
|
|
}
|
|
CharacterTextureCoordinates* tctc = &m_FontCoordinates[(unsigned char)*string];
|
|
ldata.stringwidth += (tctc->uprewidth+tctc->uwidth+tctc->upostwidth)*width+hlead;
|
|
}
|
|
|
|
// If wordwrap, whe have to see if the text fit in the line
|
|
if(options & (TEXT_JUSTIFIED|TEXT_WORDWRAP)) {
|
|
if(ldata.stringwidth-hlead > zonewidth) { // it does not : we break the line
|
|
if(lastlen>0) { // the word was not on the beginning of the line
|
|
ldata.len = lastlen;
|
|
ldata.stringwidth = lastwidth;
|
|
// We drop the last character before this word
|
|
ldata.nbspace--;
|
|
string = lastword;
|
|
} else { // first word of the line : we have to break it
|
|
if(*string != ' ') { // the character length was already added : we subtract it
|
|
CharacterTextureCoordinates* tctc = &m_FontCoordinates[(unsigned char)*string];
|
|
ldata.stringwidth -= (tctc->uprewidth+tctc->uwidth+tctc->upostwidth)*width+hlead;
|
|
if(lastword == string) string++;
|
|
lastword = string;
|
|
}
|
|
}
|
|
lastcharacterwasspace = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ldata.len++;
|
|
string++;
|
|
}
|
|
|
|
if(paragraphstart) {
|
|
ldata.len = -ldata.len;
|
|
paragraphstart = FALSE;
|
|
}
|
|
|
|
if(*string == '\n') {
|
|
paragraphstart = TRUE;
|
|
// Patch for infinite loop
|
|
if (*lastword == '\n') string++;
|
|
|
|
}
|
|
// end of a line (or text)
|
|
m_FontManager->AddLine(ldata);
|
|
|
|
if(*string && string != lastword && *lastword != '\n') string++;
|
|
}
|
|
|
|
// now we have to draw the strings
|
|
int linecount = m_FontManager->GetLineCount();
|
|
VxVector pos(textzone.left,textzone.top,0.0f);
|
|
|
|
// we now have to calculate the text extents
|
|
float textwidth = 0.0f;
|
|
float textheight= 0.0f;
|
|
m_LineCount = GetTextExtents(textwidth,textheight);
|
|
|
|
///
|
|
// Vertical Alignment Calculation
|
|
if(align & VALIGN_TOP) { // Top
|
|
pos.y = textzone.top;
|
|
} else {
|
|
if(align & VALIGN_BOTTOM) { // Bottom
|
|
int fileVersion = GetCurrentVersion();
|
|
if ( (((fileVersion&0xffff) << 16) | ((fileVersion&0xff0000) >> 8) | ((fileVersion&0xff000000) >> 24)) >= 0x20070820)
|
|
pos.y = textzone.bottom - (textheight-m_Leading.y); //remove the vertical space at the end of the text before alignment
|
|
else
|
|
pos.y = textzone.bottom - textheight; //back compatibility
|
|
} else { // Center
|
|
pos.y = (textzone.bottom+textzone.top)*0.5f-textheight*0.5f;
|
|
}
|
|
}
|
|
|
|
///
|
|
// Horizontal Alignment Calculation
|
|
if(align & HALIGN_LEFT) { // Top
|
|
pos.x = textzone.left;
|
|
} else {
|
|
if(align & HALIGN_RIGHT) { // Bottom
|
|
pos.x = textzone.right - textwidth;
|
|
} else { // Center
|
|
pos.x = (textzone.right+textzone.left)*0.5f-textwidth*0.5f;
|
|
}
|
|
}
|
|
|
|
m_TextExtents.SetDimension(pos.x,pos.y,textwidth,textheight);
|
|
|
|
///
|
|
// Resize
|
|
if(obj) { // Entity to resize ?
|
|
if(options & (TEXT_RESIZE_VERT | TEXT_RESIZE_HORI)) {
|
|
drawzone.top = pos.y;
|
|
if(options & TEXT_JUSTIFIED) { // Only vertically
|
|
drawzone.bottom = drawzone.top + textheight;
|
|
} else {
|
|
if(options & TEXT_RESIZE_HORI) drawzone.right = drawzone.left + textwidth;
|
|
if(options & TEXT_RESIZE_VERT) drawzone.bottom = drawzone.top + textheight;
|
|
}
|
|
if(options & TEXT_3D) {
|
|
if (CKIsChildClassOf(obj,CKCID_SPRITE3D)) {
|
|
CKSprite3D* spr = (CKSprite3D*)obj;
|
|
Vx2DVector v2d(textwidth,textheight);
|
|
spr->SetSize(v2d);
|
|
// spr->SetOffset(Vx2DVector(drawzone.left,-drawzone.top));
|
|
} else {
|
|
VxVector v;
|
|
((CK3dEntity*)obj)->GetScale(&v, FALSE);
|
|
|
|
if(options & TEXT_RESIZE_HORI)
|
|
v.x = (drawzone.right - drawzone.left)/2 + EPSILON;
|
|
if(options & (TEXT_RESIZE_VERT|TEXT_JUSTIFIED))
|
|
v.y = (drawzone.bottom - drawzone.top)/2 + EPSILON;
|
|
|
|
((CK3dEntity*)obj)->SetScale(&v, TRUE, FALSE);
|
|
}
|
|
}
|
|
else {
|
|
Vx2DVector v;
|
|
((CK2dEntity*)obj)->GetSize(v);
|
|
if(options & TEXT_RESIZE_HORI) v.x = drawzone.right - drawzone.left;
|
|
if(options & (TEXT_RESIZE_VERT | TEXT_JUSTIFIED))
|
|
v.y = drawzone.bottom - drawzone.top;
|
|
((CK2dEntity*)obj)->SetSize(v);
|
|
}
|
|
}
|
|
}
|
|
|
|
///
|
|
// Scroll Vertical
|
|
if(align & (VALIGN_TOP|VALIGN_BOTTOM)) { // Top|Bottom
|
|
pos.y += m_Offset.y;
|
|
}
|
|
|
|
//BackUp Some states values
|
|
CKBOOL oldZEnable = TRUE;
|
|
oldZEnable = (CKBOOL) dev->GetState(VXRENDERSTATE_ZENABLE);
|
|
|
|
//The Fill value has to be set to VXFILL_SOLID. If it is locked to another value,
|
|
//we unlock it and we will have to restore the lock after the text rendering (see below)
|
|
CKDWORD oldFillMode = VXFILL_SOLID;
|
|
dev->GetRasterizerContext()->SetRenderState(VXRENDERSTATE_FILLMODE, VXFILL_SOLID);
|
|
dev->GetRasterizerContext()->GetRenderState(VXRENDERSTATE_FILLMODE, &oldFillMode);
|
|
if (oldFillMode!=VXFILL_SOLID) {
|
|
dev->GetRasterizerContext()->LockRenderState(VXRENDERSTATE_FILLMODE, FALSE);
|
|
}
|
|
|
|
if(reallyDraw) {
|
|
// we store the zone of the rectangle to draw
|
|
if (ctdata) ctdata->m_DrawZone = drawzone;
|
|
///
|
|
// Background
|
|
if(options & TEXT_BACKGROUND) {
|
|
DrawFillRectangle(dev,mat,drawzone,m_Properties&FONT_LIGHTING,options&TEXT_3D);
|
|
}
|
|
|
|
// States
|
|
SetRenderStates(dev,options);
|
|
}
|
|
|
|
float verticalspace = m_FontCoordinates[0].vwidth*(m_Scale.y*m_ScreenExtents.y)+m_Leading.y;
|
|
|
|
// The actual Drawing
|
|
for(int i=0;i<linecount;++i) {
|
|
// currrent line
|
|
LineData* data = m_FontManager->GetLine(i);
|
|
|
|
m_SpaceSize = spacesize;
|
|
m_HLeading = hlead;
|
|
// We update the line width
|
|
m_LineWidth = data->stringwidth;
|
|
|
|
///
|
|
// Horizontal Alignment Calculation and spacing
|
|
if(options & TEXT_JUSTIFIED) {
|
|
if(data->nbspace) { // there is space, so we work on them
|
|
float delta = data->stringwidth - zonewidth;
|
|
if(delta > 0) {
|
|
m_SpaceSize = spacesize - delta/data->nbspace;
|
|
} else {
|
|
m_SpaceSize = spacesize + -delta/data->nbspace;
|
|
}
|
|
} else { // no space, we adjust leading
|
|
float delta = zonewidth - data->stringwidth;
|
|
int dlen = data->len;
|
|
if(dlen<0) dlen = -dlen;
|
|
if(dlen>1) {
|
|
if(delta > 0) {
|
|
m_HLeading = hlead + delta/(dlen-1);
|
|
} else {
|
|
m_HLeading = hlead - -delta/(dlen-1);
|
|
}
|
|
}
|
|
}
|
|
// the text has to be on the extreme left side
|
|
pos.x = textzone.left;
|
|
} else { // The text is not justified, so we have to calculate where it should be horizontally
|
|
if(align & HALIGN_LEFT) { // Left
|
|
pos.x = textzone.left + m_Offset.x;
|
|
} else {
|
|
if(align & HALIGN_RIGHT) { // Right
|
|
pos.x = m_Offset.x + textzone.right - data->stringwidth;
|
|
} else { // Center
|
|
pos.x = (textzone.right+textzone.left)*0.5f - data->stringwidth*0.5f;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Paragraph Indentation
|
|
if(data->len < 0) {
|
|
data->len = -data->len;
|
|
if(align&HALIGN_LEFT) {
|
|
pos.x += m_ParagraphIndentation.x*m_FontCoordinates[0].uwidth*(m_Scale.x*m_ScreenExtents.x);
|
|
}
|
|
if (i != 0) pos.y += m_ParagraphIndentation.y*m_FontCoordinates[0].vwidth*(m_Scale.y*m_ScreenExtents.y);
|
|
}
|
|
|
|
// WARNING quand derniere ligne ou quand ligne qui contient un \n, pas de leading ni de space modifie...
|
|
// peut etre mettre les deux a 0 lors de la creation des lines datas... et retrouver ensuite la vraie longueur
|
|
// while(*string && *string != '\n') len++;
|
|
// TODO : optimize
|
|
if(reallyDraw) {
|
|
///
|
|
// Shadow
|
|
if(m_Properties & FONT_SHADOW) {
|
|
DrawStringShadowed(dev,data->string,data->len,pos,textzone,options,ctdata);
|
|
} else {
|
|
DrawString(dev,data->string,data->len,pos,textzone,options,ctdata);
|
|
}
|
|
}
|
|
|
|
pos.y += verticalspace;
|
|
}
|
|
|
|
//Restore backedup States
|
|
dev->SetState(VXRENDERSTATE_ZENABLE,(CKDWORD)oldZEnable);
|
|
|
|
if (oldFillMode!=VXFILL_SOLID) { //it means we have modified the lock (see backup states upper)
|
|
dev->GetRasterizerContext()->SetRenderState(VXRENDERSTATE_FILLMODE,oldFillMode);
|
|
dev->GetRasterizerContext()->LockRenderState(VXRENDERSTATE_FILLMODE, TRUE);
|
|
}
|
|
}
|
|
|
|
void
|
|
CKTextureFont::DrawStringEx(CKRenderContext* iRC, const char* iString, const VxRect& iTextZone, int iOptions)
|
|
{
|
|
if (!iString) return;
|
|
|
|
VxRect textzone = iTextZone;
|
|
textzone.left += m_Margins.left;
|
|
textzone.right -= m_Margins.right;
|
|
textzone.top += m_Margins.top;
|
|
textzone.bottom -= m_Margins.bottom;
|
|
|
|
CKTexture* fonttexture = GetFontTexture();
|
|
if (fonttexture)
|
|
m_ScreenExtents.Set(fonttexture->GetWidth(),fonttexture->GetHeight());
|
|
|
|
// Dimensions variables
|
|
float width = m_Scale.x*m_ScreenExtents.x;
|
|
float hlead = m_Leading.x;
|
|
if (m_FontManager->m_VersionUpdate) {
|
|
hlead = 0.1f*width*(m_FontCoordinates[' '].uprewidth+m_FontCoordinates[' '].uwidth+m_FontCoordinates[' '].upostwidth)*m_Leading.x;
|
|
}
|
|
float spacesize = width*(m_FontCoordinates[' '].uprewidth+m_FontCoordinates[' '].uwidth+m_FontCoordinates[' '].upostwidth)+hlead;
|
|
float zonewidth = textzone.GetWidth();
|
|
|
|
VxVector pos;
|
|
pos.x = textzone.left;
|
|
pos.y = textzone.top;
|
|
|
|
// States
|
|
SetRenderStates(iRC,iOptions);
|
|
|
|
m_SpaceSize = spacesize;
|
|
m_HLeading = hlead;
|
|
// We update the line width
|
|
pos.x = textzone.left + m_Offset.x;
|
|
|
|
DrawString(iRC,(CKSTRING)iString,strlen(iString),pos,textzone,iOptions);
|
|
}
|