MFC图形引擎

MFC图形引擎

/*
文件名:  MFC里使用双缓存
创建人:   陈泽丹

创建时间: 2009-10-13
版本号:  1.0
*/

#pragma once
#include "atlimage.h"


class Engine_2D
{
 /*
 备注:MFC在系统需要重画窗口的时候会自动用指定的背景色来搽除窗口。
 可重载WM_ERASEBKGND函数,注释掉return   CWnd::OnEraseBkgnd(pDC);
 并直接return true;
 禁止系统自动搽除窗口。
 另,为避免控件的重画,可设置窗体的Clip Children 属性为真。
 */
public:
 Engine_2D();
 ~Engine_2D(void);

 void OnInit(CWnd* in_pCWnd, COLORREF BackColor = RGB(192,192,192));
 void DrawText(CString sText,int x, int y, int w, int h, int in_LineWidth, COLORREF in_Color);
 void DrawText(CString sText,RECT& rect,int in_LineWidth, COLORREF in_Color);
 void Draw(CImage& in_Image, int in_x, int in_y, int in_w, int in_h);
 void Draw(CImage& in_Image, int in_x, int in_y, int in_w, int in_h, int in_srcX, int in_srcY, int in_srcW, int in_srcH);
void DrawEllipse(int in_CenterX, int in_CenterY, int in_Radius, COLORREF color, int in_iPenType = PS_SOLID, bool in_bIsNull = true);

 void DrawPie(int in_CenterX, int in_CenterY, int in_Radius, COLORREF color, int in_StartAngle = 0, int in_HaveAngle = 360);
 void DrawLine(int in_X0, int in_Y0, int in_X1, int in_Y1, int in_LineWidth = 1, COLORREF in_Color = RGB(255,0,0), bool in_bIsAA = true);
 void DrawPointLine(int in_X0, int in_Y0, int in_X1, int in_Y1, int in_LineWidth = 2, int in_PointWidth = 4, COLORREF in_Color = RGB(255,0,0));
 void DrawRect(int in_x, int in_y, int in_w, int in_h, COLORREF color);
 void Render();
 void Clear();
 void SaveSince(const LPCWSTR in_cPath, int in_x, int in_y, int in_w, int in_h);
 void SaveClientSince(const LPCWSTR in_cPath, int in_x, int in_y, int in_w, int in_h);
 inline HDC GetHDC() { return m_pMemDC->m_hDC; }
 void Invalidate();
 void Invalidate(int x, int y, int w, int h);
 bool AngleToPostion(int& out_PosX, int& out_PosY,
          int in_CenterX, int in_CenterY,
          int in_Radius,int in_Angle = 0);

 CString IntToCString(const int in_iNum);
 CString DoubleToCString(const double in_dNum);

private:
 HBITMAP CopyScreenToBitmap(LPRECT   lpRect);   //lpRect   代表选定区域  
 int SaveBitmapToFile(HBITMAP   hBitmap,   LPCWSTR   lpFileName);   //hBitmap   为刚才的屏幕位图句柄
 void DoEvent();
 CBitmap* m_pMemBitmap; //声明内存中承载临时图象的位图
 CDC* m_pMemDC;   //声明用于缓冲作图的内存DC
 CWnd* m_pCWnd;
 COLORREF m_BackColor;
 int m_SinceW;
 int m_SinceH;
};

//

 

#include "StdAfx.h"
#include "Engine_2D.h"
#include "TGraphics.h"
#include


Engine_2D::Engine_2D(void)
{
 m_pMemBitmap = new CBitmap();
 m_pMemDC = new CDC();
 m_pCWnd = NULL;
}

Engine_2D::~Engine_2D(void)
{
 delete m_pMemBitmap;
 delete m_pMemDC;
 m_pMemBitmap = NULL;
 m_pMemDC = NULL;
}

CString Engine_2D::IntToCString(const int in_iNum)
{
 TCHAR   szString[MAX_PATH]   =   {0};  
 _sntprintf(szString,sizeof(szString)-sizeof(TCHAR),_T("%d"),in_iNum);  
 CString strRet = szString;
 return strRet;
}

CString Engine_2D::DoubleToCString(const double in_dNum)
{
 TCHAR   szString[MAX_PATH]   =   {0};  
 _sntprintf(szString,sizeof(szString)-sizeof(TCHAR),_T("%f"),in_dNum);  
 CString strRet = szString;
 return strRet;
}

void Engine_2D::OnInit(CWnd* in_pCWnd, COLORREF BackColor)
{
 m_pCWnd = in_pCWnd;
 m_BackColor = BackColor;
 RECT rect;
 in_pCWnd->GetWindowRect(&rect);
 m_SinceW = rect.right - rect.left;
 m_SinceH = rect.bottom - rect.top;
 CDC* pDC = m_pCWnd->GetDC();
 m_pMemDC->CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC
 m_pMemBitmap->CreateCompatibleBitmap(pDC,m_SinceW,m_SinceH); //创建兼容位图
 CBitmap* m_pOldBitmap=m_pMemDC->SelectObject(m_pMemBitmap); //将位图选进内存DC,原位图保存到m_pOldBitmap
 CBrush Brush(m_BackColor);
 pDC->FillRect(CRect(0,0,m_SinceW,m_SinceH),&Brush);  //设置当前区背景
 m_pCWnd->ReleaseDC(pDC);
 Clear();
}

void Engine_2D::Render()
{
 CPaintDC dc(m_pCWnd);
 CRect rc;
 m_pCWnd->GetClientRect(&rc);
 dc.BitBlt(0,0,rc.Width(),rc.Height(),m_pMemDC,0,0,SRCCOPY);
}

void Engine_2D::Clear()
{
 CBrush Brush(m_BackColor);
 m_pMemDC->FillRect(CRect(0,0,m_SinceW,m_SinceH),&Brush);   //设置客户区背景
}

void Engine_2D::Draw(CImage& in_Image, int in_x, int in_y, int in_w, int in_h)
{
 in_Image.Draw(m_pMemDC->m_hDC, in_x, in_y, in_w, in_h);
}

void Engine_2D::Draw(CImage& in_Image, int in_x, int in_y, int in_w, int in_h, int in_srcX, int in_srcY, int in_srcW, int in_srcH)
{
 in_Image.Draw(m_pMemDC->m_hDC, in_x, in_y, in_w, in_h, in_srcX, in_srcY, in_srcW, in_srcH);
}

void Engine_2D::DrawRect(int in_x, int in_y, int in_w, int in_h, COLORREF color)
{
 RECT rect;
 rect.left   = in_x;
 rect.top    = in_y;
 rect.right  = in_x+in_w;
 rect.bottom = in_y+in_h;
 CBrush brush(color);
 m_pMemDC->FillRect(&rect,&brush);
}

 

void Engine_2D::DrawEllipse(int in_CenterX, int in_CenterY, int in_Radius, COLORREF color, int in_iPenType, bool in_bIsNull)
{
 int px = in_CenterX-in_Radius;
 int py = in_CenterY-in_Radius;
 int px1 = in_CenterX+in_Radius;
 int py1 = in_CenterY+in_Radius;
 //选笔选刷
 CPen pen(in_iPenType,1,color);
 CBrush brush(color);
 CPen* pOldpen = m_pMemDC->SelectObject(&pen);
 CBrush* pOldbrush = m_pMemDC->SelectObject(&brush);
 if( in_bIsNull) m_pMemDC->SelectObject(GetStockObject(NULL_BRUSH));

 //画饼
 m_pMemDC->Ellipse(px,py,px1,py1);
 m_pMemDC->SelectObject(pOldpen);
 m_pMemDC->SelectObject(pOldbrush);
}

void Engine_2D::DrawPie(int in_CenterX, int in_CenterY, int in_Radius, COLORREF color, int in_StartAngle, int in_HaveAngle)
{
 if( in_HaveAngle <= 0) return; //不占有空间,返回

 int px = in_CenterX-in_Radius;
 int py = in_CenterY-in_Radius;
 int px1 = in_CenterX+in_Radius;
 int py1 = in_CenterY+in_Radius;
 int rx, ry, rx1, ry1;
 AngleToPostion(rx, ry, in_CenterX, in_CenterY, in_Radius, in_StartAngle);
 AngleToPostion(rx1, ry1, in_CenterX, in_CenterY, in_Radius, in_StartAngle+in_HaveAngle);

 //选笔选刷
 CPen pen(PS_SOLID,1,color);
 CBrush brush(color);
 CPen* pOldpen = m_pMemDC->SelectObject(&pen);
 CBrush* pOldbrush = m_pMemDC->SelectObject(&brush);

 //画饼
 m_pMemDC->Pie(px,py,px1,py1,rx1,ry1,rx,ry);
 m_pMemDC->SelectObject(pOldpen);
 m_pMemDC->SelectObject(pOldbrush);
}


bool Engine_2D::AngleToPostion(int& out_PosX, int& out_PosY,
          int in_CenterX, int in_CenterY, int in_Radius,int in_Angle)
{
 if( in_Angle < 0) return false; //不占有空间,返回
 while(in_Angle > 360) in_Angle -= 360;
 double ang = in_Angle/180.0*3.14159;
 //以原点为坐标
 int iStartPox_X = 0;
 int iStartPox_y = in_Radius;
 int rx = iStartPox_X*cos(ang)+iStartPox_y*sin(ang);
 int ry = -iStartPox_X*sin(ang)+iStartPox_y*cos(ang);
 //折算窗口坐标
 ry *= -1;//windows窗口坐标Y是倒立的
 out_PosX = in_CenterX+rx;
 out_PosY = in_CenterY+ry;
 return true;
}

void Engine_2D::DrawLine(int in_X0, int in_Y0, int in_X1, int in_Y1, int in_LineWidth, COLORREF in_Color, bool in_bIsAA)
{
 if( in_bIsAA)
 {
  CTGraphics tGraphics;
  for(int i=0; i  {
   tGraphics.DrawLine(*m_pMemDC, in_X0+i, in_Y0, in_X1+i, in_Y1, in_Color);
   tGraphics.DrawLine(*m_pMemDC, in_X0-i, in_Y0, in_X1-i, in_Y1, in_Color);
  }
 }
 else
 {
  CPen pen(PS_SOLID,in_LineWidth,in_Color);
  CPen* pOldpen = m_pMemDC->SelectObject(&pen);
  m_pMemDC->MoveTo(in_X0,in_Y0);
  m_pMemDC->LineTo(in_X1,in_Y1);
  m_pMemDC->SelectObject(pOldpen);
 }

}


void Engine_2D::DrawPointLine(int in_X0, int in_Y0, int in_X1, int in_Y1, int in_LineWidth, int in_PointWidth, COLORREF in_Color)
{
 DrawLine(in_X0,in_Y0,in_X1,in_Y1,in_LineWidth,in_Color);
 DrawPie(in_X0,in_Y0,in_PointWidth,in_Color);
 DrawPie(in_X1,in_Y1,in_PointWidth,in_Color);
}

void Engine_2D::Invalidate()
{
 RECT rect;
 rect.left   = 0;
 rect.top    = 0;
 rect.right  = m_SinceW;
 rect.bottom = m_SinceH;
 m_pCWnd->InvalidateRect(&rect);
 m_pCWnd->UpdateData();
 DoEvent();
}

void Engine_2D::Invalidate(int x, int y, int w, int h)
{
 RECT rect;
 rect.left   = x;
 rect.top    = y;
 rect.right  = x+w;
 rect.bottom = y+h;
 m_pCWnd->InvalidateRect(&rect);
 m_pCWnd->UpdateData();
 DoEvent();
}

void Engine_2D::DoEvent()
{
 MSG msg;
 while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE) )//判断是否有消息
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
}


void Engine_2D::SaveSince(const LPCWSTR in_cPath, int in_x, int in_y, int in_w, int in_h)
{
 RECT rect;
 rect.left = in_x;
 rect.top = in_y;
 rect.right = in_w;
 rect.bottom = in_h;
 SaveBitmapToFile(CopyScreenToBitmap(&rect),in_cPath);
}

void Engine_2D::SaveClientSince(const LPCWSTR in_cPath, int in_x, int in_y, int in_w, int in_h)
{
 RECT rect;
 rect.left = in_x;
 rect.top = in_y;
 rect.right = in_x+in_w;
 rect.bottom = in_y+in_h;
 m_pCWnd->ClientToScreen(&rect);
 SaveBitmapToFile(CopyScreenToBitmap(&rect),in_cPath);
}

HBITMAP Engine_2D::CopyScreenToBitmap(LPRECT   lpRect)   //lpRect   代表选定区域  
{  
 HDC   hScrDC,   hMemDC;              
 //   屏幕和内存设备描述表  
 HBITMAP   hBitmap,hOldBitmap;        
 //   位图句柄  
 int               nX,   nY,   nX2,   nY2;              
 //   选定区域坐标  
 int               nWidth,   nHeight;              
 //   位图宽度和高度  
 int               xScrn,   yScrn;                    
 //   屏幕分辨率  
 //   确保选定区域不为空矩形  
 if( IsRectEmpty(lpRect))  
  return   NULL;  
 //为屏幕创建设备描述表  
 hScrDC   =   CreateDC(L"DISPLAY",   NULL,   NULL,   NULL);  
 //为屏幕设备描述表创建兼容的内存设备描述表  
 hMemDC   =   CreateCompatibleDC(hScrDC);  
 //   获得选定区域坐标  
 nX   =   lpRect->left;  
 nY   =   lpRect->top;  
 nX2   =   lpRect->right;  
 nY2   =   lpRect->bottom;  
 //   获得屏幕分辨率  
 xScrn   =   GetDeviceCaps(hScrDC,   HORZRES);  
 yScrn   =   GetDeviceCaps(hScrDC,   VERTRES);  
 //确保选定区域是可见的  
 if   (nX   <   0)  
  nX   =   0;  
 if   (nY   <   0)  
  nY   =   0;  
 if   (nX2   >   xScrn)  
  nX2   =   xScrn;  
 if   (nY2   >   yScrn)  
  nY2   =   yScrn;  
 nWidth   =   nX2   -   nX;  
    nHeight   =   nY2   -   nY;  
    //   创建一个与屏幕设备描述表兼容的位图  
    hBitmap = CreateCompatibleBitmap(hScrDC,nWidth,nHeight);  
    //   把新位图选到内存设备描述表中  
    hOldBitmap = (HBITMAP)SelectObject(hMemDC,hBitmap);  
    //   把屏幕设备描述表拷贝到内存设备描述表中  
    BitBlt(hMemDC,0,0, nWidth,nHeight, hScrDC,   nX,   nY,   SRCCOPY);  
    //得到屏幕位图的句柄  
    hBitmap=(HBITMAP)SelectObject(hMemDC,hOldBitmap);  
    //清除    
    DeleteDC(hScrDC);  
    DeleteDC(hMemDC);  
    //   返回位图句柄  
    return   hBitmap;  
}

int Engine_2D::SaveBitmapToFile(HBITMAP   hBitmap,   LPCWSTR   lpFileName)   //hBitmap   为刚才的屏幕位图句柄  
{          
 //lpFileName   为位图文件名  
 HDC           hDC;                    
 //设备描述表  
 int           iBits;              
    //当前显示分辨率下每个像素所占字节数  
 WORD         wBitCount;        
 //位图中每个像素所占字节数  
 //定义调色板大小,   位图中像素字节大小   ,     位图文件大小   ,   写入文件字节数  
 DWORD                       dwPaletteSize=0,dwBmBitsSize,dwDIBSize,   dwWritten;  
 BITMAP                     Bitmap;                  
 //位图属性结构  
 BITMAPFILEHEADER       bmfHdr;                  
 //位图文件头结构  
 BITMAPINFOHEADER       bi;                          
 //位图信息头结构    
 LPBITMAPINFOHEADER   lpbi;                      
 //指向位图信息头结构  
 HANDLE                     fh,   hDib,   hPal;

 HPALETTE           hOldPal=NULL;  
 //定义文件,分配内存句柄,调色板句柄  
 //计算位图文件每个像素所占字节数  
 hDC   =   CreateDC(L"DISPLAY",NULL,NULL,NULL);  
 iBits   =   GetDeviceCaps(hDC,   BITSPIXEL)   *     GetDeviceCaps(hDC,   PLANES);  
 DeleteDC(hDC);  
    if   (iBits   <=   1)  
          wBitCount   =   1;  
    else   if   (iBits   <=   4)  
          wBitCount   =   4;  
    else   if   (iBits   <=   8)  
          wBitCount   =   8;  
 else   if   (iBits   <=   16)
  wBitCount   =   16; 
    else   if   (iBits   <=   24)  
          wBitCount   =   24; 
 else
    wBitCount = 32;
    //计算调色板大小  
    if(wBitCount   <=   8)  
          dwPaletteSize=(1< //设置位图信息头结构  
    GetObject(hBitmap,   sizeof(BITMAP),   (LPSTR)&Bitmap);  
    bi.biSize                         =   sizeof(BITMAPINFOHEADER);  
    bi.biWidth                       =   Bitmap.bmWidth;  
    bi.biHeight                     =   Bitmap.bmHeight;  
    bi.biPlanes                     =   1;  
    bi.biBitCount                   =   wBitCount;  
    bi.biCompression             =   BI_RGB;  
    bi.biSizeImage                 =   0;  
    bi.biXPelsPerMeter           =   0;  
    bi.biYPelsPerMeter           =   0;  
    bi.biClrUsed                   =   0;  
    bi.biClrImportant             =   0;  
   
    dwBmBitsSize   =   ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;  
    //为位图内容分配内存  
    hDib     =   GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));  
    lpbi   =   (LPBITMAPINFOHEADER)GlobalLock(hDib);  
    *lpbi   =   bi;  
    //   处理调色板    
    hPal   =   GetStockObject(DEFAULT_PALETTE);  
    if   (hPal)  
    {  
          hDC   =   GetDC(NULL);  
          hOldPal=SelectPalette(hDC,(HPALETTE)hPal,FALSE);  
          RealizePalette(hDC);  
    }  
    //   获取该调色板下新的像素值  
    GetDIBits(hDC,hBitmap,0,(UINT)Bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwPaletteSize,   (BITMAPINFO   *)lpbi,DIB_RGB_COLORS);  
    //恢复调色板        
    if   (hOldPal)  
    {  
          SelectPalette(hDC,   hOldPal,   TRUE);  
          RealizePalette(hDC);  
          ReleaseDC(NULL,   hDC);  
    }  
 //创建位图文件          
 fh=CreateFile(lpFileName,   GENERIC_WRITE,0,   NULL,   CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL   |   FILE_FLAG_SEQUENTIAL_SCAN,   NULL);  
    if   (fh==INVALID_HANDLE_VALUE)  
          return   FALSE;  
    //   设置位图文件头  
    bmfHdr.bfType   =   0x4D42;     //   "BM"  
 dwDIBSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;      
 bmfHdr.bfSize   =   dwDIBSize;  
 bmfHdr.bfReserved1   =   0;  
 bmfHdr.bfReserved2   =   0;  
 bmfHdr.bfOffBits   =   (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;  
 //   写入位图文件头  
 WriteFile(fh,   (LPSTR)&bmfHdr,   sizeof(BITMAPFILEHEADER),   &dwWritten,   NULL);  
 //   写入位图文件其余内容  
 WriteFile(fh,   (LPSTR)lpbi,   dwDIBSize,     &dwWritten,   NULL);  
    //清除        
    GlobalUnlock(hDib);  
    GlobalFree(hDib);  
    CloseHandle(fh);  
    return   TRUE;  
}

void Engine_2D::DrawText(CString sText,RECT& rect,int in_LineWidth, COLORREF in_Color)
{
 CPen pen(PS_SOLID,in_LineWidth,in_Color);
 CPen* pOldpen = m_pMemDC->SelectObject(&pen);
 m_pMemDC->DrawText(sText, &rect, DT_LEFT);
 m_pMemDC->SelectObject(pOldpen);
}


void Engine_2D::DrawText(CString sText,int x, int y, int w, int h, int in_LineWidth, COLORREF in_Color)
{
 RECT rect;
 rect.left = x;
 rect.top = y;
 rect.right = x+w;
 rect.bottom = y+h;
 DrawText(sText,rect,in_LineWidth, in_Color);
}

// TGraphics.cpp: implementation of the CTGraphics class.
//
//

#include "stdafx.h"
#include "TGraphics.h"
#include "math.h"

 

CTGraphics::CTGraphics()
{
}

CTGraphics::~CTGraphics()
{
}

void CTGraphics::DrawLine(HDC hDC, int x1, int y1, int x2, int y2, COLORREF color)
{
 // Calculate line params
 int dx = (x2 - x1);
 int dy = (y2 - y1);
 COLORREF bgColor;
 int temp;
 float k;

 // Set start pixel
 ::SetPixel(hDC, x1, y1, color);

 // X-dominant line
 if (abs(dx) > abs(dy))
 {
  // Ex-change line end points
  if (dx < 0)
  {
   temp = x1;
   x1 = x2;
   x2 = temp;

   temp = y1;
   y1 = y2;
   y2 = temp;
  }
  k = (float)dy / (float)dx;

  // Set middle pixels
  int xs;
  float yt = (float)y1 + k;
  float distance;
  UCHAR red, green, blue;
  for (xs=x1+1; xs  {
   distance = (float)(yt - (int)(yt));

   bgColor = ::GetPixel(hDC, xs, (int)yt);
   red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
   green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
   blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
   ::SetPixel(hDC, xs, (int)yt, RGB(red,green,blue));

   bgColor = ::GetPixel(hDC, xs, (int)yt+1);
   red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
   green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
   blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
   ::SetPixel(hDC, xs, (int)yt+1, RGB(red,green,blue));

   yt += k;
  }
 }
 // Y-dominant line
 else
 {
  // Ex-change line end points
  if (dy < 0)
  {
   temp = x1;
   x1 = x2;
   x2 = temp;

   temp = y1;
   y1 = y2;
   y2 = temp;
  }
  k = (float)dx / (float)dy;

  // Set middle pixels
  int ys;
  float xt = (float)x1 + k;
  float distance;
  UCHAR red, green, blue;
  for (ys=y1+1; ys  {
   distance = (float)(xt - (int)(xt));

   bgColor = ::GetPixel(hDC, (int)xt, ys);
   red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
   green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
   blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
   ::SetPixel(hDC, (int)xt, ys, RGB(red,green,blue));

   bgColor = ::GetPixel(hDC, (int)xt+1, ys);
   red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
   green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
   blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
   ::SetPixel(hDC, (int)xt+1, ys, RGB(red,green,blue));

   xt += k;
  }
 }

 // Set end pixel
 ::SetPixel(hDC, x2, y2, color);
}

void CTGraphics::DrawPolyline(HDC hDC, POINT* points, int numberPoints, COLORREF color)
{
 for (int i=0; i {
  DrawLine(hDC, points[i].x, points[i].y, points[i+1].x, points[i+1].y, color);
 }
}

void CTGraphics::DrawPolygon(HDC hDC, POINT* points, int numberPoints, COLORREF color)
{
 DrawPolyline(hDC, points, numberPoints, color);
 DrawLine(hDC, points[0].x, points[0].y, points[numberPoints-1].x, points[numberPoints-1].y, color);
}

void CTGraphics::DrawEllipse(HDC hDC, int x1, int y1, int x2, int y2, COLORREF color)
{
 int centerX = (x1 + x2) / 2;
 int centerY = (y1 + y2) / 2;
 int dx = (x2 - x1);
 int dy = (y2 - y1);
 int radiusX = (int)(fabs((float)dx) / 2.0f);
 int radiusY = (int)(fabs((float)dy) / 2.0f);
 float rel = (float)sqrt((float)radiusX*radiusX + radiusY*radiusY) / (float)radiusY;
 COLORREF bgColor;
 int temp;
 float distance;
 UCHAR red, green, blue;

 if (x2 < x1)
 {
  temp = x1;
  x1 = x2;
  x2 = temp;

  temp = y1;
  y1 = y2;
  y2 = temp;
 }

 int xs;
 float yt;
 for (xs=-radiusX; xs<=radiusX; xs++)
 {
  yt = (float)(radiusY * sqrt(1-(float)(xs*xs)/(float)(radiusX*radiusX)));
  distance = (float)(yt - (int)yt);

  bgColor = ::GetPixel(hDC, centerX+xs, centerY+(int)yt);
  red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
  green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
  blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
  ::SetPixel(hDC, centerX+xs, centerY+(int)yt, RGB(red,green,blue));

  bgColor = ::GetPixel(hDC, centerX+xs, centerY+(int)yt+1);
  red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
  green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
  blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
  ::SetPixel(hDC, centerX+xs, centerY+(int)yt+1, RGB(red,green,blue));

  bgColor = ::GetPixel(hDC, centerX-xs, centerY-(int)yt);
  red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
  green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
  blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
  ::SetPixel(hDC, centerX-xs, centerY-(int)yt, RGB(red,green,blue));

  bgColor = ::GetPixel(hDC, centerX-xs, centerY-(int)yt-1);
  red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
  green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
  blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
  ::SetPixel(hDC, centerX-xs, centerY-(int)yt-1, RGB(red,green,blue));
 }

 int ys;
 float xt;
 for (ys=-(int)((float)radiusY/rel); ys<=(int)((float)radiusY/rel); ys++)
 {
  xt = (float)(radiusX * sqrt(1-(float)(ys*ys)/(float)(radiusY*radiusY)));
  distance = (float)(xt - (int)xt);

  bgColor = ::GetPixel(hDC, centerX+(int)xt, centerY+ys);
  red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
  green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
  blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
  ::SetPixel(hDC, centerX+(int)xt, centerY+ys, RGB(red,green,blue));

  bgColor = ::GetPixel(hDC, centerX+(int)xt+1, centerY+ys);
  red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
  green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
  blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
  ::SetPixel(hDC, centerX+(int)xt+1, centerY+ys, RGB(red,green,blue));

  bgColor = ::GetPixel(hDC, centerX-(int)xt, centerY-ys);
  red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
  green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
  blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
  ::SetPixel(hDC, centerX-(int)xt, centerY-ys, RGB(red,green,blue));

  bgColor = ::GetPixel(hDC, centerX-(int)xt-1, centerY-ys);
  red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
  green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
  blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
  ::SetPixel(hDC, centerX-(int)xt-1, centerY-ys, RGB(red,green,blue));
 }
}

void CTGraphics::DrawArc(HDC hDC, int x1, int y1, int x2, int y2, float startAngle, float endAngle, COLORREF color)
{
 int centerX = (x1 + x2) / 2;
 int centerY = (y1 + y2) / 2;
 int dx = (x2 - x1);
 int dy = (y2 - y1);
 int radiusX = (abs(dx) / 2);
 int radiusY = (abs(dy) / 2);
 COLORREF bgColor;
 float distance;
 UCHAR red, green, blue;

 float angle = 0.0f;
 while ((angle+90.0f) < startAngle)
  angle += 90.0f;
 while (angle < endAngle)
 {
  if (startAngle >= angle)
  {
   float eAngle;
   if (endAngle <= angle+90.0f)
    eAngle = endAngle;
   else
    eAngle = angle+90.0f;

   float sx = (float)(radiusX*cos((startAngle/180.0f)*3.1415f));
   if (sx > 0.0f)
    sx += 0.5f;
   else
    sx -= 0.5f;
   int startX = (int)sx;
   int endX = (int)(radiusX*cos((eAngle/180.0f)*3.1415f));
   int deltaX;
   if (endX - startX != 0)
    deltaX = (int)((endX-startX) / fabs((float)endX-startX));
   else
    deltaX = 0;

   float sy = (float)(radiusY*sin((startAngle/180.0f)*3.1415f));
   if (sy > 0.0f)
    sy += 0.5f;
   else
    sy -= 0.5f;
   int startY = (int)sy;
   int endY = (int)(radiusY*sin((eAngle/180.0f)*3.1415f));
   int deltaY;
   if (endY - startY != 0)
    deltaY = (int)((endY-startY) / fabs((float)endY-startY));
   else
    deltaY = 0;

   if (deltaX != 0)
   {
    int oldY = startY;
    int xs = startX;
    float yt;
    while (xs != endX)
    {
     yt = (float)(radiusY * sqrt(1.0f-(float)(xs*xs)/(float)(radiusX*radiusX)));
     distance = (float)(yt - (int)yt);

     if (abs(oldY - (int)yt) < 2)
     {
      if (deltaX < 0)
      {
       if (deltaY > 0)
        bgColor = ::GetPixel(hDC, centerX+xs, centerY+(int)yt);
       else
        bgColor = ::GetPixel(hDC, centerX+xs, centerY+(int)yt);
      }
      else
      {
       if (deltaY < 0)
        bgColor = ::GetPixel(hDC, centerX+xs, centerY-(int)yt);
       else
        bgColor = ::GetPixel(hDC, centerX+xs, centerY-(int)yt);
      }
      red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
      green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
      blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
      if (deltaX < 0)
      {
       if (deltaY > 0)
        ::SetPixel(hDC, centerX+xs, centerY+(int)yt, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX+xs, centerY+(int)yt, RGB(red,green,blue));
      }
      else
      {
       if (deltaY < 0)
        ::SetPixel(hDC, centerX+xs, centerY-(int)yt, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX+xs, centerY-(int)yt, RGB(red,green,blue));
      }

      if (deltaX < 0)
      {
       if (deltaY > 0)
        bgColor = ::GetPixel(hDC, centerX+xs, centerY+(int)yt+1);
       else
        bgColor = ::GetPixel(hDC, centerX+xs, centerY+(int)yt+1);
      }
      else
      {
       if (deltaY < 0)
        bgColor = ::GetPixel(hDC, centerX+xs, centerY-(int)yt-1);
       else
        bgColor = ::GetPixel(hDC, centerX+xs, centerY-(int)yt-1);
      }
      red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
      green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
      blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
      if (deltaX < 0)
      {
       if (deltaY > 0)
        ::SetPixel(hDC, centerX+xs, centerY+(int)yt+1, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX+xs, centerY+(int)yt+1, RGB(red,green,blue));
      }
      else
      {
       if (deltaY < 0)
        ::SetPixel(hDC, centerX+xs, centerY-(int)yt-1, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX+xs, centerY-(int)yt-1, RGB(red,green,blue));
      }
     }
     
     oldY = (int)yt;
     xs += deltaX;
    }
   }

   if (deltaY != 0)
   {
    int oldX = startX;
    int ys = startY;
    float xt;
    while (ys != endY)
    {
     xt = (float)(radiusX * sqrt(1.0f-(float)(ys*ys)/(float)(radiusY*radiusY)));
     distance = (float)(xt - (int)xt);

     if (abs(oldX - (int)xt) < 2)
     {
      if (deltaX < 0)
      {
       if (deltaY > 0)
        bgColor = ::GetPixel(hDC, centerX+(int)xt, centerY+ys);
       else
        bgColor = ::GetPixel(hDC, centerX-(int)xt, centerY+ys);
      }
      else
      {
       if (deltaY < 0)
        bgColor = ::GetPixel(hDC, centerX-(int)xt, centerY+ys);
       else
        bgColor = ::GetPixel(hDC, centerX+(int)xt, centerY+ys);
      }
      red = (UCHAR)(distance*GetRValue(bgColor)) + (UCHAR)((1.0f-distance)*GetRValue(color));
      green = (UCHAR)(distance*GetGValue(bgColor)) + (UCHAR)((1.0f-distance)*GetGValue(color));
      blue = (UCHAR)(distance*GetBValue(bgColor)) + (UCHAR)((1.0f-distance)*GetBValue(color));
      if (deltaX < 0)
      {
       if (deltaY > 0)
        ::SetPixel(hDC, centerX+(int)xt, centerY+ys, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX-(int)xt, centerY+ys, RGB(red,green,blue));
      }
      else
      {
       if (deltaY < 0)
        ::SetPixel(hDC, centerX-(int)xt, centerY+ys, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX+(int)xt, centerY+ys, RGB(red,green,blue));
      }

      if (deltaX < 0)
      {
       if (deltaY > 0)
        bgColor = ::GetPixel(hDC, centerX+(int)xt+1, centerY+ys);
       else
        bgColor = ::GetPixel(hDC, centerX-(int)xt-1, centerY+ys);
      }
      else
      {
       if (deltaY < 0)
        bgColor = ::GetPixel(hDC, centerX-(int)xt-1, centerY+ys);
       else
        bgColor = ::GetPixel(hDC, centerX+(int)xt+1, centerY+ys);
      }
      red = (UCHAR)((1.0f-distance)*GetRValue(bgColor)) + (UCHAR)(distance*GetRValue(color));
      green = (UCHAR)((1.0f-distance)*GetGValue(bgColor)) + (UCHAR)(distance*GetGValue(color));
      blue = (UCHAR)((1.0f-distance)*GetBValue(bgColor)) + (UCHAR)(distance*GetBValue(color));
      if (deltaX < 0)
      {
       if (deltaY > 0)
        ::SetPixel(hDC, centerX+(int)xt+1, centerY+ys, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX-(int)xt-1, centerY+ys, RGB(red,green,blue));
      }
      else
      {
       if (deltaY < 0)
        ::SetPixel(hDC, centerX-(int)xt-1, centerY+ys, RGB(red,green,blue));
       else
        ::SetPixel(hDC, centerX+(int)xt+1, centerY+ys, RGB(red,green,blue));
      }
     }

     oldX = (int)xt;
     ys += deltaY;
    }
   }
  }

  angle += 90.0f;
  startAngle = angle;
 }
}

void CTGraphics::DrawPie(HDC hDC, int x1, int y1, int x2, int y2, float startAngle, float endAngle, COLORREF color)
{
 int centerX = (x1 + x2) / 2;
 int centerY = (y1 + y2) / 2;
 int dx = (x2 - x1);
 int dy = (y2 - y1);
 int radiusX = (abs(dx) / 2);
 int radiusY = (abs(dy) / 2);

 int startX = (int)(radiusX*cos((startAngle/180.0f)*3.1415f));
 int startY = (int)(radiusY*sin((startAngle/180.0f)*3.1415f));
 int endX = (int)(radiusX*cos((endAngle/180.0f)*3.1415f));
 int endY = (int)(radiusY*sin((endAngle/180.0f)*3.1415f));
 
 if (endX < 0)
 {
  if (endY > 0)
   endY++;
  else
   endX--;
 }
 else
 {
  if (endY < 0)
   endY--;
  else
   endX++;
 }

 DrawArc(hDC, x1, y1, x2, y2, startAngle, endAngle, color);
 DrawLine(hDC, centerX, centerY, centerX+startX, centerY+startY, color);
 DrawLine(hDC, centerX, centerY, centerX+endX, centerY+endY, color);
}

void CTGraphics::DrawChord(HDC hDC, int x1, int y1, int x2, int y2, float startAngle, float endAngle, COLORREF color)
{
 int centerX = (x1 + x2) / 2;
 int centerY = (y1 + y2) / 2;
 int dx = (x2 - x1);
 int dy = (y2 - y1);
 int radiusX = (abs(dx) / 2);
 int radiusY = (abs(dy) / 2);

 int startX = (int)(radiusX*cos((startAngle/180.0f)*3.1415f));
 int startY = (int)(radiusY*sin((startAngle/180.0f)*3.1415f));
 int endX = (int)(radiusX*cos((endAngle/180.0f)*3.1415f));
 int endY = (int)(radiusY*sin((endAngle/180.0f)*3.1415f));
 
 if (endX < 0)
 {
  if (endY > 0)
   endY++;
  else
   endX--;
 }
 else
 {
  if (endY < 0)
   endY--;
  else
   endX++;
 }

 DrawArc(hDC, x1, y1, x2, y2, startAngle, endAngle, color);
 DrawLine(hDC, centerX+startX, centerY+startY, centerX+endX, centerY+endY, color);
}

void CTGraphics::DrawRoundRect(HDC hDC, int x1, int y1, int x2, int y2, int width, int height, COLORREF color)
{
 int dx = (x2 - x1);
 int dy = (y2 - y1);
 int offsetX = width / 2;
 width = offsetX * 2;
 int offsetY = height / 2;
 height = offsetY * 2;

 if ((width > abs(dx)) || (height > abs(dy)))
 {
  DrawEllipse(hDC, x1, y1, x2, y2, color);
 }
 else
 {
  DrawLine(hDC, x1+offsetX, y1, x2-offsetX, y1, color);
  DrawArc(hDC, x2-width, y1, x2, y1+height, 270.0f, 360.0f, color);
  DrawLine(hDC, x2, y1+offsetY, x2, y2-offsetY, color);
  DrawArc(hDC, x2-width, y2-height, x2, y2, 0.0f, 90.0f, color);
  DrawLine(hDC, x2-offsetX, y2, x1+offsetX, y2, color);
  DrawArc(hDC, x1, y2-height, x1+width, y2, 90.0f, 180.0f, color);
  DrawLine(hDC, x1, y2-offsetY, x1, y1+offsetY, color);
  DrawArc(hDC, x1, y1, x1+width, y1+height, 180.0f, 270.0f, color);
 }
}

void CTGraphics::DrawBezier(HDC hDC, POINT* points, int numPoints, COLORREF color)
{
 int numCurves = (numPoints-1) / 3;
 int numReqPoints = numCurves*3 + 1;

 if (numPoints >= numReqPoints)
 {
  POINT startPoint, endPoint, controlPoint1, controlPoint2;
  float distance1, distance2, distance3, distanceX, distanceY;
  float ax, bx, cx, ay, by, cy, t, step;
  float xt, yt, k, k1;
  int oldX, oldY, oldX1, oldY1;
  for (int i=0; i  {
   startPoint = points[i*3];
   controlPoint1 = points[i*3+1];
   controlPoint2 = points[i*3+2];
   endPoint = points[i*3+3];

   if (controlPoint1.y == controlPoint2.y)
   {
    DrawLine(hDC, startPoint.x, startPoint.y, endPoint.x, endPoint.y, color);
   }
   else
   {
    distance1 = (float)sqrt(pow((float)controlPoint1.x-startPoint.x,2) + pow((float)controlPoint1.y-startPoint.y,2));
    distance2 = (float)sqrt(pow((float)controlPoint2.x-controlPoint1.x,2) + pow((float)controlPoint2.y-controlPoint1.y,2));
    distance3 = (float)sqrt(pow((float)endPoint.x-controlPoint2.x,2) + pow((float)endPoint.y-controlPoint2.y,2));
    step = 1.0f / (distance1+distance2+distance3);

    cx = 3.0f*(controlPoint1.x - startPoint.x);
    bx = 3.0f*(controlPoint2.x - controlPoint1.x) - cx;
    ax = endPoint.x - startPoint.x - bx - cx;

    cy = 3.0f*(controlPoint1.y - startPoint.y);
    by = 3.0f*(controlPoint2.y - controlPoint1.y) - cy;
    ay = endPoint.y - startPoint.y - by - cy;

    oldX = startPoint.x;
    oldY = startPoint.y;
    k1 = 0.0f;
    for (t=0.0f; t<=1.0f; t+=step)
    {
     xt = ax*(t*t*t) + bx*(t*t) + cx*t + startPoint.x;
     yt = ay*(t*t*t) + by*(t*t) + cy*t + startPoint.y;

     distanceX = (float)(xt - (int)(xt));
     distanceY = (float)(yt - (int)(yt));

     if (((int)xt != oldX) && ((int)yt != oldY))
     {
      oldX1 = oldX;
      oldY1 = oldY;

      k = (float)((int)yt - oldY) / (float)((int)xt - oldX);

      if (k != k1)
      {
       DrawLine(hDC, oldX, oldY, (int)xt, (int)yt, color);

       k1 = k;
       oldX = (int)xt;
       oldY = (int)yt;
      }
     }
    }
 
    if (((int)xt != oldX1) || ((int)yt != oldY1))
    {
     int dx = ((int)xt - oldX1);
     int dy = ((int)yt - oldY1);

     if (abs(dx) > abs(dy))
     {
      if (dy > 0)
       DrawLine(hDC, oldX, oldY, (int)xt, (int)yt+1, color);
      else
       DrawLine(hDC, oldX, oldY, (int)xt, (int)yt-1, color);
     }
     else
     {
      if (dx > 0)
       DrawLine(hDC, oldX, oldY, (int)xt+1, (int)yt, color);
      else
       DrawLine(hDC, oldX, oldY, (int)xt-1, (int)yt, color);
     }
    }
   }
  }
 }
}

你可能感兴趣的:(MFC图形引擎)