0031705: Visualization - move out construction of predefined markers from OpenGl_Aspe...
[occt.git] / src / Graphic3d / Graphic3d_MarkerImage.cxx
index a8b51dc..b56ff81 100755 (executable)
 #include <Standard_Atomic.hxx>
 #include <TColStd_HArray1OfByte.hxx>
 
+#include "Graphic3d_MarkerImage.pxx"
+
 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_MarkerImage,Standard_Transient)
 
 namespace
 {
   static volatile Standard_Integer THE_MARKER_IMAGE_COUNTER = 0;
-}
 
+  //! Returns a parameters for the marker of the specified type and scale.
+  static void getMarkerBitMapParam (const Aspect_TypeOfMarker theMarkerType,
+                                    const Standard_ShortReal theScale,
+                                    Standard_Integer& theWidth,
+                                    Standard_Integer& theHeight,
+                                    Standard_Integer& theOffset,
+                                    Standard_Integer& theNumOfBytes)
+  {
+    const Standard_Integer aType = Standard_Integer(theMarkerType > Aspect_TOM_O
+                                                  ? Aspect_TOM_O
+                                                  : theMarkerType);
+    const Standard_Real anIndex = (Standard_Real)(TEL_NO_OF_SIZES - 1) * (theScale - (Standard_Real)TEL_PM_START_SIZE)
+                                / (Standard_Real)(TEL_PM_END_SIZE - TEL_PM_START_SIZE);
+    Standard_Integer anId = (Standard_Integer)(anIndex + 0.5);
+    if (anId < 0)
+    {
+      anId = 0;
+    }
+    else if (anId >= TEL_NO_OF_SIZES)
+    {
+      anId = TEL_NO_OF_SIZES - 1;
+    }
+
+    theWidth  = (Standard_Integer)arrPMFontInfo[aType][anId].width;
+    theHeight = (Standard_Integer)arrPMFontInfo[aType][anId].height;
+    theOffset = arrPMFontInfo[aType][anId].offset;
+    const Standard_Integer aNumOfBytesInRow = theWidth / 8 + (theWidth % 8 ? 1 : 0);
+    theNumOfBytes = theHeight * aNumOfBytesInRow;
+  }
+
+  //! Merge two image pixmap into one. Used for creating image for following markers:
+  //! 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
+  static Handle(Image_PixMap) mergeImages (const Handle(Image_PixMap)& theImage1,
+                                           const Handle(Image_PixMap)& theImage2)
+  {
+    if (theImage1.IsNull() && theImage2.IsNull())
+    {
+      return Handle(Image_PixMap)();
+    }
+
+    Handle(Image_PixMap) aResultImage = new Image_PixMap();
+
+    Standard_Integer aWidth1 = 0, aHeight1 = 0;
+    if (!theImage1.IsNull())
+    {
+      aWidth1  = (Standard_Integer )theImage1->Width();
+      aHeight1 = (Standard_Integer )theImage1->Height();
+    }
+
+    Standard_Integer aWidth2 = 0, aHeight2 = 0;
+    if (!theImage2.IsNull())
+    {
+      aWidth2  = (Standard_Integer )theImage2->Width();
+      aHeight2 = (Standard_Integer )theImage2->Height();
+    }
+
+    const Standard_Integer aMaxWidth  = Max (aWidth1,  aWidth2);
+    const Standard_Integer aMaxHeight = Max (aHeight1, aHeight2);
+    const Standard_Integer aSize = Max (aMaxWidth, aMaxHeight);
+    aResultImage->InitZero (Image_Format_Alpha, aSize, aSize);
+
+    if (!theImage1.IsNull())
+    {
+      const Standard_Integer aXOffset1  = Abs (aWidth1  - aMaxWidth)  / 2;
+      const Standard_Integer anYOffset1 = Abs (aHeight1 - aMaxHeight) / 2;
+      for (Standard_Integer anY = 0; anY < aHeight1; anY++)
+      {
+        Standard_Byte* anImageLine = theImage1->ChangeRow (anY);
+        Standard_Byte* aResultImageLine = aResultImage->ChangeRow (anYOffset1 + anY);
+        for (Standard_Integer aX = 0; aX < aWidth1; aX++)
+        {
+          aResultImageLine[aXOffset1 + aX] |= anImageLine[aX];
+        }
+      }
+    }
+
+    if (!theImage2.IsNull())
+    {
+      const Standard_Integer aXOffset2  = Abs (aWidth2  - aMaxWidth)  / 2;
+      const Standard_Integer anYOffset2 = Abs (aHeight2 - aMaxHeight) / 2;
+      for (Standard_Integer anY = 0; anY < aHeight2; anY++)
+      {
+        Standard_Byte* anImageLine = theImage2->ChangeRow (anY);
+        Standard_Byte* aResultImageLine = aResultImage->ChangeRow (anYOffset2 + anY);
+        for (Standard_Integer aX = 0; aX < aWidth2; aX++)
+        {
+          aResultImageLine[aXOffset2 + aX] |= anImageLine[aX];
+        }
+      }
+    }
+
+    return aResultImage;
+  }
+
+  //! Draw inner point as filled rectangle
+  static Handle(TColStd_HArray1OfByte) fillPointBitmap (const Standard_Integer theSize)
+  {
+    const Standard_Integer        aNbBytes = (theSize / 8 + (theSize % 8 ? 1 : 0)) * theSize;
+    Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNbBytes - 1);
+    for (Standard_Integer anIter = 0; anIter < aBitMap->Length(); ++anIter)
+    {
+      aBitMap->SetValue (anIter, 255);
+    }
+    return aBitMap;
+  }
+
+  //! Returns a marker image for the marker of the specified type and scale.
+  static Handle(Graphic3d_MarkerImage) getTextureImage (const Aspect_TypeOfMarker theMarkerType,
+                                                        const Standard_ShortReal  theScale)
+  {
+    Standard_Integer aWidth = 0, aHeight = 0, anOffset = 0, aNbBytes = 0;
+    getMarkerBitMapParam (theMarkerType, theScale, aWidth, aHeight, anOffset, aNbBytes);
+
+    Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNbBytes - 1);
+    for (Standard_Integer anIter = 0; anIter < aNbBytes; ++anIter)
+    {
+      aBitMap->ChangeValue (anIter) = Graphic3d_MarkerImage_myMarkerRaster[anOffset + anIter];
+    }
+
+    Handle(Graphic3d_MarkerImage) aTexture = new Graphic3d_MarkerImage (aBitMap, aWidth, aHeight);
+    return aTexture;
+  }
+}
 
 // =======================================================================
 // function : Graphic3d_MarkerImage
 // purpose  :
 // =======================================================================
-Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(Image_PixMap)& theImage)
+Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(Image_PixMap)& theImage,
+                                              const Handle(Image_PixMap)& theImageAlpha)
 : myImage  (theImage),
+  myImageAlpha (theImageAlpha),
   myMargin (1),
   myWidth  ((Standard_Integer )theImage->Width()),
   myHeight ((Standard_Integer )theImage->Height())
@@ -42,6 +168,20 @@ Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(Image_PixMap)& theIma
 
   myImageAlphaId = TCollection_AsciiString ("Graphic3d_MarkerImageAlpha_")
                  + TCollection_AsciiString (THE_MARKER_IMAGE_COUNTER);
+
+  if (!theImageAlpha.IsNull())
+  {
+    if (theImageAlpha->Format() != Image_Format_Alpha
+     && theImageAlpha->Format() != Image_Format_Gray)
+    {
+      throw Standard_ProgramError ("Graphic3d_MarkerImage, wrong color format of alpha image");
+    }
+    if (theImageAlpha->SizeX() != theImage->SizeX()
+     || theImageAlpha->SizeY() != theImage->SizeY())
+    {
+      throw Standard_ProgramError ("Graphic3d_MarkerImage, wrong dimensions of alpha image");
+    }
+  }
 }
 
 // =======================================================================
@@ -49,8 +189,8 @@ Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(Image_PixMap)& theIma
 // purpose  :
 // =======================================================================
 Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(TColStd_HArray1OfByte)& theBitMap,
-                                              const Standard_Integer& theWidth,
-                                              const Standard_Integer& theHeight)
+                                              const Standard_Integer theWidth,
+                                              const Standard_Integer theHeight)
 : myBitMap (theBitMap),
   myMargin (1),
   myWidth  (theWidth),
@@ -63,31 +203,39 @@ Graphic3d_MarkerImage::Graphic3d_MarkerImage (const Handle(TColStd_HArray1OfByte
                  + TCollection_AsciiString (THE_MARKER_IMAGE_COUNTER);
 }
 
+// =======================================================================
+// function : IsColoredImage
+// purpose  :
+// =======================================================================
+bool Graphic3d_MarkerImage::IsColoredImage() const
+{
+  return !myImage.IsNull()
+       && myImage->Format() != Image_Format_Alpha
+       && myImage->Format() != Image_Format_Gray;
+}
+
 // =======================================================================
 // function : GetBitMapArray
 // purpose  :
 // =======================================================================
-Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Standard_Real& theAlphaValue) const
+Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Standard_Real theAlphaValue,
+                                                                     const Standard_Boolean theIsTopDown) const
 {
-  if (!myBitMap.IsNull())
+  if (!myBitMap.IsNull()
+    || myImage.IsNull())
   {
     return myBitMap;
   }
 
-  Handle(TColStd_HArray1OfByte) aBitMap;
-  if (myImage.IsNull())
-  {
-    return aBitMap;
-  }
-
   const Standard_Integer aNumOfBytesInRow = (Standard_Integer )(myImage->Width() / 8) + (myImage->Width() % 8 ? 1 : 0);
   const Standard_Integer aNumOfBytes      = (Standard_Integer )(aNumOfBytesInRow * myImage->Height());
   const Standard_Integer aHeight = (Standard_Integer )myImage->Height();
   const Standard_Integer aWidth  = (Standard_Integer )myImage->Width();
-  aBitMap = new TColStd_HArray1OfByte (0, aNumOfBytes - 1);
+  Handle(TColStd_HArray1OfByte) aBitMap = new TColStd_HArray1OfByte (0, aNumOfBytes - 1);
   aBitMap->Init (0);
   for (Standard_Integer aRow = 0; aRow < aHeight; aRow++)
   {
+    const Standard_Integer aResRow = !theIsTopDown ? (aHeight - aRow - 1) : aRow;
     for (Standard_Integer aColumn = 0; aColumn < aWidth; aColumn++)
     {
       const Quantity_ColorRGBA aColor = myImage->PixelColor (aColumn, aRow);
@@ -101,7 +249,7 @@ Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Stand
         aBitOn = aColor.Alpha() > theAlphaValue;
       }
 
-      Standard_Integer anIndex = aNumOfBytesInRow * aRow + aColumn / 8;
+      Standard_Integer anIndex = aNumOfBytesInRow * aResRow + aColumn / 8;
       aBitMap->SetValue (anIndex, (Standard_Byte)(aBitMap->Value (anIndex) + 
                                                   (aBitOn ? (0x80 >> (aColumn % 8)) : 0)));
     }
@@ -116,12 +264,8 @@ Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Stand
 // =======================================================================
 const Handle(Image_PixMap)& Graphic3d_MarkerImage::GetImage()
 {
-  if (!myImage.IsNull())
-  {
-    return myImage;
-  }
-
-  if (myBitMap.IsNull())
+  if (!myImage.IsNull()
+    || myBitMap.IsNull())
   {
     return myImage;
   }
@@ -216,3 +360,122 @@ void Graphic3d_MarkerImage::GetTextureSize (Standard_Integer& theWidth,
   theWidth  = myWidth;
   theHeight = myHeight;
 }
+
+// =======================================================================
+// function : GetMarkerImage
+// purpose  :
+// =======================================================================
+Handle(Graphic3d_MarkerImage) Graphic3d_MarkerImage::StandardMarker (const Aspect_TypeOfMarker theMarkerType,
+                                                                     const Standard_ShortReal theScale,
+                                                                     const Graphic3d_Vec4& theColor)
+{
+  switch (theMarkerType)
+  {
+    case Aspect_TOM_O_POINT:
+    case Aspect_TOM_O_PLUS:
+    case Aspect_TOM_O_STAR:
+    case Aspect_TOM_O_X:
+    {
+      // For this type of markers we merge two base bitmaps into one
+      // For example Aspect_TOM_O_PLUS = Aspect_TOM_O + Aspect_TOM_PLUS
+      Handle(Graphic3d_MarkerImage) aMarkerImage1 = getTextureImage (Aspect_TOM_O, theScale);
+      Handle(Graphic3d_MarkerImage) aMarkerImage2;
+      if (theMarkerType == Aspect_TOM_O_POINT)
+      {
+        // draw inner point as filled rectangle
+        const Standard_Integer        aSize = theScale > 7 ? 7 : (Standard_Integer)(theScale + 0.5F);
+        Handle(TColStd_HArray1OfByte) aBitMap = fillPointBitmap (aSize);
+        aMarkerImage2 = new Graphic3d_MarkerImage (aBitMap, aSize, aSize);
+      }
+      else
+      {
+        aMarkerImage2 = getTextureImage (Aspect_TypeOfMarker(theMarkerType - Aspect_TOM_O_POINT), theScale);
+      }
+      Handle(Image_PixMap) anImage = mergeImages (aMarkerImage1->GetImage(), aMarkerImage2->GetImage());
+      Handle(Graphic3d_MarkerImage) aNewMarkerImage = new Graphic3d_MarkerImage (anImage);
+      return aNewMarkerImage;
+    }
+    case Aspect_TOM_RING1:
+    case Aspect_TOM_RING2:
+    case Aspect_TOM_RING3:
+    {
+      const Standard_ShortReal aDelta = 0.1f;
+      Standard_ShortReal aScale = theScale;
+      Standard_ShortReal aLimit = 0.0f;
+      if (theMarkerType == Aspect_TOM_RING1)
+      {
+        aLimit = aScale * 0.2f;
+      }
+      else if (theMarkerType == Aspect_TOM_RING2)
+      {
+        aLimit = aScale * 0.5f;
+      }
+      else if (theMarkerType == Aspect_TOM_RING3)
+      {
+        aLimit = aScale * 0.8f;
+      }
+
+      Handle(Image_PixMap) anImage;
+      for (; aScale > aLimit && aScale >= 1.0f; aScale -= aDelta)
+      {
+        anImage = mergeImages (anImage, getTextureImage (Aspect_TOM_O, aScale)->GetImage());
+      }
+      Handle(Graphic3d_MarkerImage) aNewMarkerImage = new Graphic3d_MarkerImage (anImage);
+      return aNewMarkerImage;
+    }
+    case Aspect_TOM_BALL:
+    {
+      Standard_Integer aWidth = 0, aHeight = 0, anOffset = 0, aNbBytes = 0;
+      Standard_ShortReal aScale = theScale;
+      getMarkerBitMapParam (Aspect_TOM_O, aScale, aWidth, aHeight, anOffset, aNbBytes);
+
+      NCollection_Vec4<Standard_Real> aColor (theColor);
+
+      const Standard_Integer aSize = Max (aWidth + 2, aHeight + 2); // includes extra margin
+      Handle(Image_PixMap) anImage  = new Image_PixMap();
+      Handle(Image_PixMap) anImageA = new Image_PixMap();
+      anImage ->InitZero (Image_Format_RGBA,  aSize, aSize);
+      anImageA->InitZero (Image_Format_Alpha, aSize, aSize);
+
+      // we draw a set of circles
+      Image_ColorRGBA aColor32;
+      aColor32.a() = 255;
+      Standard_Real aHLS[3];
+      const Standard_ShortReal aDelta = 0.1f;
+      while (aScale >= 1.0f)
+      {
+        Quantity_Color::RgbHls (aColor.r(), aColor.g(), aColor.b(), aHLS[0], aHLS[1], aHLS[2]);
+        aHLS[2] *= 0.95; // 5% saturation change
+        Quantity_Color::HlsRgb (aHLS[0], aHLS[1], aHLS[2], aColor.r(), aColor.g(), aColor.b());
+        aColor32.r() = Standard_Byte (255.0 * aColor.r());
+        aColor32.g() = Standard_Byte (255.0 * aColor.g());
+        aColor32.b() = Standard_Byte (255.0 * aColor.b());
+
+        const Handle(Graphic3d_MarkerImage) aMarker = getTextureImage (Aspect_TOM_O, aScale);
+        const Handle(Image_PixMap)& aCircle = aMarker->GetImage();
+
+        const Standard_Size aDiffX = (anImage->SizeX() - aCircle->SizeX()) / 2;
+        const Standard_Size aDiffY = (anImage->SizeY() - aCircle->SizeY()) / 2;
+        for (Standard_Size aRow = 0; aRow < aCircle->SizeY(); ++aRow)
+        {
+          const Standard_Byte* aRowData = aCircle->Row(aRow);
+          for (Standard_Size aCol = 0; aCol < aCircle->SizeX(); ++aCol)
+          {
+            if (aRowData[aCol] != 0)
+            {
+              anImage->ChangeValue<Image_ColorRGBA>(aDiffX + aRow, aDiffY + aCol) = aColor32;
+              anImageA->ChangeValue<Standard_Byte> (aDiffX + aRow, aDiffY + aCol) = 255;
+            }
+          }
+        }
+        aScale -= aDelta;
+      }
+      Handle(Graphic3d_MarkerImage) aNewMarkerImage = new Graphic3d_MarkerImage (anImage, anImageA);
+      return aNewMarkerImage;
+    }
+    default:
+    {
+      return getTextureImage (theMarkerType, theScale);
+    }
+  }
+}