
// Project: Landscape atlas shading 
// Created: 2018-02-25
// Mod by Andrew Vanbeck - Added noise fog for a spooky effect

// show all errors
SetErrorMode(2)

// set window properties
SetWindowTitle( "Landscape test" )
SetWindowSize( 1920, 1080, 1 )
SetWindowAllowResize( 1 ) // allow the user to resize the window

// set display properties
SetVirtualResolution( 1920, 1080 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 60, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts

SetDefaultMinFilter(1)
SetDefaultMagFilter(1)

rem this part is used to build atlas textures automatically for you. All you need to do is take out the rem'd lines and pass the names of the images and the index locations
rem this one is designed to use images called "groundX.jpg" numbered 1 through 16. These names can be anything, but for ease I use numbers so that I can alter the load order
rem it can do any types of image, including normals, you just need to change the file names and then the extension they save with
remstart
dim layers[16]
layers[1]=1
layers[2]=1
layers[3]=2
layers[4]=2
layers[5]=3
layers[6]=3
layers[7]=3
layers[8]=3
layers[9]=4
layers[10]=4
layers[11]=4
layers[12]=4
layers[13]=5
layers[14]=5
layers[15]=5
layers[16]=5
creatememblock(900000,12+((2048*2048)*4)) // create the empty memblock for the 16*16 image
for t=1 to 16
	atlasload("ground" + str(layers[t]) + ".jpg",t)
	print("Building image " + str(t))
	sync()
next t
CreateImageFromMemblock(1,900000)
saveimage(1,"combined1.png") // set the name here to what you want - remember to change it for normals etc
remend

rem if you are using the code above to generate iatlas textures disable this line of code so that AGK doesn't try to load the image again
loadimage(1,"combined1.png") // base texture
loadimage(3,"clouds1.png") // this is the clouds used to cast a shadow. This can be any PNG file with transparency - the level of shadow is based around the level of transparency in the image
loadimage(7,"combined1_nrm.png") // this is the water displacement map
loadimage(6,"noise.png") // base texture

SetImageWrapU(1,1)
SetImageWrapV(1,1)
SetImageWrapu(3,1)
SetImageWrapV(3,1)
SetImageWrapu(7,1)
SetImageWrapV(7,1)
SetImageWrapu(6,1)
SetImageWrapV(6,1)

LoadShader(1,"terrain.vs", "terrain.ps" )

maxterrainheight=10000 // this just sets the height of the landscape - make this whatever you want
CreateObjectFromHeightMap(1,"height2.png",100000,maxterrainheight,100000,5,5)

SetSkyBoxVisible(1)
SetSkyBoxSkyColor(2,3,25)
SetSkyBoxHorizonColor(50,60,80)
SetSunColor(50,80,120)
SetSkyBoxSunColor(100,105,115)
setfogmode(1)
setfogrange(25000,50000)
setfogcolor(50,60,80)



setobjectposition(1,-50000,0,-50000)
SetObjectImage(1,1,0)
setobjectimage(1,3,7) // here we load the clouds shader
SetObjectImage(1,7,2) // normals for the landscape
SetObjectImage(1,6,6) // noise for the fog

tile=20 // this sets the tile size for the textures. Note, AGK applis this to all stages, so normals etc will all be scaled
SetObjectUVScale(1,0,tile,tile)
SetCameraRange(1,0.1,150000)
setobjectshader(1,1)
SetShaderConstantByName(1,"terrainheight",maxterrainheight*1.0,0.0,0.0,0.0)
shaderon=1

setcameraposition(1,getcamerax(1),2000,getcameraz(1))

cloudoff#=0.0
bumpon#=1.0


do

if getrawkeypressed(27)=1 then end

	SetShaderConstantByName(1,"cloudoffset",cloudoff#,0.0,0.0,0.0)
	SetShaderConstantByName(1,"bumpon",bumpon#,0.0,0.0,0.0)
	cloudoff#=cloudoff#+0.0001

	startx# = GetPointerX()
	starty# = GetPointerY()
	angx# = GetCameraAngleX(1)
	angy# = GetCameraAngleY(1)

	rem Move camera
	if ( GetRawKeyState( 87 ) ) then MoveCameraLocalZ( 1,200)
	if ( GetRawKeyState( 83 ) ) then MoveCameraLocalZ( 1, -200 )
	if ( GetRawKeyState( 65 ) ) then MoveCameraLocalX( 1, -200 )
	if ( GetRawKeyState( 68 ) ) then MoveCameraLocalX( 1, 200 )

	print("Terrain height = "+str(maxterrainheight))
	if bumpon#=0.0 then print("Press ''Y'' to toggel normal mapping (currently off)")
	if bumpon#=1.0 then print("Press ''Y'' to toggel normal mapping (currently on)")

	if getrawkeypressed(107)=1 // the "+" on the keypad
		if maxterrainheight=1
			maxterrainheight=maxterrainheight+499
		else
			maxterrainheight=maxterrainheight+500
		endif
		deleteobject(1)
		CreateObjectFromHeightMap(1,"height2.png",100000,maxterrainheight,100000,10,5)
		setobjectposition(1,-50000,0,-50000)
		if shaderon=1
			SetObjectImage(1,1,0)
			setobjectimage(1,3,7) // here we load the clouds shader
			SetObjectImage(1,7,2) // normals for the landscape
			SetObjectUVScale(1,0,tile,tile)
		else
			SetObjectImage(1,2,0)
			SetObjectUVScale(1,0,tile,tile)
		endif
		setobjectshader(1,1)		
		SetShaderConstantByName(1,"terrainheight",maxterrainheight*1.0,0.0,0.0,0.0)
	endif

	if getrawkeypressed(189)=1 // the "-" on the keypad
		maxterrainheight=maxterrainheight-500
		if maxterrainheight<1 then maxterrainheight=1
		deleteobject(1)
		CreateObjectFromHeightMap(1,"height2.png",100000,maxterrainheight,100000,10,5)
		setobjectposition(1,-50000,0,-50000)
		if shaderon=1
			SetObjectImage(1,1,0)
			setobjectimage(1,3,7) // here we load the clouds shader
			SetObjectImage(1,7,2) // normals for the landscape
			SetObjectUVScale(1,0,tile,tile)
		else
			SetObjectImage(1,2,0)
			SetObjectUVScale(1,0,tile,tile)
		endif
		setobjectshader(1,1)		
		SetShaderConstantByName(1,"terrainheight",maxterrainheight*1.0,0.0,0.0,0.0)
	endif
	
	print ("Use 1 and 2 to change the tile size (current is "+str(tile)+")")
	if getrawkeypressed(49)=1 // the "1" on the keypad
		if tile>1
			tile=tile-1
			setobjectuvscale(1,0,tile,tile)
		endif
	endif
	if getrawkeypressed(50)=1 // the "2" on the keypad
		if tile<150
			tile=tile+1
			setobjectuvscale(1,0,tile,tile)
		endif
	endif
	
	print("Press Q to turn the shader on or off")
	if getrawkeypressed(81)=1 // "Q" - turns shader on or off
		if shaderon=0
			setobjectshader(1,1)
			SetObjectImage(1,1,0)
			shaderon=1
		else
			setobjectshader(1,0)
			SetObjectImage(1,2,0)
			shaderon=0
		endif
	endif

	if getrawkeypressed(89)=1 // "Y" - toggle normal mapping
		if bumpon#=0.0
			bumpon#=1.0
			SetShaderConstantByName(1,"bumpon",bumpon#,0.0,0.0,0.0)
		else
			bumpon#=0.0
			SetShaderConstantByName(1,"bumpon",bumpon#,0.0,0.0,0.0)
		endif
	endif

	SetShaderConstantByName(1,"agk_time",timer()*0.01,0.0,0.0,0.0)

    Print( ScreenFPS() )
    Sync()
    
	fDiffX# = (GetPointerX() - startx#)/6.0
	fDiffY# = (GetPointerY() - starty#)/6.0

	newX# = angx# + fDiffY#
	if ( newX# > 89 ) then newX# = 89
	if ( newX# < -89 ) then newX# = -89
	SetCameraRotation( 1, newX#, angy# + fDiffX#, 0 )
    SetRawMousePosition(getvirtualwidth()/2,getvirtualheight()/2)

loop

function atlasload(fname$,index)
	remstart
	this code builds the atlas image based on the image data sent to it and the index position. Note this example only allows 16 images in a 4x4 layout, so index ranges are 1-16
	if the image isn't 512x512 then it;s reloaded again to make it work with the atlas
	remend
	
	LoadImage(899999,fname$)
	if getimagewidth(899999)<>512 or getimageheight(899999)<>512 then ResizeImage(899999,512,512)
	CreateMemblockFromImage(899999,899999)
	deleteimage(899999)
	img=899999

	rem here we build the atlas by copying this image into it's atlas position
	height=512
	width=512
	xoffset=0
	yoffset=0
	select index // here we set the offset position within the atlas image, based o the index of the image we passed in - this makes it really easy to alter any image within the atlas shouldd we want too
		case 2:
			xoffset=512
			yoffset=0
		endcase
		case 3:
			xoffset=512*2
			yoffset=0
		endcase
		case 4:
			xoffset=512*3
			yoffset=0
		endcase
		case 5:
			xoffset=0
			yoffset=512
		endcase
		case 6:
			xoffset=512
			yoffset=512
		endcase
		case 7:
			xoffset=512*2
			yoffset=512
		endcase
		case 8:
			xoffset=512*3
			yoffset=512
		endcase
		case 9:
			xoffset=0
			yoffset=512*2
		endcase
		case 10:
			xoffset=512
			yoffset=512*2
		endcase
		case 11:
			xoffset=512*2
			yoffset=512*2
		endcase
		case 12:
			xoffset=512*3
			yoffset=512*2
		endcase
		case 13:
			xoffset=0
			yoffset=512*3
		endcase
		case 14:
			xoffset=512
			yoffset=512*3
		endcase
		case 15:
			xoffset=512*2
			yoffset=512*3
		endcase
		case 16:
			xoffset=512*3
			yoffset=512*3
		endcase
	endselect

	for y=1 to height
		for x=1 to width
			off=12+(((y-1)*width)*4)
			off=off+((x-1)*4)
			destoff=(12+(((y-1)*(width*4))*4))+((yoffset*(width*4))*4)
			destoff=destoff+((x-1)*4)+(xoffset*4)
			r=getmemblockbyte(img,off)
			SetMemblockByte(900000,destoff,r)
			g=getmemblockbyte(img,off+1)
			SetMemblockByte(900000,destoff+1,g)
			b=getmemblockbyte(img,off+2)
			SetMemblockByte(900000,destoff+2,b)
			a=getmemblockbyte(img,off+3)
			SetMemblockByte(900000,destoff+3,a)
		next x
	next y

	rem here we set back the header dimensions of the new (atlas) image we created in the memblock so it can be used and saved if needed
	SetMemblockint(900000,0,512*4)
	SetMemblockint(900000,4,512*4)
	SetMemblockint(900000,8,32)
	deleteimage(img)
	deletememblock(img)

endfunction
