Texture a random shape.

Blitz3D Forums/Blitz3D Beginners Area/Texture a random shape.

tonyg(Posted 2005) [#1]
How could I apply a scaled, rotated texture to a random shape created with Drawline?
For example...
Graphics 640,480
setbuffer backbuffer()
Line 10,10,400,10
Line 400,10,400,200
wLine 400,200,300,200
Line 300,200,350,150
Line 350,150,10,10
Flip
WaitKey()

Thanks


Damien Sturdy(Posted 2005) [#2]
I'm going to assume you're used to Blitzmax :P

In blitz3d there is no *quick* way to do it- You could however, use copypixel to do it.... Though as i said--- itl be slow. Certainly not realtime...


tonyg(Posted 2005) [#3]
Hi Cygnus,
Thanks for the reply.
I've done it in BlitzMax using OGL.
I didn't think there was an easy answer so I'll continue using floodfill/wpf for the shapes.


Clyde(Posted 2005) [#4]
you could always do the following, which works perfect for me for creating internal textures and images.

Graphics3D 640,480
setbuffer backbuffer()

Global Mesh=LoadMesh("object name")

Global Texture=createtexture(Size,Size,Flags) ; size being 64,128, 256 etc - and flags is optional, remove if unneeded

setbuffer TextureBuffer(Texture)
Line 10,10,400,10
Line 400,10,400,200
Line 400,200,300,200
Line 300,200,350,150
Line 350,150,10,10
setbuffer backbuffer()

; rest of program


And then assign it to your mesh / object - with EntityTexture Mesh,Texture

Hope this helps ya matey,
Cheers - Clyde :)


Rhyolite(Posted 2005) [#5]
@tonyg: you talk about applying texture, this is 3D terminology but you are using 2D commands. Perhaps you should be using sprites or quads??

Rhy :)


tonyg(Posted 2005) [#6]
Hi Clyde, I *think* that will take an 'object' and apply a texture of the poly drawn with the lines.. Is that right?
What I need to do is draw a shape (possible any shape with any number of sides) and then apply a loaded texture ONLY to that shape.
I could...
a) Draw the shape on black background
b) Floodfill the shape with 255,0,255
c) Grab the resulting image.
d) maskimage 255,255,255 (or 0,0,0)
e) Draw the texture
f) Draw the shape image
g) Grab the resulting image.
In Blitzmax I can apply a texture using Triangle_strip or GL_Polygon with vertex commands.
Rhy, this *is* 2D line statements but with the limitations above.
It needs to be quite quick which is why the above is not viable.


Clyde(Posted 2005) [#7]
Soz mate, I thought you were after texturing an object by creating one internally.

Are you after creating a random model?
Im not too hot at making objects, especially within B3D. I'd suggest investigating CreateMesh, AddTriangle and AddVertex. There were some examples of various custom mesh making in the Code Archives.

Sorry I couldnt of been of more help, hope it puts you on the right path.

Cheers and good luck dude,
Clyde :)


Rhyolite(Posted 2005) [#8]
Hmmm, I am confused - probably because I do not know BlitzMax! At the risk of making a fool of myself, I will have another bash ;)

You said 'In Blitzmax I can apply a texture using Triangle_strip or GL_Polygon with vertex commands'. Vertex commands are 3D, used to create the vertices of a 3D mesh. I was suggesting you create a flat 3D object by creating a vertex at each corner then linking them up with triangles.

You can then apply your loaded texture (Global Texture=createtexture(Size,Size,Flags)) to the 3D surface you have just created. You can not apply textures to a 2D shape, as that 'shape' does not actualy exist (it is just a collection of pixels on the screen).

Sorry if you know all that,
Rhy :)


tonyg(Posted 2005) [#9]
Hi Rhy,
As Blitzmax is (really) all 3D when you use Drawpoly it takes the points and uses them in a gl_polygon command as vertex2f commands (2D float) which you can bind the texture to.
What you're suggesting sounds very similar.
Given a list of points, how would I create the flat 3D object and then use (I assume) texturecoord to texture that shape.
Don't I need a surface ID (or something) to assing texturecoords and a texture to?
I know little about 3D so it's probably me missing something obvious.


Rhyolite(Posted 2005) [#10]
You may find using sprites is the easiest (check out the 'Sprite' commands in the Blitz3D help - hit F2 or F1 twice in the default IDE, I think!). Sprites are flat 3D entities and are square in shape, but your texture can always contain transparent areas to create the look of more complex objects - depends what you need. They are easy to use and can be set (default) to always face the camera (you always need a camera and lights to view 3D objects).

However, creating your own quads is more flexible and faster (but more complicated). Check out this code I found by quickly looking in the code archives. I am not saying these are the best for you, but they look ok from a quick read through and you should be able to modify for your own needs. If all you need is a square, you only need 4 vertices and 2 triangles (a quad).

http://www.blitzbasic.com/codearcs/codearcs.php?code=463

http://www.blitzbasic.com/codearcs/codearcs.php?code=382

I learnt an awful lot by studying other peoples code, so always worth browsing the archives (and forums). 3D is a big topic, I am still learning after having Blitz3D for nearly 2 years!

Have fun,
Rhy

EDIT: Oh, and once you have your quad or sprite, you will apply your texture to it using EntityTexture. You will need to store handle of the quad or sprite in a variable which you pass to EntityTexture (see Blitz help). You can adjust texture position using UV coordinates (do a search, I am sure you find exisiting info on this).


Rhyolite(Posted 2005) [#11]
Hmmm, here is a quick snippet of code off the top of my head, should make my waffling above a bit clearer!!?? I am not guaranteeing this will work, but it should give you a basic framework :)

You will need to experiment with entity position in realtion to camera so that you can 'see' the sprite. Remember, you are creating a 3D 'world', NOT drawing to the screen.

Camera = CreateCamera()
Light = CreateLight(2)

Mesh = CreateSprite()
Texture = createtexture(Size,Size,Flags)
EntityTexture (Mesh, Texture)
PositionEntity(Mesh, 0, 0, 10)

while keyhit(1) <> 1
renderworld()
flip
wend

end


Rhyolite(Posted 2005) [#12]
Doh, another post!! I am tired, sorry ;)

To create a texture, you could use the code 'Clyde' suggested above. Alternativley create a texture in your favourite paint program and use 'LoadTexture' instead of 'CreateTexture'. Textures must be square and in powers of 2 (ie. 32x32, 64x64, 128x128 pixels etc).

To start with, the easiest to get it up and running is just use 'EntityColor' instead of applying a texture at all.


tonyg(Posted 2005) [#13]
I think what you're saying is there is no way of doing this with the pure 2D side of 3D.
Just in case, this is the 'hack' I have so far.
Graphics 640,480
SetBuffer BackBuffer()
Global msx#,msy#,point1,point2,hi_angle#=-1000,lo_angle#=1000,hi_circ_x#,hi_circ_y#,lo_circ_x#,lo_circ_y#
Global hi_pty#,hi_ptx#,lo_pty#,lo_ptx#, msxhi#, msxlo#, hi_msx#, hi_msy#, lo_msy# , lo_msx#
Global Intersection_X#									; Values returned by the Lines_Intersect() function.
Global Intersection_Y#
Global Intersection_AB#
Global Intersection_CD#
rgb = getrgb(40,40,40)
;[needed for flood fill]
Dim map(GraphicsWidth(),GraphicsHeight())
Dim stackx(GraphicsWidth()*GraphicsHeight())
Dim stacky(GraphicsWidth()*GraphicsHeight())

Dim xmove(4),ymove(4)
xmove(1)=+1
xmove(3)=-1
ymove(2)=+1
ymove(4)=-1
;[/needed]

While Not KeyHit(1)
  ClsColor 60,255,60
  Cls
  msx# = MouseX()  
  msy# = MouseY()
  Color 255,255,255
  Oval msx-100,msy-100,200,200,1
  Color 0,0,0
  Oval msx-4,msy-4,8,8
  pt1x = 360 :  pt1y = 280 :  pt2x = 380 :  pt2y = 320
  Color 40,40,40
  line_extend(pt1x,pt1y,msx,msy)
  line_extend(pt2x,pt2y,msx,msy)
  line_extend(pt1x,pt2y,msx,msy)
  line_extend(pt2x,pt1y,msx,msy)
  Line hi_ptx,hi_pty,hi_msx+hi_circ_x,hi_msy+hi_circ_y
 Line lo_ptx,lo_pty,lo_msx+lo_circ_x,lo_msy+lo_circ_y
   Line hi_ptx,hi_pty,lo_ptx,lo_pty
  lines_intersect(hi_ptx,hi_pty,lo_msx+lo_circ_x,lo_msy+lo_circ_y,lo_ptx,lo_pty,hi_msx+hi_circ_x,hi_msy+hi_circ_y)
  If ((msx-intersection_x)*(msx-intersection_x))+((msy-intersection_y)*(msy-intersection_y)) <= 10000
     fillfast(Intersection_X#,Intersection_y#,rgb,BackBuffer())
  EndIf
   Color 0,0,255
  Rect pt1x,pt1y,pt2x-pt1x,pt2y-pt1y
  Text 100,0,"low angle = " + lo_angle
  Text 100,10,"High angle = " + hi_angle
  curTime = MilliSecs()
  If curTime > checkTime Then
     checkTime = curTime + 1000
     curFPS = fpscounter
     fpscounter = 0
  Else
     fpscounter = fpscounter + 1
  End If
  Text 100,20,"FPS : " + curFPS
  Flip
  hi_angle = -1000
  lo_angle = 1000
Wend
Function line_extend(point1,point2,msx1,msy1)
  If ((msx1-point1)*(msx1-point1))+((msy1-point2)*(msy1-point2)) <= 10000
     angle = ATan2(msx1-point1,msy1-point2)
     If angle > hi_angle
        hi_angle = angle
        hi_circ_x# = -Sin(hi_angle)*100
        hi_circ_y# = -Cos(hi_angle)*100
        hi_msx = msx1
        hi_msy = msy1
        hi_ptx = point1
        hi_pty = point2
     EndIf
     If angle < lo_angle
        lo_angle = angle
        lo_circ_x# = -Sin(lo_angle)*100
        lo_circ_y# = -Cos(lo_angle)*100
        lo_msx = msx1
        lo_msy = msy1
        lo_ptx = point1
        lo_pty = point2
     EndIf
  EndIf 
End Function  
Function GetRGB% ( Red% , Green% , Blue% )  ; Combines Red, Green and Blue values into one RGB value
    Return Red Shl 16 + Green Shl 8 + Blue
End Function
Function fillfast(startx,starty,fillc,buffer)
	scx=GraphicsWidth()
	scy=GraphicsHeight()
	If startx<0 Or starty<0 Or startx>=scx Or starty>=scy Then RuntimeError "fill starting point out of bounds"

	fillover=ReadPixelFast(startx,starty)
	If fillover=fillc Then Return

	LockBuffer buffer
	
	Dim map(scx,scy)

	WritePixelFast startx,starty,fillc
	map(startx,starty)=-1
	stackx(1)=startx
	stacky(1)=starty
	i2=1
	
	Repeat
		i=i+1
		If i>i2 Then Exit
		For dir=1 To 4
			If map(stackx(i),stacky(i))<>dir Then
				x=stackx(i)+xmove(dir)
				y=stacky(i)+ymove(dir)
				If x>=0 And y>=0 And x<scx And y<scy Then
					If map(x,y)=0 Then
						If ReadPixelFast(x,y)=fillover Then
							map(x,y)=dir+2-(dir+2>4) Shl 2
							i2=i2+1
							stackx(i2)=x
							stacky(i2)=y
							WritePixelFast x,y,fillc
						EndIf
					EndIf
				EndIf
			EndIf
		Next
	Forever
	UnlockBuffer buffer
End Function

Function Lines_Intersect(Ax#, Ay#, Bx#, By#, Cx#, Cy#, Dx#, Dy#)
  

	Rn# = (Ay#-Cy#)*(Dx#-Cx#) - (Ax#-Cx#)*(Dy#-Cy#)
        Rd# = (Bx#-Ax#)*(Dy#-Cy#) - (By#-Ay#)*(Dx#-Cx#)

	If Rd# = 0 
		
		; Lines are parralel.

		; If Rn# is also 0 then lines are coincident.  All points intersect. 
		; Otherwise, there is no intersection point.
	
		Return False
	
	Else
	
		; The lines intersect at some point.  Calculate the intersection point.
	
                Sn# = (Ay#-Cy#)*(Bx#-Ax#) - (Ax#-Cx#)*(By#-Ay#)

		Intersection_AB# = Rn# / Rd#
		Intersection_CD# = Sn# / Rd#

		Intersection_X# = Ax# + Intersection_AB#*(Bx#-Ax#)
         	Intersection_Y# = Ay# + Intersection_AB#*(By#-Ay#)
			
		Return True
		
	EndIf


End Function

<some of the code has been taken from examples on bb and bc so thanks and apologies for no credits).
It's, basically, a shadow caster with a lot of stuff hard-coded at the moment.
Lines are traces from the centre of the light (black oval in big white oval) to each predetermined edge of the rectangle. The lines are then checked to cast a shadow by taking the points of the furthest intersections and using floodfill to make the resulting 'shape' black.
There's quite a few bugs (such as the flip at 180 degress) which can be worked out later.
What I really want to do is fill that shadow shape as quickly as possible.


Rhyolite(Posted 2005) [#14]
Nice effect :)

Unless what you are doing is going to develop into a 'true' 3D application, then what you are doing seems fine. As far as I know, using WritePixelFast is the quickest way to fill an area.

Just to answer all your questions, there are other ways of doing this using the 3D commands of Blitz3D. However, Blitz3D is NOT just 3D and contains a comprehensive 2D command set also, which is what you (and many others) use. BlitzPlus contains this same 2D command set plus some GUI stuff, but no 3D commands.

Rhy :)


tonyg(Posted 2005) [#15]
Hi Rhy,
Framerates will drop using WPF with multiple shadows and larger areas plus I want softshadows which would involve a bit more math using a fill routine.
I'll check whether I can do what I want with SpriteCandy or NSpritePro. I'll be using those for the lightblend and shadeblend required anyway.
Thanks for your help


Rhyolite(Posted 2005) [#16]
Have you checked out Swifts shadow system?

http://www.blitzbasic.com/toolbox/toolbox.php?tool=87


tonyg(Posted 2005) [#17]
Yes I have. Thanks for the suggestion