Rotated and scaled image drawing - Marcus - 03-03-2024
I wrote a quick prototype of drawing images with arbitrary rotation and scaling in n7. The code may look a bit too complicated for just drawing a transformed image. But when I add this stuff to the core (implement it in C and add new commands to n7), I will also let you draw textured polygons with any number of points. Here I just draw a textured rectangle, four points.
It's slow, but it's gonna get a lot faster, of course.
I'm already thinking about adding support for z coordinates and perspective correct interpolation (for polygons). Would be fun to allow some 3d rendering as in naalaa 5.
Code: include "list.n7"
'#win32
#dbg
visible vPoints = fill([x: 0, y: 0, u: 0, v: 0], 4)
visible vXval = List()
vXval.Add([0, 0, 0])
vXval.Add([0, 0, 0])
set window "test", 640, 480
set redraw off
img = loadimage("logo.png")
pln width(img) + ", " + height(img)
a = 0
while not keydown(KEY_ESCAPE, true)
a = (a + 1)%360
set color 0, 0, 0
cls
set color 255, 255, 255, 0
' DrawImageTransformed(image, x, y, scale_x, scaleY, angle, pivot_x, pivot_y)
' draw scaled and centered (= pivot at center of image).
DrawImageTransformed(img, 120, 240, 2, 2, 0, width(img)/2, height(img)/2)
' draw rotated and centered
DrawImageTransformed(img, 320, 240, 1, 1, rad(a), width(img)/2, height(img)/2)
' draw rotated and scaled but put pivot at top left corner of image.
DrawImageTransformed(img, 520, 240, 4, 4, rad(a), 0, 0)
redraw
fwait 60
wend
function DrawImageTransformed(img, drawX, drawY, scaleX, scaleY, angle, pivotX, pivotY)
srcX = 0
srcY = 0
srcW = width(img)
srcH = height(img)
xLeft = -pivotX*scaleX
xRight = (srcW - pivotX)*scaleX
yTop = -pivotY*scaleY
yBottom = (srcH - pivotY)*scaleY
vPoints[0].x = xLeft; vPoints[0].y = yTop; vPoints[0].u = 0; vPoints[0].v = 0
vPoints[1].x = xRight; vPoints[1].y = yTop; vPoints[1].u = 1; vPoints[1].v = 0
vPoints[2].x = xRight; vPoints[2].y = yBottom; vPoints[2].u = 1; vPoints[2].v = 1
vPoints[3].x = xLeft; vPoints[3].y = yBottom; vPoints[3].u = 0; vPoints[3].v = 1
for i = 0 to sizeof(vPoints) - 1
x = vPoints[i].x*cos(angle) - vPoints[i].y*sin(angle)
y = vPoints[i].y*cos(angle) + vPoints[i].x*sin(angle)
vPoints[i].x = round(drawX + x)
vPoints[i].y = round(drawY + y)
if i = 0
minX = vPoints[i].x
maxX = vPoints[i].x
minY = vPoints[i].y
maxY = vPoints[i].y
else
minX = min(vPoints[i].x, minX)
maxX = max(vPoints[i].x, maxX)
minY = min(vPoints[i].y, minY)
maxY = max(vPoints[i].y, maxY)
endif
next
if maxX < 0 or minX >= width(primary) or maxY < 0 or minY >= height(primary) return
set color 255, 255, 255, 0
for y = minY to maxY
numx = 0
for i = 0 to sizeof(vPoints) - 1
p0 = vPoints[i]
p1 = vPoints[(i + 1)%sizeof(vPoints)]
if p0.y <= y and p1.y > y or
p0.y > y and p1.y <= y
dy = p1.y - p0.y
if dy = 0
vXval[numx][0] = p0.x; vXval[numx][1] = p0.u; vXval[numx][2] = p0.v
numx = numx + 1
vXval[numx][0] = p1.x; vXval[numx][1] = p1.u; vXval[numx][2] = p1.v
numx = numx + 1
else
f = (y - p0.y)/(p1.y - p0.y)
vXval[numx][0] = p0.x + f*(p1.x - p0.x)
vXval[numx][1] = p0.u + f*(p1.u - p0.u)
vXval[numx][2] = p0.v + f*(p1.v - p0.v)
numx = numx + 1
endif
endif
next
if numx
vXval.size = numx
vXval.SortByField(0, vXval.ASCENDING)
for i = 0 to vXval.size - 2 step 2
draw hraster img, y, vXval[i][0], vXval[i + 1][0],
vXval[i][1], vXval[i][2], vXval[i + 1][1], vXval[i + 1][2]
next
endif
next
draw poly vPoints, false
endfunc
RE: Rotated and scaled image drawing - johnno56 - 03-03-2024
Very cool... Not slow at all... Nicely done!
RE: Rotated and scaled image drawing - Marcus - 03-03-2024
(03-03-2024, 08:01 PM)johnno56 Wrote: Very cool... Not slow at all... Nicely done!
It would be slow if you drew like 100 rotated and scaled images. But I'm working on the real impementation in C now, and it's a lot speedier. Hopefully I can release the real thing next week
RE: Rotated and scaled image drawing - johnno56 - 03-04-2024
ah yes... 100 images. Goes without saying... looking forward to the changes...
RE: Rotated and scaled image drawing - 1micha.elok - 03-06-2024
(03-03-2024, 10:49 AM)Marcus Wrote: I wrote a quick prototype of drawing images with arbitrary rotation and scaling in n7.
...
TEST DRIVE
Using your transform (scaling) function and polyline, here it is a car racing game.
It is not perfect yet and I don't know how to curve the road
...but it's playable
zoom in to enlarge the image
Code: '=========================================
' TEST DRIVE
'
'Controls : LEFT, RIGHT
'
'Limitation :
'- I don't know how to make a curved road
'
'Written in :
'N7 24.02.16 release
'
'Sources :
'TitleScreen https://www.imgflip.com
'TitleScreen Background music
' This World Has Gone Crazy
' by lemonmusicstudio
' https://pixabay.com
'Sport Cars https://www.pngfind.com
'=========================================
'----------------
' INITIALIZATION
'----------------
#win32
include "assets/transform.n7"
include "assets/polyline.n7"; visible path= [] ; visible distance =[]; visible move_pixel = []
include "sfx.n7" ; visible sfx = SFX() 'create an sfx instance
visible font1 = createfont("Arial",20,1,0,0,0)'name,size,bold,italic,underlined,smoothed
randomize clock()
set window "TEST DRIVE", 360, 271,false,2
set redraw off
'color definition
sky = [51,204,204]
black = [0,0,0]
gray = [100,100,100]
white = [255,255,255]
green = [51,153,102]
'Create PolyLine for each path
path[0] = PolyLine([[width(primary)/2,height(primary)/2-80],[width(primary)/2 ,height(primary)]])
path[1] = PolyLine([[width(primary)/2,height(primary)/2-80],[width(primary)/2-80,height(primary)]])
path[2] = PolyLine([[width(primary)/2,height(primary)/2-80],[width(primary)/2+80,height(primary)]])
move_pixel[0] = rnd(2,5);move_pixel[1] = rnd(2,5); move_pixel[2] = rnd(2,5);
'Sprite class definition
Sprite =
[
'--- Properties ---
img:0,x:0,y:0,dx:20,s:0,a:0,px:0,py:0,distance:1,
'--- Methods ------
Draw:function(x,y,s,a)
' DrawImageTransformed(image, x, y, scale_x, scaleY, angle, pivot_x, pivot_y)
' Parameter :
' image = .png format
' (x,y) = location of the image in the screen coordinates
' scale_x, scale_y = scale the image's size
' angle = in radian.
' (pivot_x, pivot_y) = center point of the image. E.g:(0,0) = top left.
this.x = x; this.y = y ; this.s = s; this.a = a
this.px = width(this.img)/2; this.py = height(this.img)/2
DrawImageTransformed(this.img, this.x,this.y, this.s, this.s, this.a, this.px, this.py)
endfunc,
XY:function(i)
this.distance = (this.distance + move_pixel[i])%path[i].GetLength()
pos = path[i].GetPoint(this.distance,true)
this.x = pos[0]
this.y = pos[1]
endfunc
]
'Initial Value
Player = copy(Sprite)
Player.img = loadimage("assets/player.png")
Player.x = width(primary)/2
Player.y = height(primary)-15
Player.a = rad(0)'convert degree to radian
Player.s = 1
Car = fill(Sprite,3)
Car[0].img = loadimage("assets/blue.png")
Car[1].img = loadimage("assets/red.png")
Car[2].img = loadimage("assets/yellow.png")
score = 0; lifes = 5; quit =false; collide = false
'---------------
' MAIN LOOP
'---------------
TitleScreen()
PlayTune(1)
do
'Player is sent to out of screen if collide = true
if Player.y = -100 then
while keydown(KEY_RETURN,true)
Player.y = height(primary)-15
wend
endif
'Prepare screen : green grass, blue sky, gray road, white lines, score and lifes
set color green;cls
set color sky
draw rect 0,0,width(primary),height(primary)/2-80,1
set color gray
road = [width(primary)/2-8,height(primary)/2-80,width(primary)/2+8,height(primary)/2-80
,width(primary)/2+120,height(primary),width(primary)/2-120,height(primary)]
draw poly road,1
set color white
draw line 0 ,height(primary)/2-80 ,width(primary) ,height(primary)/2-80
draw line width(primary)/2 ,height(primary)/2-80 ,width(primary)/2 ,height(primary)
draw line width(primary)/2-8,height(primary)/2-80 ,width(primary)/2-120 ,height(primary)
draw line width(primary)/2+8,height(primary)/2-80 ,width(primary)/2+120 ,height(primary)
set font font1
set caret 10,5;wln "Score : "+score
if Player.y = -100 then; set caret 120,100;wln "ENTER TO PLAY";endif
set caret width(primary)-75,5;wln "Lifes : "+lifes
score = score + 1
'Check left and right Player's boundary
if Player.x > 120 and Player.x < 240 then
boundary = true
elseif Player.x<= 120 then
boundary = false
Player.x = Player.x + 5
PlayTune(2)
else
boundrary = false
Player.x = Player.x - 5
PlayTune(2)
endif
'Player's control
if keydown(KEY_LEFT,true) and boundary then Player.x = Player.x - Player.dx
if keydown(KEY_RIGHT,true) and boundary then Player.x = Player.x + Player.dx
if keydown(KEY_ESCAPE,true) quit = true
'Draw objects
Player.Draw(Player.x,Player.y,Player.s,Player.a)
Car[0].XY(0);Car[1].XY(1);Car[2].XY(2)
foreach i in Car
if i.y > height(primary)+20 then i.y = 0
i.s = i.y/(height(primary))
i.Draw(i.x,i.y,i.s,i.a)
'Collision Detection
if (Player.x>=i.x and Player.x<=i.x+51) and
(Player.y+20>=i.y and Player.y+20<=i.y+34) then collide=true
if (Player.x+45>=i.x and Player.x+45<=i.x+51) and
(Player.y+20>=i.y and Player.y+20<=i.y+34) then collide=true
if collide then
lifes = lifes-1
collide = false
Player.y = -100
set caret width(primary)-75,5;wln "Lifes : "+lifes
PlayTune(1)
if lifes <= 0 then Ending(white)
endif
next
PlayTune(3)'car's sound effect
redraw
fwait 10
until quit=true
'-----------
' FUNCTIONS
'-----------
function TitleScreen()
car = loadimage("assets/titlescreen.png",5,3)
track = loadmusic("assets/rock.wav")
set music volume track,0.5
play music track,1 '1 = looping
i= 0
while not keydown(KEY_RETURN,true)
if i<=11 then; i = i+1; else; i=0; endif; draw image car,0,0,i
set caret width(primary)/2,20
set font font1; center "TEST DRIVE"
set font 0 'default font
center "Face the challenge"
center "Conquer the street of..."
center "The Fast and The Furious"
center "Go Now...ENTER"
redraw
fwait 60
wend
'remove from memory
free music track
free image car
endfunc
function Sound(b,x)
mytune = sfx.SquareWave(b,x,0.5)'(duration,frequency, volume)
play sound mytune; wait 50
free sound mytune 'release sound from memory
endfunc
function PlayTune(i)
select i
case 1 'starting the game's scene
Sound(0.5,261.63);Sound(0.5,293.66);Sound(0.5,329.63)
case 2 'road's boundary
Sound(0.5,329.63*3);Sound(0.5,261.63*3)
case 3 'car's sound effect
Sound(0.1,261.63/2)
endsel
endfunc
function Ending(c)
set color c
set font font1
set caret width(primary)/2,5;center "THE END"
redraw
while not keydown(KEY_ESCAPE,true)
wait 1
wend
TitleScreen()
end
endfunc
RE: Rotated and scaled image drawing - Marcus - 03-06-2024
Nice one The awesome sound effect while driving sent me back to the atari 2600 days
RE: Rotated and scaled image drawing - Marcus - 03-06-2024
Hehe, some quick code, but I'm not sure it will help much, it's just a visual thing:
Code: #win32
set window "nah ...", 320, 240, false, 2
set redraw off
road = []
for z = 0 to 200 road[z] = sin(z*0.05)*6
playerz = 0.0
playerx = 0
p = dim(8)
while not keydown(KEY_ESCAPE, true)
playerz = playerz + 0.075
if keydown(KEY_LEFT) playerx = playerx - 0.1
if keydown(KEY_RIGHT) playerx = playerx + 0.1
set color 64, 64, 128
cls
set color 200, 128, 64
draw rect 0, 125, 320, 120, true
set color 255, 255, 255
for i = int(playerz) + 20 to int(playerz)
if i < sizeof(road) - 2
z = i + 1 - playerz + 1.1
x0l = 160 + 200*(road[i + 1] - 1 - playerx)/z
x0r = 160 + 200*(road[i + 1] + 1 - playerx)/z
y0 = 120 + 130/z
z = i - playerz + 1.1
x1l = 160 + 200*(road[i] - 1 - playerx)/z
x1r = 160 + 200*(road[i] + 1 - playerx)/z
y1 = 120 + 130/z
if i%2 = 0 set color 128, 128, 128
else set color 96, 96, 96
p[0] = x0l; p[1] = y0; p[2] = x0r; p[3] = y0
p[4] = x1r; p[5] = y1; p[6] = x1l; p[7] = y1
draw poly p, true
endif
next
redraw
fwait 60
wend
RE: Rotated and scaled image drawing - Marcus - 03-06-2024
And here we go with the texture mapping using 'draw poly image'
Code: #win32
set window "nah ...", 640, 480, false
set redraw off
' create two road textures.
roadImg = []
roadImg[0] = createimage(160, 16)
set image roadImg[0]
for y = 0 to 15 for x = 0 to 159
if rnd(3) = 0 set color 128, 128, 128
else set color 112, 112, 112
set pixel x, y
next
set color 255, 255, 255
draw rect 0, 0, 8, 16, true
draw rect 152, 0, 8, 16, true
set image primary
roadImg[1] = createimage(160, 16)
set image roadImg[1]
for y = 0 to 15 for x = 0 to 159
if rnd(3) = 0 set color 96, 96, 96
else set color 80, 80, 80
set pixel x, y
next
set color 255, 255, 255
draw rect 76, 0, 8, 16, true
set image primary
road = []
for z = 0 to 200 road[z] = sin(z*0.05)*6
playerz = 0.0
playerx = 0
p = dim(16)
p[2] = 0; p[3] = 0
p[6] = 160; p[7] = 0
p[10] = 160; p[11] = 16
p[14] = 0; p[15] = 16
while not keydown(KEY_ESCAPE, true)
playerz = playerz + 0.075
if keydown(KEY_LEFT) playerx = playerx - 0.1
if keydown(KEY_RIGHT) playerx = playerx + 0.1
set color 64, 64, 128
cls
set color 200, 128, 64
draw rect 0, 125*2, 640, 240, true
set color 255, 255, 255
for i = int(playerz) + 20 to int(playerz)
if i < sizeof(road) - 2
z = i + 1 - playerz + 1.1
x0l = 320 + 400*(road[i + 1] - 1 - playerx)/z
x0r = 320 + 400*(road[i + 1] + 1 - playerx)/z
y0 = 240 + 260/z
z = i - playerz + 1.1
x1l = 320 + 400*(road[i] - 1 - playerx)/z
x1r = 320 + 400*(road[i] + 1 - playerx)/z
y1 = 240 + 260/z
' if i%2 = 0 set color 128, 128, 128
' else set color 96, 96, 96
p[0] = x0l; p[1] = y0;
p[4] = x0r; p[5] = y0
p[8] = x1r; p[9] = y1;
p[12] = x1l; p[13] = y1
draw poly image roadImg[i%2], p
endif
next
redraw
fwait 60
wend
Edit Increased the resolution
RE: Rotated and scaled image drawing - 1micha.elok - 03-07-2024
(03-06-2024, 06:20 PM)Marcus Wrote: And here we go with the texture mapping using 'draw poly image'
...
Super awesome excellent...
Now, I need to find a way to put this texture mapping into TEST DRIVE the game a.k.a The Fast and The Furious
RE: Rotated and scaled image drawing - Marcus - 03-10-2024
This graphics set might be of use for a 3d racing game, and I might give it a try: https://opengameart.org/content/25d-racing-resources
|