Trang 1 trên tổng số 3 123 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 26 kết quả

Đề tài: Lập trình đồ họa | Từng bước xây dựng cho mình một thư viện đồ họa - GDrawing

  1. #1
    Ngày gia nhập
    10 2007
    Bài viết
    169

    Mặc định Lập trình đồ họa | Từng bước xây dựng cho mình một thư viện đồ họa - GDrawing

    - Mình định sẻ đợi khi nào làm xong GImage rồi mới chuyển sang GDrawing! Nhưng khoảng thời gian này Z hơi bận nên chắc tạm ngưng GImage lại, mình sẻ làm một chút về GDrawing, khi nào Z có thời gian sẻ quay lại hoàn thiện GImage!

    - Vì GImage chưa xong nên mình sẻ làm trên struct của mình vậy, nó chỉ khác ở BYTE và DWORD nên sau này chuyển sang GImage của Z không khó khăn lắm! Các bạn có thể Download struct của mình ở đây :
    http://www.2shared.com/file/3131263/...GoldenSun.html

    - Tất cả code mình post trước đây đều chạy được trên struct này! Nếu bạn nào chạy không được thì cứ hỏi mình!
    - Vì mình dùng VS 9.0 nên nếu bạn nào dùng VC++ 6.0 thì phải tạo lại project mới vậy! Tất cả file đều nằm trong folder G2D, khi tạo project mới , các bạn phải copy folder G2D vào trong project rồi mới, add mấy file đó vào rồi mới compile nha!


    Hy vọng sẻ có nhiều bạn tham gia ^_^!

  2. #2
    Ngày gia nhập
    10 2007
    Bài viết
    169

    1.SetPixel and GetPixel :
    - Trong GImage cũng có hàm Draw_Pixel, mình chỉ thêm cho đầy đủ thôi!
    C++ Code:
    1. void GDrawing_Ind::SetPixel(int x,int y,DWORD Color)
    2. {
    3.     if(x < 0 || x >= m_pGImage->GetWidth() ||
    4.         y < 0 || y >= m_pGImage->GetHeight()) return;
    5.  
    6.     m_pGImage->GetBits()[m_pGImage->GetWidth()*y + x] = Color;
    7. }

    - Ở đây mình có thể thay đổi tí xíu, thay vì so sánh 4 lần thì sẻ chuyển về 2 lần!
    C++ Code:
    1. void GDrawing_Ind::SetPixel(int x,int y,DWORD Color)
    2. {
    3.     if(UINT(x) < m_pGImage->GetWidth() &&
    4.         UINT(y) < m_pGImage->GetHeight())
    5.     m_pGImage->GetBits()[m_pGImage->GetWidth()*y + x] = Color;
    6. }
    - Nếu x < 0 thì UINT(x) sẻ ra một số rất lớn -> ImgWidth, vì vậy mình có thể dùng cách này để giảm số lần so sánh!
    - Tuy nhiên, type cast sẻ làm giản tốc độ nên nhanh hơn không nhiều!

    - GetPixel() cũng giống vậy:
    C++ Code:
    1. DWORD GDrawing_Ind::GetPixel(int x,int y)
    2. {
    3.     return (UINT(x) < m_pGImage->GetWidth() &&
    4.         UINT(y) < m_pGImage->GetHeight()) ?
    5.         m_pGImage->GetBits()[m_pGImage->GetWidth()*y + x] : 0;
    6. }

    - Ở đây, nếu x,y ngoài image thì sẻ trả về 0, nếu các bạn muốn chính xác hơn thì có thể truyền biến để nhận giá trị trả về vào trong hàm!
    (Ex: DWORD GDrawing_Ind::GetPixel(int x,int y,DWORD &Color) )
    Đã được chỉnh sửa lần cuối bởi RadicalLight : 12-04-2008 lúc 08:37 PM.

  3. #3
    Ngày gia nhập
    10 2007
    Bài viết
    169

    À quên, còn phần blending cho pixel nửa chứ!

    Thêm hai hàm này vào:
    C++ Code:
    1.  
    2. struct SColor32
    3. {
    4.     BYTE Blue,Green,Red,Alpha;
    5. };
    6.  
    7. SColor32 GImage_Ind::MixColors(SColor32 Color1, SColor32 Color2)
    8. {
    9.     DWORD Cl = ((*(DWORD*)&Color1 >> 1) & 0xFF7F7F7F) + ((*(DWORD*)&Color2 >> 1) & 0xFF7F7F7F); // C = C1/2 + C2/2
    10.     return *(SColor32*)&Cl;
    11. }
    12. SColor32 GImage_Ind::AlphaBlend(SColor32 BkColor,SColor32 UpperColor,BYTE Transparency)
    13. {
    14.     BkColor.Blue = ((UpperColor.Blue - BkColor.Blue)*Transparency + (BkColor.Blue << 8)) >> 8;
    15.     BkColor.Green = ((UpperColor.Green - BkColor.Green)*Transparency + (BkColor.Green << 8)) >> 8;
    16.     BkColor.Red = ((UpperColor.Red - BkColor.Red)*Transparency + (BkColor.Red << 8)) >> 8;
    17.     return BkColor;
    18. }

    - MixColor() là AlphaBlend() với Transparency = 0.5!

    - Công thức Alpha blend có dạng như sau :
    + Color = UpperColor*Transparency + BkColor*(1 - Transparency) (Transparency <= 1)
    + Hay : Color = ((UpperColor - BkColor)*Transparency + (BkColor << 8) >> 8 (Transparency <= 255)

    - Như vậy blending cho SetPixel sẻ chuyển thành:
    C++ Code:
    1. inline void GDrawing_Ind::SetPixel(int x,int y,DWORD Color,BYTE Transparency)
    2.     {
    3.         if(UINT(x) < m_pGImage->GetWidth() && UINT(y) < m_pGImage->GetHeight())
    4.         {
    5.             SColor32* pColor = (SColor32*)&m_pGImage->GetBits()[m_pGImage->GetWidth()*y + x];   // A little faster than direct access
    6.             SColor32 ColorS = *(SColor32*)&Color;
    7.             pColor->Blue = ((ColorS.Blue - pColor->Blue)*Transparency + (pColor->Blue << 8)) >> 8;
    8.             pColor->Green = ((ColorS.Green - pColor->Green)*Transparency + (pColor->Green << 8)) >> 8;
    9.             pColor->Red = ((ColorS.Red - pColor->Red)*Transparency + (pColor->Red << 8)) >> 8;
    10.         }
    11.     }

    Hay:
    C++ Code:
    1. inline void GDrawing_Ind::SetPixel(int x,int y,DWORD Color,BYTE Transparency)
    2.     {
    3.         if(UINT(x) < m_pGImage->GetWidth() && UINT(y) < m_pGImage->GetHeight())
    4.         {
    5.             SColor32* pColor = (SColor32*)&m_pGImage->GetBits()[m_pGImage->GetWidth()*y + x];   // A little faster than direct access
    6.             SColor32 ColorS = *(SColor32*)&Color;
    7.             *pColor = m_pGImage->AlphaBlend(*pColor,ColorS,Transparency);
    8.         }
    9.     }

    Tạm thời chỉ có hai phần này thôi, tối về mình sẻ post tiếp phần line()!
    Đã được chỉnh sửa lần cuối bởi RadicalLight : 12-04-2008 lúc 02:35 PM.

  4. #4
    Ngày gia nhập
    10 2007
    Bài viết
    169

    2.Line :
    Bây giờ là tới phần vẻ đường thẳng!
    Mình sẻ dùng thuật toán bresenham để vẻ!

    Theo một số sách về graphics thì như sau!
    C++ Code:
    1. void Line(int x1,int y1,int x2,int y2,DWORD Color)
    2. {
    3.     int Dx,Dy,p,Const1,Const2;
    4.     int x,y;
    5.  
    6.     Dx = x2 - x1;
    7.     Dy = y2 - y1;
    8.     p = (Dy << 1) - Dx;
    9.     Const1 = Dy << 1;
    10.     Const2 = (Dy - Dx) << 1;
    11.     x = x1;
    12.     y = y1;
    13.     SetPixel(x,y,Color);
    14.     for(int i = 1;i < x2;++i)
    15.     {
    16.         if(p < 0) p += Const1;
    17.         else
    18.         {
    19.             p += Const2;
    20.             ++y;
    21.         }
    22.         ++x;
    23.         SetPixel(x,y,Color);
    24.     }
    25. }
    Phần thuật toán bresenham các bạn có thể search trên mạng, rất rõ ràng và đầy đủ! Vì vậy mình không nói nhiều đến nó!

    Nhưng theo code ở trên như vầy thì chưa tốt lắm! Vì chúng ta có thể thấy, khi p >= 0 thì mới tăng y lên mà thôi, còn lại ở mỗi bước lặp đều tăng x lên 1!
    Do đó chúng ta có thể chuyển sang dùng pointer (thay vì dùng SetPixel())!
    C++ Code:
    1. void Line(int x1,int y1,int x2,int y2,DWORD Color)
    2. {
    3.     int Dx,Dy,p,Const1,Const2;
    4.     int x,y;
    5.  
    6.     Dx = x2 - x1;
    7.     Dy = y2 - y1;
    8.     p = (Dy << 1) - Dx;
    9.     Const1 = Dy << 1;
    10.     Const2 = (Dy - Dx) << 1;
    11.     x = x1;
    12.     y = y1;
    13.     DWORD* Ptr = m_pGImage->GetBits();
    14. //    SetPixel(x,y,Color);
    15.     *Ptr = Color;
    16.     for(int i = 1;i < x2;++i)
    17.     {
    18.         if(p < 0) p += Const1;
    19.         else
    20.         {
    21.             p += Const2;
    22.             Ptr += m_pGImage->GetWidth();
    23.         //    ++y;
    24.         }
    25.         ++x;
    26.         *Ptr = Color;
    27.      //   SetPixel(x,y,Color);
    28.     }
    29. }
    Phần code ở trên chỉ vẻ được line trong 1/4 của đường tròn mà thôi! Đây là code đầy đủ của hàm Line():
    C++ Code:
    1. inline BOOL GDrawing_Ind::Line(int x1,int y1,int x2,int y2,DWORD Color)
    2.         {
    3.             // Using Bresenham algorithm
    4.             // Get two rear points of line which inside drawing area
    5.             if(GetValidLine(x1,y1,x2,y2,m_pGImage->GetWidth(),m_pGImage->GetHeight()) <= 0) return 0;
    6.             if(y1 > y2)
    7.             {
    8.                 // Be careful with same memory block
    9.                 x1 = x1^x2;
    10.                 x2 = x2^x1;
    11.                 x1 = x1^x2;
    12.        
    13.                 y1 = y1^y2;
    14.                 y2 = y2^y1;
    15.                 y1 = y1^y2;
    16.             }
    17.             UINT Dx = ((x1 - x2 < 0) ? x2 - x1 : x1 - x2) + 1;
    18.             UINT Dy = y2 - y1 + 1;
    19.  
    20.             // Vertical line
    21.             UINT ImgWidth = m_pGImage->GetWidth();
    22.             DWORD* Ptr = &m_pGImage->GetBits()[y1*ImgWidth + x1];
    23.             if(x1 == x2)
    24.             {
    25.                 for(UINT i = 0;i < Dy;++i)
    26.                 {
    27.                     *Ptr = Color;
    28.                     Ptr += ImgWidth;
    29.                 }
    30.                 return 1;
    31.             }
    32.  
    33.             // Horizontal line
    34.             if(y1 == y2)
    35.             {
    36.                 if(x2 < x1)
    37.                 {
    38.                     x1 = x1^x2;
    39.                     x2 = x2^x1;
    40.                     x1 = x1^x2;
    41.                     Ptr = &m_pGImage->GetBits()[ImgWidth*y1 + x1];
    42.                 }
    43.                 for(UINT i = 0;i < Dx;++i) *Ptr++ = Color;
    44.                 return 2;
    45.             }
    46.  
    47.             // Diagonal line
    48.             if(Dx == Dy)
    49.             {
    50.                 if(x1 < x2)
    51.                 {
    52.                     for(UINT i = 0;i < Dx;++i)
    53.                     {
    54.                         *Ptr = Color;
    55.                         ++Ptr += ImgWidth;
    56.                     }
    57.                 }
    58.                 else
    59.                 {
    60.                     for(UINT i = 0;i < Dx;++i)
    61.                     {
    62.                         *Ptr = Color;
    63.                         --Ptr += ImgWidth;
    64.                     }
    65.                 }
    66.                 return 3;
    67.             }
    68.  
    69.             // X - Major line
    70.             if(Dx > Dy)
    71.             {
    72.                 // Prepare for drawing
    73.                 int P = (Dy << 1) - Dx;
    74.                 int Offset1 = Dy << 1;
    75.                 int Offset2 = (Dy - Dx) << 1;
    76.                 if(x1 < x2)
    77.                 {
    78.                     DWORD* pEndPtr = Ptr + Dy*ImgWidth + Dx;
    79.                     for(;Ptr < pEndPtr;++Ptr)
    80.                     {
    81.                         *Ptr = Color;
    82.                         if(P < 0) P += Offset1;
    83.                         else
    84.                         {
    85.                             P += Offset2;
    86.                             Ptr += ImgWidth;
    87.                         }
    88.                     }
    89.                 }
    90.                 else
    91.                 {
    92.                     DWORD* pEndPtr = Ptr + (Dy - 1)*ImgWidth + x2 - x1;
    93.                     for(;Ptr < pEndPtr;--Ptr)
    94.                     {
    95.                         *Ptr = Color;
    96.                         if(P < 0) P += Offset1;
    97.                         else
    98.                         {
    99.                             P += Offset2;
    100.                             Ptr += ImgWidth;
    101.                         }
    102.                     }
    103.                     for(;Ptr > pEndPtr;--Ptr) *Ptr = Color;
    104.                 }
    105.             }
    106.             else    // Y - Major line
    107.             {
    108.                 // Prepare for drawing
    109.                 int P = (Dx << 1) - Dy;
    110.                 int Offset1 = Dx << 1;
    111.                 int Offset2 = (Dx - Dy) << 1;
    112.                 int x = x1,y = y1;
    113.                 if(x1 < x2)
    114.                 {
    115.                     DWORD* pEndPtr = Ptr + (Dy - 1)*ImgWidth + Dx;
    116.                     for(;Ptr < pEndPtr;Ptr += ImgWidth)
    117.                     {
    118.                         *Ptr = Color;
    119.                         if(P < 0) P += Offset1;
    120.                         else
    121.                         {
    122.                             P += Offset2;
    123.                             Ptr++;
    124.                         }
    125.                     }
    126.                 }
    127.                 else
    128.                 {
    129.                     DWORD* pEndPtr = Ptr + Dy*ImgWidth - Dx;
    130.                     for(;Ptr < pEndPtr;Ptr += ImgWidth)
    131.                     {
    132.                         *Ptr = Color;
    133.                         if(P < 0) P += Offset1;
    134.                         else
    135.                         {
    136.                             P += Offset2;
    137.                             --Ptr;
    138.                         }
    139.                     }
    140.                 }
    141.             }
    142.             return 4;
    143.         }
    Nếu muốn dùng thêm blending thì thay "*Ptr = Color;" bằng hàm blend tương ứng như trong SetPixel()

  5. #5
    Ngày gia nhập
    01 2008
    Nơi ở
    Gameloft Studio
    Bài viết
    294

    RL này. Cậu chỉnh code sao cho dễ nhìn 1 chút đi (nhất là mấy cái SetPixel ở trên đó). Mình đang hoàn thiện tiếp GImage, thứ 7 mới rãnh.

    GoodLuck.

  6. #6
    Ngày gia nhập
    10 2007
    Bài viết
    169

    Mặc định Lập trình đồ họa | Từng bước xây dựng cho mình một thư viện đồ họa - GDrawing

    Nhìn dễ hơn chưa Z!

  7. #7
    Ngày gia nhập
    01 2008
    Nơi ở
    Gameloft Studio
    Bài viết
    294

    Ok rồi!

    RL ghép SSE và Bresenham được rồi đó. Ta sẽ chia đoạn thẳng thành 4 khúc (nếu đường thẳng dài hơn 40 pixel). SSE có khả năng tính 4 phép tính float tại một thời điểm do đó mình nghĩ tốc độ tăng ít nhất là 3.5 lần trừ đi một ít sai số khi khởi tạo.

  8. #8
    Ngày gia nhập
    10 2007
    Bài viết
    169

    À, nếu ghép thì mình nghĩ nên ghép chung với MMX! MMX giống như SSE thôi nhưng dùng số nguyên (vì code trên toàn dùng số nguyên)! Z có rảnh thì dùng thử nha!

  9. #9
    Ngày gia nhập
    10 2007
    Bài viết
    169

    3.Line with antialiasing :
    - Bây giờ là tới phần AA cho line!
    - Mình sẻ dùng thuật toán WU Antialiasing!



    - Việc dùng AA là xác định mỗi row của line có bao nhiêu pixel! Khi đả xác định được số pixel thì chỉ việc lấy 255 chia cho số pixel!
    - Trong hình trên thì row đầu tiên có 8 pixel -> 255/8 ~ 32 -> mỗi lần set một pixel thì Transparency sẻ giảm đi 32!

    - Do đó, theo hình trên thì pixel thứ 1 sẻ có Transparency là 255, pixel thứ 2 sẻ có transparency là (255 - 32)! Việc giảm Transparency sẻ liên tục đến khi tọa độ y của pixel tăng lên 1 (nghĩa là sang row kế) thì Transparency sẻ được reset về 255! Và cứ thế!
    - Nhưng như vậy thì nhìn line sẻ bị hỏng, do đó người ta thêm một line thứ 2 bên dưới hoặc trên line ban đầu (để bù lỗ ^_^)! Kết quả là sẻ có line được AA như hình bên dưới!

    - Các bạn có thể xem về WU Antialiasing trên mạng! Kỹ thuật AA trên là cách mình làm thôi, còn WU thì hơi khác hơn tí xíu! Kỹ thuật AA ở trên có thể áp dụng cho tất cả các line, circle, ellipse, bezier,... nói chung là tất cả các line có chuyển tọa độ y của pixel!

    - Phần code của WU như sau:
    C++ Code:
    1. // Get two rear points of line which inside drawing area
    2. if(GetValidLine(x1,y1,x2,y2,m_pGImage->GetWidth(),m_pGImage->GetHeight()) <= 0) return 0;
    3.  
    4. // Prevent continuous-set by using pointer
    5. UINT ImgWidth = m_pGImage->GetWidth();
    6. UINT ImgHeight = m_pGImage->GetHeight();
    7. if(x1 == 0) ++x1;
    8. else if(x1 == ImgWidth - 1) --x1;
    9. if(x2 == 0) ++x2;
    10. else if(x2 == ImgWidth - 1) --x2;
    11. if(y1 == 0) ++y1;
    12. else if(y1 == ImgHeight - 1) --y1;
    13. if(y2 == 0) ++y2;
    14. else if(y2 == ImgHeight - 1) --y2;
    15.  
    16. // Reposition P1 on top of P2
    17. if(y1 > y2)
    18. {
    19.     // Be careful with same memory block
    20.     x1 = x1^x2;
    21.     x2 = x2^x1;
    22.     x1 = x1^x2;
    23.  
    24.     y1 = y1^y2;
    25.     y2 = y2^y1;
    26.     y1 = y1^y2;
    27. }
    28.  
    29. // Get distance of two point
    30. UINT dx = ((x1 - x2 < 0) ? x2 - x1 : x1 - x2) + 1;
    31. UINT dy = y2 - y1 + 1;
    32.  
    33. SColor32 ColorS = *(SColor32*)&Color;
    34. SColor32* Ptr = (SColor32*)&m_pGImage->GetBits()[y1*ImgWidth + x1];
    35.  
    36. BYTE Transparency,PaperTransparency;
    37. UINT TRatio = 0;
    38. *Ptr = ColorS;
    39.  
    40. UINT Ratio = (dy << 16)/dx;
    41. int PrevY2 = y1;
    42. SColor32* Ptr2;
    43. while(--dx)
    44. {
    45.     TRatio += Ratio;
    46.     y2 = y1 + (TRatio >> 16);
    47.  
    48.     ++Ptr;
    49.     if(PrevY2 < y2)
    50.     {
    51.         Ptr += ImgWidth;
    52.         PrevY2 = y2;
    53.     }
    54.     Ptr2 = Ptr + ImgWidth;
    55.  
    56.     Transparency = TRatio >> 8;
    57.     PaperTransparency = ~Transparency;
    58.  
    59.     // Original
    60.     *Ptr = m_pGImage->AlphaBlend(*Ptr,ColorS,PaperTransparency);
    61.  
    62.     Ptr2 = Ptr + ImgWidth;
    63.     *Ptr2 = m_pGImage->AlphaBlend(*Ptr2,ColorS,Transparency);
    64. }
    - Phần code trên là cho x - Major line (dx > dy, x1 < x2)
    - Muốn viết các trường hợp còn lại thì chỉ cần đảo các var!

    - Tồi về mình sẻ post tiếp một cách vẻ line và AA mới, nhanh hơn cả WU!

  10. #10
    Ngày gia nhập
    10 2007
    Bài viết
    169

    3 - 2 Line with antialiasing :
    - Trước khi nói về AA, mình sẻ nói về thuật toán vẻ line mới (tạm gọi là RLight Line vậy ^_^)!

    - Trước tiên xem cái hình này đả :

    - Như trên hình, việc vẻ một line là set từng pixel theo chiều ngang (x,y) (với X Major line)! Đến một lúc nào đó thì tăng y lên 1 (x,y + 1)! Nghĩa là nếu chúng ta biết khi nào cần tăng y lên thì việc vẻ Line xem như xong!
    - Thuật toán bresenham dùng công thức đường thẳng để tính các offset, còn cách của mình là dựa trên ratio giửa dx và dy!

    - Lấy vd, chúng ta sẻ vẻ một line từ 0x0 tới 9x3 -> dy/dx = (3 - 0 + 1)/(9 - 0 + 1) = 0.4
    - Vẻ tay sẻ như sau:
    Khi x = 0 -> y = 1*0.4 = 0.4 -> P(0,0)
    Khi x = 1 -> y = 2*0.4 = 0.8 -> P(1,0)
    Khi x = 2 -> y = 3*0.4 = 1.2 -> P(2,1)
    Khi x = 3 -> y = 4*0.4 = 1.6 -> P(3,1)
    Khi x = 4 -> y = 5*0.4 = 2.0 -> P(4,1)
    Khi x = 5 -> y = 6*0.4 = 2.4 -> P(5,2)
    Khi x = 6 -> y = 7*0.4 = 2.8 -> P(6,2)
    Khi x = 7 -> y = 8*0.4 = 3.2 -> P(7,3)
    Khi x = 8 -> y = 9*0.4 = 3.6 -> P(8,3)
    Khi x = 9 -> y = 10*0.4 = 4.0 -> P(9,3)

    - Kết quả sẻ như hình sau:


    - Nhưng nếu nhân kiểu này thì chết chắc!
    - Vì chúng ta đả biết ratio nên -> biết khi nào sẻ tăng y! Đặc IncWr là var để tăng offset, mỗi lần tăng x, chúng ta sẻ cộng Ratio vào IncWr, nếu IncWr > 1 có nghĩa là y sẻ tăng lên 1! Reset lại IncWr bằng cách trư đi 1!
    - Kết quả sẻ như hình sau:


    - Còn đây là code:
    C++ Code:
    1. inline BOOL GDrawing_Ind::LineRl(int x1,int y1,int x2,int y2,DWORD Color)
    2. {
    3.     #pragma region LineRl
    4.     // Using RLight Line algorithm
    5.     // Get two rear points of line which inside drawing area
    6.     if(GetValidLine(x1,y1,x2,y2,m_pGImage->GetWidth(),m_pGImage->GetHeight()) <= 0) return -1;
    7.  
    8.     // Reposition P1 on top of P2
    9.     if(y1 > y2)
    10.     {
    11.         // Be careful with same memory block
    12.         x1 = x1^x2;
    13.         x2 = x2^x1;
    14.         x1 = x1^x2;
    15.  
    16.         y1 = y1^y2;
    17.         y2 = y2^y1;
    18.         y1 = y1^y2;
    19.     }
    20.  
    21.     // Get distance of two point
    22.     UINT dx = ((x1 - x2 < 0) ? x2 - x1 : x1 - x2) + 1;
    23.     UINT dy = y2 - y1 + 1;
    24.  
    25.     // Prepare for drawing
    26.     UINT ImgWidth = m_pGImage->GetWidth();
    27.     DWORD* Ptr = &m_pGImage->GetBits()[y1*ImgWidth + x1];
    28.  
    29.     // Vertical line
    30.     if(x1 == x2)
    31.     {
    32.         for(UINT i = 0;i < dy;i++)
    33.         {
    34.             *Ptr = Color;
    35.             Ptr += ImgWidth;
    36.         }
    37.         return 1;
    38.     }
    39.     if(y1 == y2)    // Horizontal line
    40.     {
    41.         if(x2 < x1)
    42.         {
    43.             x1 = x1^x2;
    44.             x2 = x2^x1;
    45.             x1 = x1^x2;
    46.             Ptr = &m_pGImage->GetBits()[m_pGImage->GetWidth()*y1 + x1];
    47.         }
    48.         for(UINT i = 0;i < dx;i++) *Ptr++ = Color;
    49.         return 2;
    50.     }
    51.     if(dx == dy)    // Diagonal line
    52.     {
    53.         if(x1 < x2)
    54.         {
    55.             for(UINT i = 0;i < dx;i++)
    56.             {
    57.                 *Ptr = Color;
    58.                 Ptr += ImgWidth + 1;
    59.             }
    60.         }
    61.         else
    62.         {
    63.             for(UINT i = 0;i < dx;i++)
    64.             {
    65.                 *Ptr = Color;
    66.                 Ptr += ImgWidth - 1;
    67.             }
    68.         }
    69.         return 3;
    70.     }
    71.  
    72.     // X - major line
    73.     UINT StepSize = 65536;  // 2^16
    74.     if(dx > dy)
    75.     {
    76.         UINT StepWr = (dy << 16)/dx,IncWr = 0;
    77.         if(x1 < x2)
    78.         {
    79.             DWORD* pEndPtr = Ptr + (dy - 1)*ImgWidth + dx;
    80.             for(;Ptr < pEndPtr;++Ptr)
    81.             {
    82.                 IncWr += StepWr;
    83.                 if(IncWr > StepSize)
    84.                 {
    85.                     IncWr -= StepSize;
    86.                     Ptr += ImgWidth;
    87.                 }
    88.                 *Ptr = Color;
    89.             }
    90.         }
    91.         else
    92.         {
    93.             DWORD* pEndPtr = Ptr + (dy - 1)*ImgWidth + x2 - x1;
    94.             for(;Ptr < pEndPtr;--Ptr)
    95.             {
    96.                 IncWr += StepWr;
    97.                 if(IncWr > StepSize)
    98.                 {
    99.                     IncWr -= StepSize;
    100.                     Ptr += ImgWidth;
    101.                 }
    102.                 *Ptr = Color;
    103.             }
    104.             for(;Ptr >= pEndPtr;--Ptr) *Ptr = Color;
    105.         }
    106.     }
    107.     else    // Y - major line
    108.     {
    109.         UINT StepHr = (dx << 16)/dy,IncHr = 0;
    110.         if(x1 < x2)
    111.         {
    112.             DWORD* pEndPtr = Ptr + (dy - 1)*ImgWidth + dx;
    113.             for(;Ptr < pEndPtr;Ptr += ImgWidth)
    114.             {
    115.                 IncHr += StepHr;
    116.                 if(IncHr > StepSize)
    117.                 {
    118.                     IncHr -= StepSize;
    119.                     ++Ptr;
    120.                 }
    121.                 *Ptr = Color;
    122.             }
    123.         }
    124.         else
    125.         {
    126.             DWORD* pEndPtr = Ptr + dy*ImgWidth - dx;
    127.             for(;Ptr < pEndPtr;Ptr += ImgWidth)
    128.             {
    129.                 IncHr += StepHr;
    130.                 if(IncHr > StepSize)
    131.                 {
    132.                     IncHr -= StepSize;
    133.                     --Ptr;
    134.                 }
    135.                 *Ptr = Color;
    136.             }
    137.         }
    138.     }
    139.     return 1;
    140.     #pragma endregion
    141. }

    - Test thử so với bresenham xem sao!

    Line(1,1,400,4) : vẻ 1 000 000 line và cộng dồn trung bình 10 lần!
    + Dùng bresenham : 1.558410 (s)
    + Dùng RLight : 1.274334 (s)

    Line(1,1,4,400) : vẻ 1 000 000 line và cộng dồn trung bình 10 lần!
    + Dùng Bresenham : 5.762071 (s)
    + Dùng RLight : 5.755710 (s)

    Line(1,1,100,4) : vẻ 1 000 000 line và cộng dồn trung bình 10 lần!
    + Bresenham : 0.570991 (s)
    + RLight : 0.515729 (s)

    - Ủa, vậy nhanh hơn bresenham sao ta ???! Test lại với line có độ dài nhỏ xem sao!

    Line(1,1,50,4) : vẻ 1 000 000 line và cộng dồn trung bình 10 lần!
    + Bresenham : 0.367095 (s)
    + RLight : 0.388135 (s)

    Line(1,1,25,4) : vẻ 1 000 000 line và cộng dồn trung bình 10 lần!
    + Bresenham : 0.208329 (s)
    + RLight : 0.243836 (s)

    - Như vậy là vẻ mấy line nhỏ thì thuật toán của mình chậm hơn bresenham, nhưng khi vẻ mấy line dài hơn thì thuật toán của mình lại nhanh hơn (không tin các bạn cứ chép code về test thử)!

    - Có bạn nào biết vì sao vẻ mấy line dài thì bresenham chạy chậm hơn ko ^_^ (đơn giản lắm)?!
    Đã được chỉnh sửa lần cuối bởi RadicalLight : 14-04-2008 lúc 08:53 PM. Lý do: Nhằm

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn