@asman, post #241
// init struct MsgPort* disp = CreateMsgPort(); struct MsgPort* safe = CreateMsgPort(); struct Bitmap* bm1 = AllocBitMap(320,200,32, BMF_CLEAR | BMF_DISPLAYABLE , &APP_screen->BitMap); struct Bitmap* bm2 = AllocBitMap(320,200,32, BMF_CLEAR | BMF_DISPLAYABLE , &APP_screen->BitMap); struct Bitmap* bm3 = AllocBitMap(320,200,32, BMF_CLEAR | BMF_DISPLAYABLE , &APP_screen->BitMap); struct ScreenBuffer* sb1 = AllocScreenBuffer(APP_screen, 0, SB_COPY_BITMAP ); struct ScreenBuffer* sb2 = AllocScreenBuffer(APP_screen, 0,SB_COPY_BITMAP ); struct ScreenBuffer* sb3 = AllocScreenBuffer(APP_screen, 0,SB_COPY_BITMAP ); sb1->sb_BitMap = bm1; sb2->sb_BitMap = bm2; sb3->sb_BitMap = bm3; sb1->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = safe; sb1->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = disp; sb2->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = safe; sb2->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = disp; sb3->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = safe; sb3->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = disp; // loop int frame = 0; LOOP { switch (frame) { case 0: { ChangeScreenBuffer(APP_screen, sb1); APTR handle = LockBitMapTags(sb2->sb_BitMap, LBMI_BASEADDRESS, (ULONG)&x_FBAddr2, TAG_DONE); UnLockBitMap(handle); // engine output buffer and render EM_prefs.output_buffer_32 = x_FBAddr2; EM_Update_And_Render(); } break; case 1: { ChangeScreenBuffer(APP_screen, sb2); APTR handle = LockBitMapTags(sb3->sb_BitMap, LBMI_BASEADDRESS, (ULONG)&x_FBAddr3, TAG_DONE); UnLockBitMap(handle); // engine output buffer and render EM_prefs.output_buffer_32 = x_FBAddr3; EM_Update_And_Render(&APP_main_loop); } break; case 2: { ChangeScreenBuffer(APP_screen, sb3); APTR handle = LockBitMapTags(sb1->sb_BitMap, LBMI_BASEADDRESS, (ULONG)&x_FBAddr1, TAG_DONE); UnLockBitMap(handle); // engine output buffer and render EM_prefs.output_buffer_32 = x_FBAddr1; EM_Update_And_Render(&APP_main_loop); } break; } frame++; if (frame> 2) frame= 0; }
@mateusz_s, post #242
@mateusz_s, post #242
// INICJALIZACJA // create two message ports struct MsgPort* APP_port_disp = CreateMsgPort(); struct MsgPort* APP_port_safe = CreateMsgPort(); // declare Screen Buffer structure struct ScreenBuffer* APP_screen_buffer[3]; // first buffer - the bitmap won't be allocated - it will use screens bitmap APP_screen_buffer[0] = AllocScreenBuffer(APP_screen, NULL, SB_SCREEN_BITMAP); // second and third buffer - the bitmaps will be allocated APP_screen_buffer[1] = AllocScreenBuffer(APP_screen, NULL, 0); APP_screen_buffer[2] = AllocScreenBuffer(APP_screen, NULL, 0); // for some reason AllocScreenBuffer() doesn't want to correct allocate BitMap for it - so we doing this manually for Screen Buffers 1 and 2. struct BitMap* bitmap_1 = AllocBitMap(320,200,32,BMF_DISPLAYABLE , &APP_screen->BitMap ); FreeBitMap(APP_screen_buffer[1]->sb_BitMap); APP_screen_buffer[1]->sb_BitMap = bitmap_1; struct BitMap* bitmap_2 = AllocBitMap(320,200,32,BMF_DISPLAYABLE , &APP_screen->BitMap ); FreeBitMap(APP_screen_buffer[2]->sb_BitMap); APP_screen_buffer[2]->sb_BitMap = bitmap_2; // link with message ports for (int i = 0; i < 3; i++) { APP_screen_buffer[i]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = APP_port_disp; APP_screen_buffer[i]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = APP_port_safe; } // init buffer switcher int APP_current_frame_buffer = 1; int APP_next_frame_buffer = 2; // PETLA while (APP_main_loop) { if (ChangeScreenBuffer(APP_screen, APP_screen_buffer[APP_current_frame_buffer])) { // increment APP_current_frame_buffer APP_current_frame_buffer++; if (APP_current_frame_buffer > 2) APP_current_frame_buffer = 0; } APTR handle = LockBitMapTags(APP_screen_buffer[APP_next_frame_buffer]->sb_BitMap, LBMI_BASEADDRESS, (ULONG)&EM_prefs.output_buffer_32, TAG_DONE); if (handle) { EM_Update_And_Render(&APP_main_loop); // increment APP_next_frame_buffer APP_next_frame_buffer++; if (APP_next_frame_buffer > 2) APP_next_frame_buffer = 0; } UnLockBitMap(handle); }
@asman, post #241
@teh_KaiN, post #245
@Don_Adan, post #246
@asman, post #247
/* :ts=8 * doublebuffer.c - shows double-buffering, attached screens, menu lending * * (c) Copyright 1992 Commodore-Amiga, Inc. All rights reserved. * * This software is provided as-is and is subject to change; no warranties * are made. All use is at your own risk. No liability or responsibility * is assumed. * * Example shows use of V39 double-buffering functions to achieve * 60 frame-per-second animation. Also shows use of menus in * double-buffered screens, and the use of attached screens with * menu-lending to achieve the appearance of slider gadgets in * double-buffered screens. * */ /*----------------------------------------------------------------------*/ #include <exec/types.h> #include <graphics/displayinfo.h> #include <intuition/intuition.h> #include <proto/exec.h> #include <proto/graphics.h> #include <proto/intuition.h> #include <proto/Picasso96.h> #include <stdio.h> #include <stdlib.h> /*----------------------------------------------------------------------*/ STRPTR init_all( void ); void error_exit( STRPTR errorstring ); BOOL handleIntuiMessage( struct IntuiMessage *imsg ); void handleDBufMessage( struct Message *dbmsg ); ULONG handleBufferSwap( void ); struct BitMap *makeImageBM( void ); void CloseWindowSafely( struct Window *win ); int CXBRK( void ) {return( 0 );} /*----------------------------------------------------------------------*/ /* Some constants to handle the rendering of the animated face */ #define BM_WIDTH 80 #define BM_HEIGHT 80 #define BM_DEPTH 2 /* Odd numbers to give a non-repeating bounce */ ULONG SC_ID = INVALID_ID; /*----------------------------------------------------------------------*/ UWORD pens[] = { 0, /* DETAILPEN */ 1, /* BLOCKPEN */ 1, /* TEXTPEN */ 2, /* SHINEPEN */ 1, /* SHADOWPEN */ 3, /* FILLPEN */ 1, /* FILLTEXTPEN */ 0, /* BACKGROUNDPEN */ 2, /* HIGHLIGHTTEXTPEN */ 1, /* BARDETAILPEN */ 2, /* BARBLOCKPEN */ 1, /* BARTRIMPEN */ (UWORD)~0, }; struct Screen *canvassc = NULL; struct Window *canvaswin = NULL; /*----------------------------------------------------------------------*/ #define OK_REDRAW 1 /* Buffer fully detached, ready for redraw */ #define OK_SWAPIN 2 /* Buffer redrawn, ready for swap-in */ struct GfxBase *GfxBase = NULL; struct IntuitionBase *IntuitionBase = NULL; struct MsgPort *dbufport = NULL; struct MsgPort *userport = NULL; struct ScreenBuffer *scbuf[] = { NULL, NULL }; struct RastPort rport[2]; ULONG status[2]; LONG prevx[2] = { 50, 50 }; LONG prevy[2] = { 50, 50 }; ULONG buf_current, buf_nextdraw, buf_nextswap; ULONG count; struct BitMap *face = NULL; LONG x, y, xstep, xdir, ystep, ydir; /*----------------------------------------------------------------------*/ main() { STRPTR errorstring; ULONG sigs; BOOL terminated = FALSE; SC_ID = p96RequestModeIDTags(TAG_DONE); /* Let's get everything initialized */ if ( errorstring = init_all()){ error_exit( errorstring ); } count = 0; buf_current = 0; buf_nextdraw = 1; buf_nextswap = 1; sigs = 0; while ( !terminated ) { /* Check for and handle any IntuiMessages */ if(sigs & (1 << userport->mp_SigBit)){ struct Message *imsg; while(imsg = GetMsg(userport)){ terminated |= handleIntuiMessage((struct IntuiMessage *)imsg); ReplyMsg(imsg); } } /* Check for and handle any double-buffering messages. * Note that double-buffering messages are "replied" to * us, so we don't want to reply them to anyone. */ if(sigs & (1 << dbufport->mp_SigBit)){ struct Message *dbmsg; while(dbmsg = GetMsg(dbufport)){ handleDBufMessage(dbmsg); } } if ( !terminated ) { ULONG held_off = 0; /* Only handle swapping buffers if count is non-zero */ if ( count ) { held_off = handleBufferSwap(); } if ( held_off ) { /* If were held-off at ChangeScreenBuffer() time, then we * need to try ChangeScreenBuffer() again, without awaiting * a signal. We WaitTOF() to avoid busy-looping. */ WaitTOF(); } else { /* If we were not held-off, then we're all done * with what we have to do. We'll have no work to do * until some kind of signal arrives. This will normally * be the arrival of the dbi_SafeMessage from the ROM * double-buffering routines, but it might also be an * IntuiMessage. */ sigs = Wait( ( 1 << dbufport->mp_SigBit ) | ( 1 << userport->mp_SigBit ) ); } } } error_exit( NULL ); } /*----------------------------------------------------------------------*/ /* Handle the rendering and swapping of the buffers */ ULONG handleBufferSwap( void ) { ULONG held_off = 0; /* 'buf_nextdraw' is the next buffer to draw into. * The buffer is ready for drawing when we've received the * dbi_SafeMessage for that buffer. Our routine to handle * messaging from the double-buffering functions sets the * OK_REDRAW flag when this message has appeared. * * Here, we set the OK_SWAPIN flag after we've redrawn * the imagery, since the buffer is ready to be swapped in. * We clear the OK_REDRAW flag, since we're done with redrawing */ if ( status[ buf_nextdraw ] == OK_REDRAW ) { x += xstep*xdir; if ( x < 0 ) { x = 0; xdir = 1; } else if ( x > canvassc->Width - BM_WIDTH ) { x = canvassc->Width - BM_WIDTH - 1; xdir = -1; } y += ystep*ydir; if ( y < canvassc->BarLayer->Height ) { y = canvassc->BarLayer->Height; ydir = 1; } else if ( y >= canvassc->Height - BM_HEIGHT ) { y = canvassc->Height - BM_HEIGHT - 1; ydir = -1; } /* SetAPen( &rport[ buf_nextdraw ], 0 ); RectFill( &rport[ buf_nextdraw ], prevx[ buf_nextdraw ], prevy[ buf_nextdraw ], prevx[ buf_nextdraw ] + BM_WIDTH - 1, prevy[ buf_nextdraw ] + BM_HEIGHT - 1 ); */ prevx[ buf_nextdraw ] = x; prevy[ buf_nextdraw ] = y; BltBitMapRastPort(face, 0, 0, &rport[buf_nextdraw], x, y, BM_WIDTH, BM_HEIGHT, 0xc0); // WaitBlit(); /* Gots to let the BBMRP finish */ status[ buf_nextdraw ] = OK_SWAPIN; /* Toggle which the next buffer to draw is. * If you're using multiple ( >2 ) buffering, you * would use * * buf_nextdraw = ( buf_nextdraw+1 ) % NUMBUFFERS; * */ buf_nextdraw ^= 1; } /* Let's make sure that the next frame is rendered before we swap... */ if ( status[ buf_nextswap ] == OK_SWAPIN ) { scbuf[ buf_nextswap ]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = dbufport; if ( ChangeScreenBuffer( canvassc, scbuf[ buf_nextswap ] ) ) { status[ buf_nextswap ] = 0; buf_current = buf_nextswap; /* Toggle which the next buffer to swap in is. * If you're using multiple ( >2 ) buffering, you * would use * * buf_nextswap = ( buf_nextswap+1 ) % NUMBUFFERS; * */ buf_nextswap ^= 1; count--; } else { held_off = 1; } } return( held_off ); } /*----------------------------------------------------------------------*/ /* Handle Intuition messages */ BOOL handleIntuiMessage( struct IntuiMessage *imsg ) { UWORD code = imsg->Code; BOOL terminated = FALSE; switch ( imsg->Class ) { case IDCMP_VANILLAKEY: switch ( code ) { case 'S': case 's': count = 1; break; case 'R': case 'r': count = ~0; break; case 'Q': case 'q': count = 0; terminated = TRUE; break; } break; } return( terminated ); } /*----------------------------------------------------------------------*/ void handleDBufMessage( struct Message *dbmsg ) { ULONG buffer; /* dbi_SafeMessage is followed by an APTR dbi_UserData1, which * contains the buffer number. This is an easy way to extract * it. * The dbi_SafeMessage tells us that it's OK to redraw the * in the previous buffer. */ buffer = ( ULONG ) *( ( APTR ** ) ( dbmsg+1 ) ); /* Mark the previous buffer as OK to redraw into. * If you're using multiple ( >2 ) buffering, you * would use * * ( buffer + NUMBUFFERS - 1 ) % NUMBUFFERS * */ status[ buffer^1 ] = OK_REDRAW; } /*----------------------------------------------------------------------*/ /* Get the resources and objects we need */ STRPTR init_all( void ) { if ( !( GfxBase = ( struct GfxBase * ) OpenLibrary( "graphics.library", 39L ) ) ) { return( "Couldn't open Gfx V39\n" ); } if ( !( IntuitionBase = ( struct IntuitionBase * ) OpenLibrary( "intuition.library", 39L ) ) ) { return( "Couldn't open Intuition V39\n" ); } if ( !( dbufport = CreateMsgPort() ) ) { return( "Failed to create port\n" ); } if ( !( userport = CreateMsgPort() ) ) { return( "Failed to create port\n" ); } if ( !( canvassc = OpenScreenTags( NULL, SA_DisplayID, SC_ID, SA_Overscan, OSCAN_TEXT, SA_Depth, 2, SA_AutoScroll, 1, SA_Pens, pens, SA_ShowTitle, TRUE, SA_Title, "Intuition double-buffering example", SA_SysFont, 1, TAG_DONE ) ) ) { return( "Couldn't open screen\n" ); } if ( !( canvaswin = OpenWindowTags( NULL, WA_NoCareRefresh, TRUE, WA_Activate, TRUE, WA_Borderless, TRUE, WA_Backdrop, TRUE, WA_CustomScreen, canvassc, WA_NewLookMenus, TRUE, TAG_DONE ) ) ) { return( "Couldn't open window\n" ); } canvaswin->UserPort = userport; ModifyIDCMP( canvaswin, IDCMP_MENUPICK | IDCMP_VANILLAKEY ); if ( !( scbuf[ 0 ] = AllocScreenBuffer( canvassc, NULL, SB_SCREEN_BITMAP ) ) ) { return( "Couldn't allocate ScreenBuffer 1\n" ); } if ( !( scbuf[ 1 ] = AllocScreenBuffer( canvassc, NULL, SB_COPY_BITMAP ) ) ) { return( "Couldn't allocate ScreenBuffer 2\n" ); } /* Let's use the UserData to store the buffer number, for * easy identification when the message comes back. */ scbuf[ 0 ]->sb_DBufInfo->dbi_UserData1 = ( APTR ) ( 0 ); scbuf[ 1 ]->sb_DBufInfo->dbi_UserData1 = ( APTR ) ( 1 ); status[ 0 ] = OK_REDRAW; status[ 1 ] = OK_REDRAW; if ( !( face = makeImageBM() ) ) { return( "Couldn't allocate image bitmap\n" ); } InitRastPort( &rport[ 0 ] ); InitRastPort( &rport[ 1 ] ); rport[ 0 ].BitMap = scbuf[ 0 ]->sb_BitMap; rport[ 1 ].BitMap = scbuf[ 1 ]->sb_BitMap; Move(&rport[0], canvassc->Width - 50, 9); Text(&rport[0], "1", 1); Move(&rport[1], canvassc->Width - 40, 9); Text(&rport[1], "2", 1); x = 50; y = 70; xstep = 1; xdir = 1; ystep = 1; ydir = -1; /* All is OK */ return( 0 ); } /*----------------------------------------------------------------------*/ /* Draw a crude "face" for animation */ #define MAXVECTORS 10 struct BitMap *makeImageBM( void ) { struct BitMap *bm; struct RastPort rport; struct AreaInfo area; struct TmpRas tmpRas; PLANEPTR planePtr; BYTE areabuffer[ MAXVECTORS*5 ]; if(bm = (struct BitMap *)AllocBitMap(BM_WIDTH, BM_HEIGHT, BM_DEPTH, BMF_CLEAR, scbuf[ 0 ]->sb_BitMap)){ if(planePtr = AllocRaster(BM_WIDTH, BM_HEIGHT)){ InitRastPort(&rport); rport.BitMap = bm; InitArea(&area, areabuffer, MAXVECTORS); rport.AreaInfo = &area; InitTmpRas(&tmpRas, planePtr, RASSIZE(BM_WIDTH, BM_HEIGHT)); rport.TmpRas = &tmpRas; SetABPenDrMd(&rport, 3, 0, JAM1); AreaEllipse(&rport, BM_WIDTH/2, BM_HEIGHT/2, BM_WIDTH/2-4, BM_HEIGHT/2-4); AreaEnd(&rport); SetAPen(&rport, 2); AreaEllipse(&rport, 5*BM_WIDTH/16, BM_HEIGHT/4, BM_WIDTH/9, BM_HEIGHT/9); AreaEllipse(&rport, 11*BM_WIDTH/16, BM_HEIGHT/4, BM_WIDTH/9, BM_HEIGHT/9); AreaEnd(&rport); SetAPen(&rport, 1); AreaEllipse(&rport, BM_WIDTH/2, 3*BM_HEIGHT/4, BM_WIDTH/3, BM_HEIGHT/9); AreaEnd(&rport); FreeRaster(planePtr, BM_WIDTH, BM_HEIGHT); }else{ FreeBitMap(bm); bm = NULL; } return(bm); } } /*----------------------------------------------------------------------*/ /* Clean up everything and exit, printing the errorstring if any */ void error_exit(STRPTR errorstring) { if(canvaswin){ ClearMenuStrip(canvaswin); CloseWindowSafely(canvaswin); } if(canvassc){ FreeScreenBuffer(canvassc, scbuf[1]); FreeScreenBuffer(canvassc, scbuf[0]); CloseScreen(canvassc); } if(dbufport) DeleteMsgPort(dbufport); if(userport) DeleteMsgPort(userport); if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase); if(face) FreeBitMap(face); if(GfxBase) CloseLibrary((struct Library *)GfxBase); if(errorstring){ printf(errorstring); exit(20); } exit(0); } /*----------------------------------------------------------------------*/ void StripIntuiMessages( struct MsgPort *mp, struct Window *win ); /* these functions close an Intuition window * that shares a port with other Intuition * windows or IPC customers. * * We are careful to set the UserPort to * null before closing, and to free * any messages that it might have been * sent. */ #include "exec/types.h" #include "exec/nodes.h" #include "exec/lists.h" #include "exec/ports.h" #include "intuition/intuition.h" void CloseWindowSafely( struct Window *win ) { /* we forbid here to keep out of race conditions with Intuition */ Forbid(); /* send back any messages for this window * that have not yet been processed */ StripIntuiMessages( win->UserPort, win ); /* clear UserPort so Intuition will not free it */ win->UserPort = NULL; /* tell Intuition to stop sending more messages */ ModifyIDCMP( win, 0L ); /* turn multitasking back on */ Permit(); /* and really close the window */ CloseWindow( win ); } /* remove and reply all IntuiMessages on a port that * have been sent to a particular window * ( note that we don't rely on the ln_Succ pointer * of a message after we have replied it ) */ void StripIntuiMessages( mp, win ) struct MsgPort *mp; struct Window *win; { struct IntuiMessage *msg; struct Node *succ; msg = ( struct IntuiMessage * ) mp->mp_MsgList.lh_Head; while( succ = msg->ExecMessage.mn_Node.ln_Succ ) { if( msg->IDCMPWindow == win ) { /* Intuition is about to free this message. * Make sure that we have politely sent it back. */ Remove( ( struct Node * )msg ); ReplyMsg( ( struct Message * )msg ); } msg = ( struct IntuiMessage * ) succ; } } /*----------------------------------------------------------------------*/
@mateusz_s, post #250
@jimiche, post #255
@mateusz_s, post #257
@arturB, post #258
@mateusz_s, post #259
@mateusz_s, post #260
@mateusz_s, post #261
@BULI, post #263
@mateusz_s, post #268