2
* Copyright 2010 Inalogic Inc.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License version 3, as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the applicable version of the GNU Lesser General Public
12
* License for more details.
14
* You should have received a copy of both the GNU Lesser General Public
15
* License version 3 along with this program. If not, see
16
* <http://www.gnu.org/licenses/>
18
* Authored by: Jay Taoko <jay.taoko_AT_gmail_DOT_com>
23
#include "GLResource.h"
24
#include "IOpenGLResource.h"
25
#include "GLResourceManager.h"
26
#include "IOpenGLBaseTexture.h"
27
#include "GLDeviceFactory.h"
28
#include "GLTextureResourceManager.h"
30
#include "OpenGLEngine.h"
32
#include "FontTexture.h"
36
extern bool USE_ARB_SHADERS;
38
const int CURSOR_OFFSET = 0;
40
NString gFontVtxShader = TEXT("#version 110 \n\
41
attribute vec4 iOffset; \n\
42
attribute vec4 iPosition; \n\
43
attribute vec4 iScale; \n\
44
attribute vec4 iTexUV; \n\
45
uniform mat4 ViewProjectionMatrix; \n\
46
varying vec4 oTexCoord0; \n\
49
oTexCoord0 = iTexUV; \n\
50
vec4 myvertex = iPosition * iScale + iOffset; \n\
51
gl_Position = ViewProjectionMatrix * myvertex; \n\
54
NString gFontFragShader = TEXT("#version 110 \n\
55
#extension GL_ARB_texture_rectangle : enable \n\
56
uniform sampler2D FontTexture; \n\
57
uniform vec4 TextColor; \n\
58
varying vec4 oTexCoord0; \n\
61
vec4 diffuse = texture2D(FontTexture, oTexCoord0.st); \n\
62
gl_FragColor = vec4(TextColor.x, TextColor.y, TextColor.z, TextColor.w*diffuse.w); \n\
65
NString FontAsmVtx = TEXT(
67
ATTRIB iScale = vertex.attrib[9]; \n\
68
ATTRIB iOffset = vertex.attrib[10]; \n\
69
OUTPUT oPos = result.position; \n\
70
OUTPUT oTexCoord0 = result.texcoord[0]; \n\
71
# Transform the vertex to clip coordinates. \n\
73
MAD temp, vertex.position, iScale, iOffset; \n\
74
DP4 oPos.x, state.matrix.mvp.row[0], temp; \n\
75
DP4 oPos.y, state.matrix.mvp.row[1], temp; \n\
76
DP4 oPos.z, state.matrix.mvp.row[2], temp; \n\
77
DP4 oPos.w, state.matrix.mvp.row[3], temp; \n\
78
MOV oTexCoord0, vertex.attrib[8]; \n\
81
NString FontAsmFrg = TEXT(
83
PARAM color = program.local[0]; \n\
86
TEX tex0, fragment.texcoord[0], texture[0], 2D; \n\
88
MUL temp.w, color, tex0; \n\
89
MOV result.color, temp; \n\
92
FontTexture::FontTexture(const TCHAR* FontFile)
94
m_FontSearchPath.AddSearchPath(GetThreadGLWindow()->GetFontSearchPath());
95
NString FontPath = m_FontSearchPath.GetFile(FontFile);
98
fb.open (FontPath.GetTCharPtr(), std::ios::in);
104
FontTexture::FontTexture(int width, int height, BYTE *Texture)
109
FontTexture::~FontTexture()
113
int FontTexture::GetCharWidth(const TCHAR& c) const
115
int ascii = c & 0xff;
116
nuxAssert(ascii < m_Charset.NumChar);
117
if(ascii >= m_Charset.NumChar)
120
// XAdvance = abcA + abcB + abcC
121
return m_Charset.Chars[ascii].XAdvance;
124
int FontTexture::GetStringWidth(const NString& str) const
126
// unsigned int total = 0;
127
// for (unsigned int i = 0; i != (unsigned int)str.size(); ++i)
129
// total += GetCharWidth(str[i]);
132
return GetCharStringWidth(str.GetTCharPtr());
135
int FontTexture::GetCharStringWidth(const TCHAR* str) const
137
if((str == TEXT("")) || (str == 0))
139
unsigned int total = 0;
140
for(int i = 0; ; ++i)
144
total += GetCharWidth(str[i]);
149
int FontTexture::GetStringWidth(const NString& str, int num_char_to_compute) const
151
return GetCharStringWidth(str.GetTCharPtr(), num_char_to_compute);
154
int FontTexture::GetCharStringWidth(const TCHAR* str, int num_char_to_compute) const
156
if((str == TEXT("")) || (str == 0))
159
int num_chars = num_char_to_compute;
165
for(int i = 0; i < num_chars; ++i)
169
total += GetCharWidth(str[i]);
174
int FontTexture::GetFontHeight()
176
return m_Charset.FontHeight;
179
bool FontTexture::BMFontParseFNT( std::istream& Stream )
182
int KerningIndex = 0;
183
while( !Stream.eof() )
185
std::getline( Stream, Line );
187
unsigned int line_size = (unsigned int)Line.length();
188
TCHAR* tc = new TCHAR[line_size+1];
189
const TCHAR* Stream = tc;
190
Memcpy(tc, Line.c_str(), line_size+1);
192
if( ParseCommand(&Stream, TEXT("common")) /*Read == "common"*/)
194
ParseUBOOL(tc, TEXT("Bold="), m_Charset.bold);
195
ParseUBOOL(tc, TEXT("Italic="), m_Charset.italic);
196
ParseWORD(tc, TEXT("base="), m_Charset.Base);
197
ParseWORD(tc, TEXT("scaleW="), m_Charset.Width);
198
ParseWORD(tc, TEXT("scaleH="), m_Charset.Height);
199
ParseWORD(tc, TEXT("NumPages="), m_Charset.Pages);
200
ParseWORD(tc, TEXT("FontHeight="), m_Charset.FontHeight);
201
ParseWORD(tc, TEXT("Ascent="), m_Charset.Ascent);
202
ParseWORD(tc, TEXT("Descent="), m_Charset.Descent);
203
ParseINT(tc, TEXT("AvgCharWidth="), m_Charset.AvgCharWidth);
204
ParseINT(tc, TEXT("MaxCharWidth="), m_Charset.MaxCharWidth);
205
ParseINT(tc, TEXT("InternalLeading="), m_Charset.InternalLeading);
206
ParseINT(tc, TEXT("ExternalLeading="), m_Charset.ExternalLeading);
207
// Constant for now... Should be read from the font file
208
m_Charset.NumChar = 256;
210
else if(ParseCommand(&Stream, TEXT("char")))
213
unsigned short CharID = 0;
215
ParseWORD(tc, TEXT("id="), CharID);
216
ParseWORD(tc, TEXT("x="), m_Charset.Chars[CharID].x);
217
ParseWORD(tc, TEXT("y="), m_Charset.Chars[CharID].y);
218
ParseWORD(tc, TEXT("width="), m_Charset.Chars[CharID].Width);
219
ParseWORD(tc, TEXT("height="), m_Charset.Chars[CharID].Height);
220
ParseSWORD(tc, TEXT("xoffset="), m_Charset.Chars[CharID].XOffset);
221
ParseSWORD(tc, TEXT("yoffset="), m_Charset.Chars[CharID].YOffset);
222
ParseSWORD(tc, TEXT("xadvance="), m_Charset.Chars[CharID].XAdvance);
223
ParseSWORD(tc, TEXT("abcA="), m_Charset.Chars[CharID].abcA);
224
ParseSWORD(tc, TEXT("abcB="), m_Charset.Chars[CharID].abcB);
225
ParseSWORD(tc, TEXT("abcC="), m_Charset.Chars[CharID].abcC);
226
ParseWORD(tc, TEXT("page="), m_Charset.Chars[CharID].page);
228
else if( ParseCommand(&Stream, TEXT("Kerning")) )
230
ParseWORD(tc, "count=", m_Charset.NumKerningPairs);
231
if(m_Charset.NumKerningPairs > 0)
232
m_Charset.Kerning = new KerningPair[m_Charset.NumKerningPairs];
234
else if( ParseCommand(&Stream, TEXT("KerningPair")) )
236
if(KerningIndex < m_Charset.NumKerningPairs)
238
ParseWORD(tc, "first=", m_Charset.Kerning[KerningIndex].first);
239
ParseWORD(tc, "second=", m_Charset.Kerning[KerningIndex].second);
240
ParseSWORD(tc, "amount=", m_Charset.Kerning[KerningIndex].amount);
244
else if( ParseCommand(&Stream, TEXT("Texture")) )
247
unsigned short CharID = 0;
249
if(ParseLine(&Stream, texture, 256))
251
// FilePath FontPath;
252
// FontPath.AddSearchPath(""); // for case where fully qualified path is given
253
// FontPath.AddSearchPath(".");
254
// FontPath.AddSearchPath("../Fonts");
257
NString font_texture_file = m_FontSearchPath.GetFile(texture);
259
NString font_texture_file = m_FontSearchPath.GetFile(texture);
262
NTexture2D* Texture = new NTexture2D;
263
NBitmapData* BitmapData = LoadImageFile(font_texture_file.GetTCharPtr());
265
Texture->Update(BitmapData);
266
INL_SAFE_DELETE(BitmapData);
267
TextureArray.push_back(Texture);
276
// CursorPosToX (similar to ScriptStringCPtoX from Microsoft UniScript)
277
// The CursorPosToX function returns the x-coordinate for the leading or trailing edge of a character position.
281
// [in] Character position in the string.
283
// [in] Indicates the edge of the icp that corresponds to the x coordinate. If TRUE, it indicates the trailing edge. If FALSE, it indicates the leading edge.
285
// [out] Pointer to a variable that receives the corresponding x coordinate for the icp.
288
// If the function succeeds, it returns S_OK.
289
// If the function fails, it returns an HRESULT.
290
// The return value can be tested with the SUCCEEDED and FAILED macros.
291
bool FontTexture::CursorPosToX(const NString& Str,
296
if(icp > (int)Str.Size())
300
// get pX at the right of the character at position icp
301
*pX = GetStringWidth(Str, icp+1);
303
// get pX at the left of the character at position icp
304
*pX = GetStringWidth(Str, icp);
309
// XToCursorPosition (similar to ScriptStringXtoCP from Microsoft UniScript)
310
// The XToCursorPosition function converts an x-coordinate to a character position.
314
// [in] Specifies the x coordinate.
315
// FirstVisibleCharIndex,
316
// [in] Index of the first visible character in the text box
318
// [out] Pointer to a variable that receives the character position corresponding to iX.
320
// [out] Pointer to a variable that receives an indicator whether the position is the leading or trailing edge of the character.
323
// If the function is successful, it returns S_OK.
324
// If the function fails, it returns an HRESULT.
325
// The return value can be tested with the SUCCEEDED and FAILED macros.
326
bool FontTexture::XToCursorPosition(const NString& Str,
328
unsigned int FirstVisibleCharIndex,
332
unsigned int num_chars;
333
num_chars = (unsigned int)Str.Size();
334
nuxAssert(FirstVisibleCharIndex < num_chars);
339
unsigned int total = 0;
349
for (unsigned int i = 0; i < FirstVisibleCharIndex; ++i)
351
X += GetCharWidth(Str[i]);
354
for (unsigned int i = 0; i < num_chars; ++i)
356
unsigned int s = GetCharWidth(Str[i]);
357
if(i >= FirstVisibleCharIndex)
365
else if(total + s/2 > X)
372
else if(total + GetCharWidth(Str[i+1])/2 > X)
384
const Charset& FontTexture::GetFontInfo() const
389
/////////////////////////////////////////////////////////////////////////////////////////////////
391
FontRenderer::FontRenderer(GraphicsContext& OpenGLEngine)
392
: m_OpenGLEngine(OpenGLEngine)
394
//m_QuadBuffer = new TemplateQuadBuffer(GetThreadGLDeviceFactory(), SHADER_TYPE_GLSL);
397
m_PixelShaderProg = GetThreadGLDeviceFactory()->CreatePixelShader();
398
m_VertexShaderProg = GetThreadGLDeviceFactory()->CreateVertexShader();
399
m_ShaderProg = GetThreadGLDeviceFactory()->CreateShaderProgram();
401
m_VertexShaderProg->SetShaderCode(TCHAR_TO_ANSI(*gFontVtxShader));
402
m_PixelShaderProg->SetShaderCode(TCHAR_TO_ANSI(*gFontFragShader));
404
m_ShaderProg->ClearShaderObjects();
405
m_ShaderProg->AddShaderObject(m_VertexShaderProg);
406
m_ShaderProg->AddShaderObject(m_PixelShaderProg);
407
m_ShaderProg->Link();
411
m_AsmVertexShaderProg = GetThreadGLDeviceFactory()->CreateAsmVertexShader();
412
m_AsmPixelShaderProg = GetThreadGLDeviceFactory()->CreateAsmPixelShader();
413
m_AsmShaderProg = GetThreadGLDeviceFactory()->CreateAsmShaderProgram();
415
m_AsmShaderProg->LoadVertexShader(TCHAR_TO_ANSI(*FontAsmVtx));
416
m_AsmShaderProg->LoadPixelShader(TCHAR_TO_ANSI(*FontAsmFrg));
417
m_AsmShaderProg->Link();
421
FontRenderer::~FontRenderer()
423
//delete m_QuadBuffer;
426
int FontRenderer::DrawColorString(const NFontPtr& Font, int x, int y, const NString& str, const Color& color, bool WriteAlphaChannel, int SkipFirstNCharacters, int NumCharacter)
428
return RenderText(Font, x, y, str, color, WriteAlphaChannel, SkipFirstNCharacters, NumCharacter);
431
void FontRenderer::PositionString(const NFontPtr& Font, const NString& str, const PageBBox& pageBBox, StringBBox& strBBox, TextAlignment alignment, int NumCharacter)
434
int xmin, ymin, xmax, ymax;
435
xmin = pageBBox.xmin + pageBBox.x_margin;
436
xmax = pageBBox.xmax - pageBBox.x_margin;
437
ymin = pageBBox.ymin + pageBBox.y_margin;
438
ymax = pageBBox.ymax - pageBBox.y_margin;
441
if(NumCharacter == 0)
442
NumChar = str.Size();
444
NumChar = Min((int)str.Size(), NumCharacter);
446
strBBox.width = Font->GetStringWidth(str, NumChar);
447
strBBox.height = Font->GetLineHeight();
451
case eAlignTextCenter:
452
if(strBBox.width > xmax - xmin)
453
x = xmin; // the text is larger than the box: default to eAlignTextLeft for x.
455
x = xmin + ((float)(xmax - xmin) - (float)(strBBox.width))/2.0f;
456
y = ymin + ((float)(ymax - ymin) - (float)(strBBox.height))/2.0f;
459
case eAlignTextRight:
460
x = xmin + ((float)(xmax - xmin) - (float)(strBBox.width));
461
y = ymin + ((float)(ymax - ymin) - (float)(strBBox.height))/2.0f;
467
y = ymin + ((float)(ymax - ymin) - (float)(strBBox.height))/2.0f;
475
int FontRenderer::RenderColorText(const NFontPtr& Font, int x, int y, const NString& Str, const Color& color,
476
bool WriteAlphaChannel, int NumCharacter)
478
int off = DrawColorString(Font, x, y, Str, color, WriteAlphaChannel, 0, NumCharacter);
482
int FontRenderer::RenderColorTextLineStatic(const NFontPtr& Font, const PageBBox& pageSize, const NString& Str, const Color& color,
483
bool WriteAlphaChannel, TextAlignment alignment)
485
StringBBox stringBBox;
487
m_OpenGLEngine.PushClippingRectangle(Rect(pageSize.xmin, pageSize.ymin, pageSize.xmax - pageSize.xmin, pageSize.ymax - pageSize.ymin));
488
PositionString(Font, Str, pageSize, stringBBox, alignment);
489
int off = DrawColorString(Font, stringBBox.x, stringBBox.y, Str, color, WriteAlphaChannel, 0, Str.Size());
491
m_OpenGLEngine.PopClippingRectangle();
495
int FontRenderer::RenderColorTextLineEdit(const NFontPtr& Font, const PageBBox& pageSize, const NString& Str,
496
const Color& TextColor,
497
bool WriteAlphaChannel,
498
const Color& SelectedTextColor,
499
const Color& SelectedTextBackgroundColor,
500
const Color& TextBlinkColor,
501
const Color& CursorColor,
502
bool ShowCursor, unsigned int CursorPosition, int offset, int selection_start, int selection_end)
504
StringBBox stringBBox;
505
Color selection_color(0xFF888888);
507
NString substring = Str.GetSubString(selection_start, selection_end - selection_start);
508
unsigned int substring_width = Font->GetStringWidth(substring);
509
int substring_pos = Font->GetStringWidth(Str, selection_start);
511
m_OpenGLEngine.PushClippingRectangle(Rect(pageSize.xmin, pageSize.ymin, pageSize.xmax - pageSize.xmin, pageSize.ymax - pageSize.ymin));
512
if(substring_width > 0)
513
m_OpenGLEngine.QRP_GLSL_Color(pageSize.xmin + offset + substring_pos, pageSize.ymin, substring_width, pageSize.ymax - pageSize.ymin, SelectedTextBackgroundColor);
514
m_OpenGLEngine.PopClippingRectangle();
516
m_OpenGLEngine.PushClippingRectangle(Rect(pageSize.xmin, pageSize.ymin, pageSize.xmax - pageSize.xmin, pageSize.ymax - pageSize.ymin));
518
PositionString(Font, Str, pageSize, stringBBox, eAlignTextLeft);
519
//ComputeGlyphString(stringBBox.x + offset, stringBBox.y, Str.c_str());
521
// Part before selected text
522
int off = DrawColorString(Font, stringBBox.x + offset, stringBBox.y, Str, TextColor, WriteAlphaChannel, 0, selection_start);
524
off = DrawColorString(Font, stringBBox.x + offset, stringBBox.y, Str, SelectedTextColor, WriteAlphaChannel, selection_start, selection_end - selection_start);
525
// Part after selected text
526
off = DrawColorString(Font, stringBBox.x + offset, stringBBox.y, Str, TextColor, WriteAlphaChannel, selection_end, Str.Size() - selection_end);
528
m_OpenGLEngine.PopClippingRectangle();
531
NString temp = Str.GetSubString(0, CursorPosition);
532
int w = Font->GetStringWidth(temp.GetTCharPtr());
533
int h = Font->GetLineHeight();
535
glDisable(GL_TEXTURE_2D);
539
glColor4f(CursorColor.R(), CursorColor.G(), CursorColor.B(), CursorColor.A());
540
// glBegin(GL_LINES);
542
// // make sure the isn't drawn outside of the area.
543
// int x = pageSize.xmin + w + offset + CURSOR_OFFSET;
544
// x = (x >= pageSize.xmax) ? pageSize.xmax - 1 : x;
545
// glVertex3i(x, pageSize.ymin, 1);
546
// glVertex3i(x, pageSize.ymax, 1);
549
int x = pageSize.xmin + w + offset + CURSOR_OFFSET;
550
x = (x >= pageSize.xmax) ? pageSize.xmax - 1 : x;
551
m_OpenGLEngine.PushClippingRectangle(Rect(x, pageSize.ymin, 2, pageSize.ymax - pageSize.ymin));
554
// make sure the isn't drawn outside of the area.
555
glVertex3i(x, pageSize.ymin, 1);
556
glVertex3i(x, pageSize.ymax, 1);
557
glVertex3i(x+2, pageSize.ymax, 1);
558
glVertex3i(x+2, pageSize.ymin, 1);
561
DrawColorString(Font, stringBBox.x + offset, stringBBox.y, Str, TextBlinkColor, WriteAlphaChannel, CursorPosition, 1);
562
m_OpenGLEngine.PopClippingRectangle();
567
int FontRenderer::RenderText(const NFontPtr& Font, int x, int y, const NString& str, const Color& color, bool WriteAlphaChannel, int StartCharacter, int NumCharacter)
569
// !WARNING This call works if all the glyph of the font are in a single texture.
571
int StrLength = str.Size();
575
nuxAssertMsg(NumCharacter >= 0, TEXT("[FontRenderer::RenderText] Incorrect value for NumCharacter."));
576
nuxAssertMsg(StartCharacter >= 0, TEXT("[FontRenderer::RenderText] Incorrect value for StartCharacter."));
577
nuxAssertMsg(StartCharacter <= StrLength, TEXT("[FontRenderer::RenderText] Incorrect value for StartCharacter."));
579
// if(NumCharacter == 0)
580
// NumCharacter = str.Size();
582
int NumCharToDraw = Min<int>(StrLength - StartCharacter, NumCharacter);
583
//nuxAssertMsg(NumCharToDraw > 0, TEXT("[FontRenderer::RenderText] Incorrect value for NumCharToDraw."));
584
if(NumCharToDraw <= 0)
587
unsigned int CurrentPage = 0;
588
CHECKGL( glDisable(GL_CULL_FACE) );
589
int CurX = x;// + CURSOR_OFFSET;
591
GetThreadGraphicsContext()->GetRenderStates().SetBlend(TRUE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
592
GetThreadGraphicsContext()->GetRenderStates().SetColorMask(TRUE, TRUE, TRUE, WriteAlphaChannel); // Do not write the alpha of characters
594
Vector4* Position = new Vector4[StrLength*4];
595
Vector4* UV = new Vector4[StrLength*4];
596
Vector4* Offset = new Vector4[StrLength*4];
597
Vector4* Scale = new Vector4[StrLength*4];
599
TRefGL<NGLTexture2D> glTexture = m_OpenGLEngine.ResourceCache.GetCachedResource(Font->TextureArray[0]);
601
float tex_width = (float)glTexture->m_Texture->GetWidth();
602
float tex_height = (float)glTexture->m_Texture->GetHeight();
605
for(int i = 0; i < StrLength; ++i)
607
unsigned char c = static_cast<unsigned char>(str[i]);
608
unsigned int CharX = Font->m_Charset.Chars[c /*Str[i]*/].x;
609
unsigned int CharY = Font->m_Charset.Chars[c /*Str[i]*/].y;
610
unsigned int Width = Font->m_Charset.Chars[c /*Str[i]*/].Width;
611
unsigned int Height = Font->m_Charset.Chars[c /*Str[i]*/].Height;
612
int OffsetX = Font->m_Charset.Chars[c /*Str[i]*/].XOffset;
613
int OffsetY = Font->m_Charset.Chars[c /*Str[i]*/].YOffset;
614
int abcA = Font->m_Charset.Chars[c /*Str[i]*/].abcA;
615
int abcB = Font->m_Charset.Chars[c /*Str[i]*/].abcB;
616
int abcC = Font->m_Charset.Chars[c /*Str[i]*/].abcC;
617
int page = Font->m_Charset.Chars[c /*Str[i]*/].page;
619
if((i >= StartCharacter) && (i < StartCharacter + NumCharToDraw))
621
int II = i - StartCharacter;
622
Position[II*4 + 0].x = 0; // x
623
Position[II*4 + 0].y = 0; // y
624
Position[II*4 + 0].z = 0; // z
625
Position[II*4 + 0].w = 1.0f; // w
627
Position[II*4 + 1].x = 1.0f; // x
628
Position[II*4 + 1].y = 0; // y
629
Position[II*4 + 1].z = 0; // z
630
Position[II*4 + 1].w = 1; // w
632
Position[II*4 + 2].x = 1.0f; // x
633
Position[II*4 + 2].y = 1.0f; // y
634
Position[II*4 + 2].z = 0; // z
635
Position[II*4 + 2].w = 1; // w
637
Position[II*4 + 3].x = 0; // x
638
Position[II*4 + 3].y = 1.0f; // y
639
Position[II*4 + 3].z = 0; // z
640
Position[II*4 + 3].w = 1; // w
642
for(int j = 0; j < 4; j++)
644
Offset[II*4 + j].x = CurX + abcA;
645
Offset[II*4 + j].y = CurY;
646
Offset[II*4 + j].z = 0.0f;
647
Offset[II*4 + j].w = 0.0f;
649
Scale[II*4 + j].x = Width;
650
Scale[II*4 + j].y = Height;
651
Scale[II*4 + j].z = 1.0f;
652
Scale[II*4 + j].w = 1.0f;
655
UV[II*4 + 0].x = CharX/tex_width;
656
UV[II*4 + 0].y = CharY/tex_height;
657
UV[II*4 + 0].z = 0.0f;
658
UV[II*4 + 0].w = 0.0f;
661
UV[II*4 + 1].x = (CharX+Width)/tex_width;
662
UV[II*4 + 1].y = CharY/tex_height;
663
UV[II*4 + 1].z = 0.0f;
664
UV[II*4 + 1].w = 0.0f;
667
UV[II*4 + 2].x = (CharX+Width)/tex_width;
668
UV[II*4 + 2].y = (CharY+Height)/tex_height;
669
UV[II*4 + 2].z = 0.0f;
670
UV[II*4 + 2].w = 0.0f;
673
UV[II*4 + 3].x = CharX/tex_width;
674
UV[II*4 + 3].y = (CharY+Height)/tex_height;
675
UV[II*4 + 3].z = 0.0f;
676
UV[II*4 + 3].w = 0.0f;
678
CurX += abcA + abcB + abcC;
681
CHECKGL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
682
CHECKGL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
691
m_ShaderProg->Begin();
692
int ViewProjectionMatrix = m_ShaderProg->GetUniformLocationARB("ViewProjectionMatrix");
693
Matrix4 mat = GetThreadGraphicsContext()->GetModelViewProjectionMatrix();
695
m_ShaderProg->SetUniformLocMatrix4fv(ViewProjectionMatrix, 1, false, (float*)&mat);
697
iPosition = m_ShaderProg->GetAttributeLocation("iPosition");
698
iTexUV = m_ShaderProg->GetAttributeLocation("iTexUV");
699
iScale = m_ShaderProg->GetAttributeLocation("iScale");
700
iOffset = m_ShaderProg->GetAttributeLocation("iOffset");
702
int FontTexture = m_ShaderProg->GetUniformLocationARB("FontTexture");
703
int TextColor = m_ShaderProg->GetUniformLocationARB("TextColor");
705
GetThreadGraphicsContext()->SetTexture(GL_TEXTURE0, glTexture->m_Texture);
707
if(FontTexture != -1)
709
CHECKGL( glUniform1iARB(FontTexture, 0) );
714
CHECKGL( glUniform4fARB(TextColor, color.R(), color.G(), color.B(), color.A()) );
719
m_AsmShaderProg->Begin();
720
CHECKGL( glMatrixMode(GL_MODELVIEW) );
721
CHECKGL( glLoadIdentity() );
722
CHECKGL( glLoadMatrixf((FLOAT*) GetThreadGraphicsContext()->GetModelViewMatrix().m) );
723
CHECKGL( glMatrixMode(GL_PROJECTION) );
724
CHECKGL( glLoadIdentity() );
725
CHECKGL( glLoadMatrixf((FLOAT*) GetThreadGraphicsContext()->GetProjectionMatrix().m) );
727
iPosition = VTXATTRIB_POSITION;
728
iTexUV = VTXATTRIB_TEXCOORD0;
729
iScale = VTXATTRIB_TEXCOORD1;
730
iOffset = VTXATTRIB_TEXCOORD2;
732
CHECKGL( glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, color.R(), color.G(), color.B(), color.A()) );
734
GetThreadGraphicsContext()->SetTexture(GL_TEXTURE0, glTexture->m_Texture);
739
CHECKGL( glEnableVertexAttribArrayARB(iOffset) );
740
CHECKGL( glVertexAttribPointerARB(iOffset, 4, GL_FLOAT, GL_FALSE, 16, Offset) );
745
CHECKGL( glEnableVertexAttribArrayARB(iPosition) );
746
CHECKGL( glVertexAttribPointerARB(iPosition, 4, GL_FLOAT, GL_FALSE, 16, Position) );
751
CHECKGL( glEnableVertexAttribArrayARB(iScale) );
752
CHECKGL( glVertexAttribPointerARB(iScale, 4, GL_FLOAT, GL_FALSE, 16, Scale) );
757
CHECKGL( glEnableVertexAttribArrayARB(iTexUV) );
758
CHECKGL( glVertexAttribPointerARB(iTexUV, 4, GL_FLOAT, GL_FALSE, 16, UV) );
761
if(NumCharToDraw > 0)
762
CHECKGL( glDrawArrays( GL_QUADS, 0, NumCharToDraw*4 ) );
765
CHECKGL( glDisableVertexAttribArrayARB(iPosition) );
767
CHECKGL( glDisableVertexAttribArrayARB(iOffset) );
769
CHECKGL( glDisableVertexAttribArrayARB(iScale) );
771
CHECKGL( glDisableVertexAttribArrayARB(iTexUV) );
779
m_AsmShaderProg->End();
782
GetThreadGraphicsContext()->GetRenderStates().SetColorMask(TRUE, TRUE, TRUE, TRUE);
783
GetThreadGraphicsContext()->GetRenderStates().SetBlend(FALSE);
785
CHECKGL( glDisable(GL_TEXTURE_RECTANGLE_ARB) );
787
CurX -= x + CURSOR_OFFSET;
794
return CurX; // number of pixel to offset before writing the next string.
797
int FontRenderer::RenderTextToBuffer(float* VertexBuffer, int VBSize,
798
const NFontPtr& Font, Rect geo, const NString& str, const Color& color, TextAlignment alignment, int NumCharacter)
800
nuxAssertMsg(NumCharacter >= 0, TEXT("[FontRenderer::RenderTextToBuffer] Number of char to draw must be positive."));
801
int NumCharToDraw = 0;
802
if(NumCharacter == 0)
803
NumCharToDraw = str.Size();
805
NumCharToDraw = Min((int)str.Size(), NumCharacter);
807
nuxAssertMsg(3*NumCharToDraw*16 <= VBSize, TEXT("[FontRenderer::RenderTextToBuffer] VertexBuffer not large enough."));
808
if(3*NumCharToDraw*16 > VBSize)
811
StringBBox stringBBox;
813
pageBox.xmin = geo.x;
814
pageBox.xmax = geo.x + geo.GetWidth();
815
pageBox.ymin = geo.y;
816
pageBox.ymax = geo.y + geo.GetHeight();
817
pageBox.x_margin = 0;
818
pageBox.y_margin = 0;
820
unsigned int CurrentPage = 0;
822
PositionString(Font, str, pageBox, stringBBox, alignment);
824
int CurX = stringBBox.x;
825
int CurY = stringBBox.y;
827
Vector4* Position = (Vector4*)VertexBuffer;
829
for(int i = 0; i < NumCharToDraw; ++i)
831
unsigned char c = static_cast<unsigned char>(str[i]);
832
unsigned int CharX = Font->m_Charset.Chars[c /*Str[i]*/].x;
833
unsigned int CharY = Font->m_Charset.Chars[c /*Str[i]*/].y;
834
unsigned int Width = Font->m_Charset.Chars[c /*Str[i]*/].Width;
835
unsigned int Height = Font->m_Charset.Chars[c /*Str[i]*/].Height;
836
int OffsetX = Font->m_Charset.Chars[c /*Str[i]*/].XOffset;
837
int OffsetY = Font->m_Charset.Chars[c /*Str[i]*/].YOffset;
838
int abcA = Font->m_Charset.Chars[c /*Str[i]*/].abcA;
839
int abcB = Font->m_Charset.Chars[c /*Str[i]*/].abcB;
840
int abcC = Font->m_Charset.Chars[c /*Str[i]*/].abcC;
841
int page = Font->m_Charset.Chars[c /*Str[i]*/].page;
843
// Position upper left
845
Position[i*12 + 0].x = 0.0f * Width + (CurX + abcA); // x
846
Position[i*12 + 0].y = 0.0f * Height + (CurY); // y
847
Position[i*12 + 0].z = 0.0f * 1.0f + 0.0f; // z
848
Position[i*12 + 0].w = 1.0f * 1.0f + 0.0f; // w
850
Position[i*12 + 1].x = CharX;
851
Position[i*12 + 1].y = CharY;
852
Position[i*12 + 1].z = 0.0f;
853
Position[i*12 + 1].w = 1.0f;
855
Position[i*12 + 2].x = color.R();
856
Position[i*12 + 2].y = color.G();
857
Position[i*12 + 2].z = color.B();
858
Position[i*12 + 2].w = color.A();
860
// Position lower left
861
Position[i*12 + 9].x = 0.0f * Width + (CurX + abcA); // x
862
Position[i*12 + 9].y = 1.0f * Height + (CurY); // y
863
Position[i*12 + 9].z = 0.0f * 1.0f + 0.0f; // z
864
Position[i*12 + 9].w = 1.0f * 1.0f + 0.0f; // w
866
Position[i*12 + 10].x = CharX;
867
Position[i*12 + 10].y = CharY+Height;
868
Position[i*12 + 10].z = 0.0f;
869
Position[i*12 + 10].w = 1.0f;
871
Position[i*12 + 11].x = color.R();
872
Position[i*12 + 11].y = color.G();
873
Position[i*12 + 11].z = color.B();
874
Position[i*12 + 11].w = color.A();
876
// Position lower right
877
Position[i*12 + 6].x = 1.0f * Width + (CurX + abcA); // x
878
Position[i*12 + 6].y = 1.0f * Height + (CurY); // y
879
Position[i*12 + 6].z = 0.0f * 1.0f + 0.0f; // z
880
Position[i*12 + 6].w = 1.0f * 1.0f + 0.0f; // w
882
Position[i*12 + 7].x = CharX+Width;
883
Position[i*12 + 7].y = CharY+Height;
884
Position[i*12 + 7].z = 0.0f;
885
Position[i*12 + 7].w = 1.0f;
887
Position[i*12 + 8].x = color.R();
888
Position[i*12 + 8].y = color.G();
889
Position[i*12 + 8].z = color.B();
890
Position[i*12 + 8].w = color.A();
892
// Position upper right
893
Position[i*12 + 3].x = 1.0f * Width + (CurX + abcA); // x
894
Position[i*12 + 3].y = 0.0f * Height + (CurY); // y
895
Position[i*12 + 3].z = 0.0f * 1.0f + 0.0f; // z
896
Position[i*12 + 3].w = 1.0f * 1.0f + 0.0f; // w
898
Position[i*12 + 4].x = CharX+Width;
899
Position[i*12 + 4].y = CharY;
900
Position[i*12 + 4].z = 0.0f;
901
Position[i*12 + 4].w = 1.0f;
903
Position[i*12 + 5].x = color.R();
904
Position[i*12 + 5].y = color.G();
905
Position[i*12 + 5].z = color.B();
906
Position[i*12 + 5].w = color.A();
912
CurX += abcA + abcB + abcC;
915
CurX -= stringBBox.x + CURSOR_OFFSET;
916
return NumCharToDraw;