Might as well ask first... :)

BlitzPlus Forums/BlitzPlus Programming/Might as well ask first... :)

BlitzSupport(Posted 2003) [#1]
Does anyone have code that'll map an image onto a (2D) quad with arbitrarily positioned corner points?


1, 2, 3, 4 -- corners

1-------------------2
|                   |
|                   |
|     Original      |
|                   |
|                   |
3-------------------4

     1
                 2

        Remapped

                    4

  3



... so in the remapped version it'll have the image appropriately stretched/scaled, etc, between the points? I'm going to attempt it, but I think it's actually a lot harder than it looks (for me, anyway), so it'd obviously be handy if someone's already done it :)


starfox(Posted 2003) [#2]
Have you tried tformimage


Beaker(Posted 2003) [#3]
James, I think I have some code to do this from long ago. If I find it I'll put it in the code archive.

(starfox - tformimage isn't going to do any good)


DJWoodgate(Posted 2003) [#4]
I think that old 3d engine by PRJ might be worth a look.


Floyd(Posted 2003) [#5]
This will make you appreciate 3d hardware.

Of course, your rectangle and quad can each be considered as two triangles.
So the real problem is mapping triangle to triangle.

Theoretically, this would be easy. There is just one linear transformation ( 3x3 matrix ) which maps the corresponding vertices. So you apply this to the entire source triangle and you are done!

But in the approximate world of limited number of pixels it gets a lot tougher. You have to estimate values with bilinear filtering or something similar.


EOF(Posted 2003) [#6]
In case you want to go with 3D my SpriteControl uses quads like so:
v0---v1
|   /|
|  / |
| /  |
|/   |
v2---v3


Quick example:
; Sprite Control - Quad manipulation

Include "Sprite Control.bb"

Graphics3D 640,480
SetBuffer BackBuffer()
ClearTextureFilters

cam=CreateCamera()
Spritecamera cam
testsprite=LoadImage3D("checker.jpg")
copy=LoadImage3D("checker.jpg")


; move corners
s=GetSurface(testsprite,1)
VertexCoords s,0,VertexX(s,0)+0.2,VertexY(s,0)+0.4,VertexZ(s,0)
VertexCoords s,1,VertexX(s,1)-0.7,VertexY(s,1)-0.2,VertexZ(s,1)
VertexCoords s,2,VertexX(s,2)-0.3,VertexY(s,2)-0.1,VertexZ(s,2)
VertexCoords s,3,VertexX(s,3)-0.1,VertexY(s,3)+0.1,VertexZ(s,3)

DrawImage3D copy,150,220
DrawImage3D testsprite,462,220

RenderWorld
Flip
WaitKey()
End


Result (BEFORE / AFTER)



BlitzSupport(Posted 2003) [#7]
Thanks Syntax, but I definitely want 2D here!

DJ: Good point -- I'll take a look (though I'm guessing it will be too complex for me!).

Floyd: ">> There is just one linear transformation ( 3x3 matrix )" -- stop right there! Ouch... though I guess this is related to Starfox's suggestion (never quite grasped TFormImage, though the example I have seems to just show resize/scale operations)...?

Master: if you do have that code, please pass it over... :)


Floyd(Posted 2003) [#8]
James,

I wrote that off the top of my head.
On second thought it gets even messier.

The 'linear transformation' is multiplication by a 3x3 matrix ( thinking of it as 3d ).
Multiplication always takes zero to zero. This means the origin can't be moved.

That makes the problem even harder.
In fact, this is why you see 'homogeneous coordinates' in 3d graphics.

That's the the trick which replaces the 3d point (x,y,z) with the 4d point (x,y,z,1) and uses 4x4 matrices.
The corresponding 2d trick replaces (x,y) with (x,y,1).
The 3x3 matrix transforms these points, always maintaining this special form.
It always takes a point (?,?,1) to another with the same form, i.e. z=1.

So good luck with this.

The best bet is probably to go looking for an existing library in C/C++.

Actually, this is getting interesting. Maybe I'll put some real thought into it.


EOF(Posted 2003) [#9]
never quite grasped TFormImage

I had a good play with TFormImage. Have a look at the Online Docs


Beaker(Posted 2003) [#10]
James - here ya go. It's old and dirty, and I've simplified it so you can use it as a starting point. It doesn't do any fancy filtering, nor even resize the pixels, so there is still some work for you. :)

Const top = 0, bottom = 1

AppTitle "Quad function demo" 
Graphics 640,480

Dim xp#(1, bottom) , yp#(1,bottom)
Dim xdelta#(1), ydelta#(1)

image = LoadImage ("cat.png")
Global imagew = ImageWidth(image), imageh = ImageHeight(image)
Dim imageRGB(ImageW-1,ImageH-1)
Dim position(ImageW-1,ImageH-1)

LockBuffer (ImageBuffer(image))
For x = 0 To imagew-1
	For y = 0 To imageh-1
		imageRGB(x,y) = ReadPixelFast(x,y, ImageBuffer(image)) And $FFFFFF
		position(x,y) = 0
	Next
Next
UnlockBuffer(ImageBuffer(image))

		
Dim xp#(ImageW, bottom)
Dim yp#(imagew, bottom)
Dim xdelta#(imagew)	
Dim ydelta#(imagew)
	

SetBuffer BackBuffer()

angle = 0
MoveMouse width/2, height/2
Repeat
	angle = (angle + 3) Mod 360 
	cosang = Cos(angle)*100
	sinang = Sin(angle)*100
	quad (image, 130+sinang / 3,130+cosang / 3, 400+sinang / 2,90+cosang / 2, 460,260, MouseX(), MouseY()) 
	Color 255,255,255
	Text 5,460, "Quad Mapping by Beaker 2001"

	Flip:Cls
Until KeyHit(1)
End 



Function Quad (image, x0#,y0#, x1#,y1#, x2#,y2#, x3#,y3#)
	xpdtop# = (x1 - x0) / (imagew - 1)
	ypdtop# = (y1 - y0) / (imagew - 1)
	
	xpdbott# = (x2 - x3) / (imagew - 1)
	ypdbott# = (y2 - y3) / (imagew - 1)
	
 	For x = 0 To ImageW
		xp(x,top) = x0 + (x * xpdtop)
		yp(x,top) = y0 + (x * ypdtop)

		xp(x,bottom) = x3 + (x * xpdbott)
		yp(x,bottom) = y3 + (x * ypdbott)
	Next

	For x = 0 To imagew
		xdelta(x) = ((xp(x,bottom) - xp(x,top)) / (imageh - 1))
		ydelta(x) = ((yp(x,bottom) - yp(x,top)) / (imageh - 1))
	Next

		
	For x = 0 To imagew - 1
		For y = 0 To imageh - 1
			If imageRGB(x,y) > 0
				xadderTL = (xdelta(x) * y)

				position(x,y) = (xp(x,top) + (y * xdelta(x)) Shr 16) Or yp(x,top) + (y * ydelta(x))
				
				Color imageRGB(x,y) Shr 16 And $ff, imageRGB(x,y) Shr 8 And $ff, imageRGB(x,y) And $ff
				Oval xp(x,top) + (y * xdelta(x)), yp(x,top) + (y * ydelta(x)), 6,6
			EndIf
		Next
	Next
End Function



BlitzSupport(Posted 2003) [#11]
Ah, that's pretty much what I'm after, Beaks! Thanks, I'll take a good look at that. Also, good call, Syntax -- hadn't seen that TForm stuff, so I'll check that too. Thanks, all :)


jfk EO-11110(Posted 2003) [#12]
if you want a faster one then have a look on the "3D Engine" in the 2D Graphics Code Archives. It has a (linear) Texturemapper which is pretty quick.


jfk EO-11110(Posted 2003) [#13]
BTW MasterBeaker - that's a nice Function - but using Oval is slowing it really down.

Also the Size can be smaller than 6*6.
I used:
Rect xp(x,top) + (y * xdelta(x)), yp(x,top) + (y * ydelta(x)), 3,3,1
and it still looked good, but it was much faster.

Some minutes ago I realized the first time that non-opac Rect is MUCH slower than opac Rect!! (filled Rects are faster)

So when you use Rect for 90 Degs Lines Optimation, eg:

Rect 50,20,100,1
instead of
Line 50,20,150,20
then you should always use the Opac Flag:
Rect 50,20,100,1,1
Now this is about 100 times faster than the Line Function.


Beaker(Posted 2003) [#14]
Oval was only really used for demonstration of the function.

I used 6x6 because the image I tested it with was very small.


BlitzSupport(Posted 2003) [#15]
I've still to take a look at your code, Norc (going to do it now), but thanks to Syntax, I finally have some sort of grasp of TFormImage now! I actually think it should be able to do this for me, if I can just figure out the calculations needed to scale/warp to the exact offsets required...

Just posting this cos I suddenly love TFormImage (all it does is scale the image :)

; Load an image smaller than the screen size!

AppTitle "TFormImage..."

Graphics 808, 600, 0, 2
SetBuffer BackBuffer ()

image = LoadImage ("F:\My Documents\My Pictures\02porschecayenne.jpg")

; TFormImage image, a, b, c, d

; a -- Position of right edge (1 = normal)
; b -- Shear of right edge (0 = no shear)
; c -- Shear of bottom edge (0 = no shear)
; d -- Position of bottom edge (1 = normal)

TFormImage image, 1, 0, 0, 1
DrawImage image, 0, 0
Flip
;MouseWait

MoveMouse ImageWidth (image), ImageHeight (image)

TFormFilter False

Repeat

	If (MouseXSpeed ()) Or (MouseYSpeed ())
		Cls
		timage = CopyImage (image)
		If (MouseX () > 0) And (MouseY () > 0)
			TFormImage timage, Float (MouseX ()) / Float (ImageWidth (timage)), 0, 0, Float (MouseY ()) / Float (ImageHeight (timage))
			DrawImage timage, 0, 0
		EndIf
		FreeImage timage
		Flip
	EndIf

Until KeyHit (1)

End



PRJ(Posted 2003) [#16]
Check 3d.* @ http://www.stud.ntnu.no/~paulrene/blitzbasic/


BlitzSupport(Posted 2003) [#17]
Thanks Paul -- I actually found that not long after this thread was last alive (I leeched *all* of your site's Blitz stuff a couple of months ago because it rules!).

In fact I was thinking about this again today, weirdly enough, because I never quite got it right, and I remembered your engine had a function that looked like it would take care of this for me!