浏览代码

Added scene tests.

Mark Sibly 7 年之前
父节点
当前提交
bcb08ced81

+ 131 - 0
modules/mojo3d/tests/ducks-scene.monkey2

@@ -0,0 +1,131 @@
+
+Namespace myapp
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+
+#Reflect mojo3d
+
+#Import "assets/duck.gltf/@/duck.gltf"
+
+Using std..
+Using mojo..
+Using mojo3d..
+
+Class MyWindow Extends Window
+	
+	Field _scene:Scene
+	
+	Field _camera:Camera
+	
+	Field _light:Light
+	
+	Field _ground:Model
+	
+	Field _ducks:=New Stack<Model>
+	
+	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
+
+		Super.New( title,width,height,flags )
+		
+		'create scene
+		'		
+		_scene=New Scene( True )
+		
+		'for softer shadows
+		'
+		_scene.ShadowAlpha=.6
+		
+		'create camera
+		'
+		_camera=New Camera( Self )
+		_camera.Move( 0,15,-20 )
+		New FlyBehaviour( _camera )
+		
+		'create light
+		'
+		_light=New Light
+		_light.CastsShadow=True
+		_light.Rotate( 75,15,0 )
+		
+		'create ground
+		'
+		_ground=Model.CreateBox( New Boxf( -50,-1,-50,50,0,50 ),1,1,1,New PbrMaterial( Color.Green,0,1 ) )
+		_ground.CastsShadow=False
+		
+		'create ducks
+		'		
+		Local duck:=Model.Load( "asset::duck.gltf/Duck.gltf" )
+		duck.Mesh.FitVertices( New Boxf( -1,1 ) )
+		
+		Local root:=duck.Copy()
+		root.Move( 0,10,0 )
+		root.Scale=New Vec3f( 3 )
+		
+		_ducks.Push( root )
+		
+		For Local m:=0.0 To 1.0 Step .125
+		
+			For Local i:=0.0 Until 360.0 Step 24
+			
+				Local copy:=duck.Copy( root )
+				
+				copy.RotateY( i )
+				
+				copy.Move( 0,0,6+m*16 )
+
+				copy.Scale=New Vec3f( 1 )
+				
+				Local materials:=copy.Materials.Slice( 0 )
+				
+				For Local j:=0 Until materials.Length
+				
+					Local material:=Cast<PbrMaterial>( materials[j].Copy() )
+					
+					material.MetalnessFactor=m
+					material.RoughnessFactor=i/360.0
+					
+					materials[j]=material
+				Next
+				
+				copy.Materials=materials
+				
+				_ducks.Push( copy )
+			Next
+		Next
+		
+		duck.Destroy()
+		
+		_ducks[0].AddComponent<RotateBehaviour>().Speed=New Vec3f( 0,.01,0 )
+		
+		Print "Saving.."
+		
+		_scene.Save( "ducks-scene.mojo3d","modules/mojo3d/tests/assets/" )	'note: assets path is a bit of a hack! Need access to compile time assets dir path.
+		
+		Print "Loading..."
+		
+		_scene=Scene.Load( "ducks-scene.mojo3d" )
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+
+		RequestRender()
+		
+		_scene.Update()
+		
+		_scene.Render( canvas )
+
+		canvas.DrawText( "FPS="+App.FPS,Width,0,1,0 )
+	End
+	
+End
+
+Function Main()
+	
+	New AppInstance
+	
+	New MyWindow
+	
+	App.Run()
+End

+ 110 - 0
modules/mojo3d/tests/sprites-scene.monkey2

@@ -0,0 +1,110 @@
+
+Namespace myapp
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+
+#Reflect mojo3d
+
+#Import "assets/"
+
+Using std..
+Using mojo..
+Using mojo3d..
+
+Function Main()
+	
+	New AppInstance
+	
+	New MyWindow
+	
+	App.Run()
+End
+
+Class MyWindow Extends Window
+	
+	Field _scene:Scene
+	
+	Field _camera:Camera
+	
+	Field _light:Light
+	
+	Field _ground:Model
+	
+	Field _sprites:=New Stack<Sprite>
+	
+	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
+
+		Super.New( title,width,height,flags )
+		
+		_scene=New Scene( True )
+		
+		_scene.SkyTexture=_scene.LoadTexture( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
+		_scene.FogColor=Color.Sky
+		_scene.FogNear=10
+		_scene.FogFar=30
+		
+		'create camera
+		'
+		_camera=New Camera( Self )
+		_camera.Near=.1
+		_camera.Far=100
+		_camera.Move( 0,10,-10 )
+		New FlyBehaviour( _camera )
+		
+		'create light
+		'
+		_light=New Light
+		_light.Rotate( 60,45,0 )
+		
+		'create ground
+		'
+		_ground=Model.CreateBox( New Boxf( -50,-1,-50,50,0,50 ),1,1,1,New PbrMaterial( Color.Green ) )
+		
+		'create sprites
+		'
+		Local material:=SpriteMaterial.Load( "asset::Acadia-Tree-Sprite.png" )
+		
+		material.AlphaDiscard=1.0/255.0
+		
+		For Local i:=0 Until 1000
+			
+			Local sprite:=New Sprite( material )
+			
+			sprite.Move( Rnd(-50,50),0,Rnd(-50,50) )
+
+			sprite.Scale=New Vec3f( Rnd(4,5),Rnd(5,6),1 )
+			
+			sprite.Handle=New Vec2f( .5,0 )
+			
+			sprite.Mode=SpriteMode.Upright
+
+			_sprites.Push( sprite )
+		Next
+		
+		For Local i:=0 Until 100
+			
+			Local box:=Model.CreateBox( New Boxf( -5,0,-5,5,Rnd(2,10),5 ),1,1,1,New PbrMaterial( New Color( Rnd(),Rnd(),Rnd() ) ) )
+			
+			box.Move( Rnd(-50,50),0,Rnd(-50,50) )
+		next	
+		
+		_scene.Save( "sprites-scene.mojo3d","modules/mojo3d/tests/assets/" )
+		
+		_scene=Scene.Load( "sprites-scene.mojo3d" )
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+	
+		RequestRender()
+		
+		_scene.Update()
+		
+		_scene.Render( canvas )
+		
+		canvas.DrawText( "Width="+Width+", Height="+Height+", FPS="+App.FPS,0,0 )
+	End
+	
+End
+

+ 455 - 0
modules/mojo3d/tests/test-scene.monkey2

@@ -0,0 +1,455 @@
+
+Namespace mojo3d
+
+#rem monkeydoc The Scene class.
+#end
+Class Scene
+
+	#rem monkeydoc Creates a new scene.
+	
+	If there is no current scene when a new scene is created, the new scene becomes the current scene.
+		
+	#end
+	Method New( editable:Bool=False )
+		
+		If Not _current _current=Self
+			
+		_editable=editable
+		
+		_clearColor=Color.Sky
+
+		_ambientDiffuse=Color.DarkGrey
+		
+		_envColor=Color.White
+		
+		_world=New World( Self )
+		
+		If _editable
+			Local type:=TypeInfo.GetType( "mojo3d.Scene" )
+			Assert( type And type.Kind="Class","mojo3d reflection must be enabled for editable scenes" )
+			_jsonifier=New Jsonifier
+			_jsonifier.AddInstance( Self,New Variant[]( true ) )
+			_editing=True
+		Endif
+		
+	End
+	
+	#rem monkeydoc The sky texture.
+	
+	The sky texture is used to clear the scene. 
+	
+	If there is no sky texture, the clear color is used instead.
+	
+	This must currently be a valid cubemap texture.
+	
+	#end
+	[jsonify=1]
+	Property SkyTexture:Texture()
+		
+		Return _skyTexture
+	
+	Setter( texture:Texture )
+		
+		_skyTexture=texture
+	End
+	
+	#rem monkeydoc The environment texture.
+	
+	The environment textures is used to render specular reflections within the scene.
+	
+	If there is no environment texture, the sky texture is used instead.
+		
+	If there is no environment texture and no sky texture, a default internal environment texture is used.
+	
+	This must currently be a valid cubemap texture.
+	
+	#end
+	[jsonify=1]
+	Property EnvTexture:Texture()
+		
+		Return _envTexture
+	
+	Setter( texture:Texture )
+		
+		_envTexture=texture
+	End
+	
+	#rem monkey The environment color.
+	
+	#end
+	[jsonify=1]
+	Property EnvColor:Color()
+		
+		Return _envColor
+	
+	Setter( color:Color )
+		
+		_envColor=color
+	End
+	
+	#rem monkeydoc The clear color.
+	
+	The clear color is used to clear the scene.
+	
+	The clear color is only used if there is no sky texture.
+	
+	#end
+	[jsonify=1]
+	Property ClearColor:Color()
+		
+		Return _clearColor
+		
+	Setter( color:Color )
+		
+		_clearColor=color
+	End
+	
+	[jsonify=1]
+	Property FogColor:Color()
+		
+		Return _fogColor
+	
+	Setter( color:Color )
+		
+		_fogColor=color
+	End
+	
+	[jsonify=1]
+	Property FogNear:Float()
+		
+		Return _fogNear
+	
+	Setter( near:Float )
+		
+		_fogNear=near
+	End
+	
+	[jsonify=1]
+	Property FogFar:Float()
+		
+		Return _fogFar
+	
+	Setter( far:Float )
+		
+		_fogFar=far
+	End
+	
+	[jsonify=1]
+	Property ShadowAlpha:Float()
+		
+		Return _shadowAlpha
+	
+	Setter( alpha:Float )
+		
+		_shadowAlpha=alpha
+	End
+	
+	#rem monkeydoc Update rate.
+	#end
+	[jsonify=1]
+	Property UpdateRate:Float()
+		
+		Return _updateRate
+	
+	Setter( updateRate:Float )
+		
+		_updateRate=updateRate
+	End
+	
+	[jsonify=1]
+	#rem monkeydoc Number of update steps.
+	#end
+	Property MaxSubSteps:Int()
+		
+		Return _maxSubSteps
+	
+	Setter( maxSubSteps:Int )
+		
+		_maxSubSteps=maxSubSteps
+	End
+	
+	#rem monkeydoc Ambient diffuse lighting.
+	#end
+	[jsonify=1]
+	Property AmbientLight:Color()
+		
+		Return _ambientDiffuse
+		
+	Setter( color:Color )
+		
+		_ambientDiffuse=color
+	End
+	
+	#rem monkeydoc Array containing the cascaded shadow map frustum splits for directional light shadows.
+	
+	Defaults to Float[]( 8.0,16.0,64.0,256.0 )
+	
+	Must have length 4.
+		
+	#end
+	[jsonify=1]
+	Property CSMSplits:Float[]()
+		
+		Return _csmSplits
+		
+	Setter( splits:Float[] )
+		Assert( splits.Length=4,"CSMSplits array must have 4 elements" )
+		
+		_csmSplits=splits.Slice( 0 )
+	End
+	
+	#rem monkeydoc Finds an entity in the scene.
+	
+	Finds an entity in the scene with the given name.
+	
+	#end
+	Method FindEntity:Entity( name:String )
+		
+		For Local entity:=Eachin _rootEntities
+			
+			Local found:=entity.Find( name )
+			If found Return found
+		Next
+		
+		Return Null
+	End
+	
+	#rem monkeydoc Adds a post effect to the scene.
+	#end
+	Method AddPostEffect( postEffect:PostEffect )
+		
+		_postEffects.Add( postEffect )
+	End
+	
+	#rem monkeydoc Removes a post effect from the scene
+	#end
+	Method RemovePostEffect( postEffect:PostEffect )
+		
+		_postEffects.Remove( postEffect )
+	End
+	
+	#rem monkeydocs Get all post effect that have been added to the scene
+	#end
+	Method GetPostEffects:PostEffect[]()
+		
+		Return _postEffects.ToArray()
+	End
+	
+	#rem monkeydoc Destroys all entities in the scene.
+	#end
+	Method DestroyAllEntities()
+		
+		While Not _rootEntities.Empty
+
+			_rootEntities.Top.Destroy()
+		Wend
+	End
+	
+	#rem monkeydoc Updates the scene.
+	#end
+	Method Update()
+		
+		Global time:=0.0
+		
+		Local elapsed:=0.0
+		
+		If time
+			elapsed=Now()-time
+			time+=elapsed
+		Else
+			time=Now()
+		Endif
+		
+		Update( elapsed )
+	End
+	
+	#rem monkeydoc Renders the scene to	a canvas.
+	#end
+	Method Render( canvas:Canvas )
+		
+		For Local camera:=Eachin _cameras
+			
+			camera.Render( canvas )
+		Next
+	End
+	
+	Method RayCast:RayCastResult( rayFrom:Vec3f,rayTo:Vec3f,collisionMask:Int )
+		
+		Return _world.RayCast( rayFrom,rayTo,collisionMask )
+	End
+
+	#rem monkeydoc Enumerates all entities in the scene with null parents.
+	#end
+	Method GetRootEntities:Entity[]()
+		
+		Return _rootEntities.ToArray()
+	End
+	
+	'***** serialization stuff *****
+	
+	Property Editable:Bool()
+		
+		Return _editable
+	End
+	
+	Property Editing:Bool()
+		
+		Return _editing
+	
+	Setter( editing:Bool )
+		
+		If editing And Not _editable RuntimeError( "Scene is not editable" )
+		
+		_editing=editing
+	End
+	
+	Property Jsonifier:Jsonifier()
+		
+		Return _jsonifier
+	End
+	
+	Method LoadTexture:Texture( path:String,flags:TextureFlags,flipNormalY:Bool=False )
+		
+		Local texture:=Texture.Load( path,flags,flipNormalY )
+		If Not texture Return Null
+		
+		If Editing Jsonifier.AddInstance( texture,"mojo3d.Scene.LoadTexture",Self,New Variant[]( path,flags,flipNormalY ) )
+			
+		Return texture
+	End
+
+	#rem monkeydoc Saves the scene to a mojo3d scene file
+	#end
+	Method Save( path:String )
+		
+		Assert( _jsonifier,"Scene is not editable" )
+		
+		Local jobj:=_jsonifier.JsonifyInstances()
+		
+		Local json:=jobj.ToJson()
+		
+		SaveString( json,path )
+	End
+
+	#rem monkeydoc Loads a mojo3d scene file and makes it current
+	#end
+	Function Load:Scene( path:String )
+		
+		Local json:=LoadString( path )
+		If Not json Return Null
+		
+		Local jobj:=JsonObject.Parse( json )
+		If Not jobj Return Null
+		
+		Local scene:=New Scene( True )
+		
+		SetCurrent( scene )
+		
+		scene.Jsonifier.DejsonifyInstances( jobj )
+		
+		Return scene
+	End
+	
+	#rem monkeydoc Sets the current scene.
+	
+	All newly created entities (including entites created using Entity.Copy]]) are automatically added to the current scene.
+	
+	#end
+	Function SetCurrent( scene:Scene )
+		
+		_current=scene
+	End
+	
+	#rem monkeydoc Gets the current scene.
+	
+	If there is no current scene, a new scene is automatically created and made current.
+		
+	#end
+	Function GetCurrent:Scene()
+
+		If Not _current New Scene
+			
+		Return _current
+	End
+	
+	Internal
+
+	Property PostEffects:Stack<PostEffect>()
+		
+		Return _postEffects
+	End
+	
+	Property RootEntities:Stack<Entity>()
+		
+		Return _rootEntities
+	End
+	
+	Property Cameras:Stack<Camera>()
+		
+		Return _cameras
+	End
+	
+	Property Lights:Stack<Light>()
+		
+		Return _lights
+	End
+	
+	Property Renderables:Stack<Renderable>()
+	
+		Return _renderables
+	End
+	
+	Property World:World()
+		
+		Return _world
+	End
+	
+	Private
+	
+	Global _current:Scene
+	Global _defaultEnv:Texture
+	
+	Field _skyTexture:Texture
+	Field _envTexture:Texture
+	Field _envColor:Color
+	
+	Field _clearColor:Color
+	Field _ambientDiffuse:Color
+	
+	Field _fogColor:Color
+	Field _fogNear:Float
+	Field _fogFar:Float
+	
+	Field _shadowAlpha:Float=1
+
+	Field _updateRate:Float=60
+	Field _maxSubSteps:Int=1
+	
+	Field _csmSplits:=New Float[]( 8.0,16.0,64.0,256.0 )
+	
+	Field _rootEntities:=New Stack<Entity>
+	Field _cameras:=New Stack<Camera>
+	Field _lights:=New Stack<Light>
+	Field _renderables:=New Stack<Renderable>()
+	Field _postEffects:=New Stack<PostEffect>
+	
+	Field _world:World
+	
+	Field _jsonifier:Jsonifier
+	Field _editable:Bool
+	Field _editing:Bool
+	
+	Method Update( elapsed:Float )
+		
+		For Local e:=Eachin _rootEntities
+			e.BeginUpdate()
+		Next
+		
+		_world.Update( elapsed )
+		
+		For Local e:=Eachin _rootEntities
+			e.Update( elapsed )
+		Next
+	End
+			
+End

+ 89 - 0
modules/mojo3d/tests/test.monkey2

@@ -0,0 +1,89 @@
+Namespace myapp3d
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+
+#Reflect mojo3d
+
+#Import "assets/mossy-ground1.pbr/@/mossy-ground1.pbr"
+
+Using std..
+Using mojo..
+Using mojo3d..
+
+Class MyWindow Extends Window
+	
+	Field _scene:Scene
+	Field _camera:Camera
+	Field _light:Light
+	Field _ground:Model
+	Field _donut:Model
+	
+	
+	Method New( title:String="Simple mojo3d app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
+		
+		Super.New( title,width,height,flags )
+	End
+	
+	Method OnCreateWindow() Override
+		
+		'Xreate editable scene and makes it current
+		_scene=New Scene( True )
+		
+		_scene.ClearColor = New Color( 0.2, 0.6, 1.0 )
+		_scene.AmbientLight = _scene.ClearColor * 0.25
+		_scene.FogColor = _scene.ClearColor
+		_scene.FogFar = 1.0
+		_scene.FogFar = 200.0
+		
+		'create camera
+		_camera=New Camera( Self )
+		_camera.AddComponent<FlyBehaviour>()
+		_camera.Move( 0,2.5,-5 )
+		
+		'create light
+		_light=New Light
+		_light.CastsShadow=True
+		_light.Rotate( 45, 45, 0 )
+		
+		'create ground
+		Local groundBox:=New Boxf( -100,-1,-100,100,0,100 )
+		Local groundMaterial:=New PbrMaterial( Color.Lime )
+		_ground=Model.CreateBox( groundBox,1,1,1,groundMaterial )
+		_ground.CastsShadow=False
+		
+		'create donut
+		Local donutMaterial:=PbrMaterial.Load( "asset::mossy-ground1.pbr" )
+		_donut=Model.CreateTorus( 2,.5,48,24,donutMaterial )
+		_donut.Move( 0,2.5,0 )
+		
+		Print "Saving..."
+		
+		_scene.Save( "test.mojo3d" )
+		
+		Print "Loading..."
+		
+		Scene.Load( "test.mojo3d" )
+		
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+		
+		RequestRender()
+		_donut.Rotate( .2,.4,.6 )
+		_scene.Update()
+		_camera.Render( canvas )
+		canvas.DrawText( "FPS="+App.FPS,0,0 )
+	End
+	
+End
+
+Function Main()
+
+	New AppInstance
+	
+	New MyWindow
+	
+	App.Run()
+End