Type Nirvana_Vector2D
Dim X
Dim Y
End Type

Type Nirvana_Size2D
Dim Width
Dim Height
End Type

Type Nirvana_Background
Dim Image_ID
Dim RenderSetting
End Type

Type Nirvana_Shape
Dim Name$
Dim Sprite_ID
Dim ShapeType
Dim ShapeData_Matrix
End Type

Type Nirvana_Layer
Dim Name$
Dim LayerType
Dim Visible
Dim Alpha
Dim Scroll_Speed As Nirvana_Vector2D
Dim Ref_Canvas
Dim Layer_TileMap As Nirvana_TileMap
Dim Layer_TileMap2 As Nirvana_TileMap
Dim Layer_Sprite_Count
Dim Layer_Shape_Count
Dim Bkg As Nirvana_Background
Dim Layer_TS_Stack
End Type

Type Nirvana_Stage
Dim Active
Dim Name$
Dim Tile_Size As Nirvana_Size2D
Dim Stage_Size As Nirvana_Size2D
Dim Layer_Count
Dim Viewport_Size As Nirvana_Size2D
Dim Stage_Offset As Nirvana_Vector2D
End Type


NIRVANA_DATA_DIR$ = NIRVANA_PROJECT_BASE_DIR$ + NIRVANA_PATH_SEPARATOR$ + "data" + NIRVANA_PATH_SEPARATOR$
NIRVANA_BKG_DIR$ = NIRVANA_PROJECT_BASE_DIR$ + NIRVANA_PATH_SEPARATOR$ + "bkg" + NIRVANA_PATH_SEPARATOR$

NIRVANA_LAYER_TYPE_TILEMAP = 0
NIRVANA_LAYER_TYPE_ISO_TILEMAP = 1
NIRVANA_LAYER_TYPE_SPRITE = 2
NIRVANA_LAYER_TYPE_CANVAS_2D = 3
NIRVANA_LAYER_TYPE_CANVAS_3D = 4

NIRVANA_IMG_RENDER_SETTING_NORMAL = 0
NIRVANA_IMG_RENDER_SETTING_STRETCHED = 1
NIRVANA_IMG_RENDER_SETTING_TILED = 2


NIRVANA_WINDOW_WIDTH = 320
NIRVANA_WINDOW_HEIGHT = 200


Dim Nirvana_Stage_Sprites[1] As Nirvana_Sprite
Dim Nirvana_Stage_Shape_Points[1] As Nirvana_Vector2D
Dim Nirvana_Stage_Shapes[2] As Nirvana_Shape
Dim Nirvana_Stage_Layers[3] As Nirvana_Layer

Dim Nirvana_NULL_Shape As Nirvana_Shape
Nirvana_NULL_Shape.Name$ = ""
Nirvana_NULL_Shape.Sprite_ID = -1
Nirvana_NULL_Shape.ShapeType = -1
Nirvana_NULL_Shape.ShapeData_Matrix = -1
ArrayFill(Nirvana_Stage_Shapes, Nirvana_NULL_Shape)

For i = 0 To 2
	Nirvana_Stage_Layers[i].Ref_Canvas = -1
	Nirvana_Stage_Layers[i].Layer_TileMap.Tileset_ID = -1
	Nirvana_Stage_Layers[i].Layer_TileMap.TileMap_ID = -1
	Nirvana_Stage_Layers[i].Layer_TileMap2.Tileset_ID = -1
	Nirvana_Stage_Layers[i].Layer_TileMap2.TileMap_ID = -1
	Nirvana_Stage_Layers[i].Bkg.Image_ID = -1
Next

For i = 0 To 0
	Nirvana_Stage_Sprites[i].Sprite_ID = -1
Next

For i = 0 To 1
	Nirvana_Stage_Shapes[i].Sprite_ID = -1
Next

Dim Nirvana_ActiveStage As Nirvana_Stage : Nirvana_ActiveStage.Active = FALSE

'This is a utility function for reading binary data from tile maps
Function Nirvana_Read32(stream)
		Dim byte_array[4]
		byte_array[3] = ReadByte(stream)
		byte_array[2] = ReadByte(stream)
		byte_array[1] = ReadByte(stream)
		byte_array[0] = ReadByte(stream)
		Return (byte_array[0] shl 24) + (byte_array[1] shl 16) + (byte_array[2] shl 8) + byte_array[3]
End Function

Sub Nirvana_ClearStage()
	If Not Nirvana_ActiveStage.Active Then
		Return
	End If

	Nirvana_ActiveStage.Stage_Offset.X = 0
	Nirvana_ActiveStage.Stage_Offset.Y = 0

	Num_Shapes = ArraySize(Nirvana_Stage_Shapes, 1)
	For n = 0 To Num_Shapes-1
		If MatrixExists(Nirvana_Stage_Shapes[n].ShapeData_Matrix) Then
			DeleteMatrix(Nirvana_Stage_Shapes[n].ShapeData_Matrix)
		End If
		Nirvana_Stage_Shapes[n].ShapeData_Matrix = -1
	Next

	For i = 0 To Nirvana_ActiveStage.Layer_Count-1

		CloseCanvas(Nirvana_Stage_Layers[i].Ref_Canvas)
		Nirvana_Stage_Layers[i].Ref_Canvas = -1

		If Stack_N_Exists(Nirvana_Stage_Layers[i].Layer_TS_Stack) Then
			DeleteStack_N(Nirvana_Stage_Layers[i].Layer_TS_Stack)
		End If
		Nirvana_Stage_Layers[i].Layer_TS_Stack = -1

		If ImageExists(Nirvana_Stage_Layers[i].Bkg.Image_ID) Then
			DeleteImage(Nirvana_Stage_Layers[i].Bkg.Image_ID)
			Nirvana_Stage_Layers[i].Bkg.Image_ID = -1
		End If

		If Nirvana_Stage_Layers[i].LayerType = NIRVANA_LAYER_TYPE_TILEMAP Then
			DeleteTileMap(Nirvana_Stage_Layers[i].Layer_TileMap.TileMap_ID)
			DeleteTileSet(Nirvana_Stage_Layers[i].Layer_TileMap.Tileset_ID)
		ElseIf Nirvana_Stage_Layers[i].LayerType = NIRVANA_LAYER_TYPE_ISO_TILEMAP Then
			DeleteTileMap(Nirvana_Stage_Layers[i].Layer_TileMap.TileMap_ID)
			DeleteTileMap(Nirvana_Stage_Layers[i].Layer_TileMap2.TileMap_ID)
			DeleteTileSet(Nirvana_Stage_Layers[i].Layer_TileMap.Tileset_ID)
		End If

		Nirvana_Stage_Layers[i].Layer_TileMap.TileMap_ID = -1
		Nirvana_Stage_Layers[i].Layer_TileMap2.TileMap_ID = -1
		Nirvana_Stage_Layers[i].Layer_TileMap.Tileset_ID = -1

		Nirvana_Stage_Layers[i].Layer_TileMap2.Tileset_ID = -1

	Next

	While Stack_Size_N(Nirvana_Tileset_Image_Stack) > 0
		img_id = Pop_N(Nirvana_Tileset_Image_Stack)
		DeleteImage(img_id)
	Wend

	While Stack_Size_N(Nirvana_Sprite_Image_Stack) > 0
		img_id = Pop_N(Nirvana_Sprite_Image_Stack)
		DeleteImage(img_id)
	Wend

	Nirvana_Tileset_ID_0 = -1
	Nirvana_Tileset_Image_0 = -1

	Nirvana_Tileset_ID_1 = -1
	Nirvana_Tileset_Image_1 = -1

	Nirvana_Sprite_Image_0 = -1
	Nirvana_ActiveStage.Active = FALSE

End Sub

Function Nirvana_Stage_0(vp_x, vp_y, vp_w, vp_h) As Nirvana_Stage
	Nirvana_ClearStage()

	Dim nv_stage As Nirvana_Stage
	nv_stage.Name$ = "stage1"
	nv_stage.Tile_Size.Width = 32
	nv_stage.Tile_Size.Height = 32
	nv_stage.Stage_Size.Width = 300
	nv_stage.Stage_Size.Height = 300
	nv_stage.Layer_Count = 3

	'-------LAYER (background_layer)-------

	Nirvana_Stage_Layers[0].Name$ = "background_layer"
	Nirvana_Stage_Layers[0].LayerType = NIRVANA_LAYER_TYPE_CANVAS_2D
	Nirvana_Stage_Layers[0].Visible = TRUE
	Nirvana_Stage_Layers[0].Alpha = 255
	Nirvana_Stage_Layers[0].Scroll_Speed.X = 1
	Nirvana_Stage_Layers[0].Scroll_Speed.Y = 1
	Nirvana_Stage_Layers[0].Layer_TS_Stack = -1  ' This will be set to a stack if needed in sprite layer 

	Nirvana_Stage_Layers[0].Ref_Canvas = OpenCanvas(NIRVANA_WINDOW_WIDTH, NIRVANA_WINDOW_HEIGHT, vp_x, vp_y, vp_w, vp_h, 1)
	Nirvana_Stage_Layers[0].Bkg.Image_ID = LoadImage(NIRVANA_BKG_DIR$ + "bkg_sky1.png")
	Nirvana_Stage_Layers[0].Bkg.RenderSetting = NIRVANA_IMG_RENDER_SETTING_TILED

	'-------LAYER (tile_layer)-------

	Nirvana_Stage_Layers[1].Name$ = "tile_layer"
	Nirvana_Stage_Layers[1].LayerType = NIRVANA_LAYER_TYPE_TILEMAP
	Nirvana_Stage_Layers[1].Visible = TRUE
	Nirvana_Stage_Layers[1].Alpha = 255
	Nirvana_Stage_Layers[1].Scroll_Speed.X = 1
	Nirvana_Stage_Layers[1].Scroll_Speed.Y = 1
	Nirvana_Stage_Layers[1].Layer_TS_Stack = -1  ' This will be set to a stack if needed in sprite layer 

	Nirvana_Stage_Layers[1].Ref_Canvas = OpenCanvas(NIRVANA_WINDOW_WIDTH, NIRVANA_WINDOW_HEIGHT, vp_x, vp_y, vp_w, vp_h, 1)

	'------- TILEMAP -------
	Nirvana_Stage_Layers[1].Layer_TileMap = Nirvana_CreateTileMap("tset1", 300, 300)

	f = OpenFile(NIRVANA_DATA_DIR$ + "tm0.data", BINARY_INPUT)
	For y = 0 To 299
		For x = 0 To 299
			SetTile(Nirvana_Stage_Layers[1].Layer_TileMap.TileMap_ID, Nirvana_Read32(f), x, y)
		Next
	Next
	CloseFile(f)

	'-------LAYER (sprite_layer)-------

	Nirvana_Stage_Layers[2].Name$ = "sprite_layer"
	Nirvana_Stage_Layers[2].LayerType = NIRVANA_LAYER_TYPE_SPRITE
	Nirvana_Stage_Layers[2].Visible = TRUE
	Nirvana_Stage_Layers[2].Alpha = 255
	Nirvana_Stage_Layers[2].Scroll_Speed.X = 1
	Nirvana_Stage_Layers[2].Scroll_Speed.Y = 1
	Nirvana_Stage_Layers[2].Layer_TS_Stack = -1  ' This will be set to a stack if needed in sprite layer 

	Nirvana_Stage_Layers[2].Ref_Canvas = OpenCanvasSpriteLayer(vp_x, vp_y, vp_w, vp_h)
	SetSpriteCanvasRenderPriority(Nirvana_Stage_Layers[2].Ref_Canvas, SPRITE_PRIORITY_NONE, SPRITE_ORDER_ASCENDING)
	Canvas(Nirvana_Stage_Layers[2].Ref_Canvas)
	Nirvana_Stage_Layers[2].Layer_Sprite_Count = 1
	Nirvana_Stage_Layers[2].Layer_Shape_Count = 2

	'------- SPRITE ("Graizor") -------
	Nirvana_Stage_Sprites[0] = Nirvana_CreateSprite("grz", "Graizor")

	'Base Settings
	SetSpriteType(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, SPRITE_TYPE_DYNAMIC)
	SetSpriteAnimation(Nirvana_Stage_Sprites[0].Sprite_ID, 3, -1)

	'Shape
	SetSpriteShape(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, SPRITE_SHAPE_CIRCLE)
	SetSpriteShapeOffset(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, 0, 23)
	SetSpriteRadius(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, 9)

	'Transform
	SetSpritePosition(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, 202, 213)
	SetSpriteScale(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, 1, 1)
	SetSpriteRotation(Nirvana_Stage_Sprites[0].Detached_Sprite_ID, 360)

	'Render Settings
	SetSpriteAlpha(Nirvana_Stage_Sprites[0].Sprite_ID, 255)
	SetSpriteVisible(Nirvana_Stage_Sprites[0].Sprite_ID, TRUE)

	'------- SHAPE ("BOX_1") -------
	Nirvana_Stage_Shapes[0].Name$ = "BOX_1"
	Nirvana_Stage_Shapes[0].Sprite_ID = CreateSprite(-1, 1, 1)

	'Base Settings
	SetSpriteType(Nirvana_Stage_Shapes[0].Sprite_ID, SPRITE_TYPE_STATIC)
	SetSpriteSolid(Nirvana_Stage_Shapes[0].Sprite_ID, TRUE)
	'Shape
	Nirvana_Stage_Shapes[0].ShapeType = SPRITE_SHAPE_BOX
	SetSpriteShape(Nirvana_Stage_Shapes[0].Sprite_ID, Nirvana_Stage_Shapes[0].ShapeType)
	Nirvana_Stage_Shapes[0].ShapeData_Matrix = DimMatrix(4, 1)
	SetMatrixValue(Nirvana_Stage_Shapes[0].ShapeData_Matrix, 0, 0, 32)
	SetMatrixValue(Nirvana_Stage_Shapes[0].ShapeData_Matrix, 1, 0, 384)
	SetMatrixValue(Nirvana_Stage_Shapes[0].ShapeData_Matrix, 2, 0, 352)
	SetMatrixValue(Nirvana_Stage_Shapes[0].ShapeData_Matrix, 3, 0, 288)
	SetSpriteShapeOffset(Nirvana_Stage_Shapes[0].Sprite_ID, 32, 384)
	SetSpriteBox(Nirvana_Stage_Shapes[0].Sprite_ID, 352, 288)

	'Transform
	SetSpritePosition(Nirvana_Stage_Shapes[0].Sprite_ID,  0, 0) 'Set to (0,0) so that offset will be world position
	SetSpriteVisible(Nirvana_Stage_Shapes[0].Sprite_ID, FALSE) 'Image is -1 so it wouldn't render anyway

	'------- SHAPE ("BOX_2") -------
	Nirvana_Stage_Shapes[1].Name$ = "BOX_2"
	Nirvana_Stage_Shapes[1].Sprite_ID = CreateSprite(-1, 1, 1)

	'Base Settings
	SetSpriteType(Nirvana_Stage_Shapes[1].Sprite_ID, SPRITE_TYPE_STATIC)
	SetSpriteSolid(Nirvana_Stage_Shapes[1].Sprite_ID, TRUE)
	'Shape
	Nirvana_Stage_Shapes[1].ShapeType = SPRITE_SHAPE_BOX
	SetSpriteShape(Nirvana_Stage_Shapes[1].Sprite_ID, Nirvana_Stage_Shapes[1].ShapeType)
	Nirvana_Stage_Shapes[1].ShapeData_Matrix = DimMatrix(4, 1)
	SetMatrixValue(Nirvana_Stage_Shapes[1].ShapeData_Matrix, 0, 0, 640)
	SetMatrixValue(Nirvana_Stage_Shapes[1].ShapeData_Matrix, 1, 0, 384)
	SetMatrixValue(Nirvana_Stage_Shapes[1].ShapeData_Matrix, 2, 0, 320)
	SetMatrixValue(Nirvana_Stage_Shapes[1].ShapeData_Matrix, 3, 0, 288)
	SetSpriteShapeOffset(Nirvana_Stage_Shapes[1].Sprite_ID, 640, 384)
	SetSpriteBox(Nirvana_Stage_Shapes[1].Sprite_ID, 320, 288)

	'Transform
	SetSpritePosition(Nirvana_Stage_Shapes[1].Sprite_ID,  0, 0) 'Set to (0,0) so that offset will be world position
	SetSpriteVisible(Nirvana_Stage_Shapes[1].Sprite_ID, FALSE) 'Image is -1 so it wouldn't render anyway

	'------- TILE SPRITES  -------
	Nirvana_Tileset_0()
	Cut_Start_Index = 0
	Nirvana_Stage_Layers[2].Layer_TS_Stack = CreateStack_N()

	Return nv_stage
End Function


Function Nirvana_Stage_1(vp_x, vp_y, vp_w, vp_h) As Nirvana_Stage
	Nirvana_ClearStage()

	Dim nv_stage As Nirvana_Stage
	nv_stage.Name$ = "stage2"
	nv_stage.Tile_Size.Width = 32
	nv_stage.Tile_Size.Height = 32
	nv_stage.Stage_Size.Width = 100
	nv_stage.Stage_Size.Height = 100
	nv_stage.Layer_Count = 3

	'-------LAYER (tl0)-------

	Nirvana_Stage_Layers[0].Name$ = "tl0"
	Nirvana_Stage_Layers[0].LayerType = NIRVANA_LAYER_TYPE_TILEMAP
	Nirvana_Stage_Layers[0].Visible = TRUE
	Nirvana_Stage_Layers[0].Alpha = 255
	Nirvana_Stage_Layers[0].Scroll_Speed.X = 1
	Nirvana_Stage_Layers[0].Scroll_Speed.Y = 1
	Nirvana_Stage_Layers[0].Layer_TS_Stack = -1  ' This will be set to a stack if needed in sprite layer 

	Nirvana_Stage_Layers[0].Ref_Canvas = OpenCanvas(NIRVANA_WINDOW_WIDTH, NIRVANA_WINDOW_HEIGHT, vp_x, vp_y, vp_w, vp_h, 1)

	'------- TILEMAP -------
	Nirvana_Stage_Layers[0].Layer_TileMap = Nirvana_CreateTileMap("haunted", 100, 100)

	f = OpenFile(NIRVANA_DATA_DIR$ + "tm1.data", BINARY_INPUT)
	For y = 0 To 99
		For x = 0 To 99
			SetTile(Nirvana_Stage_Layers[0].Layer_TileMap.TileMap_ID, Nirvana_Read32(f), x, y)
		Next
	Next
	CloseFile(f)

	'-------LAYER (tl1)-------

	Nirvana_Stage_Layers[1].Name$ = "tl1"
	Nirvana_Stage_Layers[1].LayerType = NIRVANA_LAYER_TYPE_TILEMAP
	Nirvana_Stage_Layers[1].Visible = TRUE
	Nirvana_Stage_Layers[1].Alpha = 255
	Nirvana_Stage_Layers[1].Scroll_Speed.X = 1
	Nirvana_Stage_Layers[1].Scroll_Speed.Y = 1
	Nirvana_Stage_Layers[1].Layer_TS_Stack = -1  ' This will be set to a stack if needed in sprite layer 

	Nirvana_Stage_Layers[1].Ref_Canvas = OpenCanvas(NIRVANA_WINDOW_WIDTH, NIRVANA_WINDOW_HEIGHT, vp_x, vp_y, vp_w, vp_h, 1)

	'------- TILEMAP -------
	Nirvana_Stage_Layers[1].Layer_TileMap = Nirvana_CreateTileMap("haunted", 100, 100)

	f = OpenFile(NIRVANA_DATA_DIR$ + "tm2.data", BINARY_INPUT)
	For y = 0 To 99
		For x = 0 To 99
			SetTile(Nirvana_Stage_Layers[1].Layer_TileMap.TileMap_ID, Nirvana_Read32(f), x, y)
		Next
	Next
	CloseFile(f)

	'-------LAYER (tl2)-------

	Nirvana_Stage_Layers[2].Name$ = "tl2"
	Nirvana_Stage_Layers[2].LayerType = NIRVANA_LAYER_TYPE_TILEMAP
	Nirvana_Stage_Layers[2].Visible = TRUE
	Nirvana_Stage_Layers[2].Alpha = 255
	Nirvana_Stage_Layers[2].Scroll_Speed.X = 1
	Nirvana_Stage_Layers[2].Scroll_Speed.Y = 1
	Nirvana_Stage_Layers[2].Layer_TS_Stack = -1  ' This will be set to a stack if needed in sprite layer 

	Nirvana_Stage_Layers[2].Ref_Canvas = OpenCanvas(NIRVANA_WINDOW_WIDTH, NIRVANA_WINDOW_HEIGHT, vp_x, vp_y, vp_w, vp_h, 1)

	'------- TILEMAP -------
	Nirvana_Stage_Layers[2].Layer_TileMap = Nirvana_CreateTileMap("haunted", 100, 100)

	f = OpenFile(NIRVANA_DATA_DIR$ + "tm3.data", BINARY_INPUT)
	For y = 0 To 99
		For x = 0 To 99
			SetTile(Nirvana_Stage_Layers[2].Layer_TileMap.TileMap_ID, Nirvana_Read32(f), x, y)
		Next
	Next
	CloseFile(f)

	Return nv_stage
End Function



Function Nirvana_LoadStage(stage_name$, viewport_x, viewport_y, viewport_w, viewport_h)
	GetWindowSize(NIRVANA_WINDOW_WIDTH, NIRVANA_WINDOW_HEIGHT)

	Select Case stage_name$

	Case "stage1"
		Nirvana_ActiveStage = Nirvana_Stage_0(viewport_x, viewport_y, viewport_w, viewport_h)

	Case "stage2"
		Nirvana_ActiveStage = Nirvana_Stage_1(viewport_x, viewport_y, viewport_w, viewport_h)

	Default
		Return FALSE
	End Select

	Nirvana_ActiveStage.Active = TRUE
	Nirvana_ActiveStage.Stage_Offset.X = 0
	Nirvana_ActiveStage.Stage_Offset.Y = 0
	Nirvana_ActiveStage.Viewport_Size.Width = viewport_w
	Nirvana_ActiveStage.Viewport_Size.Height = viewport_h
	Return TRUE
End Function


