1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_CharWriter.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 23030 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <GLES2/gl2.h>
19 #include <GLES2/gl2ext.h>
20 #include <nn/types.h>
21 #include <nn/assert.h>
22 #include <nn/gx.h>
23 
24 #include <nw/config.h>
25 #include <nw/font/font_CharWriter.h>
26 #include <nw/font/font_DispStringBuffer.h>
27 #include <cstdarg>
28 #include <cstdio>
29 
30 #include <nw/assert.h>  // NW_GL_ASSERT用
31 
32 namespace nw {
33 namespace font {
34 
35 namespace {
36 
37 
38 /*!--------------------------------------------------------------------------*
39   @brief        カラーにアルファ値を掛けます。
40  *---------------------------------------------------------------------------*/
41 void
MultiplyAlpha(ut::FloatColor * pDst,const ut::Color8 src,u8 alpha)42 MultiplyAlpha(
43     ut::FloatColor*     pDst,
44     const ut::Color8    src,
45     u8                  alpha
46 )
47 {
48     const f32 floatAlphaMax = ut::Color8::ALPHA_MAX;
49 
50     pDst->r = src.r / floatAlphaMax;
51     pDst->g = src.g / floatAlphaMax;
52     pDst->b = src.b / floatAlphaMax;
53     pDst->a = (src.a / floatAlphaMax) * (alpha / floatAlphaMax);
54 }
55 
56 }   // namespace
57 
58 void
SetupGXCommon()59 CharWriter::SetupGXCommon()
60 {
61     const int *const locations = m_pTextWriterResource->GetUniformLocations();
62 
63     // フラグメントライティングの無効化
64     glUniform1i(locations[internal::LOC_FRAGMENTLIGHTING_ENABLED], GL_FALSE);
65 
66     // テクスチャユニット0を2次元テクスチャに設定
67     glUniform1i(locations[internal::LOC_TEXTURE0_SAMPLERTYPE], GL_TEXTURE_2D);
68 
69     // テクスチャユニット0をアクティブに設定
70     glActiveTexture(GL_TEXTURE0);
71 
72     // フォグの無効化
73     glUniform1i(locations[internal::LOC_FOG_MODE], GL_FALSE);
74 
75     // アルファテストの無効化 (常にパス)
76     glUniform1i(locations[internal::LOC_FRAGOPERATION_ENABLEALPHATEST], GL_FALSE);
77 
78     // ソースアルファでブレンド
79     glEnable(GL_BLEND);
80     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
81     glBlendEquation(GL_FUNC_ADD);
82 
83     // 論理演算を無効
84     glDisable(GL_COLOR_LOGIC_OP);
85 
86     NW_GL_ASSERT();
87 }
88 
89 
90 /* =======================================================================
91         public
92    ======================================================================== */
93 
94 /* ------------------------------------------------------------------------
95         コンストラクタ/デストラクタ
96    ------------------------------------------------------------------------ */
97 
CharWriter()98 CharWriter::CharWriter()
99 :   m_FixedWidth(0),
100     m_pFont(NULL),
101     m_pTextWriterResource(NULL),
102     m_pDispStringBuffer(NULL),
103     m_IsWidthFixed(false),
104     m_Alpha(ut::Color8::ALPHA_MAX)
105 {
106     ResetColorMapping();                // m_ColorMapping
107     SetGradationMode(GRADMODE_NONE);    // m_TextColor, mVertexColor
108     SetTextColor(ut::Color8::WHITE);    // m_TextColor, mVertexColor
109     SetScale(1, 1);                     // m_Scale
110     SetCursor(0, 0, 0);                 // m_CursorPos
111 
112 #if defined(NW_FONT_PROFILE)
113     m_LoadTextureCount = 0;
114     m_PrintCharCount = 0;
115     m_DispCharCount = 0;
116 #endif
117 }
118 
~CharWriter()119 CharWriter::~CharWriter()
120 {
121 }
122 
123 
124 /* ------------------------------------------------------------------------
125         描画準備
126    ------------------------------------------------------------------------ */
127 
128 void
SetupGX()129 CharWriter::SetupGX()
130 {
131     NN_NULL_ASSERT(m_pTextWriterResource);
132 
133     m_pTextWriterResource->ResetLoadingTexture();
134     SetupGXCommon();
135 
136     bool bAlphaTex = false;
137     if (m_pFont)
138     {
139         switch (m_pFont->GetTextureFormat())
140         {
141         case FONT_SHEET_FORMAT_A4:
142         case FONT_SHEET_FORMAT_A8:
143             bAlphaTex = true;
144             break;
145         }
146     }
147 
148     if ( m_Alpha != ut::Color8::ALPHA_MAX
149       || m_ColorMapping.min != DEFAULT_COLOR_MAPPING_MIN
150       || m_ColorMapping.max != DEFAULT_COLOR_MAPPING_MAX
151     )
152     {
153         SetupGXWithColorMapping(bAlphaTex);
154     }
155     else
156     {
157 
158         SetupGXDefault(bAlphaTex);
159     }
160 
161     SetupVertexFormat();
162 }
163 
164 /* ------------------------------------------------------------------------
165         文字サイズ
166    ------------------------------------------------------------------------ */
167 
168 void
SetFontSize(f32 width,f32 height)169 CharWriter::SetFontSize(
170     f32 width,
171     f32 height
172 )
173 {
174     NN_POINTER_ASSERT(m_pFont);
175     NW_FONT_MIN_ASSERT(m_pFont->GetWidth(),  1);
176     NW_FONT_MIN_ASSERT(m_pFont->GetHeight(), 1);
177     SetScale(
178         width  / m_pFont->GetWidth(),
179         height / m_pFont->GetHeight()
180     );
181 }
182 
183 void
SetFontSize(f32 height)184 CharWriter::SetFontSize(f32 height)
185 {
186     NN_POINTER_ASSERT(m_pFont);
187     NW_FONT_MIN_ASSERT(m_pFont->GetHeight(), 1);
188     const f32 scale = height / m_pFont->GetHeight();
189     SetScale(scale);
190 }
191 
192 f32
GetFontWidth() const193 CharWriter::GetFontWidth() const
194 {
195     NN_POINTER_ASSERT(m_pFont);
196     return m_pFont->GetWidth() * m_Scale.x;
197 }
198 
199 f32
GetFontHeight() const200 CharWriter::GetFontHeight() const
201 {
202     NN_POINTER_ASSERT(m_pFont);
203     return m_pFont->GetHeight() * m_Scale.y;
204 }
205 
206 f32
GetFontAscent() const207 CharWriter::GetFontAscent() const
208 {
209     NN_POINTER_ASSERT(m_pFont);
210     return m_pFont->GetAscent() * m_Scale.y;
211 }
212 
213 f32
GetFontDescent() const214 CharWriter::GetFontDescent() const
215 {
216     NN_POINTER_ASSERT(m_pFont);
217     return m_pFont->GetDescent() * m_Scale.y;
218 }
219 
220 /* ------------------------------------------------------------------------
221         文字描画
222    ------------------------------------------------------------------------ */
223 
224 f32
Print(CharCode code)225 CharWriter::Print(CharCode code)
226 {
227     NN_POINTER_ASSERT(m_pFont);
228     NN_ASSERT(code != Font::INVALID_CHARACTER_CODE);
229 
230     NW_FONT_COUNTUP(m_PrintCharCount);
231     NW_FONT_STOPWATCH_START(m_PrintCharSw);
232 
233     Glyph glyph;
234     m_pFont->GetGlyph(&glyph, code);
235 
236     CharWidths &widths = glyph.widths;
237 
238     f32 width;
239     f32 left;
240     if (m_IsWidthFixed)
241     {
242         f32 margin = (m_FixedWidth - widths.charWidth * m_Scale.x) / 2;
243 
244         width   = m_FixedWidth;
245         left    = margin + widths.left * m_Scale.x;
246     }
247     else
248     {
249         width   = widths.charWidth * m_Scale.x;
250         left    = widths.left      * m_Scale.x;
251     }
252 
253     PrintGlyph(m_CursorPos.x + left, glyph);
254 
255     m_CursorPos.x += width;
256 
257     NW_FONT_STOPWATCH_STOP(m_PrintCharSw);
258 
259     return width;
260 }
261 
262 void
DrawGlyph(const Glyph & glyph)263 CharWriter::DrawGlyph(const Glyph& glyph)
264 {
265     NN_POINTER_ASSERT(&glyph);
266     PrintGlyph(m_CursorPos.x, glyph);
267     m_CursorPos.x += glyph.widths.glyphWidth * m_Scale.x;
268 }
269 
270 
271 /* =======================================================================
272         private
273    ======================================================================== */
274 
275 
276 void
PrintGlyph(f32 x,const Glyph & glyph)277 CharWriter::PrintGlyph(
278     f32           x,
279     const Glyph&  glyph
280 )
281 {
282     NN_POINTER_ASSERT(&glyph);
283     NW_FONT_MIN_ASSERT(glyph.texWidth, 1);
284     NW_FONT_MIN_ASSERT(glyph.texHeight, 1);
285 
286     const f32 y = m_CursorPos.y;
287 
288     const f32 texLeft   = 1.0f * glyph.cellX / glyph.texWidth;
289     const f32 texRight  = 1.0f * (glyph.cellX + glyph.widths.glyphWidth)
290                           / glyph.texWidth;
291 
292     // cellYは左上原点の値が入っているので、これをOpenGLの左下原点の
293     // テクスチャ座標に変換してセットする。
294     const f32 texTop    = 1.0f * (glyph.texHeight - glyph.cellY) / glyph.texHeight;
295     const f32 texBottom = 1.0f * (glyph.texHeight - (glyph.cellY + glyph.height))
296                           / glyph.texHeight;
297 
298     if (NULL != m_pDispStringBuffer)
299     {
300         const f32 width  = glyph.widths.glyphWidth * m_Scale.x;
301         const f32 height = - glyph.height * m_Scale.y;
302 
303         const u32 charIdx = m_pDispStringBuffer->charCount;
304 
305         if (charIdx >= m_pDispStringBuffer->charCountMax)
306         {
307             NN_LOG("nw::font::CharWriter : Vertex Buffer Over.\n");
308             return;
309         }
310 
311         m_pDispStringBuffer->charCount++;
312 
313         internal::CharAttribute* pCharAttrs =
314             &m_pDispStringBuffer->GetCharAttrs()[charIdx];
315 
316         // ポジションのセット
317         pCharAttrs->pos.Set(
318             width,
319             height,
320             x,
321             y);
322 
323         // カラーのセット
324         for (int i = 0; i < internal::TEXTCOLOR_MAX; ++i)
325         {
326             pCharAttrs->color[i] = m_TextColors[i];
327         }
328 
329         // テクスチャ座標のセット
330         pCharAttrs->tex.Set(
331             texLeft,
332             texTop,
333             texRight,
334             texBottom);
335 
336         // テクスチャオブジェクトへのポインタのセット
337         NN_NULL_ASSERT(glyph.pTextureObject);
338         pCharAttrs->pTexObj = glyph.pTextureObject;
339     }
340     else
341     {
342         const f32 posLeft   = x;
343         const f32 posRight  = posLeft + glyph.widths.glyphWidth * m_Scale.x;
344     #if defined(COORDINATE_LT)
345         const f32 posTop    = y;
346         const f32 posBottom = y + glyph.height * m_Scale.y;
347     #else
348         const f32 posTop    = y + glyph.height * m_Scale.y;
349         const f32 posBottom = y;
350     #endif
351 
352         internal::VertexAttribute *const pVtxAttrs =
353             m_pTextWriterResource->GetVertexAttributeArray();
354 
355         // ポジションのセット
356         {
357             GLfloat* attrs = pVtxAttrs[internal::TRIFAN_VTX_RT].pos;
358             attrs[internal::POS_X] = posRight;
359             attrs[internal::POS_Y] = posTop;
360 
361             attrs = pVtxAttrs[internal::TRIFAN_VTX_LT].pos;
362             attrs[internal::POS_X] = posLeft;
363             attrs[internal::POS_Y] = posTop;
364 
365             attrs = pVtxAttrs[internal::TRIFAN_VTX_LB].pos;
366             attrs[internal::POS_X] = posLeft;
367             attrs[internal::POS_Y] = posBottom;
368 
369             attrs = pVtxAttrs[internal::TRIFAN_VTX_RB].pos;
370             attrs[internal::POS_X] = posRight;
371             attrs[internal::POS_Y] = posBottom;
372         }
373 
374         // カラーのセット
375         for (int i = 0; i < internal::TRIFAN_VTX_MAX; ++i)
376         {
377             pVtxAttrs[i].color = m_VertexColors[i];
378         }
379 
380         // テクスチャ座標のセット
381         {
382             GLfloat* attrs = pVtxAttrs[internal::TRIFAN_VTX_RT].tex;
383             attrs[internal::TEXCOORD_X] = texRight;
384             attrs[internal::TEXCOORD_Y] = texTop;
385 
386             attrs = pVtxAttrs[internal::TRIFAN_VTX_LT].tex;
387             attrs[internal::TEXCOORD_X] = texLeft;
388             attrs[internal::TEXCOORD_Y] = texTop;
389 
390             attrs = pVtxAttrs[internal::TRIFAN_VTX_LB].tex;
391             attrs[internal::TEXCOORD_X] = texLeft;
392             attrs[internal::TEXCOORD_Y] = texBottom;
393 
394             attrs = pVtxAttrs[internal::TRIFAN_VTX_RB].tex;
395             attrs[internal::TEXCOORD_X] = texRight;
396             attrs[internal::TEXCOORD_Y] = texBottom;
397         }
398 
399         LoadTexture(glyph);
400         m_pTextWriterResource->UpdatePosZ(m_CursorPos.z);
401 
402         glDrawArrays(GL_TRIANGLE_FAN, 0, internal::TRIFAN_VTX_MAX);
403 
404         NW_GL_ASSERT();
405     }
406 }
407 
408 void
StartPrint()409 CharWriter::StartPrint()
410 {
411     NN_NULL_ASSERT(m_pDispStringBuffer);
412 
413     m_pDispStringBuffer->charCount = 0;
414     m_pDispStringBuffer->ClearCommand();
415 }
416 
417 void
EndPrint()418 CharWriter::EndPrint()
419 {
420     NN_NULL_ASSERT(m_pDispStringBuffer);
421 }
422 
423 
424 /* ------------------------------------------------------------------------
425         内部処理
426    ------------------------------------------------------------------------ */
427 
428 void
LoadTexture(const Glyph & glyph)429 CharWriter::LoadTexture(const Glyph& glyph)
430 {
431     NN_POINTER_ASSERT(&glyph);
432 
433     bool doLoad = false;
434     GLuint texName = 0;
435 
436     if (NULL == glyph.pTextureObject)
437     {
438         texName = m_pTextWriterResource->GetTextureID();
439         doLoad =  m_pTextWriterResource->SetLoadingTexture(glyph.pTexture);
440     }
441     else
442     {
443         texName = glyph.pTextureObject->GetName();
444         if (texName == 0)
445         {
446             glGenTextures(1, &texName);
447             const_cast<internal::TextureObject*>(glyph.pTextureObject)->SetName(texName);
448             doLoad = true;
449         }
450         else
451         {
452             doLoad = 0 != glyph.isSheetUpdated;          // 強制ロード
453         }
454     }
455 
456     glBindTexture(GL_TEXTURE_2D, texName);
457 
458     if (doLoad)
459     {
460         NW_FONT_COUNTUP(m_LoadTextureCount);
461         NW_FONT_STOPWATCH_START(m_LoadTextureSw);
462 
463         internal::LoadTexture(
464             glyph.texWidth,
465             glyph.texHeight,
466             glyph.texFormat,
467             glyph.pTexture,
468             m_pFont->IsLinearFilterEnableAtSmall(),
469             m_pFont->IsLinearFilterEnableAtLarge());
470 
471         NW_FONT_STOPWATCH_STOP(m_LoadTextureSw);
472     }
473 }
474 
475 void
UpdateVertexColor()476 CharWriter::UpdateVertexColor()
477 {
478     m_VertexColors[internal::TRIFAN_VTX_LT] = m_TextColors[internal::TEXTCOLOR_START];
479     m_VertexColors[internal::TRIFAN_VTX_RT] = m_TextColors[
480         m_GradationMode != GRADMODE_H ? internal::TEXTCOLOR_START: internal::TEXTCOLOR_END];
481     m_VertexColors[internal::TRIFAN_VTX_LB] = m_TextColors[
482         m_GradationMode != GRADMODE_V ? internal::TEXTCOLOR_START: internal::TEXTCOLOR_END];
483     m_VertexColors[internal::TRIFAN_VTX_RB] = m_TextColors[
484         m_GradationMode == GRADMODE_NONE ? internal::TEXTCOLOR_START: internal::TEXTCOLOR_END];
485 }
486 
487 
488 
489 /* ------------------------------------------------------------------------
490         static
491    ------------------------------------------------------------------------ */
492 /* ------------------------------------------------------------------------
493         描画準備
494    ------------------------------------------------------------------------ */
495 
496 void
SetupVertexFormat()497 CharWriter::SetupVertexFormat()
498 {
499     NN_ASSERT(NULL == m_pDispStringBuffer);
500 
501     // バッファオブジェクトを無効化
502     glBindBuffer(GL_ARRAY_BUFFER, 0);
503     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
504 
505     const u8* basePtr = reinterpret_cast<u8*>(m_pTextWriterResource->GetVertexAttributeArray()[0].pos);
506     const GLsizei stride = sizeof(internal::VertexAttribute);
507 
508     glEnableVertexAttribArray(internal::VERTEX_ATTR_POS);
509     glVertexAttribPointer(
510         internal::VERTEX_ATTR_POS,
511         internal::POS_NUM,
512         GL_FLOAT,
513         GL_FALSE,
514         stride,
515         basePtr);
516 
517     glDisableVertexAttribArray(internal::VERTEX_ATTR_POS_Z);
518     m_pTextWriterResource->SetPosZ(m_CursorPos.z);
519 
520     glEnableVertexAttribArray(internal::VERTEX_ATTR_COLOR);
521     glVertexAttribPointer(
522         internal::VERTEX_ATTR_COLOR,
523         internal::COLOR_NUM,
524         GL_UNSIGNED_BYTE,
525         GL_FALSE,
526         stride,
527         basePtr + offsetof(internal::VertexAttribute, color));
528 
529     glEnableVertexAttribArray(internal::VERTEX_ATTR_TEXCOORD);
530     glVertexAttribPointer(
531         internal::VERTEX_ATTR_TEXCOORD,
532         internal::TEXCOORD_NUM,
533         GL_FLOAT,
534         GL_FALSE,
535         stride,
536         basePtr + offsetof(internal::VertexAttribute, tex));
537 
538     NW_GL_ASSERT();
539 }
540 
541 u32
GetDispStringBufferSize(u32 charNum)542 CharWriter::GetDispStringBufferSize(u32 charNum)
543 {
544     const u32 drawFlagBytes = math::RoundUp(charNum, 8) / 8;
545     return sizeof(DispStringBuffer)
546                 + sizeof(internal::CharAttribute) * charNum
547                 + math::RoundUp(drawFlagBytes, sizeof(u32))
548                 + sizeof(u32) * DispStringBuffer::CalcCommandBufferCapacity(charNum)
549         ;
550 }
551 
552 DispStringBuffer*
InitDispStringBuffer(void * drawBuffer,u32 charNum)553 CharWriter::InitDispStringBuffer(
554     void*   drawBuffer,
555     u32     charNum
556 )
557 {
558     NN_NULL_ASSERT(drawBuffer);
559 
560     return new (drawBuffer) DispStringBuffer(charNum);
561 }
562 
563 void
SetupGXDefault(bool bAlphaTex)564 CharWriter::SetupGXDefault(bool bAlphaTex)
565 {
566     const int (*locations)[internal::TCLOC_MAX] =
567         m_pTextWriterResource->GetTexEnvUniformLocations();
568 
569     // テクスチャコンバイナ設定
570     static const GLint src[] = { GL_PRIMARY_COLOR, GL_TEXTURE0, GL_CONSTANT };
571     static const GLint operandRgb[] = { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR };
572     static const GLint operandAlp[] = { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA };
573     const GLint combineMode = bAlphaTex ? GL_REPLACE: GL_MODULATE;
574 
575     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_SRCRGB      ], 1, src);
576     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_SRCALPHA    ], 1, src);
577     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_OPERANDRGB  ], 1, operandRgb);
578     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_OPERANDALPHA], 1, operandAlp);
579     glUniform1i (locations[internal::TEXENV_5][internal::TCLOC_COMBINERGB  ], combineMode);
580     glUniform1i (locations[internal::TEXENV_5][internal::TCLOC_COMBINEALPHA], GL_MODULATE);
581     glUniform1f (locations[internal::TEXENV_5][internal::TCLOC_SCALERGB    ], 1.0);
582     glUniform1f (locations[internal::TEXENV_5][internal::TCLOC_SCALEALPHA  ], 1.0);
583 }
584 
585 void
SetupGXWithColorMapping(bool bAlphaTex)586 CharWriter::SetupGXWithColorMapping(bool bAlphaTex)
587 {
588     const int (*locations)[internal::TCLOC_MAX] =
589         m_pTextWriterResource->GetTexEnvUniformLocations();
590 
591     // テクスチャコンバイナ設定
592     static const GLint Src0[]         = { GL_TEXTURE0, GL_CONSTANT, GL_CONSTANT };
593     static const GLint OpRgb0[]       = { GL_SRC_COLOR,           GL_SRC_COLOR, GL_SRC_COLOR };
594     static const GLint OpRgb1[]       = { GL_ONE_MINUS_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR };
595     static const GLint OpAlp0[]       = { GL_SRC_ALPHA,           GL_SRC_ALPHA, GL_SRC_ALPHA };
596     glUniform3iv(locations[internal::TEXENV_3][internal::TCLOC_SRCRGB      ], 1, Src0);
597     glUniform3iv(locations[internal::TEXENV_3][internal::TCLOC_SRCALPHA    ], 1, Src0);
598     glUniform3iv(locations[internal::TEXENV_3][internal::TCLOC_OPERANDRGB  ], 1, bAlphaTex ? OpRgb1: OpRgb0);
599     glUniform3iv(locations[internal::TEXENV_3][internal::TCLOC_OPERANDALPHA], 1, OpAlp0);
600     glUniform1i (locations[internal::TEXENV_3][internal::TCLOC_COMBINERGB  ], GL_MODULATE);
601     glUniform1i (locations[internal::TEXENV_3][internal::TCLOC_COMBINEALPHA], GL_MODULATE);
602     glUniform1f (locations[internal::TEXENV_3][internal::TCLOC_SCALERGB    ], 1.0);
603     glUniform1f (locations[internal::TEXENV_3][internal::TCLOC_SCALEALPHA  ], 1.0);
604     ut::FloatColor maxCol;
605     MultiplyAlpha(&maxCol, m_ColorMapping.max, m_Alpha);
606     glUniform4fv(locations[internal::TEXENV_3][internal::TCLOC_CONSTRGBA   ], 1, maxCol.ToArray());
607 
608     static const GLint Src1[]         = { GL_TEXTURE0, GL_CONSTANT, GL_PREVIOUS };
609     static const GLint OpAlp1[]       = { GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA };
610     glUniform3iv(locations[internal::TEXENV_4][internal::TCLOC_SRCRGB      ], 1, Src1);
611     glUniform3iv(locations[internal::TEXENV_4][internal::TCLOC_SRCALPHA    ], 1, Src1);
612     glUniform3iv(locations[internal::TEXENV_4][internal::TCLOC_OPERANDRGB  ], 1, bAlphaTex ? OpRgb0: OpRgb1);
613     glUniform3iv(locations[internal::TEXENV_4][internal::TCLOC_OPERANDALPHA], 1, OpAlp1);
614     glUniform1i (locations[internal::TEXENV_4][internal::TCLOC_COMBINERGB  ], GL_MULT_ADD_DMP);
615     glUniform1i (locations[internal::TEXENV_4][internal::TCLOC_COMBINEALPHA], GL_MULT_ADD_DMP);
616     glUniform1f (locations[internal::TEXENV_4][internal::TCLOC_SCALERGB    ], 1.0);
617     glUniform1f (locations[internal::TEXENV_4][internal::TCLOC_SCALEALPHA  ], 1.0);
618     ut::FloatColor minCol;
619     MultiplyAlpha(&minCol, m_ColorMapping.min, m_Alpha);
620     glUniform4fv(locations[internal::TEXENV_4][internal::TCLOC_CONSTRGBA   ], 1, minCol.ToArray());
621 
622     static const GLint Src2[] = { GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS };
623     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_SRCRGB      ], 1, Src2);
624     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_SRCALPHA    ], 1, Src2);
625     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_OPERANDRGB  ], 1, OpRgb0);
626     glUniform3iv(locations[internal::TEXENV_5][internal::TCLOC_OPERANDALPHA], 1, OpAlp0);
627     glUniform1i (locations[internal::TEXENV_5][internal::TCLOC_COMBINERGB  ], GL_MODULATE);
628     glUniform1i (locations[internal::TEXENV_5][internal::TCLOC_COMBINEALPHA], GL_MODULATE);
629     glUniform1f (locations[internal::TEXENV_5][internal::TCLOC_SCALERGB    ], 1.0);
630     glUniform1f (locations[internal::TEXENV_5][internal::TCLOC_SCALEALPHA  ], 1.0);
631 }
632 
633 #if defined(NW_FONT_PROFILE)
634 void
PrintProfile()635 CharWriter::PrintProfile()
636 {
637     using namespace nn::fnd;
638 
639     TimeSpan timeSpan = m_LoadTextureSw.GetElapsedTime();
640     NN_LOG("CharWriter Load Texture time %d micros, count %d.\n", (int)timeSpan.GetMilliSeconds(), m_LoadTextureCount);
641     timeSpan = m_PrintCharSw.GetElapsedTime();
642     NN_LOG("CharWriter Print time %d micros, count %d.\n", (int)timeSpan.GetMilliSeconds(), m_PrintCharCount);
643     timeSpan = m_DispCharSw.GetElapsedTime();
644     NN_LOG("CharWriter Disp time %d micros, count %d.\n", (int)timeSpan.GetMilliSeconds(), m_DispCharCount);
645 }
646 
647 void
CopyProfileData(const CharWriter & other) const648 CharWriter::CopyProfileData(const CharWriter& other) const
649 {
650     m_LoadTextureSw     = other.m_LoadTextureSw;
651     m_PrintCharSw       = other.m_PrintCharSw;
652     m_LoadTextureCount  = other.m_LoadTextureCount;
653     m_PrintCharCount    = other.m_PrintCharCount;
654 }
655 #endif
656 
657 }   // namespace font
658 }   // namespace nw
659