In the previous two parts of the series, we have covered
how to set up the BREW environment, write basic applications and test them on
the cellphone. This time we will cover more advanced topics, and see how to draw
graphics, use sounds and set up timers and such for applications that require
it.
|
Setting up the basic code
The first thing that we need to do before we start writing the code for
drawing the graphics is to set up the application structure. This is needed
because, for example, all drawing functions in BREW will require a pointer to
the display device. This pointer, and several others are included in the
application structure and put in a header file, usually to be initialized on the
start of the application and destroyed when the application closes.
Here is the code for the header file that we will use for
our brew3 project:
// brew3.h
/* Application structure */
typedef struct _CIbrew3 {
AEEApplet
a;
AEEDeviceInfo
m_deviceInfo;
IGraphics*
m_pIGraphics;
} CIbrew3;
This is a small header file, but will serve our purpose
well for now. Remember that for complex applications, you will mostly end up
keeping persistent data in this structure as well. Below is the code for brew3.c
that contains all our actual functions.
/* FILE: brew3.c */
#include "AEEModGen.h"
// Module interface definitions
#include "AEEAppGen.h"
// Applet interface definitions
#include "AEEShell.h"
// Shell interface definitions
#include "AEEStdLib.h"
// Standard libray
#include "AEEGraphics.h"
// Graphics interface definitions
#include "brew3.bid" // Binary class id
#include "brew3.h"
static boolean
brew3_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam, uint32 dwParam);
static boolean brew3_InitObjects(CIbrew3* pApp);
static void brew3_CleanObjects(CIbrew3* pApp);
static void brew3_DrawScreen(CIbrew3* pApp);
int
AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po,void ** ppObj)
{
*ppObj = NULL;
if(ClsId == AEECLSID_BREW3){
if(AEEApplet_New(sizeof(CIbrew3), ClsId,
pIShell,po,(IApplet**)ppObj, (AEEHANDLER)brew3_HandleEvent,
(PFNFREEAPPDATA)brew3_CleanObjects) == TRUE)
return(AEE_SUCCESS);
}
return (EFAILED);
}
static boolean
brew3_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam, uint32 dwParam)
{
CIbrew3* pApp
= NULL; // Applet pointer
pApp =
(CIbrew3*)pi;
if (pApp ==
NULL)
return FALSE;
switch (eCode)
{
case EVT_APP_START:
if (!brew3_InitObjects(pApp))
return FALSE;
brew3_DrawScreen(pApp);
return(TRUE);
case EVT_APP_STOP:
return TRUE;
default:
break;
}
return FALSE;
}
static boolean
brew3_InitObjects(CIbrew3* pApp) {
int nRet=0;
// Create graphics object
nRet =
ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_GRAPHICS, (void **)&pApp->m_pIGraphics);
if (nRet !=
SUCCESS)
return FALSE;
// Get device info
ISHELL_GetDeviceInfo(pApp->a.m_pIShell,
&pApp->m_deviceInfo);
return TRUE;
}
static void
brew3_CleanObjects(CIbrew3* pApp) {
// Release
graphics object
if (pApp->m_pIGraphics
!= NULL) {
IGRAPHICS_Release(pApp->m_pIGraphics);
pApp->m_pIGraphics = NULL;
}
}
static void
brew3_DrawScreen(CIbrew3* pApp) {
AEERect Rect;
IDISPLAY_ClearScreen(pApp->a.m_pIDisplay);
Rect.x = 5;
Rect.y = 5;
Rect.dx =
pApp->m_deviceInfo.cxScreen - 10;
Rect.dy =
pApp->m_deviceInfo.cyScreen - 10;
IDISPLAY_DrawRect(pApp->a.m_pIDisplay, &Rect,
MAKE_RGB(0,0,255), 0, IDF_RECT_FRAME);
IDISPLAY_Update(pApp->a.m_pIDisplay);
}
Long as it is, all it does is draw a blue border along the
border of the screen of the cellphone. Most of the code that we have put here is
necessary for the functioning of the simplest of applications, and you can build
functionality on top of this quite easily. If you trace the code, you will see
that it is the 'brew3_DrawScreen()' function that is doing the drawing. To
make our program draw other objects, we only need to modify this code. We have
initialized the pointer to the graphics interface, but haven't used it. The
rectangle function we have used does not need it, but many other graphics
functions require it. Following is a list of useful graphics functions.
IGRAPHICS_SetBackground: Sets the screen background
color
IGRAPHICS_SetClip: Sets the clipping rectangle. Any graphic updates
outside this rectangle do not take effect.
IGRAPHICS_StretchBlt: Draws an image by stretching it to fit a rectangle
IDISPLAY_BitBlt: Same as IGRAPHICS_StretchBlt, but with no stretching,
but faster
IDISPLAY_ClearScreen: Clears the screen
IDISPLAY_Update: Updates the screen after a graphics call.
Otherwise there is big a chance that the screen will remain in its previous
state
IDISPLAY_FillRect: Fills a rectangle with color
Setting up timers
Threads do not exist in BREW. This is faked using timers. Timers set up a time
delay after which a function is automatically called. For instance, consider
that you have a ball bouncing around the screen and a score running of how many
bounces it has had. After drawing the screen, you would call the function
that updates the ball position after a short delay by setting up a timer, and
meanwhile update the score if necessary. The function used to set timers is 'ISHELL_SetTimer'.
As arguments, it will take a pointer to the shell, the time delay in
milliseconds, name of the function to call, and the data that needs to be passed
to the function. 'ISHELL_CancelTimer' can be used to cancel any or all
timers in an application.
Using sound
Sound plays an important role in games and applications on cellphones. The
sound interface is also used for vibration, but that is something which is
ill-advised, since most BREW implementations of vibration differ from each other
and is difficult to standardize for. To play sounds, use the
'ISOUNDPLAYER_SetInfo' function to set the source and other settings. You
need to register a callback function (which periodically gets the status of
sound playback) using “ISOUNDPLAYER_RegisterNotify' and then actually play
using 'ISOUNDPLAYER_Play'.
Anuj Jain