MyCylinder modification

Blitz3D Forums/Blitz3D Programming/MyCylinder modification

Boiled Sweets(Posted 2005) [#1]
Hi,

I use the MyCylinder code from the archives...

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

I have noticed that the 'bottom' of the cylinder is not joined, i.e. imagine a sheet of paper bent and joined to form a cylinder, the two edges of the join have their own vertexes but in a Blitz cylinder the tris share vertexes.

Does that make sense? Is there a GURU out there how can modify the creation of the cylinder (using the above code) to make a cylinder (with segments) that is joined?

Many thanks, and you will get a special thank you in my application!!!


big10p(Posted 2005) [#2]
I have noticed that the 'bottom' of the cylinder is not joined, i.e. imagine a sheet of paper bent and joined to form a cylinder, the two edges of the join have their own vertexes but in a Blitz cylinder the tris share vertexes.


You sure? As far as I'm aware, blitz cycliners (and spheres, cones) have a 'seam' where duplicate verts are used - they're needed to UV map it correctly.


Boiled Sweets(Posted 2005) [#3]
Hmm, that is a bugger. The reason I see it is I use the RippleMesh code it 'tears' the seam. It doesn't when using a regular cylinder.


Ross C(Posted 2005) [#4]
Have you tried using the createcylinder() or a cylinder from a modelling package? To see if the problem still occurs?


Boiled Sweets(Posted 2005) [#5]
I use the MyCylinder code from the archives...

www.blitzbasic.com/codearcs/codearcs.php?code=863

i need to use that


Boiled Sweets(Posted 2005) [#6]
I need to use it as it has the segments code in it. Anyone? There must be a bb god out there who can help...


DJWoodgate(Posted 2005) [#7]
As big10p says you will get a discontinuity as the uvalue wraps from 1 to 0. There are ways to disguise this though, depending on your texture you could just mirror part of the texture and run the uvalues from 0 to 0.5 and then back to 0. Or you could run the uvalues from 0 to 1 and then back to 0 so you have the texture wrapped round the cylinder twice.

As to joining up the verts so there is no seam around the body of the cylinder, I think it goes something like this..

Change the ring segment loops to
For i=0 To (verticalsegments-2)

And change the tri fill to
; Fill in ring segment sides with triangles
For v=1 To (verticalsegments)
If v=verticalsegments Then
tl=tRing(0)
tr=tRing(v-1)
bl=bRing(0)
br=bRing(v-1)
Else
tl=tRing(v)
tr=tRing(v-1)
bl=bRing(v)
br=bRing(v-1)
EndIf

AddTriangle(thissurf,tl,tr,br)
AddTriangle(thissurf,bl,tl,br)
Next

to get the texture wrapped twice try..
udiv#=Float(2.0/(verticalsegments))
And
If i<verticalsegments/2 thisUPos#=thisUPos#-udiv# Else thisUpos=thisUpos+udiv
instead of
thisUPos#=thisUPos#-udiv#
in the loops for the ring segments.
You may have to tweak some of this though, I have not really tested it properly, but I expect you get the idea.


Boiled Sweets(Posted 2005) [#8]
Hi David,

thanks, to be honest I do not get the idea! I have tried what you suggested but it doesn't appear to work correctly - it looks very odd now, could you please send me a complete example. Many thanks!!!!


Ross C(Posted 2005) [#9]
I suppose you could create a very small fillet between the cylinder and the cap, and use the extra ring of vertices to change the vertex co-ords.


Boiled Sweets(Posted 2005) [#10]
Hey DJWoodgate,

any news on a working example?

Please mate, grovel, grovel.


_PJ_(Posted 2005) [#11]
[quote]
I suppose you could create a very small fillet between the cylinder and the cap,
[/qupte]

Mmmmmm Fillet....Chicken Fillet....KFC Chicken Fillet Tower Burgers oohhh yummmy! (Aint it lunchtime yet?)


DJWoodgate(Posted 2005) [#12]
Sorry i have not had much time to look at this. The problem is the rather simplistic way I have calculated ThisUpos. Obviously it must go to 0 and back to 1, but as it stands it will only do this properly with an even number of sides and besides which mirroring things like this requires a texture to suit. Now I was going to attempt to fix this but then I noticed Todds' original code had a problem with smoothing the normals across the seam in some cases.

This is due to a slight offfset in the vertex positions between the first and final calculated x position (most noticeable with X anyway) on the circumference of the main body and is I think due to floating point precision issues on the result returned from the cos function which is started at 90 degrees and ends at 450 degrees. The way siderotangle is stepped by means of addition probably compounds the issue and adds a little more innacuracy.

It occured to me this might be relevant to your ripple function, whatever that does, and so to fix that modify the Siderotangle step code in the two loops to
If i<(verticalsegments-1) Then SideRotAngle#=SideRotAngle#+div# Else Siderotangle#=90
This should ensure that the finals verts will be positioned in exactly the same place as the first ones which may help.


DJWoodgate(Posted 2005) [#13]
Aha. Actually if you are using that ripple code by Halo shipped with the samples, then you could modify that to treat the XYZ coords at the same Y in the same way and thus avoid tearing along the seam. I have made a quick mod to show what I mean. I expect you will be able to improve on this.

; Halo's ripple mesh code modified for use with Todd Riggins Segmented cylinder.
;==========================================================
Function ripple(mesh,omesh,depth#=0.1,speed#=0.1,freq#=200)
	Local k,surf,surf2,index,add#,pos#,newx#,newy#,newz#,time=MilliSecs()

	For k=1 To CountSurfaces(mesh)
		surf=GetSurface(mesh,k)
		surf2=GetSurface(omesh,k)
		
		For index=0 To CountVertices(surf)-1
			newy#=VertexY(surf2,index)
			pos=newy*freq
			If wrapvalue#(time*speed+pos,0,720)>230 Or wrapvalue#(time*speed+pos,0,720)<270
				add#=(Sin(time*speed+pos)*depth)
				newx#=VertexX(surf2,index)+add*VertexNX(surf2,index)
				newz#=VertexZ(surf2,index)+add*VertexNZ(surf2,index)
			Else
				add=depth*-1
				newx#=VertexX(surf2,index)+add*VertexNX(surf2,index)
				newz#=VertexZ(surf2,index)+add*VertexNZ(surf2,index)
			EndIf
			VertexCoords surf,index,newx,newy,newz
		Next
	Next
	UpdateNormals mesh
End Function



Edit. Changed it a bit so you can use updatenormals on the mesh.


Boiled Sweets(Posted 2005) [#14]
Where / what / who / why is wrapvalue#


DJWoodgate(Posted 2005) [#15]
Ah sorry, I guess you are not using Halo's code then. Have a look in the 3d samples folder under halo and meshfx.
Anyway this is the wrapvalue function he uses...

;====================
Function wrapvalue#(value#,lo#,hi#)
i=Floor(value/(hi-lo))
r#=i*(hi-lo)
Return (value-r)+lo
End Function

Edit... Well although that is elegant, it still has some issues so I am looking to improve it, particularly when lo is negative and hi is positive or hi or lo are large numbers. I can't currently figure out how to modify it though so here is an alternative
Function wrapvalue#(value#,low#,high#)
	If value<low Then value=high-(low-value) Mod (high-low)
	If value>=high Then value=low+(value-high) Mod (high-low)
	Return value
End Function


Here is another amended and more simplified version of the ripple function.

; Halo's ripple mesh code modified for use with Todd Riggins Segmented cylinder.
;==========================================================
Function ripple(mesh,omesh,depth#=0.1,speed#=0.1,freq#=200)
	Local k,surf,surf2,index,add#,pos#,newx#,newy#,newz#,time=MilliSecs() And $FFFFFF

	For k=1 To CountSurfaces(mesh)
		surf=GetSurface(mesh,k)
		surf2=GetSurface(omesh,k)
		
		For index=0 To CountVertices(surf)-1
			newy#=VertexY(surf2,index)
			pos#=newy*freq
			add#=Sin(wrapvalue(pos+time*speed,0,360))*depth
			newx#=VertexX(surf2,index)+add*VertexNX(surf2,index)
			newz#=VertexZ(surf2,index)+add*VertexNZ(surf2,index)
			VertexCoords surf,index,newx,newy,newz
		Next
	Next
	UpdateNormals mesh
End Function


In fact as this is pretty cylinder specific we can change it to deal with the end caps.

; Halo's ripple mesh code modified for use with Todd Riggins Segmented cylinder.
;==========================================================
Function ripple(mesh,omesh,depth#=0.1,speed#=0.1,freq#=200)
	Local k,surf,surf2,index,add#,pos#,newx#,newy#,newz#,mag#
	Local time=MilliSecs() And $FFFFFF

	For k=1 To CountSurfaces(mesh)
		surf=GetSurface(mesh,k)
		surf2=GetSurface(omesh,k)
		verts=CountVertices(surf)-1		

		For index=0 To verts
			newx = VertexX(surf2,index)
			newy = VertexY(surf2,index)
			newz = VertexZ(surf2,index)
			pos = newy * freq
			add = Sin(wrapvalue(pos+time*speed,0,360)) * depth
			mag = Sqr(newx*newx+newz*newz)
			newx = newx + add * newx * mag
			newz = newz + add * newz * mag
			VertexCoords surf,index,newx,newy,newz
		Next
	Next

	UpdateNormals mesh
End Function


In fact I now see you are probably using the ripplemesh code on the archives, which is very much a different kettle of fish. I guess you could do something like that with a seamed mesh, but you will have to preprocess the mesh information to capture verts into a list of some sort and ensure coincident verts receive identical transforms, unless of course you can otherwise ensure that verts with the same X Y and Z will receive the same transform, which is something to ponder.


Boiled Sweets(Posted 2005) [#16]
Hi David, tried your code but it strange horrid things!

I use this ripple mesh code from the archives...
and the cylinder code also from the archives...

Added em together, try running this, you will see the tear, can you fix this?

I will give you special credits in my app :-)

NICE ONE!

TRY THIS CODE.....

; ID: 939
; Author: Olive
; Date: 2004-02-20 07:58:15
; Title: Tunnel Effect
; Description: A tunnel effect like in demos

; CreateMyCylinder Example 
; ---------------------- 
; By Pigmin (alias Olive) 02-20-2004
;
; pigmin@...
; 
; meet me at http://www.blitz3dfr.com (forum section)
;
;
;
; With wonderfull function :
;
; CreateMyCylinder
; ---------------------- 
; By: Todd Riggins 12-22-2003 
; 
; a CreateCylinder blitz-like function. Does the Same thing. Just wanted to do 
; this to see how to actaully create a cylinder with the addvertex/addtriangle 
; commands. Just thought I would share. 

; ----------------- 
; 2004-2-19 1:10:00 
; - Added ring segments. Ring Segment param of zero acts like the 
; blitz-like Function. IE: no ring segments. 
; - The added ring segments adds vertices to help bend cylinder tunnels or angle 
; pipe meshs. Ofcoarse, you will need to add your own code to manipulate the 
; cylinder's vertices. 
; 2004-2-18 21:00:00 
; - Fixed normal vectors problem: Needed to have cylinder ends as seperate surface 
; 
; Left sphere is created by the CreateMyCylinder function. 
; Right sphere is created by blitz's CreateCylinder command. 
; 
; Controls: 
; - Use mouse to rotate the cylinders 
; - wireframe toggle 
; - Esc key to escape 

; rediminsionable arrays 
Dim tRing(0) 
Dim bRing(0) 

Type TCtrlPoint
	Field x#
	Field y#
End Type

Const MAX_CTRL_POINTS = 16
Const TWIST# = 30

Global CtrlPoints.TCtrlPoint[MAX_CTRL_POINTS]
Global CtrlPointsPhase% = 0
Global CtrlPointsPhase2% = 0

Graphics3D 640,480,0,2
SetBuffer BackBuffer() 


AmbientLight 32,0,0

camera=CreateCamera() 
CameraRange camera,.1,2000
light=CreateLight() 
RotateEntity light,90,0,0 

; enter how many segments the sphere has 
Global vsegs=32 
Global rsegs=MAX_CTRL_POINTS

;Texture
tex=CreateTexture(32,32,1+8)
SetBuffer(TextureBuffer(tex))
colR = 128
For j = 0 To 31 Step 8
	colR = 64 - colR
	For i = 0 To 31 Step 8
		colR = 64 - colR
		Color colR,colR,colR
		Rect(i,j,8,8,1)
	Next
Next
SetBuffer (BackBuffer())
ScaleTexture tex,.25,.25

;Texture2
tex2=CreateTexture(64,64,1+4+8)
SetBuffer(TextureBuffer(tex2))
For j = 0 To 16
	colR = Rand(10,64)
	colG = Rand(0,128)
	colB = Rand(0,180)
	Color colR,colG,colB
	Rect(Rand(0,63),Rand(0,63),Rand(1,2),Rand(1,31))
	Rect(Rand(0,63),Rand(0,63),Rand(1,31),Rand(1,2))
Next
SetBuffer (BackBuffer())
ScaleTexture tex2,.1,.25
TextureBlend tex,2
TextureBlend tex2,3

; Create Cylinder manually 
mycylinder=CreateMyCylinder(vsegs,rsegs,False,0)
ScaleMesh mycylinder,6,40,6
RotateMesh mycylinder,90,0,0
FlipMesh mycylinder
PositionEntity mycylinder,0,0,39 
EntityTexture mycylinder,tex,0,0
EntityTexture mycylinder,tex2,0,1

mycylindercopy = CopyMesh(mycylinder)
HideEntity mycylindercopy

;allocate control points
For i = 0 To MAX_CTRL_POINTS
	CtrlPoints[i] = New TCtrlPoint
	CtrlPoints[i]\x# = (i*260/MAX_CTRL_POINTS)
	CtrlPoints[i]\y# = (i*460/MAX_CTRL_POINTS)
Next

; key helper 
wkey=0 

xx#=0
cnt#=0
freqX = 1
freqY = 1
While Not KeyDown( 1 ) 


	Tunnel_effect(mycylinder, mycylindercopy,  CtrlPointsPhase,  CtrlPointsPhase2)
	CtrlPointsPhase = CtrlPointsPhase + freqX
	CtrlPointsPhase2 = CtrlPointsPhase2 + freqY

   ripplemesh(mycylinder,1,1,2)


	If (Not Rand(0,200))
		freqY = Rand(0,4)
	EndIf

	If (Not Rand(0,400))
		freqX = Rand(1,4)
	EndIf

	PositionTexture Tex,0,cnt#
	PositionTexture Tex2,cnt#,cnt#
	cnt#=cnt#+.01*(freqX+freqY)*.5

	If KeyDown(17) And wkey=0 
	wkey=1 
	EndIf 
	
	If KeyDown(17)=False And wkey=1 
	wkey=0 
	If wframe=0 
	wframe=1 
	Else 
	wframe=0 
	EndIf 
	If wframe=0 WireFrame False 
	If wframe=1 WireFrame True 
	EndIf 
	
	
	RenderWorld 

	Flip 
Wend 

End 

; --------------------------------------------------------- 
Function CreateMyCylinder(verticalsegments,ringsegments=0,solid=True,parent=0) 
	Local tr,tl,br,bl; side of cylinder 
	Local ts0,ts1,newts; top side vertexs 
	Local bs0,bs1,newbs; bottom side vertexs 
	If verticalsegments<3 Or verticalsegments>100 Then Return 0 
	If ringsegments<0 Or ringsegments>100 Then Return 0 
	
	thiscylinder=CreateMesh(parent) 
	thissurf=CreateSurface(thiscylinder) 
	If solid=True 
		thissidesurf=CreateSurface(thiscylinder) 
	EndIf 
	div#=Float(360.0/(verticalsegments)) 
	
	height#=1.0 
	ringSegmentHeight#=(height#*2.0)/(ringsegments+1) 
	upos#=1.0 
	udiv#=Float(1.0/(verticalsegments)) 
	vpos#=1.0 
	vdiv#=Float(1.0/(ringsegments+1)) 
	
	SideRotAngle#=90 
	
	; re-diminsion arrays to hold needed memory. 
	; this is used just for helping to build the ring segments... 
	Dim tRing(verticalsegments) 
	Dim bRing(verticalsegments) 
	
	;render end caps if solid 
	If solid=True 
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		
		ts0=AddVertex(thissidesurf,XPos#,height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		bs0=AddVertex(thissidesurf,XPos#,-height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		
		SideRotAngle#=SideRotAngle#+div# 
		
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		
		ts1=AddVertex(thissidesurf,XPos#,height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		bs1=AddVertex(thissidesurf,XPos#,-height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		
		For i=1 To (verticalsegments-2) 
			SideRotAngle#=SideRotAngle#+div# 
			
			XPos#=-Cos(SideRotAngle#) 
			ZPos#=Sin(SideRotAngle#) 
			
			newts=AddVertex(thissidesurf,XPos#,height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
			newbs=AddVertex(thissidesurf,XPos#,-height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
			
			AddTriangle(thissidesurf,ts0,ts1,newts) 
			AddTriangle(thissidesurf,newbs,bs1,bs0) 
			
			If i<(verticalsegments-2) 
				ts1=newts 
				bs1=newbs 
			EndIf 
		Next 
	EndIf 

	; ----------------------- 
	; middle part of cylinder 
	thisHeight#=height# 
	
	; top ring first 
	SideRotAngle#=90 
	XPos#=-Cos(SideRotAngle#) 
	ZPos#=Sin(SideRotAngle#) 
	thisUPos#=upos# 
	thisVPos#=0 
	tRing(0)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
	For i=0 To (verticalsegments-1) 
		SideRotAngle#=SideRotAngle#+div# 
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		thisUPos#=thisUPos#-udiv# 
		tRing(i+1)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
	Next 
	
	For ring=0 To (ringsegments) 
	
		; decrement vertical segment 
		thisHeight=thisHeight-ringSegmentHeight# 
		
		; now bottom ring 
		SideRotAngle#=90 
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		thisUPos#=upos# 
		thisVPos#=thisVPos#+vdiv# 
		bRing(0)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
		For i=0 To (verticalsegments-1) 
			SideRotAngle#=SideRotAngle#+div# 
			XPos#=-Cos(SideRotAngle#) 
			ZPos#=Sin(SideRotAngle#) 
			thisUPos#=thisUPos#-udiv# 
			bRing(i+1)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
		Next 
		
		; Fill in ring segment sides with triangles 
		For v=1 To (verticalsegments) 
			tl=tRing(v) 
			tr=tRing(v-1) 
			bl=bRing(v) 
			br=bRing(v-1) 
			
			AddTriangle(thissurf,tl,tr,br) 
			AddTriangle(thissurf,bl,tl,br) 
		Next 
		
		; make bottom ring segmentthe top ring segment for the next loop. 
		For v=0 To (verticalsegments) 
			tRing(v)=bRing(v) 
		Next 
	Next 
	
	UpdateNormals thiscylinder 
	Return thiscylinder 
End Function 

Function Tunnel_Effect(mesh, mesh_original, phase, phase2)

	cntsurf = CountSurfaces(mesh)
	
	surf=GetSurface(mesh,cntsurf)
	surf_original=GetSurface(mesh_original,cntsurf)
	
	cnt=CountVertices(surf)
	For s=0 To rsegs
	
		deltax# = Cos(CtrlPoints[s]\x# + phase)*(TWIST#/(s+1))
		deltay# = Sin(CtrlPoints[s]\y# + phase2)*(TWIST#/(s+1))
			
		firstVertice = s*(vsegs+1)
		endVertice = firstVertice + vsegs
		For a=firstVertice To endVertice
			x#=VertexX#(surf_original,a)
			y#=VertexY#(surf_original,a)
			z#=VertexZ#(surf_original,a)
								
			x#=x#+deltax#
			y#=y#+deltay#

			VertexCoords surf,a,x#,y#,z#
		Next
	Next
	UpdateNormals mesh
		
End Function


Function ripplemesh(mesh,speed#,density#,depth#)
	count=MilliSecs()*speed
	For scount=1 To CountSurfaces(mesh)
		surface = GetSurface(mesh,scount)
		numverts=CountVertices(surface)-1
		For i=0 To numverts
			a#=Cos(count+(i*density))*speed
			b#=Sin(count+(i*density))*speed
			c#=-b;Sin(count+(i*density))*speed
			nx#=VertexNX(surface,i)*depth
			ny#=VertexNY(surface,i)*depth
			nz#=VertexNZ(surface,i)*depth			
			x#=VertexX(surface,i)
			y#=VertexY(surface,i)
			z#=VertexZ(surface,i)		
			VertexCoords surface,i,x#+(a*nx),y#+(b*ny),z#+(c*nz)
		Next
	Next
End Function



DJWoodgate(Posted 2005) [#17]
I am not very good at this stuff, but I doubt that ripplemesh code on the archives is going to be of much help to you, it lacks stability for a start. I would modify your tunnel effect function, which is IMO a lot more capable.

The idea, I think, is to superimpose a "ripple" on the basic deltax and deltay tunnel distortion you are already producing.

I have made an attempt, But it is still not working properly.


Boiled Sweets(Posted 2005) [#18]
Please stick with it mate -- I would be very grateful


DJWoodgate(Posted 2005) [#19]
OK, I have solved a few issues. Still not perfect, and the ripples it does provide are tawdry affairs, so you will be able to improve on this. Use the F key to select the ripple scheme - nothing special, just some values I was playing with. The A key autoincrements ripple values, Ins/Del, Home/End and Page Up/Page Down keys manually alter the ripples, +/- on the numeric pad changes the depth and the R key resets. The space key just rotates the cylinder so you get an external view of the distortion applied.

Edit. BTW Although not particularly noticeable in this code, if you do see bad normals being generated, then it may be partly due to the use of scalemesh so you could use scaleentity instead. I have not made that change here though as the twisting you do for your tunnel effect introduces enough irregularity to stop this occuring for the most part. I think it is a problem with updatenormals.

; ID: 939
; Author: Olive
; Date: 2004-02-20 07:58:15
; Title: Tunnel Effect
; Description: A tunnel effect like in demos

; CreateMyCylinder Example 
; ---------------------- 
; By Pigmin (alias Olive) 02-20-2004
;
; pigmin@...
; 
; meet me at www.blitz3dfr.com (forum section)
;
;
;
; With wonderfull function :
;
; CreateMyCylinder
; ---------------------- 
; By: Todd Riggins 12-22-2003 
; 
; a CreateCylinder blitz-like function. Does the Same thing. Just wanted to do 
; this to see how to actaully create a cylinder with the addvertex/addtriangle 
; commands. Just thought I would share. 

; ----------------- 
; 2004-2-19 1:10:00 
; - Added ring segments. Ring Segment param of zero acts like the 
; blitz-like Function. IE: no ring segments. 
; - The added ring segments adds vertices to help bend cylinder tunnels or angle 
; pipe meshs. Ofcoarse, you will need to add your own code to manipulate the 
; cylinder's vertices. 
; 2004-2-18 21:00:00 
; - Fixed normal vectors problem: Needed to have cylinder ends as seperate surface 
; 
; Left sphere is created by the CreateMyCylinder function. 
; Right sphere is created by blitz's CreateCylinder command. 
; 
; Controls: 
; - Use mouse to rotate the cylinders 
; - wireframe toggle 
; - Esc key to escape 

; rediminsionable arrays 
Dim tRing(0) 
Dim bRing(0) 

Type TCtrlPoint
	Field x#
	Field y#
End Type

Const MAX_CTRL_POINTS = 24
Const TWIST# = 30

Global CtrlPoints.TCtrlPoint[MAX_CTRL_POINTS]
Global CtrlPointsPhase% = 0
Global CtrlPointsPhase2% = 0

Graphics3D 640,480,0,2
SetBuffer BackBuffer() 


AmbientLight 32,0,0

camera=CreateCamera() 
CameraClsColor camera, 255,0,0
CameraRange camera,.1,1000
light=CreateLight()
RotateEntity light,45,0,0 

; enter how many segments the sphere has 
Global vsegs=24 
Global rsegs=MAX_CTRL_POINTS

;Texture

tex=CreateTexture(32,32,1+8) : ScaleTexture tex,.25,.25
SetBuffer(TextureBuffer(tex))
colR = 128
For j = 0 To 31 Step 8
	colR = 64 - colR
	For i = 0 To 31 Step 8
		colR = 64 - colR
		Color colR,colR,colR
		Rect(i,j,8,8,1)
	Next
Next
SetBuffer (BackBuffer())

;Texture2
tex2=CreateTexture(64,64,1+4+8) : ScaleTexture tex2,.1,.25
SetBuffer(TextureBuffer(tex2))
For j = 0 To 16
	colR = Rand(10,64)
	colG = Rand(0,128)
	colB = Rand(0,180)
	Color colR,colG,colB
	Rect(Rand(0,63),Rand(0,63),Rand(1,2),Rand(1,31))
	Rect(Rand(0,63),Rand(0,63),Rand(1,31),Rand(1,2))
Next
SetBuffer (BackBuffer())

TextureBlend tex,2
TextureBlend tex2,3

; Create Cylinder manually 
mycylinder=CreateMyCylinder(vsegs,rsegs,False,0)
ScaleMesh mycylinder,6,40,6
RotateMesh mycylinder,90,0,0
FlipMesh mycylinder
PositionEntity mycylinder,0,0,40
EntityTexture mycylinder,tex,0,0
EntityTexture mycylinder,tex2,0,1

mycylindercopy = CopyMesh(mycylinder)
HideEntity mycylindercopy

;allocate control points
For i = 0 To MAX_CTRL_POINTS
	CtrlPoints[i] = New TCtrlPoint
	CtrlPoints[i]\x# = (i*260/MAX_CTRL_POINTS)
	CtrlPoints[i]\y# = (i*460/MAX_CTRL_POINTS)
Next

xx#=0
cnt#=0
freqX = 1
freqY = 4
rippx# = 0.0
rippy# = 0.0
rippz# = 0.0
depth# = 2.0

While Not KeyDown( 1 ) 

	If (Not Rand(0,200))
		freqY = Rand(0,4)
	EndIf

	If (Not Rand(0,400))
		freqX = Rand(1,4)
	EndIf
	
	CtrlPointsPhase = CtrlPointsPhase + freqX
	CtrlPointsPhase2 = CtrlPointsPhase2 + freqY

	cnt=wrapvalue(cnt#+.01*(freqX+freqY)*.5,0,1)

	PositionTexture Tex,0,cnt#
	PositionTexture Tex2,cnt#,cnt#
	
	If KeyHit(19) Then ; R
		rippx=0 : rippy=0 : rippz=0
	EndIf

	If KeyDown(29) Then Multiplier#=1 Else Multiplier#=0.1
	rippx=rippx+(KeyDown(210)-KeyDown(211))*multiplier ; ins/del
	rippy=rippy+(KeyDown(199)-KeyDown(207))*multiplier ; home/end
	rippz=rippz+(KeyDown(201)-KeyDown(209))*multiplier ; page up/page down
	depth=depth+(KeyDown(078)-KeyDown(074))*multiplier ; numeric +/-
	
	If KeyHit(30) Then autoinc=Not autoinc
	
	If autoinc Then 
		rippx=rippx+multiplier
		rippy=rippy+multiplier
		rippz=rippz+multiplier
	EndIf

	form=(form+KeyHit(33)) Mod 4

	Tunnel_effect(mycylinder,mycylindercopy,CtrlPointsPhase,CtrlPointsPhase2,rippx,rippy,rippz,cnt*360,depth,form)

	If KeyHit(17) Then wire=Not wire : WireFrame wire 
	If KeyDown(57) Then RotateEntity mycylinder,-90,0,0 Else RotateEntity mycylinder,0,0,0
	
	RenderWorld 
	
	Color 255,255,255
	Text 0,0,"Ripple x "+RippX+" Ripple Y "+RippY+" Ripple Z "+RippZ+" Depth "+Depth+" Form "+form

	Flip 
Wend 

End 

Function Tunnel_Effect(mesh, mesh_original, phase, phase2, fx#, fy#, fz#, offset#, depth#, form)
Local v#
	cntsurf = CountSurfaces(mesh)
	
	surf=GetSurface(mesh,cntsurf)
	surf_original=GetSurface(mesh_original,cntsurf)
	
	cnt=CountVertices(surf)
	For s=0 To rsegs

		deltax# = Cos(wrapvalue(Ctrlpoints[s]\x# + phase,0,360))*(TWIST#/(s+1))
		deltay# = Sin(wrapvalue(Ctrlpoints[s]\y# + phase2,0,360))*(TWIST#/(s+1))

		firstVertice = s*(vsegs+1)
		endVertice = firstVertice + vsegs
		For a=firstVertice To endVertice
			x#=VertexX#(surf_original,a)
			y#=VertexY#(surf_original,a)
			z#=VertexZ#(surf_original,a)
			Select form
				Case 0
				addx#=Sin(wrapvalue(z*x*fx+offset,0,360))*depth
				addy#=Cos(wrapvalue(z*y*fy+offset,0,360))*depth
				Case 1
				If a=endVertice Then v=firstVertice Else v=a ; mind the gap !
				addx#=Sin(wrapvalue(v*fx,0,360))*depth
				addy#=Cos(wrapvalue(v*fy,0,360))*depth
				Case 2
				addx#=Cos(wrapvalue(x*fx+offset,0,360))*depth
				addy#=Sin(wrapvalue(y*fy+offset,0,360))*depth
				addz#=-addx
				Case 3
				inc=inc+1 : v = (inc Mod vsegs)*S ; mind the gap !
				addx#=Sin(wrapvalue(v*fx+offset,0,360))*depth
				addy#=-Cos(wrapvalue(v*fy+offset,0,360))*depth
				addz#=Sin(-wrapvalue(v*fz+offset,0,360))*depth
			End Select		
			mag#=Sqr(x*x+y*y+z*z)
			x#=x#+addx*(x/mag)+deltax
			y#=y#+addy*(y/mag)+deltay
			z#=z#+addz*(z/mag)
			VertexCoords surf,a,x#,y#,z#
		Next
	Next
	UpdateNormals mesh
		
End Function

Function wrapvalue#(value#,lo#,hi#)
i=Floor(value/(hi-lo))
r#=i*(hi-lo)
Return (value-r)+lo
End Function

; --------------------------------------------------------- 
Function CreateMyCylinder(verticalsegments,ringsegments=0,solid=True,parent=0) 
	Local tr,tl,br,bl; side of cylinder 
	Local ts0,ts1,newts; top side vertexs 
	Local bs0,bs1,newbs; bottom side vertexs 
	If verticalsegments<3 Or verticalsegments>100 Then Return 0 
	If ringsegments<0 Or ringsegments>100 Then Return 0 
	
	thiscylinder=CreateMesh(parent) 
	thissurf=CreateSurface(thiscylinder) 
	If solid=True 
		thissidesurf=CreateSurface(thiscylinder) 
	EndIf 
	div#=Float(360.0/(verticalsegments)) 
	
	height#=1.0 
	ringSegmentHeight#=(height#*2.0)/(ringsegments+1) 
	upos#=1.0 
	udiv#=Float(1.0/(verticalsegments)) 
	vpos#=1.0 
	vdiv#=Float(1.0/(ringsegments+1)) 
	
	SideRotAngle#=90 
	
	; re-diminsion arrays to hold needed memory. 
	; this is used just for helping to build the ring segments... 
	Dim tRing(verticalsegments) 
	Dim bRing(verticalsegments) 
	
	;render end caps if solid 
	If solid=True 
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		
		ts0=AddVertex(thissidesurf,XPos#,height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		bs0=AddVertex(thissidesurf,XPos#,-height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		
		SideRotAngle#=SideRotAngle#+div# 
		
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		
		ts1=AddVertex(thissidesurf,XPos#,height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		bs1=AddVertex(thissidesurf,XPos#,-height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
		
		For i=1 To (verticalsegments-2) 
			SideRotAngle#=SideRotAngle#+div# 
			
			XPos#=-Cos(SideRotAngle#) 
			ZPos#=Sin(SideRotAngle#) 
			
			newts=AddVertex(thissidesurf,XPos#,height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
			newbs=AddVertex(thissidesurf,XPos#,-height,ZPos#,XPos#/2.0+0.5,ZPos#/2.0+0.5) 
			
			AddTriangle(thissidesurf,ts0,ts1,newts) 
			AddTriangle(thissidesurf,newbs,bs1,bs0) 
			
			If i<(verticalsegments-2) 
				ts1=newts 
				bs1=newbs 
			EndIf 
		Next 
	EndIf 

	; ----------------------- 
	; middle part of cylinder 
	thisHeight#=height# 
	
	; top ring first 
	SideRotAngle#=90 
	XPos#=-Cos(SideRotAngle#) 
	ZPos#=Sin(SideRotAngle#) 
	thisUPos#=upos# 
	thisVPos#=0 
	tRing(0)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
	For i=0 To (verticalsegments-1) 
		If i<(verticalsegments-1) Then SideRotAngle#=SideRotAngle#+div# Else Siderotangle#=90 
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		thisUPos#=thisUPos#-udiv# 
		tRing(i+1)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
	Next 
	
	For ring=0 To (ringsegments) 
	
		; decrement vertical segment 
		thisHeight=thisHeight-ringSegmentHeight# 
		
		; now bottom ring 
		SideRotAngle#=90 
		XPos#=-Cos(SideRotAngle#) 
		ZPos#=Sin(SideRotAngle#) 
		thisUPos#=upos# 
		thisVPos#=thisVPos#+vdiv# 
		bRing(0)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
		For i=0 To (verticalsegments-1) 
			If i<(verticalsegments-1) Then SideRotAngle#=SideRotAngle#+div# Else Siderotangle#=90 
			XPos#=-Cos(SideRotAngle#) 
			ZPos#=Sin(SideRotAngle#) 
			thisUPos#=thisUPos#-udiv# 
			bRing(i+1)=AddVertex(thissurf,XPos#,thisHeight,ZPos#,thisUPos#,thisVPos#) 
		Next 
		
		; Fill in ring segment sides with triangles 
		For v=1 To (verticalsegments) 
			tl=tRing(v) 
			tr=tRing(v-1) 
			bl=bRing(v) 
			br=bRing(v-1) 
			
			AddTriangle(thissurf,tl,tr,br) 
			AddTriangle(thissurf,bl,tl,br) 
		Next 
		
		; make bottom ring segmentthe top ring segment for the next loop. 
		For v=0 To (verticalsegments) 
			tRing(v)=bRing(v) 
		Next 
	Next 
	
	UpdateNormals thiscylinder 
	Return thiscylinder 
End Function 



Boiled Sweets(Posted 2005) [#20]
David,

you are a god! Would you like a free copy of the full version of my app when its ready? Also would you like to be a beta tester?

MANY MANY THANKS!

By the way the app is Vorboils - check out www.boiledsweets.com/vorboils


DJWoodgate(Posted 2005) [#21]
LOL. More godless than godlike I fear. Glad I was able to help though.

Nice colorful looking screensaver, so yes cheers and I am willing to test it for you on my old win98 system if you want.

While I am thinking about it you can perhaps avoid some of those calls to wrapvalue in the tunnel function. The Sin and Cos functions get a bit moody if their arguments are really large, as was the case in Halo's code which used millisecs, but that will probably not be a problem here as long as you do not let the ripple fx values run away.