Triangle Placing to match grid

Blitz3D Forums/Blitz3D Programming/Triangle Placing to match grid

_PJ_(Posted 2016) [#1]
In attempt to save surfaces and triangles, rather than use a number of cube primitives, I wanted to construct geometry by code to form a single-surface mesh, eradicating overlaps and invisible triangles.

Generally it seems as though the core concept is working, but there's some issues with the fidelity of placement:

I would really apprecaite any help orsuggestions on the matter.

The following code provides an executable overview of the idea and highlights the problem;

;;Identifies efficient single-surface triangleplacement for square-grid based maps.

;For this example purpose, an ARRAY data type is used, it may be more suitable to utilise banks or other data structures in actual usage.

Graphics3D 1024,768,32,2
SetBuffer BackBuffer()

Global SUN=CreateLight()

Const WLS_TOP_BOUND=1
Const WLS_BOTTOM_BOUND=2
Const WLS_LEFT_BOUND=4
Const WLS_RIGHT_BOUND=8

Const WLS_ROOF_H=16
Const WLS_ROOF_V=32

Dim ARRAY(0,0)
Dim TempArray(0,0)

Type ROOFED
	Field X
	Field Y
End Type

SeedRnd MilliSecs()

Local W=100
Local H=100
;Example Populate Random Grid map (0 = blank, 1 = Wall)
PopulateRandomMap(W,H)
WaitKey()
;Now To call the Function And generate single-surface geometry
Local MESH=CreateMesh()
Local SURF=CreateSurface(MESH)
Walls(W,H,SURF)
;EntityFX MESH,16
EntityAlpha MESH,0.5
UpdateNormals MESH

DISPLAY3DOUTPUT(MESH,W,H)

Function Walls(W,H,Surface,AddTop=True)
	W=W-1
	H=H-1
	
	Local X
	Local Y
	
	Dim TempArray(W,H)
	
	Local Bounds
	
	;First Pass : Identify each grid unit boundaries. This can remove any hidden or adjoining wall faces
	For Y=0 To H
		For X=0 To W
			Bounds=0
			
			If (ARRAY(X,Y)=1)
				Bounds=Bounds+GetTopBound(X,Y)
				Bounds=Bounds+GetBottomBound(X,Y,H)
				Bounds=Bounds+GetLeftBound(X,Y)
				Bounds=Bounds+GetRightBound(X,Y,W)
				
				TempArray(X,Y)=Bounds
			End If
			
		Next
	Next
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	;HORIZONTAL Pass : CHECK FOR CONTINUOUS HORIZONTAL WALL SEGMENTS - EACH WALL HAS A TOP (Z+1) AND BOTTOM (Z+0) FACE ALIGNED WITH X AXIS
	
	Local LengthTop
	Local LengthBottom
	Local CountingTop
	Local CountingBottom
	
	For Y=0 To H
		For X=0 To W
			
			If (TempArray(X,Y) And WLS_TOP_BOUND)
				LengthTop=LengthTop+1
				CountingTop=True
			Else
				If (CountingTop)
					AddZ_PLUSGeometry(X-LengthTop,H-Y,LengthTop,Surface)
					
					LengthTop=0
					CountingTop=False	
				End If
			End If
			
			
			If (TempArray(X,Y) And WLS_BOTTOM_BOUND)
				LengthBottom=LengthBottom+1
				CountingBottom=True
			Else
				If (CountingBottom)
					AddZ_MINUSGeometry(X-LengthBottom,H-Y,LengthBottom,Surface)
					
					LengthBottom=0
					CountingBottom=False	
				End If
			End If
			
			
			
			
		Next
		
		;Break at end of row
		If (CountingTop)
			AddZ_PLUSGeometry(X-LengthTop,H-Y,LengthTop-1,Surface)
			
			LengthTop=0
			CountingTop=False	
		End If
		
		If (CountingBottom)
			AddZ_MINUSGeometry(X-LengthBottom,H-Y,LengthBottom-1,Surface)
			
			LengthBottom=0
			CountingBottom=False	
		End If
		
	Next
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
		;VERTICAL Pass: CHECK FOR CONTINUOUS VERTICAL WALL SEGMENTS - EACH WALL HAS A RIGHT (X+1) AND LEFT (X+0) FACE ALIGNED WITH Z AXIS
	Local LengthLeft
	Local LengthRight
	Local CountingLeft
	Local CountingRight
	
	For X=0 To W
		For Y=0 To H
			
			If (TempArray(X,Y) And WLS_LEFT_BOUND)
				LengthLeft=LengthLeft+1
				CountingLeft=True
			Else
				If (CountingLeft)
					AddX_MINUSGeometry(X,H-(Y-LengthLeft),LengthLeft,Surface)
					
					LengthLeft=0
					CountingLeft=False	
				End If
			End If
			
			
			If (TempArray(X,Y) And WLS_RIGHT_BOUND)
				LengthRight=LengthRight+1
				CountingRight=True
			Else
				If (CountingRight)
					AddX_PLUSGeometry(X,H-(Y-LengthRight),LengthRight,Surface)
					
					LengthRight=0
					CountingRight=False	
				End If
			End If
			
			
			
			
		Next
		
		;Break at end of row
		If (CountingLeft)
			AddX_MINUSGeometry(X,H-(Y-LengthLeft),LengthLeft-1,Surface)
			
			LengthLeft=0
			CountingLeft=False
		End If
		
		If (CountingRight)
			AddZ_PLUSGeometry(X,H-(Y-LengthRight),LengthRight-1,Surface)
			
			LengthRight=0
			CountingRight=False	
		End If
		
		
	Next
	
	
	
	
	If (AddTop)
		;Adds a "roof" plane geometry to the walls
		
		;[Block]
	;PLANAR PASS HORIZONTAL 1 : Determines potential rows of wall segments
		
	Local CountingHorizontal
	Local HorizontalLength
	
	For Y=0 To H
		For X=0 To W
			
			If (TempArray(X,Y) And (WLS_TOP_BOUND Or WLS_BOTTOM_BOUND))
				CountingHorizontal=True
				HorizontalLength=HorizontalLength+1
			Else
				If (CountingHorizontal)
					ProcessPlanarHorizontal(X-HorizontalLength,Y,HorizontalLength)
					HorizontalLength=0
					CountingHorizontal=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingHorizontal)
			ProcessPlanarHorizontal(X-HorizontalLength,Y,HorizontalLength-1)
			
			HorizontalLength=0
			CountingHorizontal=False	
		End If
		
		
	Next
	
	;PLANAR PASS VERTICAL 1 : Determines potential columns of wall segments
	
	Local CountingVertical
	Local VerticalLength
	
	For X=0 To W
		For Y=0 To H
			
			If (TempArray(X,Y) And (WLS_LEFT_BOUND Or WLS_RIGHT_BOUND))
				CountingVertical=True
				VerticalLength=VerticalLength+1
			Else
				If (CountingVertical)
					ProcessPlanarVertical(X,Y-VerticalLength,VerticalLength)
					VerticalLength=0
					CountingVertical=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingVertical)
			ProcessPlanarVertical(X,Y-VerticalLength,VerticalLength-1)
			
			VerticalLength=0
			CountingVertical=False	
		End If
		
		
	Next
	
	
	;PLANAR PASS HORIZONTAL 2 : Appliess planar roofing geometry across horizontal wall segments
	
	
	For Y=0 To H
		For X=0 To W
			
			If (TempArray(X,Y) And (WLS_ROOF_H))
				CountingHorizontal=True
				HorizontalLength=HorizontalLength+1
			Else
				If (CountingHorizontal)
					AddPLANAR_XZ_X_Geometry(X-HorizontalLength,H-Y,HorizontalLength,Surface)
					HorizontalLength=0
					CountingHorizontal=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingHorizontal)
			AddPLANAR_XZ_X_Geometry(X-HorizontalLength,H-Y,HorizontalLength-1,Surface)
			
			HorizontalLength=0
			CountingHorizontal=False	
		End If
		
		
	Next
	
	;PLANAR PASS VERTICAL 2:  Appliess planar roofing geometry across horizontal wall segments
	
	
	For X=0 To W
		For Y=0 To H
			
			If (TempArray(X,Y) And (WLS_ROOF_V))
				CountingVertical=True
				VerticalLength=VerticalLength+1
			Else
				If (CountingVertical)
					AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength,Surface)
					VerticalLength=0
					CountingVertical=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingVertical)
			AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength-1,Surface)
			
			VerticalLength=0
			CountingVertical=False	
		End If
		
		
	Next
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	;[End Block]
End If

Dim TempArray(0,0)

End Function

Function ProcessPlanarHorizontal(X,Y,Length)
	Local X1=X
	Local X2=X+Length
	
	For X=X1 To X2
		TempArray(X,Y)=TempArray(X,Y) Or WLS_ROOF_H
	Next
End Function

Function ProcessPlanarVertical(X,Y,Length)
	Local Y1=Y
	Local Y2=Y+Length
	
	Local Skip
	
	For Y=Y1 To Y2
		Skip=False
		
		If (TempArray(X,Y) And WLS_ROOF_H)
			If (Length>0) 
				TempArray(X,Y)= (TempArray(X,Y) Xor WLS_ROOF_H)
			Else
				Skip=True
			End If
		End If
		
		If (Not(Skip))
			TempArray(X,Y)=(TempArray(X,Y) Or WLS_ROOF_V)
		End If
	
	Next
End Function

Function GetTopBound(X,Y)
	Local Value
	If (Y>0)
		Value=(ARRAY(X,Y-1)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_TOP_BOUND
End Function

Function GetBottomBound(X,Y,H)
	Local Value
	If (Y<H)
		Value=(ARRAY(X,Y+1)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_BOTTOM_BOUND
End Function

Function GetLeftBound(X,Y)
	Local Value
	If (X>0)
		Value=(ARRAY(X-1,Y)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_LEFT_BOUND
End Function

Function GetRightBound(X,Y,W)
	Local Value
	If (X<W)
		Value=(ARRAY(X+1,Y)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_RIGHT_BOUND
End Function


















;GEOM

Function AddPLANAR_XZ_X_Geometry(X,Z,Length,Surface)
	AddXZPlaneVertexPoints(X,Z,Length-1,1,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+0,v+1,v+2)
	AddTriangle(Surface,v+3,v+2,v+1)
End Function

Function AddPLANAR_XZ_Z_Geometry(X,Z,Length,Surface)
	AddXZPlaneVertexPoints(X,Z,1,Length-1,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+0,v+1,v+2)
	AddTriangle(Surface,v+3,v+2,v+1)
End Function

Function AddX_MINUSGeometry(X,Z,Length,Surface)
	AddZAxisVertexPoints(X,Z,Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+1,v+2,v+3)
	AddTriangle(Surface,v+2,v+1,v+0)
End Function

Function AddX_PLUSGeometry(X,Z,Length,Surface)
	AddZAxisVertexPoints(X+1,Z,Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+0,v+1,v+2)
	AddTriangle(Surface,v+3,v+2,v+1)
End Function

Function AddZ_PLUSGeometry(X,Z,Length,Surface)
	AddXAxisVertexPoints(X,Z,Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+1,v+2,v+3)
	AddTriangle(Surface,v+2,v+1,v+0)
End Function

Function AddZ_MINUSGeometry(X,Z,Length,Surface)
	AddXAxisVertexPoints(X+Length,Z-1,0-Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+1,v+2,v+3)
	AddTriangle(Surface,v+2,v+1,v+0)
End Function

Function AddXAxisVertexPoints(X#,Z#,Length,Surface)
	Local X1#=X#
	Local X2#=X#+Length
	
	AddVertex(Surface,X1#,1,Z#,1,0)
	AddVertex(Surface,X2#,1,Z#,0,0)
	AddVertex(Surface,X1#,0,Z#,1,1)
	AddVertex(Surface,X2#,0,Z#,0,1)
End Function

Function AddZAxisVertexPoints(X#,Z#,Length,Surface)
	Local Z1#=Z#-Length
	Local Z2#=Z#
	
	AddVertex(Surface,X#,1,Z1#,1,0)
	AddVertex(Surface,X#,1,Z2#,0,0)
	AddVertex(Surface,X#,0,Z1#,1,1)
	AddVertex(Surface,X#,0,Z2#,0,1)	
End Function

Function AddXZPlaneVertexPoints(X#,Z#,LengthX,LengthZ,Surface)
	Local X1#=X#
	Local X2#=X#+LengthX
	
	Local Z1#=Z#-LengthZ
	Local Z2#=Z#
	
	AddVertex(Surface,X1#,1,Z2#,1,0)
	AddVertex(Surface,X2#,1,Z2#,0,0)
	AddVertex(Surface,X1#,1,Z1#,1,1)
	AddVertex(Surface,X2#,1,Z1#,0,1)	
End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;the following is for example purposes only


Function PopulateRandomMap(W,H)
	;VISUAL OUTPUT
	
	Dim ARRAY(W-1,H-1)
	
	Local Iter
	
	Local Length
	Local X,Y
	
	Local Dir
	
	Local RandX,RandY
	For Iter=1 To 100
		
		Length=Rand(1,Sqr(H))
		Dir=Rand(0,1)
		
		Select (Dir)
			Case 1:
			;VERTICAL
				X=Rand(0,W-1)
				RandY=Rand(0,H-Length)
				
				For Y=RandY To (RandY+Length)-1
					ARRAY(X,Y)=1
				Next
				
			Default:
			;HORIZONTAL
				RandX=Rand(0,W-Length)
				Y=Rand(0,H-1)
				
				For X=RandX To (RandX+Length)-1
					ARRAY(X,Y)=1
				Next
		End Select
		
	Next
	
	DRAWARRAYGRID(W-1,H-1)
	UPDATEVISUALDISPLAY
End Function

;The following is just for a visual depiction of the example and are not required for use of the system

Function DRAWARRAYGRID(W,H)
	Local X
	Local Y
	
	For Y= 0 To H
		For X=0 To W
			Color 0,255*ARRAY(X,Y),255
			Rect X*10,Y*5,10,5,ARRAY(X,Y)
		Next
	Next
End Function

Function DISPLAY3DOUTPUT(Mesh,W,H)
	AmbientLight 128,128,128
	Local Cam=CreateCamera()
	MoveEntity Cam,MeshWidth(Mesh)*0.5,MeshDepth(Mesh)*0.5,0-(MeshWidth(Mesh)*0.75)
	RotateEntity Mesh,-90,0,0,True
	
	Local Wire%				=	False;
	FlushMouse();
	
	Local Prim=True
	
	Local PIV=CreatePivot()
	
	For x=0 To W-1
		For y=0 To H-1
			If ARRAY(x,y)
				c=CreateCube(PIV)
				PositionEntity c,x+0.5,((H-1)-y)-0.5,0,True
				ScaleMesh c,0.45,0.45,0.45
				EntityAlpha c,0.5
				EntityColor c,128,0,0
			End If
		Next
	Next
	
	While Not KeyDown(1)
		Cls
		
		If (KeyHit(57)>0)
			Wire			=	Not(Wire);
			WireFrame			( Wire );
		EndIf;
		
		If KeyHit(28)	
			Prim=Not(Prim)
			If Prim
				ShowEntity PIV
			Else
				HideEntity PIV
			End If
		End If	
		
		TranslateEntity Cam,Float(KeyDown(205)-KeyDown(203))*.1, Float(KeyDown(200)-KeyDown(208))*.1,MouseZSpeed(),1
		
		UpdateWorld
		RenderWorld
		
		
		Color				( 255,128,000 );
		Text				( 10,20,"Arrow -> move" );
		Text				( 10,80,"space -> wireframe" );
		Text				( 10,100,"Enter -> primitives" );
		Text				0,0,TrisRendered()
		
		UPDATEVISUALDISPLAY
	Wend
	
End Function

Function UPDATEVISUALDISPLAY()
	Flip
End Function



RemiD(Posted 2016) [#2]
why don't you add premade rectangle meshes (each corresponding to the side of a cube) to a surface ?
apart from that i would use a similar logic than the one you use (use a 2d array to store the properties of each tile and analyze if there is (or not) a tile at front, at back, at left, at right

here is the function i use to add one surface to another surface : http://www.blitzbasic.com/codearcs/codearcs.php?code=3291


_PJ_(Posted 2016) [#3]
The intent is to use the least possible triangles where possible.

This means, that when a wall segment extends along, say, 5 units, I do not need 10 triangles but just two per each side.

For example:

Using indivdual cubes:
A wall segment of 3 units comprises a total of 36 triangles:
._..._..._.
|_|.|_|.|_|


Current method:
A wall segment of 3 units comprises just 12 triangles
._________.
|_________|

________________________________________________________________________
This is detracting form the point of the discussion which is to ask for help in the position of the geometry.

I suspect, ultimately, it ought to be a minor tweak to the values of Add**Geometry() functions, since otherwise, it seems to be creating the triangles with correct facing etc.


RemiD(Posted 2016) [#4]

The intent is to use the least possible triangles where possible.
This means, that when a wall segment extends along, say, 5 units, I do not need 10 triangles but just two per each side.


ok

but you will encounter a problem (overlapping triangles) when you have tiles arranged in this way :
00100
11111
00100


_PJ_(Posted 2016) [#5]
.


RemiD(Posted 2016) [#6]
yes i took a look at your code, but i am not really in the mood to debug today. sorry

good luck


RemiD(Posted 2016) [#7]
i just remembered this code by sswift, maybe it can help : http://www.blitzbasic.com/codearcs/codearcs.php?code=526


_PJ_(Posted 2016) [#8]
I am convinced the issue lies within the Add*Geometry() functions or the values passed to them. This should help in narrowing down the root of the issue.

Thanks for taking the time to look at this, and I do very much appreciate your help and hope that you are feeling better :)


Bobysait(Posted 2016) [#9]
one question :
Do you want the walls to care about corners ?
123456
 X

numbers are just to identify the cells, the X is the block a the next line
obviously, you can create a wall along the top of the cells from 1 to 6
But what do you expect for the bottom wall ?
Does it go grom 1 to 6 ? or do you split it in 2 walls (bottom of 1, and bottom of 3 to 6)


Then, just a thing :
> in the function DISPLAY3DOUTPUT
If ARRAY(x,y)
	c=CreateCube(PIV)
	PositionEntity c,x,y,0,True
	ScaleMesh c,0.9,0.9,0.9
	EntityAlpha c,0.5
	EntityColor c,128,0,0


If you set the position of your cubes every one unit, then your scalemesh is too large -> a cube goes from -1 to 1, so scale to 0.45 if you want it do be a bit lower than one unit.


_PJ_(Posted 2016) [#10]

But what do you expect for the bottom wall ?
Does it go grom 1 to 6 ? or do you split it in 2 walls (bottom of 1, and bottom of 3 to 6)


As you will see if you run the example code, the walls do as I want in this regard.

The top wall would run from 1 to 6
the bottom wall will be split into two:

one segment at 1 (1 unit length)
another from 3 to 6 (4 unit length)


_PJ_(Posted 2016) [#11]

If you set the position of your cubes every one unit, then your scalemesh is too large -> a cube goes from -1 to 1, so scale to 0.45 if you want it do be a bit lower than one unit.


I forgot this.

Thank you.


_PJ_(Posted 2016) [#12]
Updated the initial code again.

1) The RED Primitive cubes used as template are now scaled accordingly.
2) Horizontal and Vertical Wall sections are now mostly accurate.
3) Errors at the extremeties of the map are likely to be non-critical
4) Errors as result of parrallel wall segments placed adjacently will not be an issue.
5) The PLANAR "roof" seems to fail, I suspect due to situations whereby the n -> n+Length should be n-length to n and the ordering of vertices for triangle addition needs to be amended

This is what needs to be looked at, and I am not proficient in 3D triangles and vertices to solve it.


Bobysait(Posted 2016) [#13]
here is what I got so far.




_PJ_(Posted 2016) [#14]
I think you misinterpreted the problem I have with the code. Your code sample does not solve these problems.
The problem is with the accuracy of the placement of the triangles.

__________

Your code sample has numerous issues of its own:

1) No roof for the walls - THE PROBLEM I HAVE IS WITH THE ROOF PLACEMENT _ SO HOW DOES IT HELP???
2) Wall faces are rotated through Pi * radians.


Bobysait(Posted 2016) [#15]

1) Hidden geometries within wall segments
i.e.
.___.
|_|_|

In your code the dividing wall is still present and unnecessary.



Here, the walls are split everytime it's required.
Because, I just don't understand what you're talking about, could you make a screen of what you're trying to explain (and point at the problem you're issuing if possible) ?



2) No roof for the walls


Yep, I never go further until the first step is validated, I prefer having a robust base to work on :)
(So I didn't implement the roof/floors yet ... and it seems I was right, I don't know where we are going)



3) Wall faces are rotated through Pi * radians.


Same as previous, I don't understand what you're meaning, sorry.


Bobysait(Posted 2016) [#16]
Ok, so you edited your post ... I suppose there is no problem with the walls then.


THE PROBLEM I HAVE IS WITH THE ROOF PLACEMENT _ SO HOW DOES IT HELP???


I think it's time for a break if you start yelling at me for nothing ^^.
So, help yourself, I'm not here to support this kind of behavior.


_PJ_(Posted 2016) [#17]

Here, the walls are split everytime it's required

Sorry I was wrong. You are right and the walls are divided correctly! :)


Yep, I never go further until the first step is validated, I prefer having a robust base to work on :)
(So I didn't implement the roof/floors yet ... and it seems I was right, I don't know where we are going

Roofs are where I am having the most problem, if you see the most recently updated version of my code (amended in first post).
Floors arent necessary* but are simply refection of the roof anyway so easy enough to add once roofs are working.


Same as previous, I don't understand what you're meaning, sorry.

Now that I have looked more carefully I think I understand.
You have created "Rooms" and "Corridoors" - the faces of the cuboids face inwards - whereas I was intending on an external 'maze' where the walls are 'solid'.

In your case the walls are visible from INSIDE, yet mine need to be visible from OUTSIDE only.*

A simple FlipMesh resolved this difference.

*Hopefully this distinction between inside and outside clarifies a little why the roof is important but floors arent :)


_PJ_(Posted 2016) [#18]
I wasn't intending to "yell" - the caps were to highlight the importance of the roofs. Sorry.


Bobysait(Posted 2016) [#19]
Ok no problem so.
If the walls have to be fliped, then the roof will be really complex and need a flood fill algorithm to detect the outline and exlude inner parts.

So it needs to be devided into the largest convex polygons (or at least into convex polygons ... checking the best computation case could be a total brainacke)

So, it needs to start from the first "used" cell then find the next point which create the segment (always is the same orientation), anytime you have at least 3 points, you need to check if there is any empty cell in the polygon (else, the polygon is not valid) and compute again and again until all polygons are done

In other words, it's an ear-clipping algorithm.


*Hopefully this distinction between inside and outside clarifies a little why the roof is important but floors arent :)


Actually, it probably does not change anything to the algorithm, but it certainly modify all the result. (I was thinking about an "inside" maze, which would absolutely not look like what you were doing)


_PJ_(Posted 2016) [#20]
I've jsut updated the initial code again.



So it needs to be devided into the largest convex polygons (or at least into convex polygons ... checking the best computation case could be a total brainacke)

So, it needs to start from the first "used" cell then find the next point which create the segment (always is the same orientation), anytime you have at least 3 points, you need to check if there is any empty cell in the polygon (else, the polygon is not valid) and compute again and again until all polygons are done

In other words, it's an ear-clipping algorithm.



Well considering there will (in the actual implementation of this system), not be any cases other than single-unit-thick walls - remember t's an external maze, not internal corridors -, then any area considerations should be restricted to the same as the side walls...

So my code simply checks along the horizontal walls and flags them for a roof, then the same for the vertical - with the caveat that if already earmarked, that section will be skipped over.

Then, final passes process the data for roof in the same way as the wall creation - extending the geometry to stretch from the start of a section along its length (whether in H or V direction)

This code is encapsulated between the ;[Block] and ;[End Block] lines (I use IDEal)

However, there s something faulty in that regions seem to be arbitrarily skipped and this is what I cannot understand.


_PJ_(Posted 2016) [#21]
Yet another small update to the initial code.


It is so VERY CLOSE now to completion.

The error with the roof isnow confined to SPECIFIC CASES Where:


Horizontal Wall segments (i.e extending along X axis with only "TOP"(z+1) and BOTTOM(Z-1) faces)

Length > 2 units

The segment at Length-1 from the horizontal start of the segment is skipped-

I am unsure whether to simply "kludge" a specific fix for this, or continue to try and investigate the root of the issue.


_PJ_(Posted 2016) [#22]
Ignore the above. Whilst that scenario described in the post above ALWAYS produces the error, it is not the only circumstance that does so...


Bobysait(Posted 2016) [#23]
If there are no "lines" wider than one cell, then it makes things way more simple.




ps : I see the issue in your code but it's a bit hard to notice where it comes from, because your code is a bit hard to follow (too many recursive function calls, it does not help tracking stuff).
You might want to use Vertex color and color your segment in different colors according to the place it was called from, so you should notice easier which segment is faulty.

Anyway, I think you have a weird issue that is not visible
-> you have segment with no length
On "PLANAR PASS VERTICAL 2" : extends from 1 block the length of the segment and they will appear as single blocks (so, with a unit less, they are just empty segment)

at this part of the code
						If (CountingVertical)
							;AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength,Surface)
							AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength+1,Surface); Add 1 unit to the length and the blocks appear.
							VerticalLength=0
							CountingVertical=False	
						End If



_PJ_(Posted 2016) [#24]
Adding +1 tehre only adds extra unwanted geometry.

_____________

The way the counting works is that each square is assessed in sequence the algorithm doesn't "know" it needs to start or stop counting length until it encounters the required trigger value
X		Grid		Counter
0		0			nothing
1		0			nothing
2		1			START COUNTING LENGTH=1
3		1			LENGTH=2
4		1			LENGTH=3
5		0			CEASE COUNT.  CURRENT X=5  - LENGTH (3)  = CORRECT START X 2
6		0



________________________________


The only exceptions are at the end of the rows/columns, whch, in my actual project will be inaccessible boundaries which are irrelevant.

This can be identified easily with:
Function ProcessPlanarHorizontal(X,Y,Length)
	If (Length<1) Then DebugLog(X+","+Y+" "+"H Length"+Length)
	
;.......
Function ProcessPlanarVertical(X,Y,Length)
	If (Length<1) Then DebugLog(X+","+Y+" "+"V Length"+Length)



_PJ_(Posted 2016) [#25]
If there are no "lines" wider than one cell, then it makes things way more simple.


The code you posted here works perfectly.
I am looking through it now to see how to change my code. It is a little difficult because they are similar but not identical approaches.


I apologise for the difficulty in readability of the code I've posted - the ACTUAL project relies on data stored in banks and is reliant on other variables so much that it was simpler to throw this example together.

Thanks very much for your help in this bobysait and you make it look so easy :)


RemiD(Posted 2016) [#26]
now have fun setting u,v coords to texture it properly ;)


_PJ_(Posted 2016) [#27]
now have fun setting u,v coords to texture it properly ;)


__
Not an issue, no texturing is required.

However given the triangles are all aligned to axes and set to unit dimensions, the normals belie the 'top','bottom','left','right' or roof facing, therefore, it is simple to then apply the UV to each accordingly.

_____________________________________________________________


Well I've made some progress and have the alignment correct, the roof is done, all invisible faces have no geometry and where a longer wall intersects a shorter one, the longer one takes priority in determining the roof geometry.


Bobysait(Posted 2016) [#28]
In the BuildWalls function, I forgot a small mistake (it's not a bug, but it's a totally useless check)

	For j = 0 To H
		For i = 0 To W
			; this cell has a top wall
			If ((HAS_WALL(i,j) And 1)>0) And ((HAS_WALL(i,j) And 1)>0)
				; if this wall hasn't already been built
				If ((WALL_FLAG(i,j) And 1) = 0)



-> If ((HAS_WALL(i,j) And 1)>0) And ((HAS_WALL(i,j) And 1)>0)
this is twice the same test, it's an unremoved temporary code that has not been updated.

replace it with
If ( ( HAS_WALL(i,j) And 1 ) > 0 )

I not "better safe than sorry" but here, a single test will do the same job as two but faster :p


_PJ_(Posted 2016) [#29]
Thanks, Bobysait.

I had to essentially re-write the essence of your code entirely to match the critera and conventions of my actual project (which included a more complex determination of walls than just a binary wall or no wall,as well as using banks rather than arrays) so the minor issues such as that you mention were cleared up and addressed on the way.

I do appreciate your clarity though :)