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 <Standard_Assert.hxx>
20 #include <TCollection_ExtendedString.hxx>
22 IMPLEMENT_STANDARD_HANDLE (OpenGl_Font, OpenGl_Resource)
23 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font, OpenGl_Resource)
25 // =======================================================================
26 // function : OpenGl_Font
28 // =======================================================================
29 OpenGl_Font::OpenGl_Font (const Handle(Font_FTFont)& theFont,
30 const TCollection_AsciiString& theKey)
39 myTextureFormat (GL_ALPHA)
41 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
44 // =======================================================================
45 // function : ~OpenGl_Font
47 // =======================================================================
48 OpenGl_Font::~OpenGl_Font()
53 // =======================================================================
56 // =======================================================================
57 void OpenGl_Font::Release (OpenGl_Context* theCtx)
59 if (myTextures.IsEmpty())
64 // application can not handle this case by exception - this is bug in code
65 Standard_ASSERT_RETURN (theCtx != NULL,
66 "OpenGl_Font destroyed without GL context! Possible GPU memory leakage...",);
68 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
70 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeValue (anIter);
71 aTexture->Release (theCtx);
77 // =======================================================================
80 // =======================================================================
81 bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx)
83 Release (theCtx.operator->());
84 if (myFont.IsNull() || !myFont->IsValid())
89 myAscender = myFont->Ascender();
90 myDescender = myFont->Descender();
91 myLineSpacing = myFont->LineSpacing();
92 myTileSizeX = myFont->GlyphMaxSizeX();
93 myTileSizeY = myFont->GlyphMaxSizeY();
96 return createTexture (theCtx);
99 // =======================================================================
100 // function : createTexture
102 // =======================================================================
103 bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx)
105 const Standard_Integer aMaxSize = theCtx->MaxTextureSize();
107 Standard_Integer aGlyphsNb = myFont->GlyphsNumber() - myLastTileId + 1;
109 const Standard_Integer aTextureSizeX = OpenGl_Context::GetPowerOfTwo (aGlyphsNb * myTileSizeX, aMaxSize);
110 const Standard_Integer aTilesPerRow = aTextureSizeX / myTileSizeX;
111 const Standard_Integer aTextureSizeY = OpenGl_Context::GetPowerOfTwo (GLint((aGlyphsNb / aTilesPerRow) + 1) * myTileSizeY, aMaxSize);
113 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
114 myLastTilePx.Bottom = myTileSizeY;
116 myTextures.Append (new OpenGl_Texture());
117 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
119 Image_PixMap aBlackImg;
120 if (!aBlackImg.InitZero (Image_PixMap::ImgAlpha, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY))
121 || !aTexture->Init (theCtx, aBlackImg, Graphic3d_TOT_2D)) // myTextureFormat
123 TCollection_ExtendedString aMsg;
124 aMsg += "New texture intialization of size ";
125 aMsg += aTextureSizeX;
127 aMsg += aTextureSizeY;
128 aMsg += " for textured font has failed.";
129 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMsg);
133 aTexture->Bind (theCtx);
134 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, theCtx->TextureWrapClamp());
135 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, theCtx->TextureWrapClamp());
136 aTexture->Unbind (theCtx);
140 // =======================================================================
141 // function : renderGlyph
143 // =======================================================================
144 bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
145 const Standard_Utf32Char theChar)
147 if (!myFont->RenderGlyph (theChar))
152 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
154 const Image_PixMap& anImg = myFont->GlyphImage();
155 const Standard_Integer aTileId = myLastTileId + 1;
156 myLastTilePx.Left = myLastTilePx.Right + 3;
157 myLastTilePx.Right = myLastTilePx.Left + (Standard_Integer )anImg.SizeX();
158 if (myLastTilePx.Right >= aTexture->SizeX())
160 myLastTilePx.Left = 0;
161 myLastTilePx.Right = (Standard_Integer )anImg.SizeX();
162 myLastTilePx.Top += myTileSizeY;
163 myLastTilePx.Bottom += myTileSizeY;
165 if (myLastTilePx.Bottom >= aTexture->SizeY())
167 if (!createTexture (theCtx))
171 return renderGlyph (theCtx, theChar);
175 aTexture->Bind (theCtx);
176 #if !defined(GL_ES_VERSION_2_0)
177 glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
178 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
180 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
182 glTexSubImage2D (GL_TEXTURE_2D, 0,
183 myLastTilePx.Left, myLastTilePx.Top, (GLsizei )anImg.SizeX(), (GLsizei )anImg.SizeY(),
184 GL_ALPHA, GL_UNSIGNED_BYTE, anImg.Data());
186 OpenGl_Font::Tile aTile;
187 aTile.uv.Left = GLfloat(myLastTilePx.Left) / GLfloat(aTexture->SizeX());
188 aTile.uv.Right = GLfloat(myLastTilePx.Right) / GLfloat(aTexture->SizeX());
189 aTile.uv.Top = GLfloat(myLastTilePx.Top) / GLfloat(aTexture->SizeY());
190 aTile.uv.Bottom = GLfloat(myLastTilePx.Top + anImg.SizeY()) / GLfloat(aTexture->SizeY());
191 aTile.texture = aTexture->TextureId();
192 myFont->GlyphRect (aTile.px);
194 myLastTileId = aTileId;
195 myTiles.Append (aTile);
199 // =======================================================================
200 // function : RenderGlyph
202 // =======================================================================
203 void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
204 const Standard_Utf32Char theUChar,
205 const Standard_Utf32Char theUCharNext,
206 OpenGl_Font::Tile& theGlyph,
209 Standard_Integer aTileId = 0;
210 if (!myGlyphMap.Find (theUChar, aTileId))
212 if (renderGlyph (theCtx, theUChar))
214 aTileId = myLastTileId;
218 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
221 myGlyphMap.Bind (theUChar, aTileId);
224 const OpenGl_Font::Tile& aTile = myTiles.Value (aTileId);
225 theGlyph.px.Top = thePen.y() + aTile.px.Top;
226 theGlyph.px.Bottom = thePen.y() + aTile.px.Bottom;
227 theGlyph.px.Left = thePen.x() + aTile.px.Left;
228 theGlyph.px.Right = thePen.x() + aTile.px.Right;
229 theGlyph.uv = aTile.uv;
230 theGlyph.texture = aTile.texture;
232 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);