0024288: Provide flipping text for AIS_Dimensions
[occt.git] / src / OpenGl / OpenGl_Font.cxx
CommitLineData
a174a3c5 1// Created on: 2013-01-29
2// Created by: Kirill GAVRILOV
3// Copyright (c) 2013 OPEN CASCADE SAS
4//
5// The content of this file is subject to the Open CASCADE Technology Public
6// License Version 6.5 (the "License"). You may not use the content of this file
7// except in compliance with the License. Please obtain a copy of the License
8// at http://www.opencascade.org and read it completely before using this file.
9//
10// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12//
13// The Original Code and all software distributed under the License is
14// distributed on an "AS IS" basis, without warranty of any kind, and the
15// Initial Developer hereby disclaims all such warranties, including without
16// limitation, any warranties of merchantability, fitness for a particular
17// purpose or non-infringement. Please see the License for the specific terms
18// and conditions governing the rights and limitations under the License.
19
20#include <OpenGl_Font.hxx>
21
22#include <OpenGl_Context.hxx>
23#include <Standard_Assert.hxx>
cbf18624 24#include <TCollection_ExtendedString.hxx>
a174a3c5 25
26IMPLEMENT_STANDARD_HANDLE (OpenGl_Font, OpenGl_Resource)
27IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font, OpenGl_Resource)
28
29// =======================================================================
30// function : OpenGl_Font
31// purpose :
32// =======================================================================
33OpenGl_Font::OpenGl_Font (const Handle(Font_FTFont)& theFont,
34 const TCollection_AsciiString& theKey)
35: myKey (theKey),
36 myFont (theFont),
37 myAscender (0.0f),
38 myDescender (0.0f),
39 myLineSpacing (0.0f),
40 myTileSizeX (0),
41 myTileSizeY (0),
42 myLastTileId (-1),
43 myTextureFormat (GL_ALPHA8)
44{
45 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
46}
47
48// =======================================================================
49// function : ~OpenGl_Font
50// purpose :
51// =======================================================================
52OpenGl_Font::~OpenGl_Font()
53{
54 Release (NULL);
55}
56
57// =======================================================================
58// function : Release
59// purpose :
60// =======================================================================
61void OpenGl_Font::Release (const OpenGl_Context* theCtx)
62{
63 if (myTextures.IsEmpty())
64 {
65 return;
66 }
67
68 // application can not handle this case by exception - this is bug in code
69 Standard_ASSERT_RETURN (theCtx != NULL,
70 "OpenGl_Font destroyed without GL context! Possible GPU memory leakage...",);
71
72 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
73 {
74 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeValue (anIter);
75 aTexture->Release (theCtx);
76 aTexture.Nullify();
77 }
78 myTextures.Clear();
79}
80
81// =======================================================================
82// function : Init
83// purpose :
84// =======================================================================
85bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx)
86{
87 Release (theCtx.operator->());
88 if (myFont.IsNull() || !myFont->IsValid())
89 {
90 return false;
91 }
92
93 myAscender = myFont->Ascender();
94 myDescender = myFont->Descender();
95 myLineSpacing = myFont->LineSpacing();
96 myTileSizeX = myFont->GlyphMaxSizeX();
97 myTileSizeY = myFont->GlyphMaxSizeY();
98
99 myLastTileId = -1;
100 return createTexture (theCtx);
101}
102
103// =======================================================================
104// function : createTexture
105// purpose :
106// =======================================================================
107bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx)
108{
109 const Standard_Integer aMaxSize = theCtx->MaxTextureSize();
110
111 Standard_Integer aGlyphsNb = myFont->GlyphsNumber() - myLastTileId + 1;
112
113 const Standard_Integer aTextureSizeX = OpenGl_Context::GetPowerOfTwo (aGlyphsNb * myTileSizeX, aMaxSize);
114 const Standard_Integer aTilesPerRow = aTextureSizeX / myTileSizeX;
115 const Standard_Integer aTextureSizeY = OpenGl_Context::GetPowerOfTwo (GLint((aGlyphsNb / aTilesPerRow) + 1) * myTileSizeY, aMaxSize);
116
117 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
118 myLastTilePx.Bottom = myTileSizeY;
119
120 myTextures.Append (new OpenGl_Texture());
121 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
122
123 Image_PixMap aBlackImg;
124 if (!aBlackImg.InitZero (Image_PixMap::ImgGray, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY))
125 || !aTexture->Init (theCtx, aBlackImg, Graphic3d_TOT_2D)) // myTextureFormat
126 {
cbf18624 127 TCollection_ExtendedString aMsg;
128 aMsg += "New texture intialization of size ";
129 aMsg += aTextureSizeX;
130 aMsg += "x";
131 aMsg += aTextureSizeY;
132 aMsg += " for textured font has failed.";
133 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMsg);
a174a3c5 134 return false;
135 }
136
137 aTexture->Bind (theCtx);
138 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
139 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
140 aTexture->Unbind (theCtx);
141 return true;
142}
143
144// =======================================================================
145// function : renderGlyph
146// purpose :
147// =======================================================================
148bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
149 const Standard_Utf32Char theChar)
150{
151 if (!myFont->RenderGlyph (theChar))
152 {
153 return false;
154 }
155
156 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
157
158 const Image_PixMap& anImg = myFont->GlyphImage();
159 const Standard_Integer aTileId = myLastTileId + 1;
160 myLastTilePx.Left = myLastTilePx.Right + 3;
161 myLastTilePx.Right = myLastTilePx.Left + (Standard_Integer )anImg.SizeX();
162 if (myLastTilePx.Right >= aTexture->SizeX())
163 {
164 myLastTilePx.Left = 0;
165 myLastTilePx.Right = (Standard_Integer )anImg.SizeX();
166 myLastTilePx.Top += myTileSizeY;
167 myLastTilePx.Bottom += myTileSizeY;
168
169 if (myLastTilePx.Bottom >= aTexture->SizeY())
170 {
171 if (!createTexture (theCtx))
172 {
173 return false;
174 }
175 return renderGlyph (theCtx, theChar);
176 }
177 }
178
179 aTexture->Bind (theCtx);
180 glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
181 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
182 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
183
184 glTexSubImage2D (GL_TEXTURE_2D, 0,
185 myLastTilePx.Left, myLastTilePx.Top, (GLsizei )anImg.SizeX(), (GLsizei )anImg.SizeY(),
186 GL_ALPHA, GL_UNSIGNED_BYTE, anImg.Data());
187
188 OpenGl_Font::Tile aTile;
189 aTile.uv.Left = GLfloat(myLastTilePx.Left) / GLfloat(aTexture->SizeX());
190 aTile.uv.Right = GLfloat(myLastTilePx.Right) / GLfloat(aTexture->SizeX());
191 aTile.uv.Top = GLfloat(myLastTilePx.Top) / GLfloat(aTexture->SizeY());
192 aTile.uv.Bottom = GLfloat(myLastTilePx.Top + anImg.SizeY()) / GLfloat(aTexture->SizeY());
193 aTile.texture = aTexture->TextureId();
194 myFont->GlyphRect (aTile.px);
195
196 myLastTileId = aTileId;
197 myTiles.Append (aTile);
198 return true;
199}
200
201// =======================================================================
202// function : RenderGlyph
203// purpose :
204// =======================================================================
205void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
206 const Standard_Utf32Char theUChar,
207 const Standard_Utf32Char theUCharNext,
208 OpenGl_Font::Tile& theGlyph,
209 OpenGl_Vec2& thePen)
210{
211 Standard_Integer aTileId = 0;
212 if (!myGlyphMap.Find (theUChar, aTileId))
213 {
214 if (renderGlyph (theCtx, theUChar))
215 {
216 aTileId = myLastTileId;
217 }
218 else
219 {
220 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
221 return;
222 }
223 myGlyphMap.Bind (theUChar, aTileId);
224 }
225
226 const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId);
227 theGlyph.px.Top = thePen.y() + aTile.px.Top;
228 theGlyph.px.Bottom = thePen.y() + aTile.px.Bottom;
229 theGlyph.px.Left = thePen.x() + aTile.px.Left;
230 theGlyph.px.Right = thePen.x() + aTile.px.Right;
231 theGlyph.uv = aTile.uv;
232 theGlyph.texture = aTile.texture;
233
234 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
235}