// Hide GM window
draw_enable_drawevent(false);
application_surface_draw_enable(false);

dll_init("xtreme3d.dll");

EngineCreate();
EngineShowLoadingErrors(true);
EngineSetCulling(vcNone);
EngineSetObjectsSorting(osNone);
EngineSetMaxLights(8);

// Create custom window
window = WindowCreate(0, 0, 1280, 720, false);
WindowSetTitle(window, "Xtreme3D 4 Cascaded Shadows Demo");
WindowCenter(window);

var x3dPath = environment_get_variable("userprofile") + "/Documents/Xtreme3D";
if (not directory_exists(x3dPath)) {
	directory_create(x3dPath);
}

logger = LoggerCreate(x3dPath + "/xtreme3d.log", llMax);

// Create viewer in the game window
windowHandle = WindowGetHandle(window);
viewer = ViewerCreate(0, 0, 1280, 720, windowHandle);
ViewerSetBackgroundColor(viewer, #9fdaf2);
ViewerSetLighting(viewer, true);
ViewerEnableFog(viewer, true);
ViewerSetFogColor(viewer, #85b5ca);
ViewerSetFogDistance(viewer, 0, 100);
ViewerSetAntiAliasing(viewer, csa8xHQ); //CSAA
ViewerEnableVSync(viewer, vsmNoSync);
ViewerSetAutoRender(viewer, false);

// Create main material library
matlib = MaterialLibraryCreate();
MaterialLibraryActivate(matlib);

// Create root scene objects
global.preprocess = DummycubeCreate(0);
global.back = DummycubeCreate(0);
global.scene = DummycubeCreate(0);
global.front = DummycubeCreate(0);

// Create camera
camPos = DummycubeCreate(global.scene);
camera = CameraCreate(camPos);
ViewerSetCamera(viewer, camera);
ObjectSetPosition(camPos, 0, 2, 3);
CameraSetViewDepth(camera, 1000);
CameraSetFocal(camera, 100);
CameraSetNearPlaneBias(camera, 0.2);

// Create shadow map
shadowCasters = DummycubeCreate(global.scene);

shadowTex1 = "shadowmap1";
shadowTex2 = "shadowmap2";
shadowTex3 = "shadowmap3";

function CreateShadowTexture(name, size) {
	MaterialCreate(name, "");
	MaterialGenTexture(name, size, size);
	MaterialSetTextureFormat(name, tfExtended);
	MaterialSetTextureFormatEx(name, tfDEPTH_COMPONENT24);
	MaterialSetTextureWrap(name, twSeparate);
	MaterialSetTextureWrapS(name, twClampToBorder);
	MaterialSetTextureWrapT(name, twClampToBorder);
	MaterialSetTextureBorderColor(name, c_white);
	MaterialSetTextureFilter(name, miLinear, maLinear);
	MaterialSetTextureCompareMode(name, tcmCompareRtoTexture);
	MaterialSetTextureDepthCompareFunc(name, cfLess);
}

shadowMapSize = 2048;

shadowFboMatlib = MaterialLibraryCreate();
MaterialLibraryActivate(shadowFboMatlib);
CreateShadowTexture(shadowTex1, shadowMapSize);
CreateShadowTexture(shadowTex2, shadowMapSize);
CreateShadowTexture(shadowTex3, shadowMapSize);
MaterialLibraryActivate(matlib);

lightPositionObj = DummycubeCreate(global.scene);
lightPitchObj = DummycubeCreate(lightPositionObj);
ObjectSetPosition(lightPitchObj, 0, 10, 0);
ObjectPitch(lightPitchObj, 45);

shadowCamera1 = ShadowCameraCreate(lightPitchObj);
ShadowCameraSetProjectionSize(shadowCamera1, 10);
ShadowCameraSetZClippingPlanes(shadowCamera1, -100.0, 100.0);

shadowCamera2 = ShadowCameraCreate(lightPitchObj);
ShadowCameraSetProjectionSize(shadowCamera2, 30);
ShadowCameraSetZClippingPlanes(shadowCamera2, -100.0, 100.0);

shadowCamera3 = ShadowCameraCreate(lightPitchObj);
ShadowCameraSetProjectionSize(shadowCamera3, 100);
ShadowCameraSetZClippingPlanes(shadowCamera3, -100.0, 100.0);

shadowFbo1 = FBOCreate(shadowMapSize, shadowMapSize, global.preprocess);
FBOSetMaterialLibrary(shadowFbo1, shadowFboMatlib);
FBOSetCamera(shadowFbo1, shadowCamera1);
FBOSetAspect(shadowFbo1, 1);
FBOSetRootObject(shadowFbo1, shadowCasters);
FBOSetDepthTextureName(shadowFbo1, shadowTex1);
FBOSetTargetVisibility(shadowFbo1, tvDefault);
FBOSetClearOptions(shadowFbo1, true, true, true, true);
FBOSetShadowMapMode(shadowFbo1, true);
FBOSetEnabledRenderBuffers(shadowFbo1, true, false);

shadowFbo2 = FBOCreate(shadowMapSize, shadowMapSize, global.preprocess);
FBOSetMaterialLibrary(shadowFbo2, shadowFboMatlib);
FBOSetCamera(shadowFbo2, shadowCamera2);
FBOSetAspect(shadowFbo2, 1);
FBOSetRootObject(shadowFbo2, shadowCasters);
FBOSetDepthTextureName(shadowFbo2, shadowTex2);
FBOSetTargetVisibility(shadowFbo2, tvDefault);
FBOSetClearOptions(shadowFbo2, true, true, true, true);
FBOSetShadowMapMode(shadowFbo2, true);
FBOSetEnabledRenderBuffers(shadowFbo2, true, false);

shadowFbo3 = FBOCreate(shadowMapSize, shadowMapSize, global.preprocess);
FBOSetMaterialLibrary(shadowFbo3, shadowFboMatlib);
FBOSetCamera(shadowFbo3, shadowCamera3);
FBOSetAspect(shadowFbo3, 1);
FBOSetRootObject(shadowFbo3, shadowCasters);
FBOSetDepthTextureName(shadowFbo3, shadowTex3);
FBOSetTargetVisibility(shadowFbo3, tvDefault);
FBOSetClearOptions(shadowFbo3, true, true, true, true);
FBOSetShadowMapMode(shadowFbo3, true);
FBOSetEnabledRenderBuffers(shadowFbo3, true, false);

shadowMap1 = ShadowMapCreate(shadowFbo1, viewer, shadowCamera1);
shadowMap2 = ShadowMapCreate(shadowFbo2, viewer, shadowCamera2);
shadowMap3 = ShadowMapCreate(shadowFbo3, viewer, shadowCamera3);

// Create light
light1 = LightCreate(lsParallel, lightPitchObj);
ObjectPitch(light1, -180);
LightSetAmbientColor(light1, c_black);
LightSetDiffuseColor(light1, c_white);
LightSetSpecularColor(light1, c_white);
ObjectSetPosition(light1, 0, 10, 0);

MaterialCreate("mTiles", "data/textures/tiles.jpg");
MaterialSetOptions("mTiles", true, true);

csmVertexProgram = TextRead("shaders/csm/csm-vp.glsl");
csmFragmentProgram = TextRead("shaders/csm/csm-fp.glsl");

csmShader = GLSLShaderCreate(csmVertexProgram, csmFragmentProgram);
GLSLShaderSetLogger(csmShader, logger);

csmParamDiffuseTexture = GLSLShaderCreateParameter(csmShader, "diffuseTexture");
GLSLShaderSetParameterTexture(csmParamDiffuseTexture, "", 0);

csmParamShadowmap1 = GLSLShaderCreateParameter(csmShader, "shadowMap1");
GLSLShaderSetParameterShadowTexture(csmParamShadowmap1, shadowMap1, 1);

csmParamShadowmap2 = GLSLShaderCreateParameter(csmShader, "shadowMap2");
GLSLShaderSetParameterShadowTexture(csmParamShadowmap2, shadowMap2, 2);

csmParamShadowmap3 = GLSLShaderCreateParameter(csmShader, "shadowMap3");
GLSLShaderSetParameterShadowTexture(csmParamShadowmap3, shadowMap3, 3);

csmParamShadowMatrix1 = GLSLShaderCreateParameter(csmShader, "shadowMatrix1");
GLSLShaderSetParameterShadowMatrix(csmParamShadowMatrix1, shadowMap1);

csmParamShadowMatrix2 = GLSLShaderCreateParameter(csmShader, "shadowMatrix2");
GLSLShaderSetParameterShadowMatrix(csmParamShadowMatrix2, shadowMap2);

csmParamShadowMatrix3 = GLSLShaderCreateParameter(csmShader, "shadowMatrix3");
GLSLShaderSetParameterShadowMatrix(csmParamShadowMatrix3, shadowMap3);

csmParamShadowmapSize = GLSLShaderCreateParameter(csmShader, "shadowMapSize");
GLSLShaderSetParameter2f(csmParamShadowmapSize, shadowMapSize, shadowMapSize);

csmParamUsePCF = GLSLShaderCreateParameter(csmShader, "usePCF");
GLSLShaderSetParameter1i(csmParamUsePCF, true);

csmParamDrawCascades = GLSLShaderCreateParameter(csmShader, "drawCascades");
GLSLShaderSetParameter1i(csmParamDrawCascades, false);

GLSLShaderForceDisableStencilTest(csmShader, true);

MaterialSetShader("mTiles", csmShader);

plane = PlaneCreate(0, 100, 100, 50, 50, global.scene);
ObjectSetMaterial(plane, "mTiles");
ObjectPitch(plane, 90);

cub = CubeCreate(5, 5, 5, shadowCasters); 
ObjectSetPosition(cub, 0, 2.5, -10);
ObjectSetMaterial(cub, "mTiles");

cylinder = CylinderCreate(0.25, 0.25, 3, 16, 4, 1, shadowCasters);
ObjectSetPosition(cylinder, 0, 1.5, -4);
ObjectSetMaterial(cylinder, "mTiles");

ftfont = TTFontCreate("data/fonts/DroidSans.ttf", 20);
text = HUDTextCreate(ftfont, "FPS: 0", global.front);
HUDTextSetColor(text, c_white, 1.0);
ObjectSetPosition(text, 20, 20, 0);

mouselookActive = false;
mb_left_released = true;
mx = display_get_width() / 2;
my = display_get_height() / 2;
MouseSetPosition(mx, my);

game_set_speed(60, gamespeed_fps);

canTakeScreenshot = true;
