1 // Created on: 2013-06-25
2 // Created by: Dmitry BOBYLEV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15 
16 #include <Graphic3d_MarkerImage.hxx>
17 
18 #include <Image_PixMap.hxx>
19 #include <Standard_Atomic.hxx>
20 #include <TColStd_HArray1OfByte.hxx>
21 
22 #include "Graphic3d_MarkerImage.pxx"
23 
24 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_MarkerImage,Standard_Transient)
25 
26 namespace
27 {
28   static volatile Standard_Integer THE_MARKER_IMAGE_COUNTER = 0;
29 
30   //! Names of built-in markers
31   static const char* THE_MARKER_NAMES[Aspect_TOM_USERDEFINED] =
32   {
33     ".",     // Aspect_TOM_POINT
34     "+",     // Aspect_TOM_PLUS
35     "*",     // Aspect_TOM_STAR
36     "x",     // Aspect_TOM_X
37     "o",     // Aspect_TOM_O
38     "o.",    // Aspect_TOM_O_POINT
39     "o+",    // Aspect_TOM_O_PLUS
40     "o*",    // Aspect_TOM_O_STAR
41     "ox",    // Aspect_TOM_O_X
42     "ring1", // Aspect_TOM_RING1
43     "ring2", // Aspect_TOM_RING2
44     "ring3", // Aspect_TOM_RING3
45     "ball"   // Aspect_TOM_BALL
46   };
47 
48   //! Returns a parameters for the marker of the specified type and scale.
getMarkerBitMapParam(const Aspect_TypeOfMarker theMarkerType,const Standard_ShortReal theScale,Standard_Integer & theWidth,Standard_Integer & theHeight,Standard_Integer & theOffset,Standard_Integer & theNumOfBytes)49   static void getMarkerBitMapParam (const Aspect_TypeOfMarker theMarkerType,
50                                     const Standard_ShortReal theScale,
51                                     Standard_Integer& theWidth,
52                                     Standard_Integer& theHeight,
53                                     Standard_Integer& theOffset,
54                                     Standard_Integer& theNumOfBytes)
55   {
56     const Standard_Integer aType = Standard_Integer(theMarkerType > Aspect_TOM_O
57                                                   ? Aspect_TOM_O
58                                                   : theMarkerType);
59     const Standard_Real anIndex = (Standard_Real)(TEL_NO_OF_SIZES - 1) * (theScale - (Standard_Real)TEL_PM_START_SIZE)
60                                 / (Standard_Real)(TEL_PM_END_SIZE - TEL_PM_START_SIZE);
61     Standard_Integer anId = (Standard_Integer)(anIndex + 0.5);
62     if (anId < 0)
63     {
64       anId = 0;
65     }
66     else if (anId >= TEL_NO_OF_SIZES)
67     {
68       anId = TEL_NO_OF_SIZES - 1;
69     }
70 
71     theWidth  = (Standard_Integer)arrPMFontInfo[aType][anId].width;
72     theHeight = (Standard_Integer)arrPMFontInfo[aType][anId].height;
73     theOffset = arrPMFontInfo[aType][anId].offset;
74     const Standard_Integer aNumOfBytesInRow = theWidth / 8 + (theWidth % 8 ? 1 : 0);
75     theNumOfBytes = theHeight * aNumOfBytesInRow;
76   }
77 
78   //! Merge two image pixmap into one. Used for creating image for following markers:
79   //! Aspect_TOM_O_POINT, Aspect_TOM_O_PLUS, Aspect_TOM_O_STAR, Aspect_TOM_O_X, Aspect_TOM_RING1, Aspect_TOM_RING2, Aspect_TOM_RING3
mergeImages(const Handle (Image_PixMap)& theImage1,const Handle (Image_PixMap)& theImage2)80   static Handle(Image_PixMap) mergeImages (const Handle(Image_PixMap)& theImage1,
81                                            const Handle(Image_PixMap)& theImage2)
82   {
83     if (theImage1.IsNull() && theImage2.IsNull())
84     {
85       return Handle(Image_PixMap)();
86     }
87 
88     Handle(Image_PixMap) aResultImage = new Image_PixMap();
89 
90     Standard_Integer aWidth1 = 0, aHeight1 = 0;
91     if (!theImage1.IsNull())
92     {
93       aWidth1  = (Standard_Integer )theImage1->Width();
94       aHeight1 = (Standard_Integer )theImage1->Height();
95     }
96 
97     Standard_Integer aWidth2 = 0, aHeight2 = 0;
98     if (!theImage2.IsNull())
99     {
100       aWidth2  = (Standard_Integer )theImage2->Width();
101       aHeight2 = (Standard_Integer )theImage2->Height();
102     }
103 
104     const Standard_Integer aMaxWidth  = Max (aWidth1,  aWidth2);
105     const Standard_Integer aMaxHeight = Max (aHeight1, aHeight2);
106     const Standard_Integer aSize = Max (aMaxWidth, aMaxHeight);
107     aResultImage->InitZero (Image_Format_Alpha, aSize, aSize);
108 
109     if (!theImage1.IsNull())
110     {
111       const Standard_Integer aXOffset1  = Abs (aWidth1  - aMaxWidth)  / 2;
112       const Standard_Integer anYOffset1 = Abs (aHeight1 - aMaxHeight) / 2;
113       for (Standard_Integer anY = 0; anY < aHeight1; anY++)
114       {
115         Standard_Byte* anImageLine = theImage1->ChangeRow (anY);
116         Standard_Byte* aResultImageLine = aResultImage->ChangeRow (anYOffset1 + anY);
117         for (Standard_Integer aX = 0; aX < aWidth1; aX++)
118         {
119           aResultImageLine[aXOffset1 + aX] |= anImageLine[aX];
120         }
121       }
122     }
123 
124     if (!theImage2.IsNull())
125     {
126       const Standard_Integer aXOffset2  = Abs (aWidth2  - aMaxWidth)  / 2;
127       const Standard_Integer anYOffset2 = Abs (aHeight2 - aMaxHeight) / 2;
128       for (Standard_Integer anY = 0; anY < aHeight2; anY++)
129       {
130         Standard_Byte* anImageLine = theImage2->ChangeRow (anY);
131         Standard_Byte* aResultImageLine = aResultImage->ChangeRow (anYOffset2 + anY);
132         for (Standard_Integer aX = 0; aX < aWidth2; aX++)
133         {
134           aResultImageLine[aXOffset2 + aX] |= anImageLine[aX];
135         }
136       }
137     }
138 
139     return aResultImage;
140   }
141 
142   //! Draw inner point as filled rectangle
fillPointBitmap(const Standard_Integer theSize)143   static Handle(TColStd_HArray1OfByte) fillPointBitmap (const Standard_Integer theSize)
144   {
145     const Standard_Integer        aNbBytes = (theSize / 8 + (theSize % 8 ? 1 : 0)) * theSize;
146     Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNbBytes - 1);
147     for (Standard_Integer anIter = 0; anIter < aBitMap->Length(); ++anIter)
148     {
149       aBitMap->SetValue (anIter, 255);
150     }
151     return aBitMap;
152   }
153 
154   //! Returns a marker image for the marker of the specified type and scale.
getTextureImage(const Aspect_TypeOfMarker theMarkerType,const Standard_ShortReal theScale)155   static Handle(Graphic3d_MarkerImage) getTextureImage (const Aspect_TypeOfMarker theMarkerType,
156                                                         const Standard_ShortReal  theScale)
157   {
158     Standard_Integer aWidth = 0, aHeight = 0, anOffset = 0, aNbBytes = 0;
159     getMarkerBitMapParam (theMarkerType, theScale, aWidth, aHeight, anOffset, aNbBytes);
160 
161     Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNbBytes - 1);
162     for (Standard_Integer anIter = 0; anIter < aNbBytes; ++anIter)
163     {
164       aBitMap->ChangeValue (anIter) = Graphic3d_MarkerImage_myMarkerRaster[anOffset + anIter];
165     }
166 
167     Handle(Graphic3d_MarkerImage) aTexture = new Graphic3d_MarkerImage (aBitMap, aWidth, aHeight);
168     return aTexture;
169   }
170 }
171 
172 // =======================================================================
173 // function : Graphic3d_MarkerImage
174 // purpose  :
175 // =======================================================================
Graphic3d_MarkerImage(const Handle (Image_PixMap)& theImage,const Handle (Image_PixMap)& theImageAlpha)176 Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(Image_PixMap)& theImage,
177                                               const Handle(Image_PixMap)& theImageAlpha)
178 : myImage  (theImage),
179   myImageAlpha (theImageAlpha),
180   myMargin (1),
181   myWidth  ((Standard_Integer )theImage->Width()),
182   myHeight ((Standard_Integer )theImage->Height())
183 {
184   myImageId = TCollection_AsciiString ("Graphic3d_MarkerImage_")
185             + TCollection_AsciiString (Standard_Atomic_Increment (&THE_MARKER_IMAGE_COUNTER));
186 
187   myImageAlphaId = TCollection_AsciiString ("Graphic3d_MarkerImageAlpha_")
188                  + TCollection_AsciiString (THE_MARKER_IMAGE_COUNTER);
189 
190   if (!theImageAlpha.IsNull())
191   {
192     if (theImageAlpha->Format() != Image_Format_Alpha
193      && theImageAlpha->Format() != Image_Format_Gray)
194     {
195       throw Standard_ProgramError ("Graphic3d_MarkerImage, wrong color format of alpha image");
196     }
197     if (theImageAlpha->SizeX() != theImage->SizeX()
198      || theImageAlpha->SizeY() != theImage->SizeY())
199     {
200       throw Standard_ProgramError ("Graphic3d_MarkerImage, wrong dimensions of alpha image");
201     }
202   }
203 }
204 
205 // =======================================================================
206 // function : Graphic3d_MarkerImage
207 // purpose  :
208 // =======================================================================
Graphic3d_MarkerImage(const TCollection_AsciiString & theId,const TCollection_AsciiString & theAlphaId,const Handle (Image_PixMap)& theImage,const Handle (Image_PixMap)& theImageAlpha)209 Graphic3d_MarkerImage::Graphic3d_MarkerImage (const TCollection_AsciiString& theId,
210                                               const TCollection_AsciiString& theAlphaId,
211                                               const Handle(Image_PixMap)& theImage,
212                                               const Handle(Image_PixMap)& theImageAlpha)
213 : myImageId (theId),
214   myImageAlphaId (theAlphaId),
215   myImage  (theImage),
216   myImageAlpha (theImageAlpha),
217   myMargin (1),
218   myWidth  ((Standard_Integer )theImage->Width()),
219   myHeight ((Standard_Integer )theImage->Height())
220 {
221   if (!theImageAlpha.IsNull())
222   {
223     if (theImageAlpha->Format() != Image_Format_Alpha
224      && theImageAlpha->Format() != Image_Format_Gray)
225     {
226       throw Standard_ProgramError ("Graphic3d_MarkerImage, wrong color format of alpha image");
227     }
228     if (theImageAlpha->SizeX() != theImage->SizeX()
229      || theImageAlpha->SizeY() != theImage->SizeY())
230     {
231       throw Standard_ProgramError ("Graphic3d_MarkerImage, wrong dimensions of alpha image");
232     }
233   }
234 }
235 
236 // =======================================================================
237 // function : Graphic3d_MarkerImage
238 // purpose  :
239 // =======================================================================
Graphic3d_MarkerImage(const Handle (TColStd_HArray1OfByte)& theBitMap,const Standard_Integer theWidth,const Standard_Integer theHeight)240 Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(TColStd_HArray1OfByte)& theBitMap,
241                                               const Standard_Integer theWidth,
242                                               const Standard_Integer theHeight)
243 : myBitMap (theBitMap),
244   myMargin (1),
245   myWidth  (theWidth),
246   myHeight (theHeight)
247 {
248   myImageId = TCollection_AsciiString ("Graphic3d_MarkerImage_")
249             + TCollection_AsciiString (Standard_Atomic_Increment (&THE_MARKER_IMAGE_COUNTER));
250 
251   myImageAlphaId = TCollection_AsciiString ("Graphic3d_MarkerImageAlpha_")
252                  + TCollection_AsciiString (THE_MARKER_IMAGE_COUNTER);
253 }
254 
255 // =======================================================================
256 // function : IsColoredImage
257 // purpose  :
258 // =======================================================================
IsColoredImage() const259 bool Graphic3d_MarkerImage::IsColoredImage() const
260 {
261   return !myImage.IsNull()
262        && myImage->Format() != Image_Format_Alpha
263        && myImage->Format() != Image_Format_Gray;
264 }
265 
266 // =======================================================================
267 // function : GetBitMapArray
268 // purpose  :
269 // =======================================================================
Handle(TColStd_HArray1OfByte)270 Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Standard_Real theAlphaValue,
271                                                                      const Standard_Boolean theIsTopDown) const
272 {
273   if (!myBitMap.IsNull()
274     || myImage.IsNull())
275   {
276     return myBitMap;
277   }
278 
279   const Standard_Integer aNumOfBytesInRow = (Standard_Integer )(myImage->Width() / 8) + (myImage->Width() % 8 ? 1 : 0);
280   const Standard_Integer aNumOfBytes      = (Standard_Integer )(aNumOfBytesInRow * myImage->Height());
281   const Standard_Integer aHeight = (Standard_Integer )myImage->Height();
282   const Standard_Integer aWidth  = (Standard_Integer )myImage->Width();
283   Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNumOfBytes - 1);
284   aBitMap->Init (0);
285   for (Standard_Integer aRow = 0; aRow < aHeight; aRow++)
286   {
287     const Standard_Integer aResRow = !theIsTopDown ? (aHeight - aRow - 1) : aRow;
288     for (Standard_Integer aColumn = 0; aColumn < aWidth; aColumn++)
289     {
290       const Quantity_ColorRGBA aColor = myImage->PixelColor (aColumn, aRow);
291       Standard_Boolean aBitOn = Standard_False;
292       if (myImage->Format() == Image_Format_Gray)
293       {
294         aBitOn = aColor.GetRGB().Red() > theAlphaValue;
295       }
296       else //if (myImage->Format() == Image_Format_Alpha)
297       {
298         aBitOn = aColor.Alpha() > theAlphaValue;
299       }
300 
301       Standard_Integer anIndex = aNumOfBytesInRow * aResRow + aColumn / 8;
302       aBitMap->SetValue (anIndex, (Standard_Byte)(aBitMap->Value (anIndex) +
303                                                   (aBitOn ? (0x80 >> (aColumn % 8)) : 0)));
304     }
305   }
306 
307   return aBitMap;
308 }
309 
310 // =======================================================================
311 // function : GetImage
312 // purpose  :
313 // =======================================================================
Handle(Image_PixMap)314 const Handle(Image_PixMap)& Graphic3d_MarkerImage::GetImage()
315 {
316   if (!myImage.IsNull()
317     || myBitMap.IsNull())
318   {
319     return myImage;
320   }
321 
322   // Converting a byte array to bitmap image. Row and column offsets are used
323   // to store bitmap in a square image, so the image will not be stretched
324   // when rendering with point sprites.
325   const Standard_Integer aNumOfBytesInRow = myWidth / 8 + (myWidth % 8 ? 1 : 0);
326   const Standard_Integer aSize            = Max (myWidth, myHeight);
327   const Standard_Integer aRowOffset       = (aSize - myHeight) / 2 + myMargin;
328   const Standard_Integer aColumnOffset    = (aSize - myWidth ) / 2 + myMargin;
329   const Standard_Integer aLowerIndex      = myBitMap->Lower();
330 
331   myImage = new Image_PixMap();
332   myImage->InitZero (Image_Format_Alpha, aSize + myMargin * 2, aSize + myMargin * 2);
333   for (Standard_Integer aRowIter = 0; aRowIter < myHeight; aRowIter++)
334   {
335     Standard_Byte* anImageRow = myImage->ChangeRow (aRowIter + aRowOffset);
336     for (Standard_Integer aColumnIter = 0; aColumnIter < myWidth; aColumnIter++)
337     {
338       Standard_Boolean aBitOn = (myBitMap->Value (aLowerIndex + aNumOfBytesInRow * aRowIter + aColumnIter / 8) & (0x80 >> (aColumnIter % 8))) != 0;
339       anImageRow[aColumnIter + aColumnOffset] = aBitOn ? 255 : 0;
340     }
341   }
342 
343   return myImage;
344 }
345 
346 // =======================================================================
347 // function : GetImageAlpha
348 // purpose  :
349 // =======================================================================
Handle(Image_PixMap)350 const Handle(Image_PixMap)& Graphic3d_MarkerImage::GetImageAlpha()
351 {
352   if (!myImageAlpha.IsNull())
353   {
354     return myImageAlpha;
355   }
356 
357   if (!myImage.IsNull())
358   {
359     if (myImage->Format() == Image_Format_Gray
360      || myImage->Format() == Image_Format_Alpha)
361     {
362       myImageAlpha = myImage;
363     }
364     else
365     {
366       myImageAlpha = new Image_PixMap();
367       myImageAlpha->InitZero (Image_Format_Alpha, myImage->Width(), myImage->Height());
368       myImageAlpha->SetTopDown (Standard_False);
369       for (Standard_Size aRowIter = 0; aRowIter < myImage->Height(); aRowIter++)
370       {
371         Standard_Byte* anImageRow = myImageAlpha->ChangeRow (aRowIter);
372         for (Standard_Size aColumnIter = 0; aColumnIter < myImage->Width(); aColumnIter++)
373         {
374           const Quantity_ColorRGBA aColor = myImage->PixelColor ((Standard_Integer)aColumnIter, (Standard_Integer)aRowIter);
375           anImageRow[aColumnIter] = Standard_Byte (255.0 * aColor.Alpha());
376         }
377       }
378     }
379   }
380 
381   return myImageAlpha;
382 }
383 
384 // =======================================================================
385 // function : GetImageId
386 // purpose  :
387 // =======================================================================
GetImageId() const388 const TCollection_AsciiString& Graphic3d_MarkerImage::GetImageId() const
389 {
390   return myImageId;
391 }
392 
393 // =======================================================================
394 // function : GetImageAlphaId
395 // purpose  :
396 // =======================================================================
GetImageAlphaId() const397 const TCollection_AsciiString& Graphic3d_MarkerImage::GetImageAlphaId() const
398 {
399   return myImageAlphaId;
400 }
401 
402 // =======================================================================
403 // function : GetTextureSize
404 // purpose  :
405 // =======================================================================
GetTextureSize(Standard_Integer & theWidth,Standard_Integer & theHeight) const406 void Graphic3d_MarkerImage::GetTextureSize (Standard_Integer& theWidth,
407                                             Standard_Integer& theHeight) const
408 {
409   theWidth  = myWidth;
410   theHeight = myHeight;
411 }
412 
413 // =======================================================================
414 // function : GetMarkerImage
415 // purpose  :
416 // =======================================================================
Handle(Graphic3d_MarkerImage)417 Handle(Graphic3d_MarkerImage) Graphic3d_MarkerImage::StandardMarker (const Aspect_TypeOfMarker theMarkerType,
418                                                                      const Standard_ShortReal theScale,
419                                                                      const Graphic3d_Vec4& theColor)
420 {
421   if (theMarkerType == Aspect_TOM_USERDEFINED
422    || theMarkerType == Aspect_TOM_EMPTY)
423   {
424     return Handle(Graphic3d_MarkerImage)();
425   }
426 
427   // predefined markers are defined with 0.5 step
428   const Standard_Integer aScaleInt = Standard_Integer(theScale * 10.0f + 0.5f);
429   TCollection_AsciiString aKey  = TCollection_AsciiString ("Graphic3d_MarkerImage_")      + THE_MARKER_NAMES[theMarkerType] + "_" + aScaleInt;
430   TCollection_AsciiString aKeyA = TCollection_AsciiString ("Graphic3d_MarkerImageAlpha_") + THE_MARKER_NAMES[theMarkerType] + "_" + aScaleInt;
431   if (theMarkerType == Aspect_TOM_BALL)
432   {
433     unsigned int aColor[3] =
434     {
435       (unsigned int )(255.0f * theColor.r()),
436       (unsigned int )(255.0f * theColor.g()),
437       (unsigned int )(255.0f * theColor.b())
438     };
439     char aBytes[8];
440     sprintf (aBytes, "%02X%02X%02X", aColor[0], aColor[1], aColor[2]);
441     aKey += aBytes;
442   }
443 
444   switch (theMarkerType)
445   {
446     case Aspect_TOM_O_POINT:
447     case Aspect_TOM_O_PLUS:
448     case Aspect_TOM_O_STAR:
449     case Aspect_TOM_O_X:
450     {
451       // For this type of markers we merge two base bitmaps into one
452       // For example Aspect_TOM_O_PLUS = Aspect_TOM_O + Aspect_TOM_PLUS
453       Handle(Graphic3d_MarkerImage) aMarkerImage1 = getTextureImage (Aspect_TOM_O, theScale);
454       Handle(Graphic3d_MarkerImage) aMarkerImage2;
455       if (theMarkerType == Aspect_TOM_O_POINT)
456       {
457         // draw inner point as filled rectangle
458         const Standard_Integer        aSize = theScale > 7 ? 7 : (Standard_Integer)(theScale + 0.5F);
459         Handle(TColStd_HArray1OfByte) aBitMap = fillPointBitmap (aSize);
460         aMarkerImage2 = new Graphic3d_MarkerImage (aBitMap, aSize, aSize);
461       }
462       else
463       {
464         aMarkerImage2 = getTextureImage (Aspect_TypeOfMarker(theMarkerType - Aspect_TOM_O_POINT), theScale);
465       }
466       Handle(Image_PixMap) anImage = mergeImages (aMarkerImage1->GetImage(), aMarkerImage2->GetImage());
467       Handle(Graphic3d_MarkerImage) aNewMarkerImage = new Graphic3d_MarkerImage (aKey, aKey, anImage);
468       return aNewMarkerImage;
469     }
470     case Aspect_TOM_RING1:
471     case Aspect_TOM_RING2:
472     case Aspect_TOM_RING3:
473     {
474       const Standard_ShortReal aDelta = 0.1f;
475       Standard_ShortReal aScale = theScale;
476       Standard_ShortReal aLimit = 0.0f;
477       if (theMarkerType == Aspect_TOM_RING1)
478       {
479         aLimit = aScale * 0.2f;
480       }
481       else if (theMarkerType == Aspect_TOM_RING2)
482       {
483         aLimit = aScale * 0.5f;
484       }
485       else if (theMarkerType == Aspect_TOM_RING3)
486       {
487         aLimit = aScale * 0.8f;
488       }
489 
490       Handle(Image_PixMap) anImage;
491       for (; aScale > aLimit && aScale >= 1.0f; aScale -= aDelta)
492       {
493         anImage = mergeImages (anImage, getTextureImage (Aspect_TOM_O, aScale)->GetImage());
494       }
495       Handle(Graphic3d_MarkerImage) aNewMarkerImage = new Graphic3d_MarkerImage (aKey, aKey, anImage);
496       return aNewMarkerImage;
497     }
498     case Aspect_TOM_BALL:
499     {
500       Standard_Integer aWidth = 0, aHeight = 0, anOffset = 0, aNbBytes = 0;
501       Standard_ShortReal aScale = theScale;
502       getMarkerBitMapParam (Aspect_TOM_O, aScale, aWidth, aHeight, anOffset, aNbBytes);
503 
504       NCollection_Vec4<Standard_Real> aColor (theColor);
505 
506       const Standard_Integer aSize = Max (aWidth + 2, aHeight + 2); // includes extra margin
507       Handle(Image_PixMap) anImage  = new Image_PixMap();
508       Handle(Image_PixMap) anImageA = new Image_PixMap();
509       anImage ->InitZero (Image_Format_RGBA,  aSize, aSize);
510       anImageA->InitZero (Image_Format_Alpha, aSize, aSize);
511 
512       // we draw a set of circles
513       Image_ColorRGBA aColor32;
514       aColor32.a() = 255;
515       Standard_Real aHLS[3];
516       const Standard_ShortReal aDelta = 0.1f;
517       while (aScale >= 1.0f)
518       {
519         Quantity_Color::RgbHls (aColor.r(), aColor.g(), aColor.b(), aHLS[0], aHLS[1], aHLS[2]);
520         aHLS[2] *= 0.95; // 5% saturation change
521         Quantity_Color::HlsRgb (aHLS[0], aHLS[1], aHLS[2], aColor.r(), aColor.g(), aColor.b());
522         aColor32.r() = Standard_Byte (255.0 * aColor.r());
523         aColor32.g() = Standard_Byte (255.0 * aColor.g());
524         aColor32.b() = Standard_Byte (255.0 * aColor.b());
525 
526         const Handle(Graphic3d_MarkerImage) aMarker = getTextureImage (Aspect_TOM_O, aScale);
527         const Handle(Image_PixMap)& aCircle = aMarker->GetImage();
528 
529         const Standard_Size aDiffX = (anImage->SizeX() - aCircle->SizeX()) / 2;
530         const Standard_Size aDiffY = (anImage->SizeY() - aCircle->SizeY()) / 2;
531         for (Standard_Size aRow = 0; aRow < aCircle->SizeY(); ++aRow)
532         {
533           const Standard_Byte* aRowData = aCircle->Row(aRow);
534           for (Standard_Size aCol = 0; aCol < aCircle->SizeX(); ++aCol)
535           {
536             if (aRowData[aCol] != 0)
537             {
538               anImage->ChangeValue<Image_ColorRGBA>(aDiffX + aRow, aDiffY + aCol) = aColor32;
539               anImageA->ChangeValue<Standard_Byte> (aDiffX + aRow, aDiffY + aCol) = 255;
540             }
541           }
542         }
543         aScale -= aDelta;
544       }
545       Handle(Graphic3d_MarkerImage) aNewMarkerImage = new Graphic3d_MarkerImage (aKey, aKeyA, anImage, anImageA);
546       return aNewMarkerImage;
547     }
548     default:
549     {
550       Handle(Graphic3d_MarkerImage) aNewMarkerImage = getTextureImage (theMarkerType, theScale);
551       aNewMarkerImage->myImageId = aKey;
552       aNewMarkerImage->myImageAlphaId = aKey;
553       return aNewMarkerImage;
554     }
555   }
556 }
557