
global SS3D_FileRoot = "";

// CORE

function SS3D_Event( renderer, e )
{
	if( e.type == SDL_VIDEODEVICELOST ) renderer.onDeviceLost();
	if( e.type == SDL_VIDEODEVICERESET ) renderer.onDeviceReset();
	if( e.type == SDL_WINDOWEVENT && e.event == SDL_WINDOWEVENT_SIZE_CHANGED )
		renderer.resize( e.data1, e.data2 );
}

// TEXTURES

function _SS3D_Texture_GetType( filepath )
{
	if( string_find( filepath, "normal" ) !== null ) return SS3DTEXTURE_USAGE_NORMAL;
	if( string_find( string_tolower( filepath ), "ui/" ) !== null ) return SS3DTEXTURE_USAGE_MISC;
	return SS3DTEXTURE_USAGE_ALBEDO;
}

// SHADERS

function _SS3D_Shader_CleanCachePath( path )
{
	return string_replace( path, ":", "_" );
}

function _SS3D_Shader_NamePath( name )
{
	name = string_replace( name, "\\", "/" );
	parts = string_explode( name, "/" );
	parts.pop();
	return string_implode( parts, "/" );
}

function _SS3D_Shader_ParseIncludes( renderer, name, data )
{
	path = _SS3D_Shader_NamePath( name );
	pos = data.length;
	while( ( pos = string_find_rev( data, "#include", pos ) ) !== null )
	{
		pos2a = string_find( data, "\n", pos );
		pos2b = string_find( data, "\r", pos );
		if( pos2a && ( !pos2b || pos2a < pos2b ) )
			pos2 = pos2a;
		else
			pos2 = pos2b;
		cut = string_cut( data, pos + 8, pos2 - 1 );
		cut = string_trim( cut, "\" " );
		
		guts = _SS3D_Shader_LoadFile( renderer, path $ "/" $ cut );
		data = string_part( data, 0, pos ) $ guts $ string_part( data, pos2 );
	}
	return data;
}

function _SS3D_Shader_LoadFile( renderer, name )
{
	filename = SS3D_FileRoot $ "shaders_" $ renderer $ "/" $ name $ ".shd";
	if( !io_file_exists( filename ) )
		return WARNING( "shader file does not exist: " $ filename );
	data = io_file_read( filename );
	data = _SS3D_Shader_ParseIncludes( renderer, name, data );
	return data;
}

function _SS3D_Shader_LoadCodeInternal( renderer, name )
{
	if( string_part( name, 0, 4 ) == "mtl:" )
	{
		info = string_explode( name, ":" );
		if( info.size != 3 )
			return WARNING( "invalid material name, expected mtl:<name>:<type>" );
		return string_replace
		(
			_SS3D_Shader_LoadFile( renderer, "tpl_" $ info[2] ),
			"__CODE__",
			_SS3D_Shader_LoadFile( renderer, "mtl_" $ info[1] )
		);
	}
	return _SS3D_Shader_LoadFile( renderer, name );
}

function _SS3D_Shader_LoadCode( ss3d, renderer, name )
{
	filename = _SS3D_Shader_CleanCachePath( SS3D_FileRoot $ "shaders_" $ renderer $ "/" $ name $ ".csh" );
	code = @io_file_read( filename );
	if( code !== null )
		return code;
	code = _SS3D_Shader_LoadCodeInternal( renderer, name );
	if( code !== null )
		code = ss3d.compileShader( code );
	io_file_write( filename, code );
	return code;
}

// CACHES

function SS3D_GetVertexDecl( ss3d, decl )
{
	if( !isset( ss3d.store, "vdecls" ) ) ss3d.store.vdecls = {};
	vdecls = ss3d.store.vdecls;
	if( !isset( vdecls, decl ) )
	{
		inst = ss3d.createVertexDecl( decl );
		if( inst )
			vdecls[ decl ] = inst;
	}
	else
		inst = vdecls[ decl ];
	return inst;
}

// MESH LOADING

function SS3D_MeshLoad_GetVertexDecl( ss3d, decl ){ return SS3D_GetVertexDecl( ss3d, decl ); }
function SS3D_MeshLoad_GetTexture( ss3d, texture ){ return ss3d.getTexture( SS3D_FileRoot $ texture ); }

// MESH GEN

global cSS3D_GenMeshVertexFormat = "pf30f2nf3tf4cf4";
global cSS3D_GenParticleVertexFormat = "pf30f2cf4";
global cSS3D_GenTerrainVertexFormat = "pf30f21f2nf3tf4";

function SS3D_CreateCubeMesh( ss3d, extents, position, color )
{
	(vdata,idata,vcount,icount) = SS3D_MeshGen_Cube( extents, position, color );
	mesh = ss3d.createMesh();
	mesh.setVertexData( vdata, SS3D_GetVertexDecl( ss3d, cSS3D_GenMeshVertexFormat ), false );
	mesh.setIndexData( idata, false );
	mesh.numParts = 1;
	mesh.setPartRanges( 0, 0, vcount, 0, icount );
	return mesh;
}

function SS3D_UpdateParticleMesh( ss3d, mesh, viewmatrix, positions, sizes, colors, angles )
{
	(vdata,idata,vcount,icount) = SS3D_MeshGen_Particles( viewmatrix, positions, sizes, colors, angles );
	
	vdecl = SS3D_GetVertexDecl( ss3d, cSS3D_GenParticleVertexFormat );
	if( mesh.vertexDataSize < vdata.length )
		mesh.initVertexBuffer( vdata.length );
	mesh.updateVertexData( vdata, vdecl, false );
	mesh.setAABBFromVertexData( vdata, vdecl );
	
	if( mesh.indexDataSize < idata.length )
		mesh.initIndexBuffer( idata.length, false );
	mesh.updateIndexData( idata );
	
	mesh.numParts = 1;
	mesh.setPartRanges( 0, 0, vcount, 0, icount );
}

function SS3D_CreateTerrainMeshFromImage( ss3d, filename, min, max )
{
	image = SS_LoadImage( filename );
	if( !image )
		return null;
	heights = floatarray_from_uint8_buffer( image.getData(), 1/255, 4 );
	(vdata,idata,vcount,icount) = SS3D_MeshGen_Terrain( image.width, image.height, heights, min, max );
	
	vdecl = SS3D_GetVertexDecl( ss3d, cSS3D_GenTerrainVertexFormat );
	mesh = ss3d.createMesh();
	mesh.setVertexData( vdata, vdecl, false );
	mesh.setAABBFromVertexData( vdata, vdecl );
	mesh.setIndexData( idata, true );
	mesh.numParts = 1;
	mesh.setPartRanges( 0, 0, vcount, 0, icount );
	return mesh;
}
