/***************************************************************************** This source code is made available to you under the terms of the Open Development License. This Package should be accompanied by a file that contains the associated licensing terms. If you are unable to find this file, please refer to its location on the Internet at www.rocklyte.com/license.html. ****************************************************************************** This program can be run from Athene or your native desktop environment. It opens a window that draws a series of faded circles when the mouse pointer is moved over the window area. *****************************************************************************/ #include <pandora/system/all.h> #include <pandora/graphics/all.h> #include <pandora/input/joyport.h> #include <pandora/functions/set.c> #include <pandora/startup.h> STRING ProgName = "Movement Demo"; STRING ProgAuthor = "Rocklyte Systems"; STRING ProgDate = "December 2003"; STRING ProgCopyright = "Copyright Rocklyte Systems (c) 2001-2003. All rights reserved."; LONG ProgDebug = 0; FLOAT ProgKernelVersion = 1.0; extern struct KernelBase *KernelBase; ERROR PROGRAM_ActionNotify(OBJECTPTR, struct acActionNotify *); ERROR PROGRAM_Timer(OBJECTPTR, struct acTimer *); void demo(void); ERROR msghandler(struct Message *); struct BitmapPen *Pen = 0; OBJECTID glRenderID = 0, glWindowID; #define AMT_ELEMENTS 10 #define COL_RED 255 #define COL_GREEN 80 #define COL_BLUE 80 struct Element { WORD XCoord; WORD YCoord; }; struct Element elements[AMT_ELEMENTS]; LONG ChangeCount = AMT_ELEMENTS; /***************************************************************************** ** Main. */ void program(void) { OBJECTPTR window; FLOAT top, bottom, right, left; APTR *actions; print(ProgName); print(ProgCopyright); if (GetField(CurrentTask(), FID_Actions, FT_POINTER, &actions) IS ERR_Okay) { actions[AC_ActionNotify] = PROGRAM_ActionNotify; actions[AC_Timer] = PROGRAM_Timer; } if (CreateObject(ID_PEN, NULL, &Pen, NULL, TAGEND) != ERR_Okay) goto exit; /*** Activate our message handler ***/ SetResource(RES_MESSAGEHANDLER, (LARGE)&msghandler); if (CreateObject(ID_WINDOW, NULL, &window, &glWindowID, FID_Title|TSTRING, ProgName, FID_InsideBorder|TLONG, TRUE, FID_InsideWidth|TLONG, 200, FID_InsideHeight|TLONG, 200, FID_Icon|TSTRING, "misc/cube", FID_Center|TLONG, TRUE, TAGEND) IS ERR_Okay) { GetFields(window, FID_LeftMargin|TFLOAT, &left, FID_TopMargin|TFLOAT, &top, FID_BottomMargin|TFLOAT, &bottom, FID_RightMargin|TFLOAT, &right, TAGEND); ReleaseObject(window); /*** Create a render area for drawing graphics inside the window ***/ if (CreateObject(ID_RENDER, NF_SHARED, NULL, &glRenderID, FID_Owner|TLONG, glWindowID, FID_XCoord|TFLOAT, left, FID_YCoord|TFLOAT, top, FID_XOffset|TFLOAT, right, FID_YOffset|TFLOAT, bottom, TAGEND) IS ERR_Okay) { demo(); } } exit: if (Pen) Action(AC_Free, Pen, NULL); } /***************************************************************************** ** Function: msghandler() ** ** This function is called by the system whenever it decides that we have ** messages that need to be processed. */ ERROR msghandler(struct Message *Message) { /* Return a terminate code if MSGID_QUIT is detected. This forces ** the ProcessMessages() function to break its processing and return. */ if (Message->Type IS MSGID_QUIT) return(ERR_Terminate); return(ERR_Failed); /* Return failure if message unrecognised */ } /***************************************************************************** ** Function: demo() */ void demo(void) { struct Render *render; LONG i; if (AccessObject(glRenderID, 3000, (OBJECTPTR *)&render) IS ERR_Okay) { /*** Subscribe to the Render object so that we can draw graphics ***/ SubscribeActionTags(render, CurrentTask(), AC_Draw, AC_UserMovement, TAGEND); /*** Show the Render object ***/ Action(AC_Show, render, NULL); ReleaseObject(render); } for (i=0; i < AMT_ELEMENTS; i++) { elements[0].XCoord = -10000; elements[0].YCoord = -10000; } /*** Subscribe to the system timer at a 50FPS rate ***/ SubscribeTimer(CurrentTaskID(), 20); ActionMsg(AC_Show, glWindowID, NULL); /* This is our main loop. Our program will sit and wait until the ** ProcessMessages() routine breaks (refer to the msghandler() routine ** to see how). */ ProcessMessages(NULL, MF_WAIT); /*** Unsubscribe from the system timer ***/ UnsubscribeTimer(CurrentTaskID()); } /***************************************************************************** ** Program: ActionNotify() */ static LONG glDrawableWidth, glDrawableHeight; ERROR PROGRAM_ActionNotify(OBJECTPTR Self, struct acActionNotify *Args) { if ((Args->ActionID IS AC_Draw) AND (Args->Error IS ERR_Okay)) { struct Bitmap *Bitmap; OBJECTPTR Drawable; LONG i, size, offset; if (AccessObject(Args->ObjectID, 0, &Drawable) IS ERR_Okay) { if (GetFields(Drawable, FID_Bitmap|TPTR, &Bitmap, FID_Width|TLONG, &glDrawableWidth, FID_Height|TLONG, &glDrawableHeight, TAGEND) IS ERR_Okay) { Action(AC_Clear, Bitmap, NULL); size = glDrawableWidth * 0.20; offset = 0; SetLong(Pen, FID_PenShape, PEN_ELLIPSE); Pen->TipSize = 1; Pen->Fill = TRUE; Pen->Bitmap = Bitmap; for (i=AMT_ELEMENTS-1; i >= 0; i--) { Pen->XCoord = elements[i].XCoord + offset - (size/2); Pen->YCoord = elements[i].YCoord + offset - (size/2); Pen->Width = (size * i) / AMT_ELEMENTS; Pen->Height = (size * i) / AMT_ELEMENTS; Pen->Red = (COL_RED * (AMT_ELEMENTS-i)) / AMT_ELEMENTS; Pen->Green = (COL_GREEN * (AMT_ELEMENTS-i)) / AMT_ELEMENTS; Pen->Blue = (COL_BLUE * (AMT_ELEMENTS-i)) / AMT_ELEMENTS; Action(AC_Draw, Pen, NULL); offset += (glDrawableWidth * 0.01); } } ReleaseObject(Drawable); } } else if ((Args->ActionID IS AC_UserMovement) AND (Args->Error IS ERR_Okay)) { struct acUserMovement *move; move = (struct acUserMovement *)Args->Args; if (move->OverObject IS glRenderID) { elements[0].XCoord = (WORD)(move->XCoord - 5); elements[0].YCoord = (WORD)(move->YCoord - 5); } else { elements[0].XCoord = -10000; elements[0].YCoord = -10000; } ChangeCount = AMT_ELEMENTS; } else if ((Args->ActionID IS AC_Free) AND (Args->ObjectID IS glRenderID)) { SendMessage(NULL, MSGID_QUIT, NULL, NULL, NULL); } return(ERR_Okay); } /***************************************************************************** ** Program: Timer ** ** This timer routine is called on a regular basis due to our earlier call to ** SubscribeTimer(). The purpose of this timer routine is to update the ** movement circles and then issue a redraw call. */ ERROR PROGRAM_Timer(OBJECTPTR Self, struct acTimer *Args) { LONG i; for (i=AMT_ELEMENTS-1; i > 0; i--) { elements[i].XCoord = elements[i-1].XCoord; elements[i].YCoord = elements[i-1].YCoord; } ChangeCount--; if (ChangeCount >= 0) ActionMsg(AC_Draw, glRenderID, NULL); return(ERR_Okay); }