我使用SDL制作了一个小应用程序来显示一些精灵动画,并且效果很好。重要的是渲染必须尽可能平滑。
因为现在我需要一些GUI,所以我决定使用wxWidgets 3来创建相同的应用程序,但是现在我还可以在其中添加一些GUI元素,例如菜单,模式等。
进入wxWidget的Wiki后,我发现有多种方法可以绘制窗口。
例如:
我还发现了其他种类的类,例如“ 图形上下文类”,但我仍然不确定它们是否可以满足我的需求。
我的应用程序已经使用了一个内部缓冲区,只需要复制即可。
我的问题是,在wxWidgets上执行此操作的最合适方法是什么? 而且,该解决方案带来了多少性能/开销?
wxWidgets在窗口内绘制像素的不同方法之间的性能/开销有什么区别?为什么一个人使用OnPaint事件而其他人不使用。
答案 0 :(得分:1)
这是执行此操作的一种方法:
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/timer.h>
#include <wx/dcclient.h>
#include <wx/rawbmp.h>
///////////// Declarations
class MyFrame : public wxFrame
{
public:
MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
~MyFrame();
private:
// Event Handlers
void OnPaint( wxPaintEvent& event );
void OnTimer(wxTimerEvent& event);
// Helper function
void RebuildBufferAndRefresh();
// Private data
wxWindow* m_renderSurface;
int m_width;
int m_height;
wxBitmap m_bitmapBuffer;
wxTimer m_timer;
int m_curRGB;
unsigned char* m_pixelData;
};
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
wxDECLARE_APP(MyApp);
///////////// Implementation
MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
wxSize size, int style )
:wxFrame( parent, id, title, pos, size, style )
{
m_width=100;
m_height=100;
m_pixelData = new unsigned char[3*m_width*m_height];
m_renderSurface = new wxWindow(this, wxID_ANY, wxDefaultPosition,
wxSize(m_width,m_height));
m_renderSurface->SetBackgroundStyle(wxBG_STYLE_PAINT);
m_renderSurface->Bind(wxEVT_PAINT,&MyFrame::OnPaint,this);
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
bSizer->Add( m_renderSurface, 0 );
this->SetSizer( bSizer );
Layout();
m_timer.SetOwner(this);
m_timer.Start(17);
this->Bind(wxEVT_TIMER,&MyFrame::OnTimer,this);
m_curRGB=0;
}
MyFrame::~MyFrame()
{
m_timer.Stop();
delete[] m_pixelData;
}
void MyFrame::OnPaint( wxPaintEvent& event )
{
wxPaintDC dc(m_renderSurface);
if(m_bitmapBuffer.IsOk())
{
dc.DrawBitmap(m_bitmapBuffer,0,0);
}
}
void MyFrame::OnTimer(wxTimerEvent& event)
{
RebuildBufferAndRefresh();
}
void MyFrame::RebuildBufferAndRefresh()
{
// Build the pixel buffer here, for this simple example just set all
// pixels to the same value and then increment that value.
for ( int y = 0; y < m_height; ++y )
{
for ( int x = 0; x < m_width; ++x )
{
m_pixelData[3*y*m_width+3*x]=m_curRGB;
m_pixelData[3*y*m_width+3*x+1]=m_curRGB;
m_pixelData[3*y*m_width+3*x+2]=m_curRGB;
}
}
++m_curRGB;
if(m_curRGB>255)
{
m_curRGB=0;
}
// Now transfer the pixel data into a wxBitmap
wxBitmap b(m_width,m_height,24);
wxNativePixelData data(b);
if ( !data )
{
// ... raw access to bitmap data unavailable, do something else ...
return;
}
wxNativePixelData::Iterator p(data);
int curPixelDataLoc = 0;
for ( int y = 0; y < m_height; ++y )
{
wxNativePixelData::Iterator rowStart = p;
for ( int x = 0; x < m_width; ++x, ++p )
{
p.Red() = m_pixelData[curPixelDataLoc++];
p.Green() = m_pixelData[curPixelDataLoc++];
p.Blue() = m_pixelData[curPixelDataLoc++];
}
p = rowStart;
p.OffsetY(data, 1);
}
m_bitmapBuffer=b;
m_renderSurface->Refresh();
m_renderSurface->Update();
}
bool MyApp::OnInit()
{
MyFrame* frame = new MyFrame(NULL);
frame->Show();
return true;
}
wxIMPLEMENT_APP(MyApp);
这里的基本思想是将缓冲区复制到wxBitmap中,然后在绘制处理程序中绘制该位图。然后,通过调用“刷新”和“更新”来触发绘制处理程序。原因是系统还会出于各种原因(例如鼠标光标在渲染表面上运行)而调用paint方法。通过这种方式,可以为您和系统调用绘制一个位图以刷新表面。
在上面发布的简单示例中,我只是使用一个简单的计时器每秒大约调用60次RebuildBufferAndRefresh方法。您的应用程序可能会有更好的方法来确定何时需要刷新,而您可以使用该方法来调用RebuildBufferAndRefresh。
显然,大多数工作是在RebuildBufferAndRefresh方法中完成的。该方法分为三个部分。第一部分构建内部缓冲区。第二部分由于上述原因将缓冲区复制到wxBitmap中。第三部分只是调用刷新和更新,以强制重绘渲染表面。
也许有更好的方法来执行此操作,但是我认为这是最直接的wxWidgets-ey,它可以不断地将像素数据的缓冲区呈现到窗口。
关于这种方法需要多少开销,基本上是从缓冲区到位图的内存复制,但嵌套循环的效率不如真实内存复制。之后,绘制处理程序不执行任何操作,只绘制位图。这可能是通过对系统的后备缓冲区进行blit来完成的,并且应该相当快。希望对您有所帮助。