For a game I am trying to make, I made a small program which reads a bitmap and makes rotated versions which can be draw with put. One simple rotation an one using bilinear interpolation.
The image I used is:
Code: Select all
const pi as double = 3.1415926535897932
const rad as double = 180 / pi
'bmp header description, copy/pasta from wiki
Type bitmap_header Field = 1
bfType As UShort
bfsize As ULong
bfReserved1 As UShort
bfReserved2 As UShort
bfOffBits As ULong
biSize As ULong
biWidth As ULong
biHeight As ULong
biPlanes As UShort
biBitCount As UShort
biCompression As ULong
biSizeImage As ULong
biXPelsPerMeter As ULong
biYPelsPerMeter As ULong
biClrUsed As ULong
biClrImportant As ULong
End Type
type rgbc_type
r as integer
g as integer
b as integer
c as integer
end type
sub colorToRGB(byref colour as rgbc_type)
colour.b = colour.c and &h000000FF
colour.g = (colour.c and &h0000FF00) shr 8
colour.r = (colour.c and &h00FF0000) shr 16
end sub
sub rgbToColor(byref colour as rgbc_type)
colour.c = rgb(colour.r, colour.g, colour.b)
end sub
declare sub sprite_rotate(srcImg as any ptr, dstImg as any ptr, rotation as single, defaultColour as integer)
declare sub sprite_rotate_bilinear(srcImg as any ptr, dstImg as any ptr, rotation as single, defaultColour as integer)
declare function inLimits(i as integer, iMin as integer, imax as integer) as integer
Dim bmp_header As bitmap_header
dim as any ptr image(1) '1 means 2 images: 0 and 1
dim as single rotation
dim as integer defaultColour
dim as string bmp_file_name = "tank_04.bmp"
screen 19, 32, 2
Open bmp_file_name For Binary As #1
Get #1, , bmp_header
Close #1
image(0) = imagecreate(bmp_header.biWidth, bmp_header.biHeight)
image(1) = imagecreate(bmp_header.biWidth, bmp_header.biHeight)
bload bmp_file_name, image(0)
put (100, 100), image(0), pset
'defaultColour = &hff7f7f7f
defaultColour = &hffffffff
'defaultColour = &hff000000
rotation = 0' 10 / rad
while inkey$ = ""
sprite_rotate(image(0), image(1), rotation, defaultColour)
put (300, 100), image(1), pset
sprite_rotate_bilinear(image(0), image(1), rotation, defaultColour)
put (500, 100), image(1), pset
sleep 20
rotation += (2 / rad)
wend
imagedestroy(image(0))
imagedestroy(image(1))
sleep
sub sprite_rotate(srcImg as any ptr, dstImg as any ptr, rotation as single, defaultColour as integer)
dim as integer srcWidth, srcHeight
dim as single xctr, yctr
dim as integer x, y
dim as integer xsrc, ysrc
dim as integer colour
dim as integer colourInterpol(3)
imageInfo srcImg, srcWidth, srcHeight
xctr = srcWidth / 2
yctr = srcHeight / 2
for y = 0 to srcHeight-1
for x = 0 to srcWidth-1
xsrc = int((x - xctr) * cos(rotation) - (y - yctr) * sin(rotation) + xctr + 0.5)
ysrc = int((x - xctr) * sin(rotation) + (y - yctr) * cos(rotation) + yctr + 0.5)
if inLimits(xsrc, 0, srcWidth-1) and inLimits(ysrc, 0, srcHeight-1) then
colour = point(xsrc, ysrc, srcImg)
else
colour = defaultColour
end if
pset dstImg, (x, y), colour
next
next
end sub
sub sprite_rotate_bilinear(srcImg as any ptr, dstImg as any ptr, rotation as single, defaultColour as integer)
dim as integer srcWidth, srcHeight
dim as single xctr, yctr
dim as integer x, y
dim as single xSrc, ySrc, xFact, yFact
dim as integer xSrcLeft, xSrcRight, ySrcUp, ySrcDown
dim as rgbc_type colour, cLeftUp, cLeftDown, cRightUp, cRightDown
imageInfo srcImg, srcWidth, srcHeight
xctr = srcWidth / 2
yctr = srcHeight / 2
for y = 0 to srcHeight-1
for x = 0 to srcWidth-1
xSrc = (x - xctr) * cos(rotation) + (y - yctr) * sin(-rotation) + xctr
ySrc = (x - xctr) * sin(rotation) + (y - yctr) * cos(rotation) + yctr
xSrcLeft = int(xSrc)
xSrcRight = int(xSrc) + 1
xFact = xSrc - xSrcLeft
ySrcUp = int(ySrc)
ySrcDown = int(ySrc) + 1
yFact = ySrc - ySrcUp
if inLimits(xSrcLeft, 0, srcWidth-1) and inLimits(ySrcUp, 0, srcHeight-1) then
cLeftUp.c = point(xSrcLeft, ySrcUp, srcImg)
else
cLeftUp.c = defaultColour
end if
if inLimits(xSrcRight, 0, srcWidth-1) and inLimits(ySrcUp, 0, srcHeight-1) then
cRightUp.c = point(xSrcRight, ySrcUp, srcImg)
else
cRightUp.c = defaultColour
end if
if inLimits(xSrcLeft, 0, srcWidth-1) and inLimits(ySrcDown, 0, srcHeight-1) then
cLeftDown.c = point(xSrcLeft, ySrcDown, srcImg)
else
cLeftDown.c = defaultColour
end if
if inLimits(xSrcRight, 0, srcWidth-1) and inLimits(ySrcDown, 0, srcHeight-1) then
cRightDown.c = point(xSrcRight, ySrcDown, srcImg)
else
cRightDown.c = defaultColour
end if
colorToRGB(cLeftUp)
colorToRGB(cLeftDown)
colorToRGB(cRightUp)
colorToRGB(cRightDown)
colour.r = cLeftUp.r * (1-xFact) * (1-yFact) + cRightUp.r * xFact * (1-yFact)_
+ cLeftDown.r * (1-xFact) * yFact + cRightDown.r * xFact * yFact
colour.g = cLeftUp.g * (1-xFact) * (1-yFact) + cRightUp.g * xFact * (1-yFact)_
+ cLeftDown.g * (1-xFact) * yFact + cRightDown.g * xFact * yFact
colour.b = cLeftUp.b * (1-xFact) * (1-yFact) + cRightUp.b * xFact * (1-yFact)_
+ cLeftDown.b * (1-xFact) * yFact + cRightDown.b * xFact * yFact
rgbToColor(colour)
pset dstImg, (x, y), colour.c
next
next
end sub
function inLimits(i as integer, iMin as integer, imax as integer) as integer
if (i < iMin) then return 0
if (i > iMax) then return 0
return 1
end function