/***************************************************************************** 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 lines that bounce off the window edges. *****************************************************************************/ #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 = "Moire 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 *); FLOAT X1Speed, Y1Speed, X2Speed, Y2Speed; WORD LineRed, LineGreen, LineBlue; LONG RenderWidth, RenderHeight; OBJECTID glRenderID = NULL, glWindowID = NULL; #define AMT_LINES 20 struct Line { FLOAT X1; FLOAT Y1; FLOAT X2; FLOAT Y2; }; struct Line lines[AMT_LINES]; /***************************************************************************** ** Main. */ void program(void) { OBJECTPTR window; LONG topmargin, bottommargin, rightmargin, leftmargin; APTR *actions; print(ProgName); print(ProgCopyright); /*** Intercept some actions that are required for our program ***/ if (GetField(CurrentTask(), FID_Actions, FT_POINTER, &actions) IS ERR_Okay) { actions[AC_ActionNotify] = PROGRAM_ActionNotify; actions[AC_Timer] = PROGRAM_Timer; } 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", TAGEND) IS ERR_Okay) { /*** Get the window margins ***/ GetFields(window, FID_LeftMargin|TLONG, &leftmargin, FID_TopMargin|TLONG, &topmargin, FID_BottomMargin|TLONG, &bottommargin, FID_RightMargin|TLONG, &rightmargin, TAGEND); ReleaseObject(window); /*** Create a render area for drawing graphics inside the window ***/ if (CreateObject(ID_RENDER, NULL, NULL, &glRenderID, FID_Owner|TLONG, glWindowID, FID_XCoord|TLONG, leftmargin, FID_YCoord|TLONG, topmargin, FID_XOffset|TLONG, rightmargin, FID_YOffset|TLONG, bottommargin, TAGEND) IS ERR_Okay) { demo(); } } } /***************************************************************************** ** 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, TAGEND); RenderWidth = render->Width; RenderHeight = render->Height; /*** Show the Render object ***/ Action(AC_Show, render, NULL); ReleaseObject(render); } /*** Initialise line data ***/ lines[0].X1 = RandomNumber(100); lines[0].Y1 = RandomNumber(100); lines[0].X2 = RandomNumber(100); lines[0].Y2 = RandomNumber(100); LineRed = 100 + RandomNumber(156); LineGreen = 100 + RandomNumber(156); LineBlue = 100 + RandomNumber(156); for (i=1; i < AMT_LINES; i++) { lines[i].X1 = lines[0].X1; lines[i].Y1 = lines[0].Y1; lines[i].X2 = lines[0].X2; lines[i].Y2 = lines[0].Y2; } X1Speed = ((FLOAT)RandomNumber(7000))/1000 + 2; X2Speed = ((FLOAT)RandomNumber(7000))/1000 + 2; Y1Speed = ((FLOAT)RandomNumber(7000))/1000 + 2; Y2Speed = ((FLOAT)RandomNumber(7000))/1000 + 2; /*** 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). */ SetResource(RES_MESSAGEHANDLER, (LARGE)&msghandler); ProcessMessages(NULL, MF_WAIT); /*** Unsubscribe from the system timer ***/ UnsubscribeTimer(CurrentTaskID()); } /***************************************************************************** ** Program: ActionNotify() */ ERROR PROGRAM_ActionNotify(OBJECTPTR Self, struct acActionNotify *Args) { LONG i; if ((Args->ActionID IS AC_Draw) AND (Args->Error IS ERR_Okay)) { struct mtDrawRGBLine line; struct Bitmap *Bitmap; OBJECTPTR Drawable; if (AccessObject(Args->ObjectID, 0, &Drawable) IS ERR_Okay) { if (GetFields(Drawable, FID_Bitmap|TPTR, &Bitmap, FID_Width|TLONG, &RenderWidth, FID_Height|TLONG, &RenderHeight, TAGEND) IS ERR_Okay) { Action(AC_Clear, Bitmap, NULL); for (i=AMT_LINES-1; i >= 0; i--) { line.XCoord = lines[i].X1; line.YCoord = lines[i].Y1; line.XEnd = lines[i].X2; line.YEnd = lines[i].Y2; line.Red = (LineRed / AMT_LINES) * (AMT_LINES-i); line.Green = (LineGreen / AMT_LINES) * (AMT_LINES-i); line.Blue = (LineBlue / AMT_LINES) * (AMT_LINES-i); Action(MT_DrawRGBLine, Bitmap, &line); } } ReleaseObject(Drawable); } } 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 line ** positions and then issue a redraw call. */ ERROR PROGRAM_Timer(OBJECTPTR Self, struct acTimer *Args) { LONG i; for (i=AMT_LINES-1; i > 0; i--) { lines[i].X1 = lines[i-1].X1; lines[i].Y1 = lines[i-1].Y1; lines[i].X2 = lines[i-1].X2; lines[i].Y2 = lines[i-1].Y2; } lines[0].X1 += X1Speed; lines[0].Y1 += Y1Speed; lines[0].X2 += X2Speed; lines[0].Y2 += Y2Speed; if (lines[0].X1 < 0) { lines[0].X1 = 0; X1Speed = (((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].Y1 < 0) { lines[0].Y1 = 0; Y1Speed = (((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].X2 < 0) { lines[0].X2 = 0; X2Speed = (((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].Y2 < 0) { lines[0].Y2 = 0; Y2Speed = (((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].X1 > RenderWidth - 1) { lines[0].X1 = RenderWidth-1; X1Speed = -(((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].Y1 > RenderHeight - 1) { lines[0].Y1 = RenderHeight - 1; Y1Speed = -(((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].X2 > RenderWidth-1) { lines[0].X2 = RenderWidth-1; X2Speed = -(((FLOAT)RandomNumber(7000))/1000 + 2); } if (lines[0].Y2 > RenderHeight-1) { lines[0].Y2 = RenderHeight-1; Y2Speed = -(((FLOAT)RandomNumber(7000))/1000 + 2); } ActionMsg(AC_Draw, glRenderID, NULL); return(ERR_Okay); }