wxWidgets第十七課 採用AGG渲染庫

說明

    已有的wxDC以及所有的派生類相關的設備環境均沒有實現抗鋸齒的功能,畢竟wxDC也只是對CDC的封裝,只有GDI+才支持抗鋸齒。

    在如下的代碼中定義rasterizer等爲靜態變量的核心原因是其在進行渲染計算的時候會分配大量的內存,容易造成內存碎片,當然agg::pixfmt_bgra32 和agg::renderer_scanline_aa_solid

等並沒有進行什麼內存分配,但是統一起見,所以構造爲靜態變量,實際上,還有申請的渲染緩存指向的區域也應該設置爲靜態變量,然後通過指定寬和高,即可最大限度的避免了內存碎片


代碼

頭文件

#include "wx/wx.h"


#include "agg/agg_scanline_p.h"

#include "agg/agg_renderer_scanline.h"

#include "agg/agg_pixfmt_rgba.h"

#include "agg/agg_rasterizer_scanline_aa.h"


struct PosCoordinate

{

double x;

double y;

};

class CFlightInstrumentCompassCtrl : public wxControl

{

private:

DECLARE_EVENT_TABLE()

public:

CFlightInstrumentCompassCtrl() {Init();}

void Init() {}


CFlightInstrumentCompassCtrl(wxWindow *parent,

wxWindowID id,

const wxPoint& pos = wxDefaultPosition,

const wxSize& size = wxDefaultSize,

long style = 0,

const wxValidator& validator = wxDefaultValidator)

{

Init();

Create(parent, id, pos, size, style, validator);

}


bool Create(wxWindow *parent,

wxWindowID id,

const wxPoint& pos = wxDefaultPosition,

const wxSize& size = wxDefaultSize,

long style = 0,

const wxValidator& validator = wxDefaultValidator);

~CFlightInstrumentCompassCtrl(void);


void SetCompassParameter(double leanAngle, double leanDistance, int rollAngle);


void SetSize(wxSize size)

{

m_size = size;

}


private:

void GetFitCircleInfo(double &circleRaduis, double &circleCenterX, double &circleCenterY);


private:

double m_arrowDiviationAngle;

double m_arrowAngle;

double m_leanDistance;

int   m_curRollAngle;

wxSize m_size;


protected:

void OnPaint(wxPaintEvent& event);


void OnEraseBackground(wxEraseEvent& event);


public:

//對需要使用的AGG對象進行聲明,因爲是靜態變量還需要在源文件中進行定義,否則出現無法解析的外部符號錯誤

static agg::rendering_buffer m_rbuf;

static agg::pixfmt_bgra32 m_pixf;

static agg::renderer_base<agg::pixfmt_bgra32> m_renb;

static agg::renderer_scanline_aa_solid<agg::renderer_base<agg::pixfmt_bgra32> > m_ren;

static agg::rasterizer_scanline_aa<> m_ras;

static agg::scanline_p8 m_sl;

};


源文件

#include "flightinstrumentcompass.h"

#include "wx/msw/window.h"

#include <windows.h>

#include "wx/dc.h"


BEGIN_EVENT_TABLE(CFlightInstrumentCompassCtrl, wxControl)

EVT_PAINT(CFlightInstrumentCompassCtrl::OnPaint)

EVT_ERASE_BACKGROUND(CFlightInstrumentCompassCtrl::OnEraseBackground)

END_EVENT_TABLE()


//靜態AGG對象的定義

agg::rendering_buffer CFlightInstrumentCompassCtrl::m_rbuf;

agg::pixfmt_bgra32 CFlightInstrumentCompassCtrl::m_pixf;

agg::renderer_base<agg::pixfmt_bgra32> CFlightInstrumentCompassCtrl::m_renb;

agg::renderer_scanline_aa_solid<agg::renderer_base<agg::pixfmt_bgra32> > CFlightInstrumentCompassCtrl::m_ren;

agg::rasterizer_scanline_aa<> CFlightInstrumentCompassCtrl::m_ras;

agg::scanline_p8 CFlightInstrumentCompassCtrl::m_sl;



bool CFlightInstrumentCompassCtrl::Create(wxWindow *parent,

  wxWindowID id,

  const wxPoint& pos ,

  const wxSize& size ,

  long style ,

  const wxValidator& validator)

{

if (!wxControl::Create(parent, id, pos, size, style, validator))

{

return false;

}

return true;

}



CFlightInstrumentCompassCtrl::~CFlightInstrumentCompassCtrl(void)

{


}


void CFlightInstrumentCompassCtrl::OnPaint( wxPaintEvent& event )

{

WXHWND hWnd = GetHWND();

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hWnd, &ps);


RECT rt;

::GetClientRect(hWnd, &rt);


int width = rt.right - rt.left;

int height = rt.bottom - rt.top;


BITMAPINFO bmp_info; 

bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 

bmp_info.bmiHeader.biWidth = width; 

bmp_info.bmiHeader.biHeight = height; 

bmp_info.bmiHeader.biPlanes = 1; 

bmp_info.bmiHeader.biBitCount = 32; 

bmp_info.bmiHeader.biCompression = BI_RGB; 

bmp_info.bmiHeader.biSizeImage = 0; 

bmp_info.bmiHeader.biXPelsPerMeter = 0; 

bmp_info.bmiHeader.biYPelsPerMeter = 0; 

bmp_info.bmiHeader.biClrUsed = 0; 

bmp_info.bmiHeader.biClrImportant = 0; 


HDC mem_dc = ::CreateCompatibleDC(hdc); 


void* buf = 0; 


HBITMAP bmp = ::CreateDIBSection( 

mem_dc, 

&bmp_info, 

DIB_RGB_COLORS, 

&buf, 

0, 

);



// Selecting the object before doing anything allows you 

// to use AGG together with native Windows GDI.

HBITMAP temp = (HBITMAP)::SelectObject(mem_dc, bmp);



//============================================================ 

// AGG lowest level code.

m_rbuf.attach((unsigned char*)buf, width, height, -width*4); // Use negative stride in order

m_pixf.attach(m_rbuf);

m_renb.attach(m_pixf);

m_ren.attach(m_renb);


m_renb.clear(agg::rgba8(255, 255, 255, 255));


m_ras.move_to_d(20.7, 34.15);

m_ras.line_to_d(398.23, 123.43);

m_ras.line_to_d(165.45, 401.87);


// Setting the attrribute (color) & Rendering

m_ren.color(agg::rgba8(80, 90, 60));

agg::render_scanlines(m_ras, m_sl, m_ren);

//============================================================




//------------------------------------------------------------ 

// Display the image. If the image is B-G-R-A (32-bits per pixel)

// one can use AlphaBlend instead of BitBlt. In case of AlphaBlend

// one also should clear the image with zero alpha, i.e. rgba8(0,0,0,0)


::BitBlt(

hdc,  

rt.left,      

rt.top,      

width,  

height, 

mem_dc,

0,

0,     

SRCCOPY

);


// Free resources 

::SelectObject(mem_dc, temp); 

::DeleteObject(bmp); 

::DeleteObject(mem_dc);


EndPaint(hWnd, &ps);

return;

}



注意

1 爲了能夠使用wxClientDC等wxDC派生類,需要包含頭文件wx/wx.h,否則在調用DrawText渲染字體的時候出現如下的編譯錯誤:DrawTextW不是wxClientDC 的成員


2 在使用了AGG渲染之後,沒有必要使用wxDC的派生類進行渲染。AGG渲染是首先在構建一張位圖,在此基礎上渲染完畢,進行圖像的粘貼,如果要使用wxClientDC,會造成閃爍,如果使用wxMemoryDC(也是構建一塊內存位圖,然後進行貼圖),也只能採用裁剪函數貼圖某一個區域,不可能進行混合渲染,否則會覆蓋已有的渲染,並且在拉伸窗口的過程中,發現AGG渲染成功,但是wxClientDC等看不到任何渲染的結果


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章