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