/*****************************************************************************
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
#include
#include
#include
#include
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);
}