;; ----------------------------------------------------------------------------
;; Irrlicht Wrapper For Imperative Languages - Purebasic Examples
;; IrrlichtWrapper and FreeBasic-Example by Frank Dodd (2006)
;; Improved IrrlichtWrapper and PureBasicExample by Michael Taupitz (2006)
;; ----------------------------------------------------------------------------
;; Example 29 : Shaders
;; This example shows 3 Cubes with different Shaders.
;; ----------------------------------------------------------------------------

;; ////////////////////////////////////////////////////////////////////////////
;; Include the Irr3D-Requester
XIncludeFile "Irr3DRequester.pb"

EnableExplicit

Global UseHighLevelShaders.l = #False

;; ////////////////////////////////////////////////////////////////////////////
;; Global variables
Define *OurCamera.irr_camera
Define *IrrSkyBox.l
Define *CubeNode.irr_node
Define *RenderTarget.irr_texture
Define *light.irr_node
Define newMaterialType1.l = 0
Define newMaterialType2.l = 0
Define *Font.l
Define *node.l,*nodetext.l,*texture.l
Define Result.l


; We Need a Shader-Callback :
ProcedureC.l MyShaderCallBack(*service.l,userdata.l) 
  Define i.l,*activeCam.l
  Dim CamPosArray.f(3)
  Dim LightColorArray.f(4)
  Dim matrix4.f(16);
  Dim matrix4_2.f(16);
  

; 		// set inverted world matrix
; 		// If we are using highlevel shaders (the user can Select this when
; 		// starting the program), we must set the constants by name.

    
    IrrMatrixGetTransform(#IRR_ETS_WORLD,@matrix4(0))
    IrrMatrixMakeInverse(@matrix4(0),@matrix4_2(0))
    
    
    If UseHighLevelShaders = #True
      IrrSetVertexShaderConstantName(*service,"mInvWorld",@matrix4_2(0),16)
    Else
      IrrSetVertexShaderConstant(*service,@matrix4_2(0),0,4)
    EndIf

; 		// set clip matrix
    IrrMatrixGetWorldView(@matrix4(0))
    
    If UseHighLevelShaders = #True
    			IrrSetVertexShaderConstantName(*service,"mWorldViewProj", @matrix4(0), 16);
		Else
  		IrrSetVertexShaderConstant(*service, @matrix4(0),4,4)
    EndIf

; 		// set camera position
    *activeCam.l = IrrGetActiveCamera();
    
    IrrGetNodeAbsolutePosition(*activeCam,@CamPosArray(0),@CamPosArray(1),@CamPosArray(2))
        

    If UseHighLevelShaders = #True
			IrrSetVertexShaderConstantName(*service,"mLightPos", @CamPosArray(0), 3);
    Else
  		IrrSetVertexShaderConstant(*service, @CamPosArray(0),8,1)
    EndIf
     
; 		// set light color 
      LightColorArray(0) = 0.0
      LightColorArray(1) = 1.0
      LightColorArray(2) = 1.0
      LightColorArray(3) = 0.0
; 
    If UseHighLevelShaders = #True
			IrrSetVertexShaderConstantName(*service,"mLightColor", @LightColorArray(0), 4);
		Else
  		IrrSetVertexShaderConstant(*service, @LightColorArray(0),9,1)
    EndIf 
; 		// set transposed world matrix
 	
    IrrMatrixGetTransform(#IRR_ETS_WORLD,@matrix4(0))
    IrrMatrixGetTransposed(@matrix4(0),@matrix4_2(0))
	    		
    If UseHighLevelShaders = #True
      IrrSetVertexShaderConstantName(*service,"mTransWorld", @matrix4_2(0), 16);       	    		
    Else
      IrrSetVertexShaderConstant(*service,@matrix4_2(0), 10, 4)      
    EndIf

EndProcedure


; -----------------------------------------------------------------------------
; To Start the Irrlicht-Device we use the Irr3DRequester, to make it more comfortable
; for the Users, and also easier to test different resolutions and devices.
If Irr3DRequester()
    
  Result.l = MessageRequester("Shaderquestion", "Use Highlevel-Shaders ?", #PB_MessageRequester_YesNo)
  If Result = #PB_MessageRequester_Yes       ; Ja-Schalter wurde gedrückt
    UseHighLevelShaders = #True
  EndIf
  
  
  ; set the window caption
  IrrSetWindowCaption( "Example 29: Shaders" )
  
  ; add credits for the model as a static text GUI object on the display
  IrrGuiAddStaticText( "Render to Target (the Cube) - Move with mouse and keys.", 4,0,200,16, #IRR_GUI_NO_BORDER, #IRR_GUI_NO_WRAP )
  
  
  Define vsFileName.s = ""  ; // filename for the vertex shader
  Define psFileName.s = ""  ; // filename for the pixel shader
  
  
  Select irr3DRequesterSetting\device
    Case #IRR_EDT_DIRECT3D8:
  		psFileName = "media\d3d8.psh";
  		vsFileName = "media\d3d8.vsh";
  	Case #IRR_EDT_DIRECT3D9:
  		If UseHighLevelShaders = #True
  			psFileName = "media\d3d9.hlsl";
  			vsFileName = psFileName   ; // both shaders are in the same file
  		Else
  			psFileName = "media\d3d9.psh";
  			vsFileName = "media\d3d9.vsh";
      EndIf
  	Case #IRR_EDT_OPENGL:
  		If UseHighLevelShaders = #True
  			psFileName = "media\opengl.frag";
  			vsFileName = "media\opengl.vert";
  		Else
  			psFileName = "media\opengl.psh";
  			vsFileName = "media\opengl.vsh";
  		EndIf
  EndSelect
  
  
  ;	In addition, we check If the hardware And the selected renderer is capable 
  ;	of executing the shaders we want. If Not, we simply set the filename string
  ;	To 0. This is Not necessary, but useful in this example: For example, If 
  ;	the hardware is able To execute vertex shaders but Not pixel shaders, we create
  ;	a new material which only uses the vertex shader, And no pixel shader. 
  ;	Otherwise, If we would tell the engine To create this material And the engine
  ;	sees that the hardware wouldn't be able to fullfill the request completely,
  ;	it would Not create any new material at all. So in this example you would see
  ;	at least the vertex shader in action, without the pixel shader.
  
  
	  
  
  If IrrQueryFeature(#IRR_EVDF_PIXEL_SHADER_1_1)=#False And IrrQueryFeature(#IRR_EVDF_ARB_FRAGMENT_PROGRAM_1)=#False
    Debug("WARNING: Pixel shaders disabled because of missing driver/hardware support.")
    psFileName = ""
  EndIf
  	
  If IrrQueryFeature(#IRR_EVDF_VERTEX_SHADER_1_1)=#False And IrrQueryFeature(#IRR_EVDF_ARB_VERTEX_PROGRAM_1)=#False
    Debug("WARNING: Vertex shaders disabled because of missing driver/hardware support.")
    vsFileName = ""
  EndIf
  
  
  ;	Now lets create the new materials.
  ;	As you maybe know from previous examples, a material type in the Irrlicht engine
  ;	is set by simply changing the MaterialType value in the SMaterial struct. And this
  ;	value is just a simple 32 bit value, like video::EMT_SOLID. So we only need the 
  ;	engine to create a new value for us which we can set there. 
  ;	To do this, we get a pointer to the IGPUProgrammingServices and call 
  ;	addShaderMaterialFromFiles(), which returns such a new 32 bit value. That's all.
  ;	The parameters to this method are the following:
  ;	First, the names of the files containing the code of the vertex and the pixel shader.
  ;	If you would use addShaderMaterial() instead, you would not need file names, then you 
  ;	could write the code of the shader directly as string.
  ;	The following parameter is a pointer to the IShaderConstantSetCallBack class we wrote
  ;	at the beginning of this tutorial. If you don't want to set constants, set this to 0.
  ;	The last paramter tells the engine which material it should use as base material. 
  ;	To demonstrate this, we create two materials with a different base material, one
  ;	with EMT_SOLID and one with EMT_TRANSPARENT_ADD_COLOR.
  
  
  ; create materials
    
  ; create the shaders depending on If the user wanted high level
  ; or low level shaders:
  
  If UseHighLevelShaders 
    ; create material from high level shaders (hlsl Or glsl)
    newMaterialType1 = IrrAddHighLevelShaderMaterialFromFiles(vsFileName,	"vertexMain", #IRR_EVST_VS_1_1, psFileName, "pixelMain", #IRR_EPST_PS_1_1, @MyShaderCallBack(), #IRR_EMT_SOLID) 
    newMaterialType2 = IrrAddHighLevelShaderMaterialFromFiles(vsFileName, 	"vertexMain", #IRR_EVST_VS_1_1, psFileName, "pixelMain", #IRR_EPST_PS_1_1, @MyShaderCallBack(), #IRR_EMT_TRANSPARENT_ADD_COLOR) 
  Else  
    ; create material from low level shaders (asm Or arb_asm)
    newMaterialType1 = IrrAddShaderMaterialFromFiles(vsFileName,psFileName,@MyShaderCallBack(), #IRR_EMT_SOLID)
    newMaterialType2 = IrrAddShaderMaterialFromFiles(vsFileName,psFileName,@MyShaderCallBack(), #IRR_EMT_TRANSPARENT_ADD_COLOR)
  EndIf
; ; ;   
; ; ;   Debug("vsFileName=" + vsFileName)
; ; ;   Debug("psFileName=" + psFileName)
; ; ;   
; ; ;   Debug("*newMaterialType1=" + Str(newMaterialType1))
; ; ;   Debug("*newMaterialType2=" + Str(newMaterialType2))
; ; ;   
  ; Now time for testing out the materials. We create a test cube
  ; and set the material we created. In addition, we add a text scene node to
  ; the cube and a rotation animator to make it look more interesting and 
  ; important. 
  
    *font.l = IrrGetBuitInFont()
  
  ; create test scene node 1, With the new created material type 1
  
    *node.l = IrrAddCubeSceneNode(50)
    IrrSetNodePosition(*node,0,0,0)  
    *texture.l = IrrGetTexture("media\wall.bmp")
    IrrSetNodeMaterialTexture(*node,*texture,0)
    IrrSetNodeMaterialFlag(*node,#IRR_EMF_LIGHTING, #False);
    IrrSetNodeMaterialType(*node,newMaterialType1);
    *nodetext.l = IrrAddTextSceneNode(*font,"PS & VS & EMT_SOLID")
    IrrAddChildToParent(*nodetext,*node)
    IrrAddRotationAnimator(*node,0,0.3,0)
  
  	;Same For the second cube, but With the second material we created.
  
  	; create test scene node 2, With the new created material type 2
  
    *node.l = IrrAddCubeSceneNode(50)
    IrrSetNodePosition(*node,0,-10,50)  
    *texture.l = IrrGetTexture("media\wall.bmp")
    IrrSetNodeMaterialTexture(*node,*texture,0)
    IrrSetNodeMaterialFlag(*node,#IRR_EMF_LIGHTING, #False);
    IrrSetNodeMaterialType(*node,newMaterialType2);
    *nodetext.l = IrrAddTextSceneNode(*font,"PS & VS & EMT_TRANSPARENT")
    IrrAddChildToParent(*nodetext,*node)
    IrrAddRotationAnimator(*node,0,0.3,0)
  
  
  	;
  	; Then we add a third cube without a shader on it, To be able To compare the
  	; cubes.
  	; 
  
  	; add a scene node With no shader 
  
    *node.l = IrrAddCubeSceneNode(50)
    IrrSetNodePosition(*node,0,50,25)  
    *texture.l = IrrGetTexture("media\wall.bmp")
    IrrSetNodeMaterialTexture(*node,*texture,0)
    IrrSetNodeMaterialFlag(*node,#IRR_EMF_LIGHTING, #False);
    *nodetext.l = IrrAddTextSceneNode(*font,"NO SHADER")
    IrrAddChildToParent(*nodetext,*node)
  
  
  ; And last, we add a skybox And a user controlled camera To the scene.
  ; For the skybox textures, we disable mipmap generation, because we don't
  ; need mipmaps on it.
  
  ; add a nice skybox
  
    IrrSetTextureCreationFlag(#IRR_ETCF_CREATE_MIP_MAPS, #False);
    *IrrSkyBox = IrrAddSkyBoxToScene( IrrGetTexture("media\irrlicht2_up.jpg"),IrrGetTexture("media\irrlicht2_dn.jpg"),IrrGetTexture("media\irrlicht2_lf.jpg"),      IrrGetTexture("media\irrlicht2_rt.jpg"),        IrrGetTexture("media\irrlicht2_ft.jpg"),        IrrGetTexture("media\irrlicht2_bk.jpg"))
    IrrSetTextureCreationFlag(#IRR_ETCF_CREATE_MIP_MAPS, #True);
    
  	; add a camera And disable the mouse cursor
    *OurCamera = IrrAddFPSCamera()
    IrrSetNodePosition(*OurCamera, -100,50,100)
    IrrSetCameraTarget(*OurCamera, 0,0,0 )
  
  ;disable mouse cursor
  IrrHideMouse()
  
  ; -----------------------------------------------------------------------------
  ; while the irrlicht environment is still running
  While IrrRunning()
      ; begin the scene, erasing the canvas with sky-blue before rendering
      IrrBeginScene( 240, 255, 255 )
      
      IrrDrawScene()
      ; draw the GUI
      IrrDrawGUI()
  
      ; end drawing the scene and render it
      IrrEndScene()
  Wend
  
  ; -----------------------------------------------------------------------------
  ; Stop the irrlicht engine and release resources
  IrrStop()
EndIf


End

; jaPBe Version=3.7.10.668
; Build=0
; FirstLine=84
; CursorPosition=112
; ExecutableFormat=Console
; DontSaveDeclare
; EOF