0025271: Wrong result obtained by solid classifier algorithm
[occt.git] / src / OpenGl / OpenGl_Font.cxx
CommitLineData
a174a3c5 1// Created on: 2013-01-29
2// Created by: Kirill GAVRILOV
d5f74e42 3// Copyright (c) 2013-2014 OPEN CASCADE SAS
a174a3c5 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
a174a3c5 6//
d5f74e42 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
973c2be1 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.
a174a3c5 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
a174a3c5 15
16#include <OpenGl_Font.hxx>
17
18#include <OpenGl_Context.hxx>
19#include <Standard_Assert.hxx>
cbf18624 20#include <TCollection_ExtendedString.hxx>
a174a3c5 21
22IMPLEMENT_STANDARD_HANDLE (OpenGl_Font, OpenGl_Resource)
23IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Font, OpenGl_Resource)
24
25// =======================================================================
26// function : OpenGl_Font
27// purpose :
28// =======================================================================
29OpenGl_Font::OpenGl_Font (const Handle(Font_FTFont)& theFont,
30 const TCollection_AsciiString& theKey)
31: myKey (theKey),
32 myFont (theFont),
33 myAscender (0.0f),
34 myDescender (0.0f),
35 myLineSpacing (0.0f),
36 myTileSizeX (0),
37 myTileSizeY (0),
38 myLastTileId (-1),
ca3c13d1 39 myTextureFormat (GL_ALPHA)
a174a3c5 40{
41 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
42}
43
44// =======================================================================
45// function : ~OpenGl_Font
46// purpose :
47// =======================================================================
48OpenGl_Font::~OpenGl_Font()
49{
50 Release (NULL);
51}
52
53// =======================================================================
54// function : Release
55// purpose :
56// =======================================================================
10b9c7df 57void OpenGl_Font::Release (OpenGl_Context* theCtx)
a174a3c5 58{
59 if (myTextures.IsEmpty())
60 {
61 return;
62 }
63
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...",);
67
68 for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
69 {
70 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeValue (anIter);
71 aTexture->Release (theCtx);
72 aTexture.Nullify();
73 }
74 myTextures.Clear();
75}
76
77// =======================================================================
78// function : Init
79// purpose :
80// =======================================================================
81bool OpenGl_Font::Init (const Handle(OpenGl_Context)& theCtx)
82{
83 Release (theCtx.operator->());
84 if (myFont.IsNull() || !myFont->IsValid())
85 {
86 return false;
87 }
88
89 myAscender = myFont->Ascender();
90 myDescender = myFont->Descender();
91 myLineSpacing = myFont->LineSpacing();
92 myTileSizeX = myFont->GlyphMaxSizeX();
93 myTileSizeY = myFont->GlyphMaxSizeY();
94
95 myLastTileId = -1;
96 return createTexture (theCtx);
97}
98
99// =======================================================================
100// function : createTexture
101// purpose :
102// =======================================================================
103bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx)
104{
105 const Standard_Integer aMaxSize = theCtx->MaxTextureSize();
106
107 Standard_Integer aGlyphsNb = myFont->GlyphsNumber() - myLastTileId + 1;
108
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);
112
113 memset (&myLastTilePx, 0, sizeof(myLastTilePx));
114 myLastTilePx.Bottom = myTileSizeY;
115
116 myTextures.Append (new OpenGl_Texture());
117 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
118
119 Image_PixMap aBlackImg;
076ca35c 120 if (!aBlackImg.InitZero (Image_PixMap::ImgAlpha, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY))
a174a3c5 121 || !aTexture->Init (theCtx, aBlackImg, Graphic3d_TOT_2D)) // myTextureFormat
122 {
cbf18624 123 TCollection_ExtendedString aMsg;
124 aMsg += "New texture intialization of size ";
125 aMsg += aTextureSizeX;
126 aMsg += "x";
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);
a174a3c5 130 return false;
131 }
132
133 aTexture->Bind (theCtx);
ca3c13d1 134 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, theCtx->TextureWrapClamp());
135 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, theCtx->TextureWrapClamp());
a174a3c5 136 aTexture->Unbind (theCtx);
137 return true;
138}
139
140// =======================================================================
141// function : renderGlyph
142// purpose :
143// =======================================================================
144bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
145 const Standard_Utf32Char theChar)
146{
147 if (!myFont->RenderGlyph (theChar))
148 {
149 return false;
150 }
151
152 Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast();
153
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())
159 {
160 myLastTilePx.Left = 0;
161 myLastTilePx.Right = (Standard_Integer )anImg.SizeX();
162 myLastTilePx.Top += myTileSizeY;
163 myLastTilePx.Bottom += myTileSizeY;
164
165 if (myLastTilePx.Bottom >= aTexture->SizeY())
166 {
167 if (!createTexture (theCtx))
168 {
169 return false;
170 }
171 return renderGlyph (theCtx, theChar);
172 }
173 }
174
175 aTexture->Bind (theCtx);
ca3c13d1 176#if !defined(GL_ES_VERSION_2_0)
a174a3c5 177 glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
178 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
ca3c13d1 179#endif
a174a3c5 180 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
181
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());
185
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);
193
194 myLastTileId = aTileId;
195 myTiles.Append (aTile);
196 return true;
197}
198
199// =======================================================================
200// function : RenderGlyph
201// purpose :
202// =======================================================================
203void OpenGl_Font::RenderGlyph (const Handle(OpenGl_Context)& theCtx,
204 const Standard_Utf32Char theUChar,
205 const Standard_Utf32Char theUCharNext,
206 OpenGl_Font::Tile& theGlyph,
207 OpenGl_Vec2& thePen)
208{
209 Standard_Integer aTileId = 0;
210 if (!myGlyphMap.Find (theUChar, aTileId))
211 {
212 if (renderGlyph (theCtx, theUChar))
213 {
214 aTileId = myLastTileId;
215 }
216 else
217 {
218 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
219 return;
220 }
221 myGlyphMap.Bind (theUChar, aTileId);
222 }
223
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;
231
232 thePen.x() += myFont->AdvanceX (theUChar, theUCharNext);
233}