#COMPILE EXE #DIM ALL 'Compress via: \work\upx304w\upx.exe -9 \work\graphicsplay\zenspritetest.exe #RESOURCE "zenspritetest.pbr" #INCLUDE ONCE "WIN32API.INC" #INCLUDE ONCE "COMMCTRL.INC" #INCLUDE ONCE "PBForms.INC" %IDD_DIALOG = 101 %IDC_GRAPHIC = 1001 %IDC_LAYERS = 1003 %IDC_BACKGROUND = 1004 %IDC_REARSPRITES = 1006 %IDC_FOREGROUNDSPRITES = 1007 %IDC_SNOW = 1008 %IDC_TITLETEXT = 1009 %MAXSNOW = 200 GLOBAL hDlg AS DWORD GLOBAL hImgBackground AS DWORD GLOBAL hImgAri AS DWORD GLOBAL hImgAriMask AS DWORD GLOBAL hImgTitle AS DWORD GLOBAL hImgTitleMask AS DWORD GLOBAL hImgSnowflake() AS DWORD GLOBAL hImgUfo() AS DWORD GLOBAL hImgUfoMask() AS DWORD GLOBAL hImgSnoverlay AS DWORD GLOBAL killThread AS LONG GLOBAL showBackground AS LONG GLOBAL showRear AS LONG GLOBAL showForeground AS LONG GLOBAL showTitle AS LONG GLOBAL showSnow AS LONG GLOBAL hasSnoverlay AS LONG DECLARE CALLBACK FUNCTION ShowDIALOGProc() DECLARE FUNCTION ShowDIALOG(BYVAL hParent AS DWORD) AS LONG FUNCTION PBMAIN() PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR %ICC_INTERNET_CLASSES) ShowDIALOG %HWND_DESKTOP END FUNCTION SUB initBMP() 'Load all the BMP files from the resource file... 'Note: ideally these would be compressed properly, and because none of them use alpha layers (they use separate map files), 'there is no reason why they couldn't be done in a MUCH more efficiant way. LOCAL ctr AS LONG GRAPHIC BITMAP NEW 544, 368 TO hImgSnoverlay GRAPHIC ATTACH hImgSnoverlay, 0 GRAPHIC CLEAR %RGB_BLACK, 0 hasSnoverlay = %FALSE GRAPHIC ATTACH hDlg, %IDC_GRAPHIC, REDRAW GRAPHIC BITMAP LOAD "IMG_BACKGROUND", 526, 850 TO hImgBackground GRAPHIC BITMAP LOAD "IMG_ARI", 90, 139 TO hImgAri GRAPHIC BITMAP LOAD "MASK_ARI", 90, 139 TO hImgAriMask GRAPHIC BITMAP LOAD "IMG_TITLE", 507, 145 TO hImgTitle GRAPHIC BITMAP LOAD "MASK_TITLE", 507, 145 TO hImgTitleMask REDIM hImgSnowflake(1 TO 10) AS DWORD REDIM hImgUfo(1 TO 3, 1 TO 10) AS DWORD REDIM hImgUfoMask(1 TO 3, 1 TO 10) AS DWORD FOR ctr = 1 TO 10 GRAPHIC BITMAP LOAD "SNOWFLAKE_" & FORMAT$(ctr), 10, 10 TO hImgSnowflake(ctr) GRAPHIC BITMAP LOAD "UFO_1_" & FORMAT$(ctr, "00") & "_IMAGE", 90, 38 TO hImgUfo(1, ctr) GRAPHIC BITMAP LOAD "UFO_1_" & FORMAT$(ctr, "00") & "_MASK", 90, 38 TO hImgUfoMask(1, ctr) GRAPHIC BITMAP LOAD "UFO_2_" & FORMAT$(ctr, "00") & "_IMAGE", 120, 45 TO hImgUfo(2, ctr) GRAPHIC BITMAP LOAD "UFO_2_" & FORMAT$(ctr, "00") & "_MASK", 120, 45 TO hImgUfoMask(2, ctr) GRAPHIC BITMAP LOAD "UFO_3_" & FORMAT$(ctr, "00") & "_IMAGE", 100, 34 TO hImgUfo(3, ctr) GRAPHIC BITMAP LOAD "UFO_3_" & FORMAT$(ctr, "00") & "_MASK", 100, 34 TO hImgUfoMask(3, ctr) NEXT END SUB SUB killBMP() 'This frees the memory being used by all the BMPs LOCAL ctr AS LONG, ctr2 AS LONG GRAPHIC ATTACH hImgSnoverlay, 0 GRAPHIC BITMAP END GRAPHIC ATTACH hImgBackground, 0 GRAPHIC BITMAP END GRAPHIC ATTACH hImgAri, 0 GRAPHIC BITMAP END GRAPHIC ATTACH hImgAriMask, 0 GRAPHIC BITMAP END GRAPHIC ATTACH hImgTitle, 0 GRAPHIC BITMAP END GRAPHIC ATTACH hImgTitleMask, 0 GRAPHIC BITMAP END FOR ctr = 1 TO 10 GRAPHIC ATTACH hImgSnowflake(ctr), 0 GRAPHIC BITMAP END FOR ctr2 = 1 TO 3 GRAPHIC ATTACH hImgUfo(ctr2, ctr), 0 GRAPHIC BITMAP END GRAPHIC ATTACH hImgUfoMask(ctr2, ctr), 0 GRAPHIC BITMAP END NEXT NEXT END SUB SUB drawBackground(offX AS LONG, offY AS LONG) 'This draws the seamless background LOCAL tempX AS LONG, tempY AS LONG 'Figure out where the pieces go tempX = offX MOD 526 tempY = offY IF tempY < 0 THEN tempY = 0 ELSEIF tempY > 480 THEN tempY = 480 END IF tempY = -tempY 'Draw the two (or sometimes one) images to make the never-ending background (Costa Rica if you're wondering) GRAPHIC COPY hImgBackground, 0 TO (tempX, tempY), %MIX_COPYSRC IF tempX > 0 THEN GRAPHIC COPY hImgBackground, 0 TO (tempX - 526, tempY), %MIX_COPYSRC ELSEIF offX < 0 THEN GRAPHIC COPY hImgBackground, 0 TO (tempX + 526, tempY), %MIX_COPYSRC END IF END SUB FUNCTION doStuff(BYVAL dummy AS DWORD) AS DWORD 'Animate all the layers; this thread runs non-stop LOCAL backX AS DOUBLE, backY AS DOUBLE, backDirX AS DOUBLE, backDirY AS DOUBLE LOCAL curX AS LONG, curY AS LONG, forespriteX AS DOUBLE, forespriteY AS DOUBLE LOCAL ctr AS LONG, X1 AS DOUBLE, Y1 AS DOUBLE, bgYmove AS DOUBLE LOCAL ufoInfo() AS DOUBLE, UFOctr() AS LONG, UFOdir() AS LONG, ufoFlipper() AS LONG, ufoSteps() AS LONG LOCAL cX AS LONG, cY AS LONG, ctr2 AS LONG LOCAL snowParticles() AS DOUBLE '1=x, 2=y, 3=speed, 4=angle LOCAL colorCheck AS LONG, foundHitX AS LONG, foundHitY AS LONG, foundPlaceY AS LONG 'Set up initial values and arrays DIM snowParticles(1 TO %MAXSNOW, 1 TO 5) AS DOUBLE '1=x, 2=y, 3=speed, 4=angle, 5=avail DIM ufoInfo(1 TO 3, 1 TO 4) AS DOUBLE '(1=x, 2=y, 3=tox, 4=toy) DIM ufoFlipper(1 TO 3) DIM ufoSteps(1 TO 3) DIM UFOctr(1 TO 3) DIM UFOdir(1 TO 3) FOR ctr = 1 TO 3 ufoSteps(ctr) = (RND * 40) + 15 ufoFlipper(ctr) = RND * 10 + 5 ufoInfo(ctr, 1) = (RND * 450) + 52 ufoInfo(ctr, 2) = (RND * 200) + 30 ufoInfo(ctr, 3) = (RND * 450) + 52 ufoInfo(ctr, 4) = (RND * 200) + 30 UFOctr(ctr) = 1 UFOdir(ctr) = 1 NEXT backDirY = (RND * 0.5) + 0.1 backDirX = (RND * 3) + 1 backX = 0 backY = 0 forespriteX = RND * 544 forespriteY = RND * 368 'By default we're drawing in the main window (only the snow routine does otherwise) GRAPHIC ATTACH hDlg, %IDC_GRAPHIC, REDRAW 'Loop, but watch for the kill request on exit DO UNTIL killThread = %TRUE 'Is the background being animated? IF showBackground = %TRUE THEN 'Pan through background, looping as needed backX = backX + backDirX backY = backY + backDirY bgYmove = backDirX IF backY > 450 THEN backDirY = 0 - ((RND * 0.5) + 0.1) backDirX = (RND * 7) - 3 IF backDirX = 0 THEN backDirX = 1 backY = 450 ELSEIF backY < 0 THEN backDirY = (RND * 0.5) + 0.1 backDirX = (RND * 7) - 3 IF backDirX = 0 THEN backDirX = -1 backY = 0 END IF 'Draw it drawBackground(INT(backX), INT(backY)) ELSE 'If background is not being painted from BMP, just fill it in light blue bgYmove = 0 GRAPHIC CLEAR %RGB_LIGHTBLUE, 0 END IF 'Is the rear layer (UFOs) of sprites being drawn? IF showRear = %TRUE THEN 'Loop through all three FOR ctr = 1 TO 3 'Grab the size of this one SELECT CASE ctr CASE 1 cX = ufoInfo(ctr, 1) - 60 cY = ufoInfo(ctr, 2) - 27 CASE 2 cX = ufoInfo(ctr, 1) - 60 cY = ufoInfo(ctr, 2) - 27 CASE 3 cX = ufoInfo(ctr, 1) - 50 cY = ufoInfo(ctr, 2) - 17 END SELECT 'Step closer toward flipping to the next frame in the animation, which we cycle back and forth through DECR ufoFlipper(ctr) IF ufoFlipper(ctr) <= 0 THEN ufoFlipper(ctr) = INT(RND * 10) + 5 UFOctr(ctr) = UFOctr(ctr) + UFOdir(ctr) IF UFOctr(ctr) = 11 THEN UFOctr(ctr) = 9 UFOdir(ctr) = -1 ELSEIF UFOctr(ctr) = 0 THEN UFOctr(ctr) = 2 UFOdir(ctr) = 1 END IF END IF 'Move 1/32 of the way to the next step ufoInfo(ctr, 1) = ((ufoInfo(ctr, 1) * ufoSteps(ctr)) + ufoInfo(ctr, 3)) / (ufoSteps(ctr) + 1) ufoInfo(ctr, 2) = ((ufoInfo(ctr, 2) * ufoSteps(ctr)) + ufoInfo(ctr, 4)) / (ufoSteps(ctr) + 1) 'Are we within three pixels of the destination? If so, pick a new destination IF ABS(ufoInfo(ctr, 1) - ufoInfo(ctr, 3)) < 3 AND ABS(ufoInfo(ctr, 2) - ufoInfo(ctr, 4)) < 3 THEN ufoInfo(ctr, 3) = (RND * 450) + 52 ufoInfo(ctr, 4) = (RND * 200) + 30 END IF 'Write the UFO to the screen; mask then image GRAPHIC COPY hImgUfoMask(ctr, UFOctr(ctr)), 0 TO (cX, cY), %MIX_MERGESRC GRAPHIC COPY hImgUfo(ctr, UFOctr(ctr)), 0 TO (cX, cY), %MIX_MASKSRC NEXT END IF 'Are we drawing the foreground (the picture of my daughter that follows the mouse)? IF showForeground = %TRUE THEN 'Get the current mouse location, relative to the graphic control GrabMouse curX, curY 'Move the sprite 1/32 of the way toward the mouse forespriteX = ((forespriteX * 31) + curX) / 32 forespriteY = ((forespriteY * 31) + curY) / 32 'If we've moved off the window, just lock the sprite to the border IF forespriteX < 0 THEN forespriteX = 0 ELSEIF forespriteX > 544 THEN forespriteX = 544 END IF IF forespriteY < 0 THEN forespriteY = 0 ELSEIF forespriteY > 368 THEN forespriteY = 368 END IF 'Write Ari to the screen; mask then image as with all of them (see the BMP files for an explanation) GRAPHIC COPY hImgAriMask, 0 TO (forespriteX - 45, forespriteY - 69), %MIX_MERGESRC GRAPHIC COPY hImgAri, 0 TO (forespriteX - 45, forespriteY - 69), %MIX_MASKSRC END IF 'Are we drawing the snowstorm? IF showSnow = %TRUE THEN 'Do we need to create a snowflake? IF INT(RND * 1.5) = 0 THEN 'adjust rate for heavier/less heavy snowfall 'Try and find an empty space in the array to put this flake into FOR ctr = 1 TO %MAXSNOW IF snowParticles(ctr, 5) = 0 THEN 'it's available snowParticles(ctr, 1) = (RND * 544) 'x loc start snowParticles(ctr, 2) = -5 'y loc always -5 snowParticles(ctr, 3) = (RND * 1) + 0.5 'drop speed snowParticles(ctr, 4) = -20 + (RND * 40) 'angle (not including jitter) snowParticles(ctr, 5) = 1 'set as active EXIT FOR END IF NEXT END IF 'Snowflake motion loop FOR ctr = 1 TO %MAXSNOW 'Move snowflakes movePoint snowParticles(ctr, 1), snowParticles(ctr, 2), snowParticles(ctr, 4), snowParticles(ctr, 3), snowParticles(ctr, 1), snowParticles(ctr, 2) 'Add a little left/right random jitter snowParticles(ctr, 1) = snowParticles(ctr, 1) + (RND * 1) - 0.5 'Deal with snowflake collisions here IF showTitle = %TRUE THEN 'only deal with snow if we have a title to have it fall on... '1/3: Is the current location colliding with the title text or the already fallen snow? foundHitX = 0 foundHitY = 0 'See if it's inside the title text IF snowParticles(ctr, 1) >= 17 AND snowParticles(ctr, 1) <= 524 AND snowParticles(ctr, 2) >= 0 AND snowParticles(ctr, 2) < 367 THEN 'Convert graphic-relative coordinates to sprite-relative coordinates for check X1 = snowParticles(ctr, 1) - 17 Y1 = snowParticles(ctr, 2) - 200 'Is this a non-black space in the sprite? IF X1 >= 0 AND X1 <= 506 AND Y1 >= 0 AND Y1 <= 145 THEN GRAPHIC ATTACH hImgTitleMask, 0, REDRAW GRAPHIC GET PIXEL (X1, Y1) TO colorCheck ELSE colorCheck = 0 END IF IF colorCheck = 0 THEN 'It's black (no hit), so we must check the snoverlay IF hasSnoverlay <> %FALSE THEN 'Do we have snow at all? 'Check for hit with already built-up snow pile IF snowParticles(ctr, 1) >= 0 AND snowParticles(ctr, 1) <= 543 AND snowParticles(ctr, 2) >= 0 AND snowParticles(ctr, 2) <= 367 THEN GRAPHIC ATTACH hImgSnoverlay, 0, REDRAW GRAPHIC GET PIXEL (snowParticles(ctr, 1), snowParticles(ctr, 2)) TO colorCheck ELSE colorCheck = 0 END IF IF colorCheck <> 0 THEN 'It's non-black, meaning that we hit it foundHitX = snowParticles(ctr, 1) foundHitY = snowParticles(ctr, 2) END IF END IF ELSE 'It's non-black in the sprite, meaning we hit something foundHitX = snowParticles(ctr, 1) foundHitY = snowParticles(ctr, 2) END IF END IF 'Did we hit something? IF foundHitX <> 0 THEN '2/3: If so, "look up"; do we have a clear space within a few pixels that the snow can rest on? foundPlaceY = 0 'travel up from one above the "hit" pixel to three above FOR ctr2 = foundHitY - 1 TO foundHitY - 3 STEP -1 IF ctr2 >= 0 THEN GRAPHIC ATTACH hImgSnoverlay, 0, REDRAW GRAPHIC GET PIXEL (foundHitX, ctr2) TO colorCheck IF colorCheck = 0 THEN 'It's black in the snoverlay (potential hit) Y1 = ctr2 - 200 IF Y1 >= 0 THEN 'Still inside title sprite, must check it too GRAPHIC ATTACH hImgTitleMask, 0, REDRAW GRAPHIC GET PIXEL (foundHitX - 17, Y1) TO colorCheck IF colorCheck = 0 THEN 'It's black (available) inside the sprite foundPlaceY = ctr2 END IF ELSE foundPlaceY = ctr2 END IF END IF IF foundPlaceY <> 0 THEN EXIT FOR END IF NEXT '3/3: If sim put the particle there, adding it to the snoverlay map (and turning that on) and killing the flake IF foundPlaceY <> 0 THEN 'Draw the snowflake (1-5, the smaller ones) onto the snowverlay GRAPHIC ATTACH hImgSnoverlay, 0, REDRAW GRAPHIC COPY hImgSnowflake(INT(RND * 5) + 1), 0 TO (foundHitX - 5, foundPlaceY - 3), %MIX_MERGESRC hasSnoverlay = %TRUE 'Kill off flake in real world snowParticles(ctr, 5) = 0 END IF END IF 'Re-attach to main drawing window GRAPHIC ATTACH hDlg, %IDC_GRAPHIC, REDRAW END IF 'Kill snowflakes that need killing (because they've moved past the bottom) IF snowParticles(ctr, 2) > 373 THEN snowParticles(ctr, 5) = 0 END IF 'Adjust for X-motion, that is, sync to background (snowflakes move faster because they are closer to the viewer BTW) snowParticles(ctr, 1) = snowParticles(ctr, 1) + (bgYmove / 0.75) 'Loop across edges (we need to do this to fake out the motion if we're moving fast left to right) IF snowParticles(ctr, 1) < 0 THEN snowParticles(ctr, 1) = snowParticles(ctr, 1) + 544 ELSEIF snowParticles(ctr, 1) > 544 THEN snowParticles(ctr, 1) = snowParticles(ctr, 1) - 544 END IF 'Redraw current snowflake with random flake IF snowParticles(ctr, 5) > 0 THEN 'Draw it if it's valid GRAPHIC COPY hImgSnowflake(INT(RND * 10) + 1), 0 TO (snowParticles(ctr, 1) - 5, snowParticles(ctr, 2) - 5), %MIX_MERGESRC END IF NEXT END IF 'Are we drawing the title text? IF showTitle = %TRUE THEN 'Write it in place by copying the mask into place and then the title GRAPHIC COPY hImgTitleMask, 0 TO (17, 200), %MIX_MERGESRC GRAPHIC COPY hImgTitle, 0 TO (17, 200), %MIX_MASKSRC 'Are we using the snoverlay that tracks snow that's piled up on the top of the title? IF showSnow = %TRUE AND hasSnoverlay = %TRUE THEN GRAPHIC COPY hImgSnoverlay, 0 TO (0, 0), %MIX_MERGESRC END IF END IF 'Redraw the window GRAPHIC REDRAW 'And make a tiny pause (this probably means this program will run quite differently on different computers due 'to the lack of any real speed control functions) SLEEP 10 LOOP END FUNCTION CALLBACK FUNCTION ShowDIALOGProc() LOCAL dummy AS LONG, dummyThread??? LOCAL res AS LONG SELECT CASE AS LONG CB.MSG CASE %WM_INITDIALOG 'Initialization handler 'Say hello to the user MSGBOX "To use this sprite rendering test, individually turn on and off the elements of the display using the buttons beneath the graphics. " + _ "Please visit ZENTASTIC.COM for the source code or to contact me.", %MB_ICONINFORMATION, "ZenSpriteTest" 'Initialize/load bitmaps initBMP() RANDOMIZE TIMER 'Create the thread than handles the animations THREAD CREATE doStuff(dummy) TO dummyThread??? THREAD CLOSE dummyThread??? TO res CASE %WM_DESTROY 'Send a kill signal to the animation thread killThread = %TRUE 'Pause to let it wrap up SLEEP 100 'Release the memory we're using killBMP() CASE %WM_NCACTIVATE STATIC hWndSaveFocus AS DWORD IF ISFALSE CB.WPARAM THEN ' Save control focus hWndSaveFocus = GetFocus() ELSEIF hWndSaveFocus THEN ' Restore control focus SetFocus(hWndSaveFocus) hWndSaveFocus = 0 END IF CASE %WM_COMMAND 'Buttons and graphic (clicking on it just resets the snow) SELECT CASE AS LONG CB.CTL CASE %IDC_GRAPHIC IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN GRAPHIC ATTACH hImgSnoverlay, 0 GRAPHIC CLEAR %RGB_BLACK, 0 hasSnoverlay = %FALSE GRAPHIC ATTACH hDlg, %IDC_GRAPHIC, REDRAW END IF CASE %IDC_BACKGROUND IF CB.CTLMSG = %BN_CLICKED THEN CONTROL GET CHECK CBHNDL, %IDC_BACKGROUND TO res IF res = %FALSE THEN showBackground = %FALSE ELSE showBackground = %TRUE END IF END IF CASE %IDC_REARSPRITES IF CB.CTLMSG = %BN_CLICKED THEN CONTROL GET CHECK CBHNDL, %IDC_REARSPRITES TO res IF res = %FALSE THEN showRear = %FALSE ELSE showRear = %TRUE END IF END IF CASE %IDC_FOREGROUNDSPRITES IF CB.CTLMSG = %BN_CLICKED THEN CONTROL GET CHECK CBHNDL, %IDC_FOREGROUNDSPRITES TO res IF res = %FALSE THEN showForeground = %FALSE ELSE showForeground = %TRUE END IF END IF CASE %IDC_SNOW IF CB.CTLMSG = %BN_CLICKED THEN CONTROL GET CHECK CBHNDL, %IDC_SNOW TO res IF res = %FALSE THEN showSnow = %FALSE ELSE 'The snow button also resets the snoverlay GRAPHIC ATTACH hImgSnoverlay, 0 GRAPHIC CLEAR %RGB_BLACK, 0 hasSnoverlay = %FALSE GRAPHIC ATTACH hDlg, %IDC_GRAPHIC, REDRAW showSnow = %TRUE END IF END IF CASE %IDC_TITLETEXT IF CB.CTLMSG = %BN_CLICKED THEN CONTROL GET CHECK CBHNDL, %IDC_TITLETEXT TO res IF res = %FALSE THEN showTitle = %FALSE ELSE showTitle = %TRUE END IF END IF END SELECT END SELECT END FUNCTION FUNCTION ShowDIALOG(BYVAL hParent AS DWORD) AS LONG LOCAL lRslt AS LONG LOCAL hFont1 AS DWORD LOCAL hInstance AS DWORD 'Use DDT to create the dialog... easy! DIALOG NEW PIXELS, hParent, "ZenSpriteTest", 196, 135, 563, 418, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR _ %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_CENTER OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _ %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC, "", 8, 8, 544, 368, %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %SS_NOTIFY CONTROL ADD LABEL, hDlg, %IDC_LAYERS, "Layers: ", 8, 384, 56, 24, %WS_CHILD OR %WS_VISIBLE OR %SS_RIGHT OR %SS_CENTERIMAGE, %WS_EX_LEFT OR %WS_EX_LTRREADING CONTROL ADD CHECKBOX, hDlg, %IDC_BACKGROUND, "Background", 72, 384, 88, 24, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_AUTOCHECKBOX OR %BS_PUSHLIKE OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING CONTROL ADD CHECKBOX, hDlg, %IDC_REARSPRITES, "Rear Sprites", 168, 384, 88, 24, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_AUTOCHECKBOX OR %BS_PUSHLIKE OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING CONTROL ADD CHECKBOX, hDlg, %IDC_FOREGROUNDSPRITES, "Foreground Sprite", 264, 384, 120, 24, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_AUTOCHECKBOX OR %BS_PUSHLIKE OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING CONTROL ADD CHECKBOX, hDlg, %IDC_SNOW, "Snow", 392, 384, 64, 24, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_AUTOCHECKBOX OR %BS_PUSHLIKE OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING CONTROL ADD CHECKBOX, hDlg, %IDC_TITLETEXT, "Title Text", 464, 384, 88, 24, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR %BS_AUTOCHECKBOX OR %BS_PUSHLIKE OR %BS_CENTER OR %BS_VCENTER, %WS_EX_LEFT OR %WS_EX_LTRREADING FONT NEW "MS Sans Serif", 8, 1, %ANSI_CHARSET TO hFont1 CONTROL SET FONT hDlg, %IDC_LAYERS, hFont1 GRAPHIC ATTACH hDlg, %IDC_GRAPHIC, REDRAW hInstance = GetModuleHandle("") DIALOG SEND hDlg, %WM_SETICON, %ICON_BIG, LoadIcon(hInstance, "0L") DIALOG SHOW MODAL hDlg, CALL ShowDIALOGProc TO lRslt FONT END hFont1 FUNCTION = lRslt END FUNCTION SUB GrabMouse(X AS LONG, Y AS LONG) 'Grab the mouse location, relative to the graphic control LOCAL mousePt AS POINT GetCursorPos mousePt 'Get the current mouse location ScreenToClient hDlg, mousePt 'And convert it to being relative to this dialog X = mousePt.x - 5 'Make it relative to the graphic control Y = mousePt.y - 5 END SUB 'PB uses radians rather than degrees for its trig functions MACRO Angle2radians(AngleDeg) = (AngleDeg * 0.0174532925199433) SUB movePoint(X AS DOUBLE, Y AS DOUBLE, Angle AS DOUBLE, Distance AS DOUBLE, Xout AS DOUBLE, Yout AS DOUBLE) 'Move a point a distance at a given angle 'Do I remember high-school math class? I guess I do... Xout = X + (Distance * SIN(Angle2radians(Angle))) Yout = Y + (Distance * COS(Angle2radians(Angle))) END SUB