|
A problem about al_destory_bitmap function |
Quanwei Yuan
Member #14,752
December 2012
|
I put a bitmap pointer into this class 1class skyGUIEditBox : public skyGUIObject{
2public:
3 skyGUIEditBox(int _id,int _w,int _h,float _x,float _y,ALLEGRO_FONT * _fnt,ALLEGRO_DISPLAY* _dispaly);
4 ~skyGUIEditBox();
5 void SetText(const wchar_t* _text);
6 const wchar_t* GetText();
7
8 void Focus(bool bFocused);
9 void Render();
10 void Update(double dt,ALLEGRO_EVENT * _event=0);
11private:
12 void OnKey( UINT nKey, UINT nRepCnt, UINT nFlags );
13 void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );
14 void InsertChar(wchar_t aChar);
15 void DeleteChar(TDP aPos);
16 void ClearCookie();
17
18private:
19 int m_wdith;
20 int m_height;
21 ALLEGRO_FONT *m_fnt;
22 ALLEGRO_USTR *m_str;
23 ALLEGRO_BITMAP *m_bg; //I put a bitmap pointer into this class
24 wchar_t m_textbuff[1024];
25 UINT m_charpos;
26 bool m_posI;
27 bool m_gposI;
28 static LRESULT CALLBACK SkyEditWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
29};
Then, in the constructor to initialize it 1skyGUIEditBox::skyGUIEditBox(int _id,int _w,int _h,float _x,float _y,ALLEGRO_FONT * _fnt,ALLEGRO_DISPLAY* _dispaly)
2{
3
4 id=_id;
5
6 bStatic=false;
7 m_wdith=_w;
8 m_height=_h;
9 bVisible=true;
10 bEnabled=true;
11 rect.Set(_x, _y, _x+_w, _y+_h);
12 m_fnt=_fnt;
13 m_charpos=0;
14 m_gposI=false;
15 HWND hWnd = al_get_win_window_handle(_dispaly);
16
17 if (g_LastWndProc == NULL)
18 {
19 g_LastWndProc = (WNDPROC)::GetWindowLong(hWnd,GWL_WNDPROC);
20 if(g_LastWndProc != (WNDPROC)::SetWindowLong(hWnd,GWL_WNDPROC,(LONG)SkyEditWndProc))throw NULL;
21 }
22 ClearCookie();
23 m_str=al_ustr_new_from_utf16((uint16_t*)m_textbuff);
24///////////////////////Here/////////////////////////////////////
25 m_bg=0;
26 m_bg=al_create_bitmap(_w,_h);
27 if(!m_bg)throw NULL;
28////////////////////////////////////////////////////////////////
29}
use it in following function 1void skyGUIEditBox::Render(){
2
3 al_set_target_bitmap(m_bg);
4 al_clear_to_color(al_map_rgba(0,0,0,0));
5 al_draw_ustr(m_fnt,color,1,1,0,m_str);
6 al_draw_rectangle(0,0,m_wdith,m_height,color,1.0f);
7 if(m_posI && m_gposI){
8 int f_height=al_get_font_line_height(m_fnt)-4;
9 int t_width =al_get_ustr_width(m_fnt,m_str);
10 int x1=t_width+1;
11 int y1=2;
12 int x2=x1;
13 int y2=y1+f_height;
14 al_draw_line(x1,y1,x2,y2,color,1.0f);
15 }
16 ALLEGRO_DISPLAY *dis=al_get_current_display();
17 al_set_target_bitmap(al_get_backbuffer(dis));
18 al_draw_bitmap(m_bg,rect.x1,rect.y1,0);
19}
but,when i destory it in destructor function, skyGUIEditBox::~skyGUIEditBox(){ if(m_bg){ al_destroy_bitmap(m_bg); } ClearCookie(); m_fnt=0; } The following error occurred: "Unhandled exception: 0xC0000005: read location 0x00000000 when an access violation occurs in the 0x645c4b16 at 地图编辑器.exe "
|
fallenlight12
Member #14,669
October 2012
|
That's easy. The reason this is happening is because it's destroying the bitmap after allegro has killed itself. At least that's what I think is happening. Something is making those bitmap pointers invalid. I had this happen when I was first starting out too. My solution evolved to "KillAllegro()" and to careful destruction of the bitmaps so they precede the end of main(). Basically, do not destroy bitmaps in the destructor of a class. Ideally, create all your images through the same routine and store a list of pointers to them. When the application terminates, destroy them one by one. Something (hacked together some code for you): 1#include <list>
2
3typedef std::list<ALLEGRO_BITMAP*> t_imglist;
4
5class myimages {
6public:
7 myimages(){}
8 ~myimages(){}
9
10 ALLEGRO_BITMAP * loadbitmap(const char *path);
11 void killbitmaps();
12private:
13 std::list<ALLEGRO_BITMAP*> m_img;
14}
15
16ALLEGRO_BITMAP * myimages::loadbitmap(const char *path)
17{
18 ALLEGRO_BITMAP * pbm=NULL;
19 if( !(pbm = al_load_bitmap(path)) ) {
20 // if you have log file then log it
21 return NULL;
22 }
23 // add the bitmap pointer to the list
24 m_img.push_back(pbm);
25
26 return pbm;
27}
28
29void myimages::killbitmaps()
30{
31 t_imglist::iterator pend = m_img.end();
32 for(t_imglist::iterator p1=m_img.begin(); p1 != pend; ++p1) {
33 al_destroy_bitmap(*p1);
34 }
35
36 m_img.clear();
37}
If I read what you wrote wrong, I'm sorry. I have to go to bed now. .
|
Kris Asick
Member #1,424
July 2001
|
I find it's generally not a good idea to put stuff related to Allegro into pointer destructors, since if Allegro shuts down before such a struct/class is destroyed then any calls to most Allegro functions will cause crashes. When it comes to bitmaps, what I like to do is load all of my bitmaps into global pointer arrays, then simply copy those pointers into my class/struct objects. When I shut down my program I simply destroy the bitmaps in their global arrays before closing out Allegro, thus meaning I can just completely ignore the outdated pointers in my class/struct objects. If you absolutely must load your bitmaps directly into your objects, (which is still a bad idea for other reasons, such as being a waste of memory if multiple objects load up identical bitmaps, or being difficult to reload if display conditions change), then what you can do is make sure all such objects are declared explicitly: skyGUIEditBox *SGUIEB = new skyGUIEditBox; Then, BEFORE you shut down Allegro at the end of your program: delete SGUIEB; Ideally though, you should load your bitmaps separate from your objects into a global array and simply copy the existing bitmap pointers into your objects. It'll save you a lot of trouble in the long run. --- Kris Asick (Gemini) |
Quanwei Yuan
Member #14,752
December 2012
|
Thank you fo your answer. |
Joachim Arting
Member #13,584
September 2011
|
I had the same problem recently. Something like fallelight12 wrote, but simpler: 1class CData
2{
3private:
4 ALLEGRO_BITMAP* image[IMG_AMT];
5 ...
6
7public:
8 ...
9 bool loadImages();
10 void destroyImages();
11};
12
13bool CData::loadImages()
14{
15 image[0] = al_load_bitmap( "data\\gfx\\image1.png" );
16 ...
17}
18
19void CData::destroyImages()
20{
21 for ( int i = 0; i < IMG_AMT; i++ )
22 {
23 al_destroy_bitmap( image[i] );
24 }
25}
26
27int main()
28{
29 initialize etc.
30 data.loadImages();
31
32 game loop
33 ...
34
35 exit game loop
36
37 data.destroyImages();
38 return 0;
39}
Not a perfect example, but you get the idea ------------------------------------------------------------------------------- |
Itachihro
Member #12,001
May 2010
|
I think it would be best to wrap Allegro in a C++ class to make it work better with automatic destruction. You could use unique_ptr, but I think a real wrapper may work better. |
|