1 // Copyright (c) 2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <OpenGl_AspectsSprite.hxx>
15
16 #include <OpenGl_Context.hxx>
17 #include <OpenGl_PointSprite.hxx>
18 #include <OpenGl_TextureSet.hxx>
19
20 #include <Image_PixMap.hxx>
21 #include <Graphic3d_MarkerImage.hxx>
22 #include <TColStd_HArray1OfByte.hxx>
23
24 namespace
25 {
26 static const TCollection_AsciiString THE_EMPTY_KEY;
27 }
28
29 // =======================================================================
30 // function : Release
31 // purpose :
32 // =======================================================================
Release(OpenGl_Context * theCtx)33 void OpenGl_AspectsSprite::Release (OpenGl_Context* theCtx)
34 {
35 myIsSpriteReady = Standard_False;
36 if (mySprite.IsNull())
37 {
38 return;
39 }
40
41 if (theCtx != NULL)
42 {
43 if (mySprite->ResourceId().IsEmpty())
44 {
45 theCtx->DelayedRelease (mySprite);
46 theCtx->DelayedRelease (mySpriteA);
47 }
48 else
49 {
50 {
51 const TCollection_AsciiString aSpriteKey = mySprite->ResourceId();
52 mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
53 theCtx->ReleaseResource (aSpriteKey, Standard_True);
54 }
55 if (!mySpriteA.IsNull())
56 {
57 const TCollection_AsciiString aSpriteKeyA = mySpriteA->ResourceId();
58 mySpriteA.Nullify();
59 theCtx->ReleaseResource (aSpriteKeyA, Standard_True);
60 }
61 }
62 }
63 mySprite.Nullify();
64 mySpriteA.Nullify();
65 }
66
67 // =======================================================================
68 // function : HasPointSprite
69 // purpose :
70 // =======================================================================
HasPointSprite(const Handle (OpenGl_Context)& theCtx,const Handle (Graphic3d_Aspects)& theAspects)71 bool OpenGl_AspectsSprite::HasPointSprite (const Handle(OpenGl_Context)& theCtx,
72 const Handle(Graphic3d_Aspects)& theAspects)
73 {
74 const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
75 return !aSprite.IsNull()
76 && !aSprite->IsDisplayList();
77 }
78
79 // =======================================================================
80 // function : IsDisplayListSprite
81 // purpose :
82 // =======================================================================
IsDisplayListSprite(const Handle (OpenGl_Context)& theCtx,const Handle (Graphic3d_Aspects)& theAspects)83 bool OpenGl_AspectsSprite::IsDisplayListSprite (const Handle(OpenGl_Context)& theCtx,
84 const Handle(Graphic3d_Aspects)& theAspects)
85 {
86 #if !defined(GL_ES_VERSION_2_0)
87 const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
88 return !aSprite.IsNull()
89 && aSprite->IsDisplayList();
90 #else
91 (void )theCtx;
92 (void )theAspects;
93 return false;
94 #endif
95 }
96
97 // =======================================================================
98 // function : UpdateRediness
99 // purpose :
100 // =======================================================================
UpdateRediness(const Handle (Graphic3d_Aspects)& theAspect)101 void OpenGl_AspectsSprite::UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect)
102 {
103 // update sprite resource bindings
104 TCollection_AsciiString aSpriteKeyNew, aSpriteAKeyNew;
105 spriteKeys (theAspect->MarkerImage(), theAspect->MarkerType(), theAspect->MarkerScale(), theAspect->ColorRGBA(), aSpriteKeyNew, aSpriteAKeyNew);
106 const TCollection_AsciiString& aSpriteKeyOld = !mySprite.IsNull() ? mySprite ->ResourceId() : THE_EMPTY_KEY;
107 const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
108 if (aSpriteKeyNew.IsEmpty() || aSpriteKeyOld != aSpriteKeyNew
109 || aSpriteAKeyNew.IsEmpty() || aSpriteAKeyOld != aSpriteAKeyNew)
110 {
111 myIsSpriteReady = Standard_False;
112 myMarkerSize = theAspect->MarkerScale();
113 }
114 }
115
116 // =======================================================================
117 // function : Sprite
118 // purpose :
119 // =======================================================================
Handle(OpenGl_PointSprite)120 const Handle(OpenGl_PointSprite)& OpenGl_AspectsSprite::Sprite (const Handle(OpenGl_Context)& theCtx,
121 const Handle(Graphic3d_Aspects)& theAspects,
122 bool theIsAlphaSprite)
123 {
124 if (!myIsSpriteReady)
125 {
126 build (theCtx, theAspects->MarkerImage(), theAspects->MarkerType(), theAspects->MarkerScale(), theAspects->ColorRGBA(), myMarkerSize);
127 myIsSpriteReady = true;
128 }
129 return theIsAlphaSprite && !mySpriteA.IsNull() && mySpriteA->IsValid()
130 ? mySpriteA
131 : mySprite;
132 }
133
134 // =======================================================================
135 // function : build
136 // purpose :
137 // =======================================================================
build(const Handle (OpenGl_Context)& theCtx,const Handle (Graphic3d_MarkerImage)& theMarkerImage,Aspect_TypeOfMarker theType,Standard_ShortReal theScale,const Graphic3d_Vec4 & theColor,Standard_ShortReal & theMarkerSize)138 void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
139 const Handle(Graphic3d_MarkerImage)& theMarkerImage,
140 Aspect_TypeOfMarker theType,
141 Standard_ShortReal theScale,
142 const Graphic3d_Vec4& theColor,
143 Standard_ShortReal& theMarkerSize)
144 {
145 // generate key for shared resource
146 TCollection_AsciiString aNewKey, aNewKeyA;
147 spriteKeys (theMarkerImage, theType, theScale, theColor, aNewKey, aNewKeyA);
148
149 const TCollection_AsciiString& aSpriteKeyOld = !mySprite.IsNull() ? mySprite ->ResourceId() : THE_EMPTY_KEY;
150 const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
151
152 // release old shared resources
153 const Standard_Boolean aNewResource = aNewKey.IsEmpty()
154 || aSpriteKeyOld != aNewKey;
155 if (aNewResource)
156 {
157 if (!mySprite.IsNull())
158 {
159 if (mySprite->ResourceId().IsEmpty())
160 {
161 theCtx->DelayedRelease (mySprite);
162 mySprite.Nullify();
163 }
164 else
165 {
166 const TCollection_AsciiString anOldKey = mySprite->ResourceId();
167 mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
168 theCtx->ReleaseResource (anOldKey, Standard_True);
169 }
170 }
171 }
172 if (aNewKeyA.IsEmpty() || aSpriteAKeyOld != aNewKeyA)
173 {
174 if (!mySpriteA.IsNull())
175 {
176 if (mySpriteA->ResourceId().IsEmpty())
177 {
178 theCtx->DelayedRelease (mySpriteA);
179 mySpriteA.Nullify();
180 }
181 else
182 {
183 const TCollection_AsciiString anOldKey = mySpriteA->ResourceId();
184 mySpriteA.Nullify(); // we need nullify all handles before ReleaseResource() call
185 theCtx->ReleaseResource (anOldKey, Standard_True);
186 }
187 }
188 }
189
190 if (!aNewResource)
191 {
192 const OpenGl_PointSprite* aSprite = dynamic_cast<OpenGl_PointSprite*> (mySprite.get());
193 if (!aSprite->IsDisplayList())
194 {
195 theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
196 }
197 return;
198 }
199 if (theType == Aspect_TOM_POINT
200 || theType == Aspect_TOM_EMPTY
201 || (theType == Aspect_TOM_USERDEFINED && theMarkerImage.IsNull()))
202 {
203 // nothing to do - just simple point
204 return;
205 }
206
207 Handle(OpenGl_PointSprite)& aSprite = mySprite;
208 Handle(OpenGl_PointSprite)& aSpriteA = mySpriteA;
209 if (!aNewKey.IsEmpty())
210 {
211 theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKeyA, aSpriteA); // alpha sprite could be shared
212 theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKey, aSprite);
213 }
214
215 const bool hadAlreadyRGBA = !aSprite.IsNull();
216 const bool hadAlreadyAlpha = !aSpriteA.IsNull();
217 if (hadAlreadyRGBA
218 && hadAlreadyAlpha)
219 {
220 // reuse shared resource
221 if (!aSprite->IsDisplayList())
222 {
223 theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
224 }
225 return;
226 }
227
228 if (!hadAlreadyAlpha)
229 {
230 aSpriteA = new OpenGl_PointSprite (aNewKeyA);
231 }
232 if (!hadAlreadyRGBA)
233 {
234 aSprite = new OpenGl_PointSprite (aNewKey);
235 }
236 if (!aNewKey.IsEmpty())
237 {
238 if (!hadAlreadyRGBA)
239 {
240 theCtx->ShareResource (aNewKey, aSprite);
241 }
242 if (!hadAlreadyAlpha)
243 {
244 theCtx->ShareResource (aNewKeyA, aSpriteA);
245 }
246 }
247
248 Handle(Graphic3d_MarkerImage) aNewMarkerImage = theType == Aspect_TOM_USERDEFINED && !theMarkerImage.IsNull()
249 ? theMarkerImage
250 : Graphic3d_MarkerImage::StandardMarker (theType, theScale, theColor);
251 if (aNewMarkerImage.IsNull())
252 {
253 return;
254 }
255
256 if (theCtx->core20fwd != NULL
257 && (!theCtx->caps->pntSpritesDisable || theCtx->core11ffp == NULL))
258 {
259 // Creating texture resource for using it with point sprites
260 Handle(Image_PixMap) anImage = aNewMarkerImage->GetImage();
261 theMarkerSize = Max ((Standard_ShortReal )anImage->Width(),(Standard_ShortReal )anImage->Height());
262
263 if (!hadAlreadyRGBA)
264 {
265 aSprite->Init (theCtx, *anImage, Graphic3d_TOT_2D, true);
266 }
267 if (!hadAlreadyAlpha)
268 {
269 if (Handle(Image_PixMap) anImageA = aSprite->GetFormat() != GL_ALPHA ? aNewMarkerImage->GetImageAlpha() : Handle(Image_PixMap)())
270 {
271 aSpriteA->Init (theCtx, *anImageA, Graphic3d_TOT_2D, true);
272 }
273 }
274 }
275 else if (theCtx->core11ffp != NULL)
276 {
277 #if !defined(GL_ES_VERSION_2_0)
278 // Creating list with bitmap for using it in compatibility mode
279 GLuint aBitmapList = theCtx->core11ffp->glGenLists (1);
280 aSprite->SetDisplayList (theCtx, aBitmapList);
281
282 Handle(Image_PixMap) anImage = aNewMarkerImage->IsColoredImage()
283 ? aNewMarkerImage->GetImage()
284 : Handle(Image_PixMap)();
285 const OpenGl_TextureFormat aFormat = !anImage.IsNull()
286 ? OpenGl_TextureFormat::FindFormat (theCtx, anImage->Format(), true)
287 : OpenGl_TextureFormat();
288 if (aFormat.IsValid())
289 {
290 if (anImage->IsTopDown())
291 {
292 Handle(Image_PixMap) anImageCopy = new Image_PixMap();
293 anImageCopy->InitCopy (*anImage);
294 Image_PixMap::FlipY (*anImageCopy);
295 anImage = anImageCopy;
296 }
297 const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8);
298 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
299
300 const GLint anExtraBytes = GLint (anImage->RowExtraBytes());
301 const GLint aPixelsWidth = GLint (anImage->SizeRowBytes() / anImage->SizePixelBytes());
302 const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
303 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
304
305 theCtx->core11ffp->glNewList (aBitmapList, GL_COMPILE);
306 const Standard_Integer aWidth = (Standard_Integer )anImage->Width(), aHeight = (Standard_Integer )anImage->Height();
307 theCtx->core11ffp->glBitmap (0, 0, 0, 0, GLfloat(-0.5f * aWidth), GLfloat(-0.5f * aHeight), NULL); // make offsets that will be added to the current raster position
308 theCtx->core11ffp->glDrawPixels (GLsizei(anImage->Width()), GLsizei(anImage->Height()), aFormat.PixelFormat(), aFormat.DataType(), anImage->Data());
309 theCtx->core11ffp->glEndList();
310 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
311 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
312 }
313
314 if (!aFormat.IsValid() || !hadAlreadyAlpha)
315 {
316 if (aFormat.IsValid())
317 {
318 aBitmapList = glGenLists (1);
319 aSpriteA->SetDisplayList (theCtx, aBitmapList);
320 }
321
322 Standard_Integer aWidth = 0, aHeight = 0;
323 aNewMarkerImage->GetTextureSize (aWidth, aHeight);
324 if (Handle(TColStd_HArray1OfByte) aBitMap = aNewMarkerImage->GetBitMapArray())
325 {
326 theCtx->core11ffp->glNewList (aBitmapList, GL_COMPILE);
327 theCtx->core11ffp->glBitmap ((GLsizei)aWidth, (GLsizei)aHeight, (GLfloat)(0.5f * aWidth), (GLfloat)(0.5f * aHeight),
328 0.f, 0.f, (const GLubyte*)&aBitMap->First());
329 theCtx->core11ffp->glEndList();
330 }
331 }
332 #endif
333 }
334 }
335 // =======================================================================
336 // function : spriteKeys
337 // purpose :
338 // =======================================================================
spriteKeys(const Handle (Graphic3d_MarkerImage)& theMarkerImage,Aspect_TypeOfMarker theType,Standard_ShortReal theScale,const Graphic3d_Vec4 & theColor,TCollection_AsciiString & theKey,TCollection_AsciiString & theKeyA)339 void OpenGl_AspectsSprite::spriteKeys (const Handle(Graphic3d_MarkerImage)& theMarkerImage,
340 Aspect_TypeOfMarker theType,
341 Standard_ShortReal theScale,
342 const Graphic3d_Vec4& theColor,
343 TCollection_AsciiString& theKey,
344 TCollection_AsciiString& theKeyA)
345 {
346 // generate key for shared resource
347 if (theType == Aspect_TOM_USERDEFINED)
348 {
349 if (!theMarkerImage.IsNull())
350 {
351 theKey = theMarkerImage->GetImageId();
352 theKeyA = theMarkerImage->GetImageAlphaId();
353 }
354 }
355 else if (theType != Aspect_TOM_POINT
356 && theType != Aspect_TOM_EMPTY)
357 {
358 // predefined markers are defined with 0.5 step
359 const Standard_Integer aScale = Standard_Integer(theScale * 10.0f + 0.5f);
360 theKey = TCollection_AsciiString ("OpenGl_AspectMarker") + theType + "_" + aScale;
361 theKeyA = theKey + "A";
362 if (theType == Aspect_TOM_BALL)
363 {
364 unsigned int aColor[3] =
365 {
366 (unsigned int )(255.0f * theColor.r()),
367 (unsigned int )(255.0f * theColor.g()),
368 (unsigned int )(255.0f * theColor.b())
369 };
370 char aBytes[8];
371 sprintf (aBytes, "%02X%02X%02X", aColor[0], aColor[1], aColor[2]);
372 theKey += aBytes;
373 }
374 }
375 }
376