06-14-2023, 09:46 PM
Below is the image for my entry in the summer banner challenge.
The attached ZIP file contains the code and images to create the banner.
The sunflower field is randomly generated. Each sunflower is created from random petal placements around a randomly created seed pod. Every time you run the code a new sunflower field is generated containing new entirely random sunflowers. The image is then saved as "SummerBanner.PNG" thanks to Steve's Image Library.
The attached ZIP file contains the code and images to create the banner.
The sunflower field is randomly generated. Each sunflower is created from random petal placements around a randomly created seed pod. Every time you run the code a new sunflower field is generated containing new entirely random sunflowers. The image is then saved as "SummerBanner.PNG" thanks to Steve's Image Library.
Code: (Select All)
'+---------------------------------------------------------------------------+
'| Terry's Sunflower Field Generator |
'| June 14th, 2023 |
'| |
'| Creates a random sunflower field banner for the summer banner competition |
'+---------------------------------------------------------------------------+
'Steve's SaveImage Library
'$INCLUDE:'saveimage.bi'
'OPTION _EXPLICIT ' Had to disable because of library
TYPE Type_POINT ' a single coordinate
x AS SINGLE
y AS SINGLE
END TYPE
TYPE Type_FLOWER ' sunflower part
Image AS LONG ' image of petal / stem
w AS INTEGER ' width of image
h AS INTEGER ' height of image
END TYPE
DIM Petal(14) AS Type_FLOWER ' 14 petal images
DIM Stem(14) AS Type_FLOWER ' 14 stem images
DIM Seed AS LONG ' image of sunflower seed
DIM p AS INTEGER ' generic counter
DIM Degree AS SINGLE ' angle in degrees
DIM VecX(359) AS SINGLE ' precalculated sine values for degrees
DIM VecY(359) AS SINGLE ' precalculated cosine values for degrees
DIM Background AS LONG ' background image
DIM Logo AS LONG ' QB64PE logo image
DIM stepper AS INTEGER ' spacing of sunflowers in each row in field
DIM Yloc AS INTEGER ' y location of row of sonflowers in field
DIM Size AS SINGLE ' size of sunflowers in each row in field
DIM r AS INTEGER ' introduce random height variances with each sunflower in sunflower rows
DIM SaveImg AS INTEGER ' result of Steve's SaveImage library
'+---------------------------------------+
'| Precalculate rotational vector values |
'+---------------------------------------+
Degree = 0 ' reset degree counter
DO ' cycle through 360 degrees (0 to 359)
VecX(Degree) = SIN(_D2R(Degree)) ' degree to vector calculations for matrix rotation and direction
VecY(Degree) = -COS(_D2R(Degree)) ' degrees converted to negative radians for clockwise rotation
Degree = Degree + 1 ' increment degree value
LOOP UNTIL Degree = 360 ' leave when 360 degrees calculated
'+------------------------------------------------------------------+
'| Load petal and stem images and create a mirror image of each one |
'+------------------------------------------------------------------+
FOR p = 1 TO 7 ' load 7 petal images
Petal(p).Image = _LOADIMAGE("petal" + _TRIM$(STR$(p)) + ".png", 32) ' load petal image
Petal(p).w = _WIDTH(Petal(p).Image) ' width of image
Petal(p).h = _HEIGHT(Petal(p).Image) ' height of image
Petal(p + 7).Image = _NEWIMAGE(Petal(p).w, Petal(p).h, 32) ' create image holder
Petal(p + 7).w = Petal(p).w ' width of new image
Petal(p + 7).h = Petal(p).h ' height of new image
_PUTIMAGE , Petal(p).Image, Petal(p + 7).Image, (Petal(p).w - 1, 0)-(0, Petal(p).h - 1) ' flip image horizontally in new image holder
Stem(p).Image = _LOADIMAGE("stem" + _TRIM$(STR$(p)) + ".png", 32) ' load stem image
Stem(p).w = _WIDTH(Stem(p).Image) ' width of image
Stem(p).h = _HEIGHT(Stem(p).Image) ' height of image
Stem(p + 7).Image = _NEWIMAGE(Stem(p).w, Stem(p).h, 32) ' create image holder
Stem(p + 7).w = Stem(p).w ' width of new image
Stem(p + 7).h = Stem(p).h ' height of new image
_PUTIMAGE , Stem(p).Image, Stem(p + 7).Image, (Stem(p).w - 1, 0)-(0, Stem(p).h - 1) ' flip image horizontally in new image holder
NEXT p
'+-----------------------+
'| Load remaining images |
'+-----------------------+
Background = _LOADIMAGE("background.png", 32) ' load background imgage
Logo = _LOADIMAGE("pelogo.png", 32) ' load QB64PE logo image
Seed = _LOADIMAGE("seed.png", 32) ' load seed image
'+---------------+
'| Begin Program |
'+---------------+
SCREEN Background ' 1400x256 screen
RANDOMIZE TIMER ' randomize
'+------------------------+
'| Create sunflower field |
'+------------------------+
stepper = 8 ' set sunflower spacing
Yloc = 128 ' set sunflower row location
Size = .05 ' set sunflower size
r = 5 ' set random sunflower height variance
DO ' start making sunflower rows
FOR p = 0 TO 1400 STEP stepper ' create a row with pre-determined sunflower spaceing
MakeFlower p, Yloc + INT((RND - RND) * r), Size ' draw a sunflower on the background
NEXT p
Yloc = Yloc + 10 ' move next sunflower row down
stepper = stepper + 5 ' increase sunflower spacing
Size = Size + .025 ' increase size of sunflowers
r = r + 2 ' increase height variance
LOOP UNTIL Yloc > 280 ' leave when all rows created
_PUTIMAGE (25, 30), Logo ' draw QB64PE logo images
_PUTIMAGE (1240, 30), Logo
SaveImg = SaveImage("SummerBanner.png", 0, 0, 0, _WIDTH - 1, _HEIGHT - 1) ' save finished banner to drive
SLEEP ' wait for a key press
'+----------+
'| Clean up |
'+----------+
SCREEN 0, 0, 0, 0 ' go to screen 0
CLS ' clear the screen
FOR p = 1 TO 14 ' cycle through images
_FREEIMAGE Petal(p).Image ' remove petal images
_FREEIMAGE Stem(p).Image ' remove stem images
NEXT p
_FREEIMAGE Background ' remove remaining images
_FREEIMAGE Logo
_FREEIMAGE Seed
SYSTEM ' return to operating system
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB MakeFlower (x AS INTEGER, y AS INTEGER, Zoom AS SINGLE) ' MakeFlower |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Creates a sunflower the hard way |
'\_______________________________________________________________________________________________________________________________________________/
SHARED Petal() AS Type_FLOWER ' petal images
SHARED Stem() AS Type_FLOWER ' stem images
SHARED Origin AS Type_POINT ' rotation origin
SHARED pPoint AS Type_POINT ' a single coordinate
SHARED Seed AS LONG ' seed image
DIM Degree AS SINGLE ' angle in degrees
DIM p AS INTEGER ' generic counter
DIM pp AS INTEGER ' generic counter
DIM InImg AS LONG ' image returned from rotozoom
DIM Flower AS LONG ' flower image
DIM Stem AS LONG ' stem image (flower image gets placed on top)
DIM r AS INTEGER ' random stem image
'+--------------------------------------+
'| Create flower and stem image holders |
'+--------------------------------------+
Flower = _NEWIMAGE(221, 221, 32) ' create flower image holder
r = INT(RND * 14) + 1 ' get random stem number
Stem = _NEWIMAGE(Stem(r).w, Stem(r).h + 140, 32) ' create stem image holder
_PUTIMAGE (0, 140), Stem(r).Image, Stem ' place stem image onto lower portion of stem image holder
_DEST Flower ' draw on flower image
'+---------------+
'| Create petals |
'+---------------+
Origin.x = 110 ' rotation origin point
Origin.y = 110
pPoint.x = 110 ' location of point that rotates
pPoint.y = Origin.y - 70
Degree = 0 ' reset degree angle
FOR pp = 1 TO 2 ' 2 layers of petals
FOR p = 1 TO 24 ' 24 petals on each later
Rotate pPoint, 15, Origin ' rotate point 15 degrees
Degree = Degree + 15 ' increase degree angle by 15 degrees
InImg = _COPYIMAGE(Petal(INT(RND * 14) + 1).Image) ' create a copy of a random petal image
__ROTOZOOM_IMAGE InImg, Degree, 1 ' rotate the petal image
_PUTIMAGE (pPoint.x - _WIDTH(InImg) / 2, pPoint.y - _HEIGHT(InImg) / 2), InImg ' draw rotated petal image onto flower image holder
_FREEIMAGE InImg ' free the image copy
NEXT p
Rotate pPoint, 7.5, Origin ' rotate the point half of 15 degrees for next layer
Degree = 7 ' set degree angle equal to 7
pPoint.y = Origin.y - 50 ' move this row of petals in closer to the center
NEXT pp
'+-----------------+
'| Create seed pod |
'+-----------------+
pPoint.x = 110 ' new rotation origin point
pPoint.y = Origin.y - 3
Degree = 0 ' reset degree angle
FOR pp = 1 TO 16 ' 16 rows of seeds
FOR p = 1 TO 120 ' 120 seeds in each row
Rotate pPoint, 3, Origin ' rotate point 3 degrees
Degree = Degree + 3 ' increase degree angle by 3 degrees
InImg = _COPYIMAGE(Seed) ' copy the seed image
__ROTOZOOM_IMAGE InImg, Degree, 1 ' rotate the seed image
_PUTIMAGE (pPoint.x - _WIDTH(InImg) / 2, pPoint.y - _HEIGHT(InImg) / 2), InImg ' draw rotated seed image onto flower image holder
_FREEIMAGE InImg ' free the image copy
NEXT p
Rotate pPoint, 6, Origin ' rotate the point 6 degrees for the next row
Degree = Degree + 6 ' increase degree angle by 6 degrees
pPoint.y = pPoint.y + 3 ' next row of seeds out a little farther
NEXT pp
_PUTIMAGE (Stem(r).w / 2 - 110, 0), Flower, Stem ' place the flower image on top of the stem image
_DEST 0 ' draw on background image
'+------------------------------------------------+
'| Zoom the flower image and draw onto background |
'+------------------------------------------------+
_PUTIMAGE (x - (Stem(r).w / 2) * Zoom, y - ((Stem(r).h + 140) / 2) * Zoom)-(x + (Stem(r).w / 2) * Zoom, y + ((Stem(r).h + 140) / 2) * Zoom), Stem
_FREEIMAGE Flower ' free image holders created
_FREEIMAGE Stem
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB Rotate (pPoint AS Type_POINT, AngleDeg AS SINGLE, Origin AS Type_POINT) ' Rotate |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Rotate a point around an origin using linear transformation. |
'| |
'| Vec : the point to rotate (NOTE these values get modified and passed back) |
'| AngleDeg : the angle in degrees to rotate (additive) |
'| Origin : the rotation point of origin |
'\_______________________________________________________________________________________________________________________________________________/
DIM x AS SINGLE ' location of point's x with origin at 0
DIM y AS SINGLE ' location of point's y with origin at 0
DIM Cosine AS SINGLE ' cosine of angle
DIM Sine AS SINGLE ' sine of angle
DIM xPrime AS SINGLE ' new point x location with original origin
DIM yPrime AS SINGLE ' new point y location with original origin
x = pPoint.x - Origin.x ' move rotation origin to 0
y = pPoint.y - Origin.y
Cosine = COS(_D2R(AngleDeg)) ' calculate sine and cosine of angle
Sine = SIN(_D2R(AngleDeg))
xPrime = (x * Cosine) - (y * Sine) ' calculate rotated location of vector
yPrime = (x * Sine) + (y * Cosine)
xPrime = xPrime + Origin.x ' move back to original origin
yPrime = yPrime + Origin.y
pPoint.x = xPrime ' pass back rotated vector
pPoint.y = yPrime
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __ROTOZOOM_IMAGE (InImg AS LONG, Deg AS INTEGER, Zoom AS SINGLE) ' __ROTOZOOM_IMAGE |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Rotates and zooms an input image by the amounts specified. |
'| |
'| __ROTOZOOM_IMAGE MyImage, 180 |
'| |
'| InImg - image to rotate and zoom. ImImg is modified to contain the updated rotated and zoomed image. |
'| Deg - amount of image rotation (0 to 359) |
'| Zoom - amount to zoom image (.5 = 50%, 1 = 100%, 1.5 = 150%, etc..) |
'| |
'| This subroutine based on code provided by Rob (Galleon) on the QB64.NET website in 2009. |
'| Special thanks to Luke for explaining the matrix rotation formula used in this routine. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED VecX() AS SINGLE ' need access to precalculated x vector values
SHARED VecY() AS SINGLE ' need access to precalculated y vector values
DIM px(3) AS INTEGER ' x vector values of four corners of image
DIM py(3) AS INTEGER ' y vector values of four corners of image
DIM Left AS INTEGER ' left-most value seen when calculating rotated image size
DIM Right AS INTEGER ' right-most value seen when calculating rotated image size
DIM Top AS INTEGER ' top-most value seen when calculating rotated image size
DIM Bottom AS INTEGER ' bottom-most value seen when calculating rotated image size
DIM WOutImg AS INTEGER ' width of rotated image
DIM HOutImg AS INTEGER ' height of rotated image
DIM WInImg AS INTEGER ' width of original image
DIM HInImg AS INTEGER ' height of original image
DIM CenterX AS INTEGER ' offsets used to move (0,0) back to upper left corner of image
DIM CenterY AS INTEGER
DIM x AS SINGLE ' new x vector of rotated point
DIM y AS SINGLE ' new y vector of rotated point
DIM v AS INTEGER ' vector counter
DIM Degree AS INTEGER ' corrected input degree
DIM OrigImg AS LONG ' temporary copy of input image
'+-----------------------+
'| Rotate and zoom image |
'+-----------------------+
OrigImg = _COPYIMAGE(InImg) ' copy input image
Degree = __FIX_DEGREE(Deg) ' keep degree within 0 to 359
WInImg = _WIDTH(InImg) ' width of input image
HInImg = _HEIGHT(InImg) ' height of input image
_FREEIMAGE InImg ' free input image from RAM
'+----------------------------------+
'| Make 0,0 the center of the image |
'+----------------------------------+
px(0) = -WInImg / 2 * Zoom ' -x,-y ----------------- x,-y
py(0) = -HInImg / 2 * Zoom ' py(0),| | px(3) Create points around (0,0)
px(1) = px(0) ' px(0) | | py(3) that match the size of the
py(1) = HInImg / 2 * Zoom ' | . | original image. This
px(2) = WInImg / 2 * Zoom ' | (0,0) | creates fouor vector
py(2) = py(1) ' px(1),| | px(2), quantities to work with.
px(3) = px(2) ' py(1) | | py(2)
py(3) = py(0) ' -x,y ----------------- x,y
'+--------------------------------------------------------+
'| Perform matrix rotation on all four corner coordinates |
'+--------------------------------------------------------+
DO ' cycle through vectors
x = px(v) * -VecY(Degree) + -VecX(Degree) * py(v) ' perform 2D rotation matrix on vector
y = py(v) * -VecY(Degree) - px(v) * -VecX(Degree) ' https://en.wikipedia.org/wiki/Rotation_matrix
px(v) = x ' save new x vector
py(v) = y ' save new y vector
'+--------------------------------------------------------------------------------+
'| Image size changes when rotated so remember lowest and highest x,y values seen |
'+--------------------------------------------------------------------------------+
IF px(v) < Left THEN Left = px(v) ' lowest x coordinate seen
IF px(v) > Right THEN Right = px(v) ' highest x coordinate seen
IF py(v) < Top THEN Top = py(v) ' lowest y coordinate seen
IF py(v) > Bottom THEN Bottom = py(v) ' highest y coordinate seen
v = v + 1 ' increment vector counter
LOOP UNTIL v = 4 ' leave when all vectors processed (0 through 3)
'+------------------------------------+
'| Make 0,0 the top left of the image |
'+------------------------------------+
WOutImg = Right - Left + 1 ' calculate width of rotated image
HOutImg = Bottom - Top + 1 ' calculate height of rotated image
CenterX = WOutImg \ 2 ' place (0,0) in upper left corner of rotated image
CenterY = HOutImg \ 2
v = 0 ' reset vector counter
DO ' cycle through rotated image coordinates
px(v) = px(v) + CenterX ' move image coordinates so (0,0) at upper left corner
py(v) = py(v) + CenterY ' and (width-1,height-1) at lower right
v = v + 1 ' increment corner counter
LOOP UNTIL v = 4 ' leave when all four vectors of image moved
InImg = _NEWIMAGE(WOutImg, HOutImg, 32) ' create new rotated image canvas
'+-------------------------------------+
'| Map triangles onto new image canvas |
'+-------------------------------------+
_MAPTRIANGLE (0, 0)-(0, HInImg - 1)-(WInImg - 1, HInImg - 1), OrigImg TO(px(0), py(0))-(px(1), py(1))-(px(2), py(2)), InImg
_MAPTRIANGLE (0, 0)-(WInImg - 1, 0)-(WInImg - 1, HInImg - 1), OrigImg TO(px(0), py(0))-(px(3), py(3))-(px(2), py(2)), InImg
_FREEIMAGE OrigImg ' free original image from RAM
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __FIX_DEGREE (Degree AS INTEGER) ' __FIX_DEGREE |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Normalizes degree to between 0 and 359. |
'| |
'| Degree = __FIX_DEGREE(-270) |
'\_______________________________________________________________________________________________________________________________________________/
DIM Deg AS INTEGER ' degree value passed in
Deg = Degree ' get passed in degree value
IF Deg < 0 OR Degree > 359 THEN ' degree out of range?
Deg = Deg MOD 360 ' yes, get remainder of modulus 360
IF Deg < 0 THEN Deg = Deg + 360 ' add 360 if less than 0
END IF
__FIX_DEGREE = Deg ' return degree
END FUNCTION
' Steve's SaveImage Library
'$INCLUDE:'saveimage.bm'