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> |
24 | |
25 | IMPLEMENT_STANDARD_HANDLE (OpenGl_Font, OpenGl_Resource) |
26 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font, OpenGl_Resource) |
27 | |
28 | // ======================================================================= |
29 | // function : OpenGl_Font |
30 | // purpose : |
31 | // ======================================================================= |
32 | OpenGl_Font::OpenGl_Font (const Handle(Font_FTFont)& theFont, |
33 | const TCollection_AsciiString& theKey) |
34 | : myKey (theKey), |
35 | myFont (theFont), |
36 | myAscender (0.0f), |
37 | myDescender (0.0f), |
38 | myLineSpacing (0.0f), |
39 | myTileSizeX (0), |
40 | myTileSizeY (0), |
41 | myLastTileId (-1), |
42 | myTextureFormat (GL_ALPHA8) |
43 | { |
44 | memset (&myLastTilePx, 0, sizeof(myLastTilePx)); |
45 | } |
46 | |
47 | // ======================================================================= |
48 | // function : ~OpenGl_Font |
49 | // purpose : |
50 | // ======================================================================= |
51 | OpenGl_Font::~OpenGl_Font() |
52 | { |
53 | Release (NULL); |
54 | } |
55 | |
56 | // ======================================================================= |
57 | // function : Release |
58 | // purpose : |
59 | // ======================================================================= |
60 | void OpenGl_Font::Release (const OpenGl_Context* theCtx) |
61 | { |
62 | if (myTextures.IsEmpty()) |
63 | { |
64 | return; |
65 | } |
66 | |
67 | // application can not handle this case by exception - this is bug in code |
68 | Standard_ASSERT_RETURN (theCtx != NULL, |
69 | "OpenGl_Font destroyed without GL context! Possible GPU memory leakage...",); |
70 | |
71 | for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter) |
72 | { |
73 | Handle(OpenGl_Texture)& aTexture = myTextures.ChangeValue (anIter); |
74 | aTexture->Release (theCtx); |
75 | aTexture.Nullify(); |
76 | } |
77 | myTextures.Clear(); |
78 | } |
79 | |
80 | // ======================================================================= |
81 | // function : Init |
82 | // purpose : |
83 | // ======================================================================= |
84 | bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx) |
85 | { |
86 | Release (theCtx.operator->()); |
87 | if (myFont.IsNull() || !myFont->IsValid()) |
88 | { |
89 | return false; |
90 | } |
91 | |
92 | myAscender = myFont->Ascender(); |
93 | myDescender = myFont->Descender(); |
94 | myLineSpacing = myFont->LineSpacing(); |
95 | myTileSizeX = myFont->GlyphMaxSizeX(); |
96 | myTileSizeY = myFont->GlyphMaxSizeY(); |
97 | |
98 | myLastTileId = -1; |
99 | return createTexture (theCtx); |
100 | } |
101 | |
102 | // ======================================================================= |
103 | // function : createTexture |
104 | // purpose : |
105 | // ======================================================================= |
106 | bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx) |
107 | { |
108 | const Standard_Integer aMaxSize = theCtx->MaxTextureSize(); |
109 | |
110 | Standard_Integer aGlyphsNb = myFont->GlyphsNumber() - myLastTileId + 1; |
111 | |
112 | const Standard_Integer aTextureSizeX = OpenGl_Context::GetPowerOfTwo (aGlyphsNb * myTileSizeX, aMaxSize); |
113 | const Standard_Integer aTilesPerRow = aTextureSizeX / myTileSizeX; |
114 | const Standard_Integer aTextureSizeY = OpenGl_Context::GetPowerOfTwo (GLint((aGlyphsNb / aTilesPerRow) + 1) * myTileSizeY, aMaxSize); |
115 | |
116 | memset (&myLastTilePx, 0, sizeof(myLastTilePx)); |
117 | myLastTilePx.Bottom = myTileSizeY; |
118 | |
119 | myTextures.Append (new OpenGl_Texture()); |
120 | Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast(); |
121 | |
122 | Image_PixMap aBlackImg; |
123 | if (!aBlackImg.InitZero (Image_PixMap::ImgGray, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY)) |
124 | || !aTexture->Init (theCtx, aBlackImg, Graphic3d_TOT_2D)) // myTextureFormat |
125 | { |
126 | return false; |
127 | } |
128 | |
129 | aTexture->Bind (theCtx); |
130 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
131 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
132 | aTexture->Unbind (theCtx); |
133 | return true; |
134 | } |
135 | |
136 | // ======================================================================= |
137 | // function : renderGlyph |
138 | // purpose : |
139 | // ======================================================================= |
140 | bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx, |
141 | const Standard_Utf32Char theChar) |
142 | { |
143 | if (!myFont->RenderGlyph (theChar)) |
144 | { |
145 | return false; |
146 | } |
147 | |
148 | Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast(); |
149 | |
150 | const Image_PixMap& anImg = myFont->GlyphImage(); |
151 | const Standard_Integer aTileId = myLastTileId + 1; |
152 | myLastTilePx.Left = myLastTilePx.Right + 3; |
153 | myLastTilePx.Right = myLastTilePx.Left + (Standard_Integer )anImg.SizeX(); |
154 | if (myLastTilePx.Right >= aTexture->SizeX()) |
155 | { |
156 | myLastTilePx.Left = 0; |
157 | myLastTilePx.Right = (Standard_Integer )anImg.SizeX(); |
158 | myLastTilePx.Top += myTileSizeY; |
159 | myLastTilePx.Bottom += myTileSizeY; |
160 | |
161 | if (myLastTilePx.Bottom >= aTexture->SizeY()) |
162 | { |
163 | if (!createTexture (theCtx)) |
164 | { |
165 | return false; |
166 | } |
167 | return renderGlyph (theCtx, theChar); |
168 | } |
169 | } |
170 | |
171 | aTexture->Bind (theCtx); |
172 | glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); |
173 | glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); |
174 | glPixelStorei (GL_UNPACK_ALIGNMENT, 1); |
175 | |
176 | glTexSubImage2D (GL_TEXTURE_2D, 0, |
177 | myLastTilePx.Left, myLastTilePx.Top, (GLsizei )anImg.SizeX(), (GLsizei )anImg.SizeY(), |
178 | GL_ALPHA, GL_UNSIGNED_BYTE, anImg.Data()); |
179 | |
180 | OpenGl_Font::Tile aTile; |
181 | aTile.uv.Left = GLfloat(myLastTilePx.Left) / GLfloat(aTexture->SizeX()); |
182 | aTile.uv.Right = GLfloat(myLastTilePx.Right) / GLfloat(aTexture->SizeX()); |
183 | aTile.uv.Top = GLfloat(myLastTilePx.Top) / GLfloat(aTexture->SizeY()); |
184 | aTile.uv.Bottom = GLfloat(myLastTilePx.Top + anImg.SizeY()) / GLfloat(aTexture->SizeY()); |
185 | aTile.texture = aTexture->TextureId(); |
186 | myFont->GlyphRect (aTile.px); |
187 | |
188 | myLastTileId = aTileId; |
189 | myTiles.Append (aTile); |
190 | return true; |
191 | } |
192 | |
193 | // ======================================================================= |
194 | // function : RenderGlyph |
195 | // purpose : |
196 | // ======================================================================= |
197 | void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx, |
198 | const Standard_Utf32Char theUChar, |
199 | const Standard_Utf32Char theUCharNext, |
200 | OpenGl_Font::Tile& theGlyph, |
201 | OpenGl_Vec2& thePen) |
202 | { |
203 | Standard_Integer aTileId = 0; |
204 | if (!myGlyphMap.Find (theUChar, aTileId)) |
205 | { |
206 | if (renderGlyph (theCtx, theUChar)) |
207 | { |
208 | aTileId = myLastTileId; |
209 | } |
210 | else |
211 | { |
212 | thePen.x() += myFont->AdvanceX (theUChar, theUCharNext); |
213 | return; |
214 | } |
215 | myGlyphMap.Bind (theUChar, aTileId); |
216 | } |
217 | |
218 | const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId); |
219 | theGlyph.px.Top = thePen.y() + aTile.px.Top; |
220 | theGlyph.px.Bottom = thePen.y() + aTile.px.Bottom; |
221 | theGlyph.px.Left = thePen.x() + aTile.px.Left; |
222 | theGlyph.px.Right = thePen.x() + aTile.px.Right; |
223 | theGlyph.uv = aTile.uv; |
224 | theGlyph.texture = aTile.texture; |
225 | |
226 | thePen.x() += myFont->AdvanceX (theUChar, theUCharNext); |
227 | } |