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 | |
26 | IMPLEMENT_STANDARD_HANDLE (OpenGl_Font, OpenGl_Resource) |
27 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font, OpenGl_Resource) |
28 | |
29 | // ======================================================================= |
30 | // function : OpenGl_Font |
31 | // purpose : |
32 | // ======================================================================= |
33 | OpenGl_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 | // ======================================================================= |
52 | OpenGl_Font::~OpenGl_Font() |
53 | { |
54 | Release (NULL); |
55 | } |
56 | |
57 | // ======================================================================= |
58 | // function : Release |
59 | // purpose : |
60 | // ======================================================================= |
61 | void 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 | // ======================================================================= |
85 | bool 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 | // ======================================================================= |
107 | bool 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 | // ======================================================================= |
148 | bool 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 | // ======================================================================= |
205 | void 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 | } |