Development: Gradients

From WxWiki

Jump to: navigation, search

Gradient Patch:

Index: docs/latex/wx/dc.tex
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/docs/latex/wx/dc.tex,v
retrieving revision 1.41
diff -b -u -2 -r1.41 dc.tex
--- docs/latex/wx/dc.tex	2003/01/18 00:16:31	1.41
+++ docs/latex/wx/dc.tex	2003/07/13 05:40:44
@@ -504,4 +504,24 @@
 function will still return true.
 
+membersection{wxDC::GradientFillLinear}label{wxdcgradientfilllinear}
+
+func{void}{GradientFillConcentric}{param{const wxRect&}{ rect}, param{const wxColour&}{ initialColour}, param{const wxColour&}{ destColour} }
+
+func{void}{GradientFillConcentric}{param{const wxRect&}{ rect}, param{const wxColour&}{ initialColour}, param{const wxColour&}{ destColour}, param{const wxPoint&}{ circleCenter } }
+
+Fill the area specified by rect with a radial gradient, starting from initialColour 
+and eventually fading to destColour. 
+
+initialColour is the color of the inside of the circle, whereas destColour is the 
+color outside of the circle.
+
+circleCenter is the center of the circle within the constraints of rect.  If not specified,
+it is placed within the center of rect.
+
+func{void}{GradientFillLinear}{param{const wxRect&}{ rect}, param{const wxColour&}{ initialColour}, param{const wxColour&}{ destColour}, param{wxDirection}{ nDirection = wxEAST}}
+
+Fill the area specified by rect with a linear gradient, starting from initialColour 
+and eventually fading to destColour. nDirection is the direction of the destination color.   
+
 membersection{wxDC::GetBackground}label{wxdcgetbackground}
 
Index: include/wx/dc.h
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/include/wx/dc.h,v
retrieving revision 1.44
diff -b -u -2 -r1.44 dc.h
--- include/wx/dc.h	2003/06/26 13:15:02	1.44
+++ include/wx/dc.h	2003/07/13 05:40:47
@@ -157,4 +157,33 @@
         { return DoFloodFill(pt.x, pt.y, col, style); }
 
+    //  Fill the area specified by rect with a radial gradient -
+    //  Starting from initialColour and eventually fading to destColour.
+    //
+    //  initialColour is the color of the inside of the circle,
+    //  whereas destColour is the color outside of the circle.
+    //
+    //  circleLocation is the upper-left corner of the circle
+    //  within the rect, starting at (0,0)
+    void GradientFillConcentric(const wxRect& rect,
+                                const wxColour& initialColour, 
+                                const wxColour& destColour)
+    {  GradientFillConcentric(rect, initialColour, destColour, wxPoint(rect.GetWidth() / 2,
+                                                                       rect.GetHeight() / 2)); }
+
+    void GradientFillConcentric(const wxRect& rect,
+                                const wxColour& initialColour, 
+                                const wxColour& destColour,
+                                const wxPoint& circleCenter);
+
+    //  Fill the area specified by rect with a linear gradient -
+    //  Starting from initialColour and eventually fading to destColour.
+    //
+    //  nDirection is the direction of the destination color.
+    //
+    //  FIXME: Using SetPen instead of m_pen.SetColour, as it doesn't work on MSW
+    void GradientFillLinear(const wxRect& rect, const wxColour& initialColour, 
+                            const wxColour& destColour, wxDirection nDirection)
+        { DoGradientFillLinear(rect, initialColour, destColour, nDirection);}
+
     bool GetPixel(wxCoord x, wxCoord y, wxColour *col) const
         { return DoGetPixel(x, y, col); }
@@ -604,4 +633,7 @@
                              int style = wxFLOOD_SURFACE) = 0;
 
+    virtual void DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour,
+                                      const wxColour& destColour, wxDirection nDirection);
+    
     virtual bool DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const = 0;
 
Index: include/wx/msw/dc.h
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/include/wx/msw/dc.h,v
retrieving revision 1.39
diff -b -u -2 -r1.39 dc.h
--- include/wx/msw/dc.h	2003/01/02 23:37:45	1.39
+++ include/wx/msw/dc.h	2003/07/13 05:40:50
@@ -139,4 +139,7 @@
                              int style = wxFLOOD_SURFACE);
 
+    virtual void DoGradientFillLinear (const wxRect& rect, const wxColour& initialColour,
+                                       const wxColour& destColour, wxDirection nDirection);
+
     virtual bool DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const;
 
Index: src/common/dcbase.cpp
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/src/common/dcbase.cpp,v
retrieving revision 1.20
diff -b -u -2 -r1.20 dcbase.cpp
--- src/common/dcbase.cpp	2003/07/12 20:36:49	1.20
+++ src/common/dcbase.cpp	2003/07/13 05:41:02
@@ -545,2 +545,160 @@
     CalcBoundingBox(x0 + width0, y0 + height);
 }
+
+void wxDCBase::DoGradientFillLinear(const wxRect& rect,
+                                    const wxColour& initialColour, 
+                                    const wxColour& destColour, 
+                                    wxDirection nDirection) 
+{
+    //save old pen
+    wxPen oldPen = m_pen;
+
+    wxUint8 nR1 = destColour.Red();
+    wxUint8 nG1 = destColour.Green();
+    wxUint8 nB1 = destColour.Blue();
+    wxUint8 nR2 = initialColour.Red();
+    wxUint8 nG2 = initialColour.Green();
+    wxUint8 nB2 = initialColour.Blue();
+    wxUint8 nR, nG, nB;
+
+        if(nDirection == wxEAST ||
+           nDirection == wxWEST) //paint horizontal rect;
+        {
+            wxInt32 x = rect.GetWidth();
+            wxInt32 w = x;	// width of area to shade
+            wxInt32 xDelta = w/256;//dwColorShades;	//height of one shade bend
+                if (xDelta < 1)
+                    xDelta = 1;
+
+                while (x >= xDelta)
+                {
+                    x -= xDelta;
+                    if (nR1 > nR2)
+                        nR = nR1 - (nR1-nR2)*(w-x)/w;
+                    else
+                        nR = nR1 + (nR2-nR1)*(w-x)/w;
+
+                    if (nG1 > nG2)
+                        nG = nG1 - (nG1-nG2)*(w-x)/w;
+                    else
+                        nG = nG1 + (nG2-nG1)*(w-x)/w;
+
+                    if (nB1 > nB2)
+                        nB = nB1 - (nB1-nB2)*(w-x)/w;
+                    else
+                        nB = nB1 + (nB2-nB1)*(w-x)/w;
+
+                    SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID));
+                    if(nDirection == wxEAST)
+                        DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
+                                      xDelta, rect.GetHeight());
+                    else //nDirection == wxWEST
+                        DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(),
+                                      xDelta, rect.GetHeight());
+                }
+        }
+        else    //nDirection == wxNORTH || nDirection == wxSOUTH
+        {
+            wxInt32 y = rect.GetHeight();
+            wxInt32 w = y;			// height of area to shade
+            wxInt32 yDelta = w/255;//dwColorShades;	//height of one shade bend
+                if (yDelta < 1)
+                    yDelta = 1;
+
+                while (y > 0)
+                {
+                    y -= yDelta;
+                    if (nR1 > nR2)
+                        nR = nR1 - (nR1-nR2)*(w-y)/w;
+                    else
+                        nR = nR1 + (nR2-nR1)*(w-y)/w;
+
+                    if (nG1 > nG2)
+                        nG = nG1 - (nG1-nG2)*(w-y)/w;
+                    else
+                        nG = nG1 + (nG2-nG1)*(w-y)/w;
+
+                    if (nB1 > nB2)
+                        nB = nB1 - (nB1-nB2)*(w-y)/w;
+                    else
+                        nB = nB1 + (nB2-nB1)*(w-y)/w;
+
+                    SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID));
+                    if(nDirection == wxNORTH)
+                        DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
+                                      rect.GetWidth(), yDelta);
+                    else //nDirection == wxSOUTH
+                        DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta,
+                                      rect.GetWidth(), yDelta);
+                }
+        }
+    SetPen(oldPen);
+}
+
+void wxDCBase::GradientFillConcentric(const wxRect& rect,
+                                      const wxColour& initialColour, 
+                                      const wxColour& destColour,
+                                      const wxPoint& circleCenter)
+{   
+    //save the old pen color
+    wxColour oldPenColour = m_pen.GetColour();
+
+    wxUint8 nR1 = destColour.Red();
+    wxUint8 nG1 = destColour.Green();
+    wxUint8 nB1 = destColour.Blue();
+    wxUint8 nR2 = initialColour.Red();
+    wxUint8 nG2 = initialColour.Green();
+    wxUint8 nB2 = initialColour.Blue();
+    wxUint8 nR, nG, nB;
+
+    
+    //offsets of the current pixel
+    wxInt32 x, y;
+
+    //Color difference
+    wxInt32 nGradient;
+   
+    //Radius
+    wxInt32 cx = rect.GetWidth() / 2;   
+    wxInt32 cy = rect.GetHeight() / 2;
+    wxInt32 nRadius;
+    if (cx < cy)
+        nRadius = cx;
+    else
+        nRadius = cy;
+
+    //Offset of circle
+    wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
+    wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
+
+    for (x = 0; x < rect.GetWidth(); x++)
+    {
+        for (y = 0; y < rect.GetHeight(); y++)
+        {
+            //get color difference
+            nGradient = (
+                         (nRadius -
+                          (wxInt32)sqrt(
+                                        pow(x - cx - nCircleOffX, 2) + 
+                                        pow(y - cy - nCircleOffY, 2)
+                                        )
+                          ) * 100
+                         ) / nRadius;
+
+            //normalize Gradient
+            if (nGradient < 0 )
+                nGradient = 0;
+
+            //get dest colors
+            nR = nR1 + ((nR2 - nR1) * nGradient / 100);
+            nG = nG1 + ((nG2 - nG1) * nGradient / 100);
+            nB = nB1 + ((nB2 - nB1) * nGradient / 100);
+
+            //set the pixel
+            m_pen.SetColour(wxColour(nR,nG,nB));
+            DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
+        }
+    }
+    //return old pen color
+    m_pen.SetColour(oldPenColour);
+}
Index: src/msw/dc.cpp
===================================================================
RCS file: /pack/cvsroots/wxwindows/wxWindows/src/msw/dc.cpp,v
retrieving revision 1.150
diff -b -u -2 -r1.150 dc.cpp
--- src/msw/dc.cpp	2003/07/11 21:49:59	1.150
+++ src/msw/dc.cpp	2003/07/13 05:41:09
@@ -2428,2 +2428,82 @@
 
 #endif // #ifdef wxHAVE_RAW_BITMAP
+
+void wxDC::DoGradientFillLinear (const wxRect& rect,
+                                 const wxColour& initialColour,
+                                 const wxColour& destColour,
+                                 wxDirection nDirection)
+{
+#if defined wxUSE_DYNLIB_CLASS
+    //Open Msimg32.dll
+    wxLog::EnableLogging(false);
+    wxDynamicLibrary dllMSIMG(_T("Msimg32.dll"));
+    wxLog::EnableLogging(true);
+    //is it there?
+    if (!dllMSIMG.IsLoaded())
+    {
+        //if not, then call the wx version
+        wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
+        return;
+    }
+
+    typedef BOOL (*GradientFill_t) (HDC,PTRIVERTEX, ULONG, PVOID, ULONG, ULONG);
+    GradientFill_t pfnGradientFill;
+
+    //the following shouldn't fail...
+    wxLog::EnableLogging(false);
+    pfnGradientFill = (GradientFill_t) dllMSIMG.GetSymbol(_T("GradientFill"));
+    wxLog::EnableLogging(true);
+
+    if (pfnGradientFill == NULL)
+    {
+        //if it does, call the wx version
+        wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection);
+        return;
+    }
+
+    TRIVERTEX vertexes[2];  //vertexes - 2 - one for upper left and one for upper-right
+
+    GRADIENT_RECT grect;    
+    grect.UpperLeft = 0;
+    grect.LowerRight = 1;
+
+    //If wxNORTH or wxWEST then we are specifying the colors in the opposite direction
+    int nInitialVertex = nDirection == wxNORTH || nDirection == wxWEST;
+
+    vertexes[0].x = rect.GetLeft();
+    vertexes[0].y = rect.GetTop();
+    vertexes[1].x = rect.GetRight();
+    vertexes[1].y = rect.GetBottom();
+
+    //colors, << 8 to convert from wx to windows
+    vertexes[nInitialVertex].Red = initialColour.Red() << 8;
+    vertexes[nInitialVertex].Green = initialColour.Green() << 8;
+    vertexes[nInitialVertex].Blue = initialColour.Blue() << 8;
+    vertexes[nInitialVertex].Alpha = 0;
+    vertexes[!nInitialVertex].Red = destColour.Red() << 8;
+    vertexes[!nInitialVertex].Green = destColour.Green() << 8;
+    vertexes[!nInitialVertex].Blue = destColour.Blue() << 8;
+    vertexes[!nInitialVertex].Alpha = 0;
+
+    BOOL bSuccess;
+
+    //call the gradient fill function
+    if (nDirection == wxWEST || 
+        nDirection == wxEAST)
+        bSuccess = (*pfnGradientFill)((HDC)m_hDC, vertexes, 2, &grect, 1, GRADIENT_FILL_RECT_H);
+    else
+        bSuccess = (*pfnGradientFill)((HDC)m_hDC, vertexes, 2, &grect, 1, GRADIENT_FILL_RECT_V);
+
+    //shouldn't happen
+    if (bSuccess == FALSE)
+        wxLogLastError(_T("GradientFill"));
+
+    //Detach the dll... may want to unload
+    dllMSIMG.Detach();
+#else   //wxUSE_DYNLIB_CLASS
+ 
+    //no dynlib - call wx version
+    wxDCBase::DoGradientFillLinear(rect,initialColour,destColour,nDirection);
+
+#endif
+} 
  • Radial Gradient: Google for Chris Lomont, he did an implementation of practically every implementation known to man, some REALLY fast ones there.
Personal tools