/'*****************************************************************************
*
* Tilengine sample
* 2015 Marc Palacios
* http://www.tilengine.org
*
* This example show a classic Mode 7 perspective projection plane like the 
* one seen in SNES games like Super Mario Kart. It uses a single transformed
* layer with a raster effect setting the scaling factor for each line
*
*****************************************************************************'/

#include once "Tilengine.bi"

#ifndef NULL
#define NULL cptr(any ptr,0)
#endif

#ifndef M_PI
#define M_PI 3.14159265f
#endif

dim shared as long sintable(360-1)
dim shared as long costable(360-1)

sub BuildSinTable
  for c as integer = 0 to 359
	  sintable(c) = sin(c*M_PI/180)*256
		costable(c) = cos(c*M_PI/180)*256
	next
end sub

function CalcSin(angle as long, factor as long) as long
	if (angle > 359) then angle = angle mod 360
	return (sintable(angle)*factor) shr 8
end function

function CalcCos(angle as long, factor as long) as long
	if (angle > 359) then angle = angle mod 360
  return (costable(angle)*factor) shr 8
end function


#define SCR_WIDTH  400
#define SCR_HEIGHT 240

' linear interploation
#define lerp(x, x0,x1, fx0,fx1) (fx0) + ((fx1) - (fx0))*((x) - (x0))/((x1) - (x0))


' layers
enum
	LAYER_FOREGROUND
	LAYER_BACKGROUND
	MAX_LAYER
end enum

enum
	MAP_HORIZON
	MAP_TRACK
	MAX_MAP
end enum

dim as long pos_foreground
dim as long pos_background(6-1)
dim as long inc_background(6-1)
dim shared as TLN_Tileset tilesets(MAX_MAP-1)
dim shared as TLN_Tilemap tilemaps(MAX_MAP-1)
dim as ulong frame
dim as ulong _time
dim shared as fix_t x,y,s,a

dim shared as TLN_Affine affine
dim as long angle

' raster callback (virtual HBLANK)
sub raster_callback cdecl(byval _line as long)
	if (_line = 24) then
	  TLN_SetLayer (LAYER_BACKGROUND, tilesets(MAP_TRACK), tilemaps(MAP_TRACK))
		TLN_SetLayerPosition(LAYER_BACKGROUND, fix2int(x), fix2int(y))
		TLN_DisableLayer(LAYER_FOREGROUND)
	end if

	if (_line >= 24) then
		dim as fix_t s0 = float2fix(0.2f)
		dim as fix_t s1 = float2fix(5.0f)
		dim as fix_t s = lerp (_line, 24,SCR_HEIGHT, s0,s1)
		dim as single scale = fix2float(s)

		affine.sx = scale
		affine.sy = scale		
		TLN_SetLayerAffineTransform (LAYER_BACKGROUND, @affine)
	end if
end sub



' setup engine
TLN_Init (SCR_WIDTH,SCR_HEIGHT, MAX_LAYER, 0, 5)
TLN_SetRasterCallback(@raster_callback)
TLN_SetBGColor(0,0,0)

' load resources
TLN_SetLoadPath ("../assets/smk")
tilesets(MAP_HORIZON) = TLN_LoadTileset("track1_bg.tsx")
tilemaps(MAP_HORIZON) = TLN_LoadTilemap("track1_bg.tmx", NULL)
tilesets(MAP_TRACK  ) = TLN_LoadTileset("track1.tsx")
tilemaps(MAP_TRACK  ) = TLN_LoadTilemap("track1.tmx", NULL)

' startup display
TLN_CreateWindow(NULL, 0)

x = int2fix(-136)
y = int2fix(336)
s = 0
a = float2fix(0.2f)
angle = 0

BuildSinTable()

affine.dx = SCR_WIDTH/2
affine.dy = SCR_HEIGHT
affine.sx = 1.0f
affine.sy = 1.0f
affine.angle = angle

' main loop
while TLN_ProcessWindow()
' timekeeper
  _time = frame

  TLN_SetLayer(LAYER_FOREGROUND, tilesets(MAP_HORIZON), tilemaps(MAP_HORIZON))
  TLN_SetLayer(LAYER_BACKGROUND, tilesets(MAP_HORIZON), tilemaps(MAP_HORIZON))
  TLN_SetLayerPosition(LAYER_FOREGROUND, lerp(angle*2, 0,360, 0,256), 24)
  TLN_SetLayerPosition(LAYER_BACKGROUND, lerp(angle, 0,360, 0,256), 0)
  TLN_SetLayerAffineTransform(LAYER_BACKGROUND, NULL)

  ' input  
  if TLN_GetInput(INPUT_LEFT) then
    angle-=2
  elseif TLN_GetInput(INPUT_RIGHT) then
    angle+=2
  end if  

  if TLN_GetInput(INPUT_UP) then
    s += a
    if (s > int2fix(2)) then s = int2fix(2)
  elseif (s >= a) then
    s -= a
  end if

  if (TLN_GetInput (INPUT_DOWN)) then
    s -= a
    if (s < -int2fix(2)) then  s = -int2fix(2)
  elseif (s <= -a) then
    s += a
  end if
  
  if (s<>0) then
    angle = angle mod 360
    if (angle < 0) then  angle += 360
    x += CalcSin(angle, s)
    y -= CalcCos(angle, s)
  end if

  affine.angle = angle
  ' render to window
  TLN_DrawFrame(_time)
  frame+=1
wend

' deinit
TLN_DeleteTileset(tilesets(MAP_HORIZON))
TLN_DeleteTilemap(tilemaps(MAP_HORIZON))
TLN_DeleteTileset(tilesets(MAP_TRACK  ))
TLN_DeleteTilemap(tilemaps(MAP_TRACK  ))
TLN_DeleteWindow()
TLN_Deinit()




