REM. Apple deform 3
     REM. A rotating, stretching, squashing, colour-changing apple


     
*ESC OFF


     *FLOAT 64


     ON ERROR PROCerror( REPORT$, TRUE )


     REM. Reserve 2 MB of RAM for this program
     
M% = 2
     HIMEM = LOMEM + M%*&100000
     HIMEM = (HIMEM + 3) AND -4


     REM. Prevent the user from resizing the window
     REM. (although it can still be minimized)
     
PROCfixWindowSize


     SYS "SetWindowText", @hwnd%, "A rotating, stretching, squashing, colour-changing apple"


     REM. Set our program window's dimensions
     
WinW% = 640
     WinH% = 512
     VDU 23, 22, WinW%; WinH%; 8, 16, 16, 0 : OFF


     
REM. Install and initialise GFXLIB and the required external modules
     
INSTALL @lib$ + "GFXLIB2"                              : PROCInitGFXLIB
     INSTALL @lib$ + "GFXLIB_modules\BPlotScaleNC.BBC"      : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotRotateScale2.BBC"  : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\ChangeBitmapRGBLevels" : PROCInitModule


     REM. Load in the 400x400 apple bitmap (JPEG image)
     REM. The image will automatically be converted to the format (32bpp ARGB) required by GFXLIB
     
bm% = FNLoadImg( @dir$ + "apple_400x400.JPG", 0 )


     REM. Set up a bitmap buffer of sufficient size to contain a 32bpp 640x512 bitmap
     
bm2% = FNmalloc( 4*640*512 )


     REM. Declare the colour table structure
     
DIM table{(255) b&, g&, r&, a&}


     REM. bmW% and bmH% must be the bitmap's actual width and height
     
bmW% = 400
     bmH% = 400


     REM. Get base address of dispVars struct into D% (for slightly more access speed)
     
D% = dispVars{}


     REM. Disable the automatic window refresh
     
*REFRESH OFF


     REPEAT

       SYS
GFXLIB_Clr%, dispVars{}, FNrgb( 255, 255, 255 )

       T% = TIME

       
newBmH% = bmH% + 100*SIN(T%/35)*COS(T%/56)

       bmX% = (WinW% - bmW%) DIV 2
       bmY% = (WinH% - newBmH%) DIV 2

       REM. dx is the time-varying X displacement of the middle point of the quadratic curve
       
dx = 1.6 * (newBmH% - bmH%)


       REM. Set up our quadratic curve coordinates
       REM. (x1,y1),  (x2,y2),  (x3,y3)
       
x1 = bmX%
       y1 = bmY%

       x2 = x1 + dx
       y2 = y1 + newBmH%DIV2

       x3 = x1
       y3 = y1 + newBmH%


       REM. Our quadratic curve is of the form X = aY^2 + bY + c
       REM. We now need to compute a, b and c
       
PROCgetQuadraticCoeffs( y1, x1, y2, x2, y3, x3, a, b, c )


       REM. Some "pre-calculations" (to improve loop efficiency)
       REM. Sorry if this appears rather cryptic
       
hScale% = newBmH% / bmH%
       bmW4% = 4 * bmW%
       x2`% = 2*bmX% + bmW%
       dy% = y3 - bmY%
       s = bmH% / dy%


       REM. Now draw the scaled rows of pixels from the bitmap
       
SYS GFXLIB_SaveDispVars%, dispVars{}
       SYS GFXLIB_SetDispVars2%, dispVars{}, bm2%, 640, 512
       SYS GFXLIB_Clr%, dispVars{}, 0
       REM. Draw the individual scaled rows of pixels from the bitmap
       
FOR Y% = y1 TO y3-1

         REM. Calculate the base address of a row of pixels
         
pRow% = bm% + bmW4% * INT(s*(Y%-bmY%))

         REM. Calculate the X-coordinate of the row
         
X = a*Y%^2 + b*Y% + c

         REM. Calculate the width of the row
         
rowWidth% = x2`% - 2*X

         REM. Draw the row of pixels
         
SYS GFXLIB_BPlotScaleNC%, D%, pRow%, bmW%, 1, rowWidth%, hScale%+1, X, Y%

       NEXT
       SYS
GFXLIB_RestoreDispVars%, dispVars{}


       REM. Display the rotated and scaled stretched/squashed apple bitmap
       
SYS GFXLIB_PlotRotateScale2%, dispVars{}, bm2%, 640, 512, WinW%DIV2, WinH%DIV2, \
       
\ &100000*360*SIN(T%/400), &100000*(0.5 + ABS(2.5*SIN(T%/2500)*COS(T%/3371)))


       REM. Set up the colour table for GFXLIB_ChangeBitmapRGBLevels
       
FOR I% = 0 TO 255
         t# = 2*PI * I%/255
         table{(I%)}.r& = 128 + 127*SIN(t# + T%/180)
         table{(I%)}.g& = 128 + 127*COS(t# - T%/170)
         table{(I%)}.b& = 128 + 127*SIN(t# + T%/160)*COS(t# - T%/220)
       NEXT I%


       REM. Perform the gradual "colour morphing"
       
SYS GFXLIB_ChangeBitmapRGBLevels%, dispVars.bmBuffAddr%, dispVars.bmBuffAddr%, WinW%*WinH%, ^table{(0)}.b&


       REM. Render the completed image to the program window
       
PROCdisplay

     UNTIL FALSE


     
DEF PROCgetQuadraticCoeffs( x1, y1, x2, y2, x3, y3, RETURN a, RETURN b, RETURN c )
     PROCsolve2x2( x1^2-x2^2, x1-x2, y1-y2, \
     
\ x1^2-x3^2, x1-x3, y1-y3, \
     
\ a, b )
     c = y1 - (a*x1^2 + b*x1)
     ENDPROC


     
DEF PROCsolve2x2(A, B, C, D, E, F, RETURN x, RETURN y)
     LOCAL d
     d = (A*E - B*D)^-1
     x = d * (E*C - B*F)
     y = d * (A*F - D*C)
     ENDPROC


     
DEF PROCfixWindowSize
     LOCAL GWL_STYLE, WS_THICKFRAME, WS_MAXIMIZEBOX, ws%
     GWL_STYLE = -16
     WS_THICKFRAME = &40000
     WS_MAXIMIZEBOX = &10000
     SYS "GetWindowLong", @hwnd%, GWL_STYLE TO ws%
     SYS "SetWindowLong", @hwnd%, GWL_STYLE, ws% AND NOT (WS_THICKFRAME+WS_MAXIMIZEBOX)
     ENDPROC


     
DEF PROCerror( msg$, L% )
     OSCLI "REFRESH ON" : ON
     COLOUR
1, &FF, &FF, &FF
     COLOUR 1
     PRINT TAB(1,1)msg$;
     IF L% THEN
       PRINT
" at line "; ERL;
     ENDIF
     VDU
7
     REPEAT UNTIL INKEY(1)=0
     ENDPROC