1 // Created on: 2013-01-29
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_Font.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <Graphic3d_TextureParams.hxx>
20 #include <Standard_Assert.hxx>
21 #include <TCollection_ExtendedString.hxx>
23 IMPLEMENT_STANDARD_HANDLE (OpenGl_Font, OpenGl_Resource)
24 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font, OpenGl_Resource)
26 // =======================================================================
27 // function : OpenGl_Font
29 // =======================================================================
30 OpenGl_Font::OpenGl_Font (const Handle(Font_FTFont)& theFont,
31 const TCollection_AsciiString& theKey)
40 myTextureFormat (GL_ALPHA)
42 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
45 // =======================================================================
46 // function : ~OpenGl_Font
48 // =======================================================================
49 OpenGl_Font::~OpenGl_Font()
54 // =======================================================================
57 // =======================================================================
58 void OpenGl_Font::Release (OpenGl_Context* theCtx)
60 if (myTextures.IsEmpty())
65 // application can not handle this case by exception - this is bug in code
66 Standard_ASSERT_RETURN (theCtx != NULL,
67 "OpenGl_Font destroyed without GL context! Possible GPU memory leakage...",);
69 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
71 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeValue (anIter);
72 aTexture->Release (theCtx);
78 // =======================================================================
81 // =======================================================================
82 bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx)
84 Release (theCtx.operator->());
85 if (myFont.IsNull() || !myFont->IsValid())
90 myAscender = myFont->Ascender();
91 myDescender = myFont->Descender();
92 myLineSpacing = myFont->LineSpacing();
93 myTileSizeX = myFont->GlyphMaxSizeX();
94 myTileSizeY = myFont->GlyphMaxSizeY();
97 return createTexture (theCtx);
100 // =======================================================================
101 // function : createTexture
103 // =======================================================================
104 bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx)
106 const Standard_Integer aMaxSize = theCtx->MaxTextureSize();
108 Standard_Integer aGlyphsNb = myFont->GlyphsNumber() - myLastTileId + 1;
110 const Standard_Integer aTextureSizeX = OpenGl_Context::GetPowerOfTwo (aGlyphsNb * myTileSizeX, aMaxSize);
111 const Standard_Integer aTilesPerRow = aTextureSizeX / myTileSizeX;
112 const Standard_Integer aTextureSizeY = OpenGl_Context::GetPowerOfTwo (GLint((aGlyphsNb / aTilesPerRow) + 1) * myTileSizeY, aMaxSize);
114 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
115 myLastTilePx.Bottom = myTileSizeY;
117 Handle(Graphic3d_TextureParams) aParams = new Graphic3d_TextureParams();
118 aParams->SetModulate (Standard_False);
119 aParams->SetRepeat (Standard_False);
120 aParams->SetFilter (Graphic3d_TOTF_BILINEAR);
121 aParams->SetAnisoFilter (Graphic3d_LOTA_OFF);
123 myTextures.Append (new OpenGl_Texture (aParams));
124 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
126 Image_PixMap aBlackImg;
127 if (!aBlackImg.InitZero (Image_PixMap::ImgAlpha, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY))
128 || !aTexture->Init (theCtx, aBlackImg, Graphic3d_TOT_2D)) // myTextureFormat
130 TCollection_ExtendedString aMsg;
131 aMsg += "New texture intialization of size ";
132 aMsg += aTextureSizeX;
134 aMsg += aTextureSizeY;
135 aMsg += " for textured font has failed.";
136 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMsg);
143 // =======================================================================
144 // function : renderGlyph
146 // =======================================================================
147 bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
148 const Standard_Utf32Char theChar)
150 if (!myFont->RenderGlyph (theChar))
155 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
157 const Image_PixMap& anImg = myFont->GlyphImage();
158 const Standard_Integer aTileId = myLastTileId + 1;
159 myLastTilePx.Left = myLastTilePx.Right + 3;
160 myLastTilePx.Right = myLastTilePx.Left + (Standard_Integer )anImg.SizeX();
161 if (myLastTilePx.Right >= aTexture->SizeX())
163 myLastTilePx.Left = 0;
164 myLastTilePx.Right = (Standard_Integer )anImg.SizeX();
165 myLastTilePx.Top += myTileSizeY;
166 myLastTilePx.Bottom += myTileSizeY;
168 if (myLastTilePx.Bottom >= aTexture->SizeY())
170 if (!createTexture (theCtx))
174 return renderGlyph (theCtx, theChar);
178 aTexture->Bind (theCtx);
179 #if !defined(GL_ES_VERSION_2_0)
180 glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
181 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
183 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
185 glTexSubImage2D (GL_TEXTURE_2D, 0,
186 myLastTilePx.Left, myLastTilePx.Top, (GLsizei )anImg.SizeX(), (GLsizei )anImg.SizeY(),
187 GL_ALPHA, GL_UNSIGNED_BYTE, anImg.Data());
189 OpenGl_Font::Tile aTile;
190 aTile.uv.Left = GLfloat(myLastTilePx.Left) / GLfloat(aTexture->SizeX());
191 aTile.uv.Right = GLfloat(myLastTilePx.Right) / GLfloat(aTexture->SizeX());
192 aTile.uv.Top = GLfloat(myLastTilePx.Top) / GLfloat(aTexture->SizeY());
193 aTile.uv.Bottom = GLfloat(myLastTilePx.Top + anImg.SizeY()) / GLfloat(aTexture->SizeY());
194 aTile.texture = aTexture->TextureId();
195 myFont->GlyphRect (aTile.px);
197 myLastTileId = aTileId;
198 myTiles.Append (aTile);
202 // =======================================================================
203 // function : RenderGlyph
205 // =======================================================================
206 void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
207 const Standard_Utf32Char theUChar,
208 const Standard_Utf32Char theUCharNext,
209 OpenGl_Font::Tile& theGlyph,
212 Standard_Integer aTileId = 0;
213 if (!myGlyphMap.Find (theUChar, aTileId))
215 if (renderGlyph (theCtx, theUChar))
217 aTileId = myLastTileId;
221 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
224 myGlyphMap.Bind (theUChar, aTileId);
227 const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId);
228 theGlyph.px.Top = thePen.y() + aTile.px.Top;
229 theGlyph.px.Bottom = thePen.y() + aTile.px.Bottom;
230 theGlyph.px.Left = thePen.x() + aTile.px.Left;
231 theGlyph.px.Right = thePen.x() + aTile.px.Right;
232 theGlyph.uv = aTile.uv;
233 theGlyph.texture = aTile.texture;
235 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);