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