Browse Source

Rearranged mojo3d project structure and began work on scene jsonification.

Mark Sibly 7 years ago
parent
commit
8684f13ba8
41 changed files with 1753 additions and 116 deletions
  1. 44 34
      modules/mojo3d/mojo3d.monkey2
  2. 0 0
      modules/mojo3d/scene/bttypeconvs.monkey2
  3. 9 0
      modules/mojo3d/scene/component.monkey2
  4. 0 0
      modules/mojo3d/scene/components/animation.monkey2
  5. 0 0
      modules/mojo3d/scene/components/animator.monkey2
  6. 0 0
      modules/mojo3d/scene/components/behaviour.monkey2
  7. 0 0
      modules/mojo3d/scene/components/collider.monkey2
  8. 6 0
      modules/mojo3d/scene/components/flybehaviour.monkey2
  9. 45 0
      modules/mojo3d/scene/components/movebehaviour.monkey2
  10. 0 0
      modules/mojo3d/scene/components/native/internaledges.cpp
  11. 0 0
      modules/mojo3d/scene/components/native/internaledges.h
  12. 0 0
      modules/mojo3d/scene/components/rigidbody.monkey2
  13. 45 0
      modules/mojo3d/scene/components/rotatebehaviour.monkey2
  14. 0 0
      modules/mojo3d/scene/effects/bloomeffect.monkey2
  15. 0 0
      modules/mojo3d/scene/effects/fogeffect.monkey2
  16. 0 0
      modules/mojo3d/scene/effects/monochromeeffect.monkey2
  17. 29 4
      modules/mojo3d/scene/entities/camera.monkey2
  18. 26 30
      modules/mojo3d/scene/entities/light.monkey2
  19. 45 20
      modules/mojo3d/scene/entities/model.monkey2
  20. 0 0
      modules/mojo3d/scene/entities/particlebuffer.monkey2
  21. 0 0
      modules/mojo3d/scene/entities/particlematerial.monkey2
  22. 0 0
      modules/mojo3d/scene/entities/particlesystem.monkey2
  23. 2 2
      modules/mojo3d/scene/entities/renderable.monkey2
  24. 10 0
      modules/mojo3d/scene/entities/sprite.monkey2
  25. 44 3
      modules/mojo3d/scene/entity.monkey2
  26. 112 0
      modules/mojo3d/scene/jsonifier/comparejson.monkey2
  27. 109 0
      modules/mojo3d/scene/jsonifier/invocation.monkey2
  28. 312 0
      modules/mojo3d/scene/jsonifier/jsonifier.monkey2
  29. 164 0
      modules/mojo3d/scene/jsonifier/jsonifierexts.monkey2
  30. 425 0
      modules/mojo3d/scene/jsonifier/test.monkey2
  31. 16 2
      modules/mojo3d/scene/material.monkey2
  32. 15 1
      modules/mojo3d/scene/materials/pbrmaterial.monkey2
  33. 0 0
      modules/mojo3d/scene/materials/spritematerial.monkey2
  34. 0 0
      modules/mojo3d/scene/materials/watermaterial.monkey2
  35. 17 0
      modules/mojo3d/scene/mesh.monkey2
  36. 59 19
      modules/mojo3d/scene/meshprims.monkey2
  37. 0 0
      modules/mojo3d/scene/posteffect.monkey2
  38. 111 0
      modules/mojo3d/scene/scene.monkey2
  39. 0 0
      modules/mojo3d/scene/util3d.monkey2
  40. 8 1
      modules/mojo3d/tests/cubes.monkey2
  41. 100 0
      modules/mojo3d/tests/loadscene.monkey2

+ 44 - 34
modules/mojo3d/mojo3d.monkey2

@@ -5,43 +5,17 @@ Namespace mojo3d
 #Import "<mojo>"
 #Import "<mojo>"
 #Import "<opengl>"
 #Import "<opengl>"
 #import "<bullet>"
 #import "<bullet>"
+#Import "<reflection>"
 
 
 Using std..
 Using std..
 Using mojo..
 Using mojo..
+Using mojo3d..
 Using opengl..
 Using opengl..
 Using bullet..
 Using bullet..
+Using reflection..
 
 
 #Import "assets/"
 #Import "assets/"
 
 
-#Import "components/animation"
-#Import "components/animator"
-#Import "components/rigidbody"
-#Import "components/collider"
-#Import "components/behaviour"
-#Import "components/flybehaviour"
-
-#Import "entities/camera"
-#Import "entities/light"
-#Import "entities/model"
-#Import "entities/particlebuffer"
-#Import "entities/particlematerial"
-#Import "entities/particlesystem"
-#Import "entities/renderable"
-#Import "entities/sprite"
-
-#Import "render/material"
-#Import "render/renderer"
-#Import "render/renderqueue"
-#Import "render/spritebuffer"
-#Import "render/posteffect"
-
-#Import "render/materials/pbrmaterial"
-#Import "render/materials/spritematerial"
-#Import "render/materials/watermaterial"
-
-#Import "render/effects/bloomeffect"
-#Import "render/effects/monochromeeffect"
-
 #Import "scene/raycastresult"
 #Import "scene/raycastresult"
 #Import "scene/component"
 #Import "scene/component"
 #Import "scene/dynamicobject"
 #Import "scene/dynamicobject"
@@ -49,16 +23,52 @@ Using bullet..
 #Import "scene/entityexts"
 #Import "scene/entityexts"
 #Import "scene/scene"
 #Import "scene/scene"
 #Import "scene/world"
 #Import "scene/world"
+#Import "scene/material"
+#Import "scene/posteffect"
+
+#Import "scene/components/animation"
+#Import "scene/components/animator"
+#Import "scene/components/rigidbody"
+#Import "scene/components/collider"
+#Import "scene/components/behaviour"
+#Import "scene/components/flybehaviour"
+#Import "scene/components/movebehaviour"
+#Import "scene/components/rotatebehaviour"
+
+#Import "scene/entities/camera"
+#Import "scene/entities/light"
+#Import "scene/entities/model"
+#Import "scene/entities/particlebuffer"
+#Import "scene/entities/particlematerial"
+#Import "scene/entities/particlesystem"
+#Import "scene/entities/renderable"
+#Import "scene/entities/sprite"
+
+#Import "scene/materials/pbrmaterial"
+#Import "scene/materials/spritematerial"
+#Import "scene/materials/watermaterial"
+
+#Import "scene/effects/bloomeffect"
+#Import "scene/effects/monochromeeffect"
+
+#Import "scene/jsonifier/jsonifier"
+#Import "scene/jsonifier/invocation"
+#Import "scene/jsonifier/jsonifierexts"
+#Import "scene/jsonifier/comparejson"
+
+#Import "scene/mesh"
+#Import "scene/meshprims"
+#Import "scene/bttypeconvs"
+'#Import "scene/util3d"
+
+#Import "render/renderer"
+#Import "render/renderqueue"
+#Import "render/spritebuffer"
 
 
 #Import "loader/loader"
 #Import "loader/loader"
 #Import "loader/gltf2"
 #Import "loader/gltf2"
 #Import "loader/gltf2loader"
 #Import "loader/gltf2loader"
 
 
-#Import "geometry/mesh"
-#Import "geometry/meshprims"
-'#Import "geometry/util3d"
-#Import "geometry/bttypeconvs"
-
 Function Main()
 Function Main()
 	
 	
 #If __DESKTOP_TARGET__
 #If __DESKTOP_TARGET__

+ 0 - 0
modules/mojo3d/geometry/bttypeconvs.monkey2 → modules/mojo3d/scene/bttypeconvs.monkey2


+ 9 - 0
modules/mojo3d/scene/component.monkey2

@@ -73,6 +73,15 @@ Class Component
 		_type=Null
 		_type=Null
 	End
 	End
 	
 	
+Protected
+
+	Method AddInstance()
+		
+		Local scene:=_entity.Scene
+		
+		If scene.Editing scene.Jsonifier.AddInstance( Self,New Variant[]( _entity ) )
+	End
+	
 Internal
 Internal
 
 
 	Method OnCopy:Component( entity:Entity ) Virtual
 	Method OnCopy:Component( entity:Entity ) Virtual

+ 0 - 0
modules/mojo3d/components/animation.monkey2 → modules/mojo3d/scene/components/animation.monkey2


+ 0 - 0
modules/mojo3d/components/animator.monkey2 → modules/mojo3d/scene/components/animator.monkey2


+ 0 - 0
modules/mojo3d/components/behaviour.monkey2 → modules/mojo3d/scene/components/behaviour.monkey2


+ 0 - 0
modules/mojo3d/components/collider.monkey2 → modules/mojo3d/scene/components/collider.monkey2


+ 6 - 0
modules/mojo3d/components/flybehaviour.monkey2 → modules/mojo3d/scene/components/flybehaviour.monkey2

@@ -6,8 +6,11 @@ Class FlyBehaviour Extends Behaviour
 	Method New( entity:Entity )
 	Method New( entity:Entity )
 		
 		
 		Super.New( entity )
 		Super.New( entity )
+		
+		AddInstance()
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property Speed:Float()
 	Property Speed:Float()
 		
 		
 		Return _speed
 		Return _speed
@@ -17,6 +20,7 @@ Class FlyBehaviour Extends Behaviour
 		_speed=speed
 		_speed=speed
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property RotSpeed:Float()
 	Property RotSpeed:Float()
 		
 		
 		Return _rspeed
 		Return _rspeed
@@ -52,6 +56,7 @@ Class FlyBehaviour Extends Behaviour
 			entity.MoveZ( -_speed * 60 * elapsed )
 			entity.MoveZ( -_speed * 60 * elapsed )
 		Endif
 		Endif
 		
 		
+#If __MOBILE_TARGET__
 		If Mouse.ButtonDown( MouseButton.Left )
 		If Mouse.ButtonDown( MouseButton.Left )
 			If Mouse.X<view.Width/3
 			If Mouse.X<view.Width/3
 				entity.RotateY( rspeed,True )
 				entity.RotateY( rspeed,True )
@@ -61,6 +66,7 @@ Class FlyBehaviour Extends Behaviour
 				entity.Move( New Vec3f( 0,0,_speed * 60 * elapsed ) )
 				entity.Move( New Vec3f( 0,0,_speed * 60 * elapsed ) )
 			Endif
 			Endif
 		Endif
 		Endif
+#endif
 		
 		
 	End
 	End
 	
 	

+ 45 - 0
modules/mojo3d/scene/components/movebehaviour.monkey2

@@ -0,0 +1,45 @@
+Namespace mojo3d
+
+Class MoveBehaviour Extends Behaviour
+	
+	Method New( entity:Entity )
+		
+		Super.New( entity )
+		
+		AddInstance()
+	End
+	
+	[jsonify=1]
+	Property Speed:Vec3f()
+		
+		Return _speed
+	
+	Setter( speed:Vec3f )
+		
+		_speed=speed
+	End
+	
+	[jsonify=1]
+	Property LocalSpace:Bool()
+		
+		Return _localSpace
+	
+	Setter( localSpace:Bool )
+		
+		_localSpace=localSpace
+	End
+	
+	Protected
+	
+	Method OnUpdate( elapsed:Float ) Override
+		
+		Entity.Move( _speed,_localSpace )
+	End
+	
+	Private
+	
+	Field _speed:Vec3f
+	
+	Field _localSpace:Bool
+	
+End

+ 0 - 0
modules/mojo3d/components/native/internaledges.cpp → modules/mojo3d/scene/components/native/internaledges.cpp


+ 0 - 0
modules/mojo3d/components/native/internaledges.h → modules/mojo3d/scene/components/native/internaledges.h


+ 0 - 0
modules/mojo3d/components/rigidbody.monkey2 → modules/mojo3d/scene/components/rigidbody.monkey2


+ 45 - 0
modules/mojo3d/scene/components/rotatebehaviour.monkey2

@@ -0,0 +1,45 @@
+Namespace mojo3d
+
+Class RotateBehaviour Extends Behaviour
+	
+	Method New( entity:Entity )
+		
+		Super.New( entity )
+		
+		AddInstance()
+	End
+	
+	[jsonify=1]
+	Property Speed:Vec3f()
+		
+		Return _speed
+	
+	Setter( speed:Vec3f )
+		
+		_speed=speed
+	End
+	
+	[jsonify=1]
+	Property LocalSpace:Bool()
+		
+		Return _localSpace
+	
+	Setter( localSpace:Bool )
+		
+		_localSpace=localSpace
+	End
+	
+	Protected
+	
+	Method OnUpdate( elapsed:Float ) Override
+		
+		Entity.Rotate( _speed,_localSpace )
+	End
+	
+	Private
+	
+	Field _speed:Vec3f
+	
+	Field _localSpace:Bool
+	
+End

+ 0 - 0
modules/mojo3d/render/effects/bloomeffect.monkey2 → modules/mojo3d/scene/effects/bloomeffect.monkey2


+ 0 - 0
modules/mojo3d/render/effects/fogeffect.monkey2 → modules/mojo3d/scene/effects/fogeffect.monkey2


+ 0 - 0
modules/mojo3d/render/effects/monochromeeffect.monkey2 → modules/mojo3d/scene/effects/monochromeeffect.monkey2


+ 29 - 4
modules/mojo3d/entities/camera.monkey2 → modules/mojo3d/scene/entities/camera.monkey2

@@ -8,24 +8,32 @@ Class Camera Extends Entity
 	#rem monkeydoc Creates a new camera.
 	#rem monkeydoc Creates a new camera.
 	#end	
 	#end	
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
+		
 		Super.New( parent )
 		Super.New( parent )
 		
 		
+		Name="Camera"
 		Viewport=New Recti( 0,0,640,480 )
 		Viewport=New Recti( 0,0,640,480 )
 		Near=.1
 		Near=.1
 		Far=100
 		Far=100
 		FOV=90
 		FOV=90
 		
 		
+		AddInstance()
+		
 		Visible=True
 		Visible=True
 	End
 	End
-	
+
 	Method New( view:View,parent:Entity=Null )
 	Method New( view:View,parent:Entity=Null )
-		Super.New( parent )
 		
 		
+		Super.New( parent )
+
+		Name="Camera"		
 		View=view
 		View=view
 		Near=.1
 		Near=.1
 		Far=100
 		Far=100
 		FOV=90
 		FOV=90
 		
 		
+		AddInstance()
+		
 		Visible=True
 		Visible=True
 	End
 	End
 	
 	
@@ -33,7 +41,7 @@ Class Camera Extends Entity
 	#end
 	#end
 	Method Copy:Camera( parent:Entity=Null ) Override
 	Method Copy:Camera( parent:Entity=Null ) Override
 		
 		
-		Local copy:=New Camera( Self,parent )
+		Local copy:=OnCopy( parent )
 		
 		
 		CopyTo( copy )
 		CopyTo( copy )
 		
 		
@@ -87,6 +95,7 @@ Class Camera Extends Entity
 	Defaults to 90.0.
 	Defaults to 90.0.
 	
 	
 	#end
 	#end
+	[jsonify=1]
 	Property FOV:Float()
 	Property FOV:Float()
 	
 	
 		Return _fov
 		Return _fov
@@ -105,6 +114,7 @@ Class Camera Extends Entity
 	The ratio of Far/Near clip planes should be kept as low as possible to reduce numerical precision errors.
 	The ratio of Far/Near clip planes should be kept as low as possible to reduce numerical precision errors.
 	
 	
 	#end
 	#end
+	[jsonify=1]
 	Property Near:Float()
 	Property Near:Float()
 	
 	
 		Return _near
 		Return _near
@@ -123,6 +133,7 @@ Class Camera Extends Entity
 	The ratio of Far/Near clip planes should be kept as low as possible to reduce numerical precision errors.
 	The ratio of Far/Near clip planes should be kept as low as possible to reduce numerical precision errors.
 	
 	
 	#end
 	#end
+	[jsonify=1]
 	Property Far:Float()
 	Property Far:Float()
 	
 	
 		Return _far
 		Return _far
@@ -158,7 +169,11 @@ Class Camera Extends Entity
 	#end
 	#end
 	Method Render( canvas:Canvas )
 	Method Render( canvas:Canvas )
 		
 		
-		If _view SetViewport( _view.Rect )
+		If _view
+			SetViewport( _view.Rect )
+		Else
+			SetViewport( New Recti( 0,0,canvas.RenderBounds.Size ) )
+		Endif
 		
 		
 		Local target:=canvas.GraphicsDevice.RenderTarget
 		Local target:=canvas.GraphicsDevice.RenderTarget
 		
 		
@@ -167,6 +182,8 @@ Class Camera Extends Entity
 '		Local viewport:=canvas.RenderMatrix * Viewport
 '		Local viewport:=canvas.RenderMatrix * Viewport
 		Local viewport:=canvas.RenderBounds
 		Local viewport:=canvas.RenderBounds
 		
 		
+'		Print "camera viewport="+viewport
+		
 		canvas.Flush()
 		canvas.Flush()
 		
 		
 		Local renderer:=Renderer.GetCurrent()
 		Local renderer:=Renderer.GetCurrent()
@@ -238,12 +255,20 @@ Class Camera Extends Entity
 	Protected
 	Protected
 
 
 	Method New( camera:Camera,parent:Entity )
 	Method New( camera:Camera,parent:Entity )
+		
 		Super.New( camera,parent )
 		Super.New( camera,parent )
 		
 		
 		Viewport=camera.Viewport
 		Viewport=camera.Viewport
 		Near=camera.Near
 		Near=camera.Near
 		Far=camera.Far
 		Far=camera.Far
 		FOV=camera.FOV
 		FOV=camera.FOV
+		
+		AddInstance( camera )
+	End
+	
+	Method OnCopy:Camera( parent:Entity ) Override
+		
+		Return New Camera( Self,parent )
 	End
 	End
 	
 	
 	Method OnShow() Override
 	Method OnShow() Override

+ 26 - 30
modules/mojo3d/entities/light.monkey2 → modules/mojo3d/scene/entities/light.monkey2

@@ -24,12 +24,15 @@ Class Light Extends Entity
 	#rem monkeydoc Creates a new light.
 	#rem monkeydoc Creates a new light.
 	#end
 	#end
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
+		
 		Super.New( parent )
 		Super.New( parent )
 		
 		
+		Name="Light"
 		Type=LightType.Directional
 		Type=LightType.Directional
-		Color=Color.White
-		Range=10
 		CastsShadow=False
 		CastsShadow=False
+		Range=10
+		
+		AddInstance()
 		
 		
 		Visible=True
 		Visible=True
 	End
 	End
@@ -38,24 +41,13 @@ Class Light Extends Entity
 	#end
 	#end
 	Method Copy:Light( parent:Entity=Null ) Override
 	Method Copy:Light( parent:Entity=Null ) Override
 		
 		
-		Local copy:=New Light( Self,parent )
+		Local copy:=OnCopy( parent )
 		
 		
 		CopyTo( copy )
 		CopyTo( copy )
 		
 		
 		Return copy
 		Return copy
 	End
 	End
 	
 	
-	#rem monkeydoc Light shadows enabled flag.
-	#end
-	Property CastsShadow:Bool()
-		
-		Return _castsShadow
-		
-	Setter( shadows:Bool )
-		
-		_castsShadow=shadows
-	End
-	
 	#rem monkeydoc The light type.
 	#rem monkeydoc The light type.
 	#end
 	#end
 	Property Type:LightType()
 	Property Type:LightType()
@@ -67,21 +59,21 @@ Class Light Extends Entity
 		_type=type
 		_type=type
 	End
 	End
 	
 	
-	#rem
-	#rem monkeydoc The light color.
+	#rem monkeydoc Light shadows enabled flag.
 	#end
 	#end
-	Property Color:Color()
-	
-		Return _color
-	
-	Setter( color:Color )
-	
-		_color=color
+	[jsonify=1]
+	Property CastsShadow:Bool()
+		
+		Return _castsShadow
+		
+	Setter( shadows:Bool )
+		
+		_castsShadow=shadows
 	End
 	End
-	#end
 	
 	
 	#rem monkeydoc The light range.
 	#rem monkeydoc The light range.
 	#end
 	#end
+	[jsonify=1]
 	Property Range:Float()
 	Property Range:Float()
 	
 	
 		Return _range
 		Return _range
@@ -93,25 +85,29 @@ Class Light Extends Entity
 	
 	
 	Protected
 	Protected
 
 
-	#rem monkeydoc @hidden
-	#end	
 	Method New( light:Light,parent:Entity )
 	Method New( light:Light,parent:Entity )
+		
 		Super.New( light,parent )
 		Super.New( light,parent )
 		
 		
 		Type=light.Type
 		Type=light.Type
 		Color=light.Color
 		Color=light.Color
 		Range=light.Range
 		Range=light.Range
+		
+		AddInstance( light )
+	End
+	
+	Method OnCopy:Light( parent:Entity ) Override
+		
+		Return New Light( Self,parent )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end	
 	Method OnShow() Override
 	Method OnShow() Override
+		
 		Scene.Lights.Add( Self )
 		Scene.Lights.Add( Self )
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end	
 	Method OnHide() Override
 	Method OnHide() Override
+		
 		Scene.Lights.Remove( Self )
 		Scene.Lights.Remove( Self )
 	End
 	End
 
 

+ 45 - 20
modules/mojo3d/entities/model.monkey2 → modules/mojo3d/scene/entities/model.monkey2

@@ -15,16 +15,27 @@ Class Model Extends Renderable
 	#rem monkeydoc Creates a new model.
 	#rem monkeydoc Creates a new model.
 	#end
 	#end
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
+		
 		Super.New( parent )
 		Super.New( parent )
 		
 		
+		Name="Model"
+		
+		AddInstance()
+		
 		Visible=True
 		Visible=True
 	End
 	End
 	
 	
 	Method New( mesh:Mesh,material:Material,parent:Entity=Null )
 	Method New( mesh:Mesh,material:Material,parent:Entity=Null )
-		super.New( parent )
 		
 		
-		_mesh=mesh
-		_materials=New Material[]( material )
+		Super.New( parent )
+		
+		Name="Model"
+		
+		AddInstance( New Variant[]( mesh,material,parent ) )
+		
+		Mesh=mesh
+		Materials=New Material[]( material )
+		Material=material
 		
 		
 		Visible=True
 		Visible=True
 	End
 	End
@@ -33,7 +44,7 @@ Class Model Extends Renderable
 	#end	
 	#end	
 	Method Copy:Model( parent:Entity=Null ) Override
 	Method Copy:Model( parent:Entity=Null ) Override
 		
 		
-		Local copy:=New Model( Self,parent )
+		Local copy:=OnCopy( parent )
 		
 		
 		CopyTo( copy )
 		CopyTo( copy )
 		
 		
@@ -48,7 +59,8 @@ Class Model Extends Renderable
 	End
 	End
 
 
 	#rem monkeydoc The mesh rendered by the model.
 	#rem monkeydoc The mesh rendered by the model.
-	#end	
+	#end
+	[jsonify=1]
 	Property Mesh:Mesh()
 	Property Mesh:Mesh()
 		
 		
 		Return _mesh
 		Return _mesh
@@ -58,8 +70,20 @@ Class Model Extends Renderable
 		_mesh=mesh
 		_mesh=mesh
 	End
 	End
 	
 	
+	#rem monkeydoc The materials to use for rendering.
+	#end
+	Property Materials:Material[]()
+		
+		Return _materials
+		
+	Setter( materials:Material[] )
+		
+		_materials=materials
+	End
+	
 	#rem monkeydoc The default material to use for rendering.
 	#rem monkeydoc The default material to use for rendering.
 	#end
 	#end
+	[jsonify=1]
 	Property Material:Material()
 	Property Material:Material()
 		
 		
 		Return _material
 		Return _material
@@ -69,17 +93,6 @@ Class Model Extends Renderable
 		_material=material
 		_material=material
 	End
 	End
 
 
-	#rem monkeydoc The materials to use for rendering.
-	#end	
-	Property Materials:Material[]()
-		
-		Return _materials
-		
-	Setter( materials:Material[] )
-		
-		_materials=materials
-	End
-	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
 	Property Bones:Bone[]()
 	Property Bones:Bone[]()
@@ -113,7 +126,11 @@ Class Model Extends Renderable
 		
 		
 			Local model:=loader.LoadModel( path )
 			Local model:=loader.LoadModel( path )
 			
 			
-			If model Return model
+			If Not model Continue
+			
+			If model.Scene.Editing model.Scene.Jsonifier.AddInstance( model,"mojo3d.Model.Load",New Variant[]( path )  )
+				
+			Return model
 		Next
 		Next
 		
 		
 		Return Null
 		Return Null
@@ -150,13 +167,21 @@ Class Model Extends Renderable
 	Protected
 	Protected
 
 
 	Method New( model:Model,parent:Entity )
 	Method New( model:Model,parent:Entity )
+		
 		Super.New( model,parent )
 		Super.New( model,parent )
 		
 		
-		_mesh=model._mesh
+		Mesh=model.Mesh
 		
 		
-		_material=model._material
+		Materials=model.Materials
+		
+		Material=model.Material
+		
+		AddInstance( model )
+	End
+	
+	Method OnCopy:Model( parent:Entity ) Override
 		
 		
-		_materials=model._materials.Slice( 0 )
+		Return New Model( Self,parent )
 	End
 	End
 	
 	
 	Internal
 	Internal

+ 0 - 0
modules/mojo3d/entities/particlebuffer.monkey2 → modules/mojo3d/scene/entities/particlebuffer.monkey2


+ 0 - 0
modules/mojo3d/entities/particlematerial.monkey2 → modules/mojo3d/scene/entities/particlematerial.monkey2


+ 0 - 0
modules/mojo3d/entities/particlesystem.monkey2 → modules/mojo3d/scene/entities/particlesystem.monkey2


+ 2 - 2
modules/mojo3d/entities/renderable.monkey2 → modules/mojo3d/scene/entities/renderable.monkey2

@@ -4,8 +4,8 @@ Namespace mojo3d
 Class Renderable Extends Entity Abstract
 Class Renderable Extends Entity Abstract
 
 
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
+		
 		Super.New( parent )
 		Super.New( parent )
-
 	End
 	End
 	
 	
 	Property CastsShadow:bool()
 	Property CastsShadow:bool()
@@ -23,7 +23,7 @@ Class Renderable Extends Entity Abstract
 	
 	
 		Super.New( renderable,parent )
 		Super.New( renderable,parent )
 		
 		
-		_castsShadow=renderable.CastsShadow
+		CastsShadow=renderable.CastsShadow
 	End
 	End
 	
 	
 	Method OnShow() Override
 	Method OnShow() Override

+ 10 - 0
modules/mojo3d/entities/sprite.monkey2 → modules/mojo3d/scene/entities/sprite.monkey2

@@ -21,7 +21,12 @@ Class Sprite Extends Renderable
 	#rem monkeydoc Creates a new sprite.
 	#rem monkeydoc Creates a new sprite.
 	#end
 	#end
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
+		
 		Super.New( parent )
 		Super.New( parent )
+		
+		Name="Sprite"
+		
+		AddInstance()
 	End
 	End
 
 
 	Method New( material:Material,parent:Entity=Null )
 	Method New( material:Material,parent:Entity=Null )
@@ -29,6 +34,11 @@ Class Sprite Extends Renderable
 		
 		
 		_material=material
 		_material=material
 		
 		
+		Name="Sprite"
+		Material=material
+		
+		AddInstance( New Variant[]( material,parent ) )
+		
 		Visible=True
 		Visible=True
 	End
 	End
 
 

+ 44 - 3
modules/mojo3d/scene/entity.monkey2

@@ -61,11 +61,11 @@ Class Entity Extends DynamicObject
 	#end
 	#end
 	Method Copy:Entity( parent:Entity=Null ) Virtual
 	Method Copy:Entity( parent:Entity=Null ) Virtual
 		
 		
-		Local copy:=New Entity( Self,parent )
+		Local copy:=OnCopy( parent )
 		
 		
 		CopyTo( copy )
 		CopyTo( copy )
 		
 		
-		return copy
+		Return copy
 	End
 	End
 	
 	
 	#rem monkeydoc Sequence id.
 	#rem monkeydoc Sequence id.
@@ -80,6 +80,7 @@ Class Entity Extends DynamicObject
 	
 	
 	#rem monkeydoc Entity name.
 	#rem monkeydoc Entity name.
 	#end
 	#end
+	[jsonify=1]
 	Property Name:String()
 	Property Name:String()
 		
 		
 		Return _name
 		Return _name
@@ -160,6 +161,7 @@ Class Entity Extends DynamicObject
 
 
 	#rem monkeydoc Visibility flag.
 	#rem monkeydoc Visibility flag.
 	#end
 	#end
+	[jsonify=1]
 	Property Visible:Bool()
 	Property Visible:Bool()
 		
 		
 		Return _visible
 		Return _visible
@@ -189,6 +191,7 @@ Class Entity Extends DynamicObject
 	
 	
 	#rem monkeydoc Master color.
 	#rem monkeydoc Master color.
 	#end
 	#end
+	[jsonify=1]
 	Property Color:Color()
 	Property Color:Color()
 		
 		
 		Return _color
 		Return _color
@@ -200,6 +203,7 @@ Class Entity Extends DynamicObject
 	
 	
 	#rem monkeydoc Master alpha.
 	#rem monkeydoc Master alpha.
 	#end
 	#end
+	[jsonify=1]
 	Property Alpha:Float()
 	Property Alpha:Float()
 		
 		
 		Return _alpha
 		Return _alpha
@@ -297,6 +301,7 @@ Class Entity Extends DynamicObject
 	The local matrix combines the local position, orientation and scale of the entity into a single affine 4x4 matrix.
 	The local matrix combines the local position, orientation and scale of the entity into a single affine 4x4 matrix.
 	
 	
 	#end
 	#end
+	[jsonify=1]
 	Property LocalMatrix:AffineMat4f()
 	Property LocalMatrix:AffineMat4f()
 		
 		
 		If _dirty & Dirty.M
 		If _dirty & Dirty.M
@@ -361,6 +366,20 @@ Class Entity Extends DynamicObject
 		Invalidate()
 		Invalidate()
 	End
 	End
 
 
+	#rem monkeydoc Finds an entity with the given name.
+	#end
+	Method Find:Entity( name:String )
+		
+		If _name=name Return Self
+		
+		For Local child:=Eachin _children
+			Local found:=child.Find( name )
+			If found Return found
+		Next
+		
+		Return Null
+	End
+	
 	#rem monkeydoc Destroys the entity and all of its children.
 	#rem monkeydoc Destroys the entity and all of its children.
 	#end
 	#end
 	Method Destroy()
 	Method Destroy()
@@ -442,8 +461,10 @@ Class Entity Extends DynamicObject
 	#rem monkeydoc Copy constructor
 	#rem monkeydoc Copy constructor
 	#end
 	#end
 	Method New( entity:Entity,parent:Entity )
 	Method New( entity:Entity,parent:Entity )
+		
 		Self.New( parent )
 		Self.New( parent )
 		
 		
+		_name="Copy of "+entity._name
 		_t=entity._t
 		_t=entity._t
 		_r=entity._r
 		_r=entity._r
 		_s=entity._s
 		_s=entity._s
@@ -451,6 +472,11 @@ Class Entity Extends DynamicObject
 		Invalidate()
 		Invalidate()
 	End
 	End
 	
 	
+	Method OnCopy:Entity( parent:Entity ) Virtual
+		
+		Return New Entity( Self,parent )
+	End
+		
 	#rem monkeydoc Invoked when entity transitions from hidden->visible.
 	#rem monkeydoc Invoked when entity transitions from hidden->visible.
 	#end
 	#end
 	Method OnShow() Virtual
 	Method OnShow() Virtual
@@ -477,7 +503,7 @@ Class Entity Extends DynamicObject
 		_lastCopy=copy
 		_lastCopy=copy
 		
 		
 		For Local child:=Eachin _children
 		For Local child:=Eachin _children
-			child.Copy( copy )
+			child.CopyTo( child.OnCopy( copy ) )
 		Next
 		Next
 		
 		
 		'should really be different pass...ie: ALL entities should be copied before ANY components?
 		'should really be different pass...ie: ALL entities should be copied before ANY components?
@@ -494,6 +520,21 @@ Class Entity Extends DynamicObject
 	
 	
 	Internal
 	Internal
 	
 	
+	Method AddInstance()
+		
+		If _scene.Editing _scene.Jsonifier.AddInstance( Self,New Variant[]( _parent ) )
+	End
+	
+	Method AddInstance( entity:Entity )
+		
+		If _scene.Editing _scene.Jsonifier.AddInstance( Self,New Variant[]( entity,_parent ) )
+	End
+	
+	Method AddInstance( args:Variant[] )
+		
+		If _scene.Editing _scene.Jsonifier.AddInstance( Self,args )
+	End
+	
 	Method AddComponent( c:Component )
 	Method AddComponent( c:Component )
 		
 		
 		Local type:=c.Type
 		Local type:=c.Type

+ 112 - 0
modules/mojo3d/scene/jsonifier/comparejson.monkey2

@@ -0,0 +1,112 @@
+Namespace mojo3d.jsonifier
+
+Function CompareJson:Int( x:JsonObject,y:JsonValue )
+	If y=JsonValue.NullValue Return 1
+	Local r:=Cast<JsonObject>( y )
+	If Not r Return 1
+	Local xit:=x.All(),rit:=r.All()
+	While Not xit.AtEnd And Not rit.AtEnd
+		Local cmp:=xit.Current.Key<=>rit.Current.Key
+		If cmp Return cmp
+		cmp=CompareJson( xit.Current.Value,rit.Current.Value )
+		If cmp Return cmp
+		xit.Bump()
+		rit.Bump()
+	Wend
+	Return x.Count()<=>r.Count()
+End
+
+Function CompareJson:Int( x:JsonArray,y:JsonValue )
+	If y=JsonValue.NullValue Or y.IsBool Or y.IsNumber Or y.IsString Return 1
+	Local r:=Cast<JsonArray>( y )
+	If Not r Return -1
+	For Local i:=0 Until Min( x.Length,r.Length )
+		Local cmp:=CompareJson( x[i],r[i] )
+		If cmp Return cmp
+	Next
+	Return x.Length<=>r.Length
+End
+
+Function CompareJson:Int( x:JsonString,y:JsonValue )
+	If y=JsonValue.NullValue Or y.IsBool Or y.IsNumber Return 1
+	Local r:=Cast<JsonString>( y )
+	Return r ? x.Data<=>r.Data Else -1
+End
+
+Function CompareJson:Int( x:JsonNumber,y:JsonValue )
+	If y=JsonValue.NullValue Or y.IsBool Return 1
+	Local r:=Cast<JsonNumber>( y )
+	Return r ? x.Data<=>r.Data Else -1
+End
+
+Function CompareJson:Int( x:JsonBool,y:JsonValue )
+	If y=JsonValue.NullValue Return 1
+	Local r:=Cast<JsonBool>( y )
+	Return r ? x.Data<=>r.Data Else -1
+End
+
+Function CompareJson:Int( x:JsonValue,y:JsonValue )
+	If x=JsonValue.NullValue Return y=JsonValue.NullValue ? 0 Else -1
+	Local jbool:=Cast<JsonBool>( x )
+	If jbool Return CompareJson( jbool,y )
+	Local jnumber:=Cast<JsonNumber>( x )
+	If jnumber Return CompareJson( jnumber,y )
+	Local jstring:=Cast<JsonString>( x )
+	If jstring Return CompareJson( jstring,y )
+	local jarray:=Cast<JsonArray>( x )
+	If jarray Return CompareJson( jarray,y )
+	Local jobj:=Cast<JsonObject>( x )
+	If jobj Return CompareJson( jobj,y )
+	RuntimeError( "TODO" )
+	Return 0
+End
+
+#rem
+Function RndJson:JsonValue( range:Int=6 )
+	
+	Select Int( Rnd( range ) )
+	Case 0 
+		Return JsonValue.NullValue
+	Case 1 
+		Return Rnd()>.5 ? JsonBool.TrueValue Else JsonBool.FalseValue
+	Case 2 
+		Return New JsonNumber( Rnd(10000) )
+	Case 3 
+		Return New JsonString( Rnd(10000) )
+	Case 4
+		Local data:=New Stack<JsonValue>( Rnd( 10,20 ) )
+		For Local i:=0 Until data.Length
+			data[i]=RndJson( 4 )
+		Next
+		Return New JsonArray( data )
+	Case 5
+		Local data:=New StringMap<JsonValue>
+		For Local i:=0 Until Rnd( 10,20 )
+			data[ Rnd(100) ]=RndJson( 4 )
+		Next
+		Return New JsonObject( data )
+	End
+	Return Null
+End
+
+Function Main()
+	
+	Print "Start..."
+	
+	For Local i:=1 To 100000
+		
+		Local x:=RndJson()
+		Local y:=RndJson()
+		
+		Local cmp1:=CompareJson( x,y )
+		Local cmp2:=CompareJson( y,x )
+		
+		If cmp1<0 Assert( cmp2>=0 )
+		If cmp1=0 Assert( cmp2 =0 )
+		If cmp1>0 Assert( cmp2<=0 )
+	End
+	
+	Print "Success!"
+		
+End
+#end

+ 109 - 0
modules/mojo3d/scene/jsonifier/invocation.monkey2

@@ -0,0 +1,109 @@
+Namespace mojo3d.jsonifier
+
+Class Invocation
+	
+	Method New( scope:TypeInfo,decl:DeclInfo,inst:Variant,args:Variant[] )
+		_scope=scope
+		_decl=decl
+		_inst=inst
+		_args=args
+	End
+	
+	Method New( scope:TypeInfo,decl:String,inst:Variant,args:Variant[] )
+		Init( scope,decl,inst,args )
+	End
+	
+	Method New( name:String,inst:Variant,args:Variant[] )
+		Local i:=name.FindLast( "." )
+		Init( TypeInfo.GetType( name.Slice( 0,i ) ),name.Slice( i+1 ),inst,args )
+	End
+	
+	Property Scope:TypeInfo()
+		
+		Return _scope
+	End
+	
+	Property Decl:DeclInfo()
+		
+		Return _decl
+	End
+	
+	Property Inst:Variant()
+		
+		Return _inst
+	End
+	
+	Property Args:Variant[]()
+		
+		Return _args
+	End
+	
+	Method Execute:Variant()
+		
+		Return _decl.Invoke( _inst,_args )
+	End
+	
+	Private
+	
+	Field _scope:TypeInfo
+	Field _decl:DeclInfo
+	Field _inst:Variant
+	Field _args:Variant[]
+	
+	Function FindDecl:DeclInfo( scope:TypeInfo,name:String,args:Variant[] )
+	
+		For Local decl:=Eachin scope.GetDecls( name )
+			
+			Local ftype:=decl.Type
+			If ftype.ParamTypes.Length<>args.Length Continue
+			
+			Local match:=True
+			For Local i:=0 Until args.Length
+				
+				If args[i]
+					
+					If args[i].Type.ExtendsType( ftype.ParamTypes[i] ) Continue
+					
+					If args[i].Type.Kind="Class" And ftype.ParamTypes[i].Kind="Class"
+						
+						Local obj:=Cast<Object>( args[i] )
+						
+						If Not obj Or obj.DynamicType.ExtendsType( ftype.ParamTypes[i] ) Continue
+						
+					Endif
+					
+				Else
+					If ftype.ParamTypes[i].Kind="Class" Continue
+				Endif
+				match=False
+				Exit
+			Next
+			
+			If match Return decl
+			
+		Next
+		
+		Return Null
+	End
+
+	Method Init( scope:TypeInfo,name:String,inst:Variant,args:Variant[] )
+		
+		_scope=scope
+		_inst=inst
+		_args=args
+		
+		_decl=FindDecl( _scope,name,args )
+		
+		If Not _decl
+			For Local type:=Eachin GetTypeExtensions( _scope )
+				_decl=FindDecl( type,name,args )
+				If Not _decl Continue
+				_scope=type
+				Exit
+			Next
+			Assert( _decl )
+		Endif
+	End
+	
+End
+

+ 312 - 0
modules/mojo3d/scene/jsonifier/jsonifier.monkey2

@@ -0,0 +1,312 @@
+Namespace mojo3d.jsonifier
+
+Class Jsonifier
+	
+	Method AddInstance( obj:Object,ctor:Invocation )
+		
+		Assert( Not _instsByObj.Contains( obj ) )
+		
+		Local inst:=New Instance
+		inst.obj=obj
+		inst.id="@"+String(_insts.Length)
+		inst.ctor=ctor
+		inst.initialState=JsonifyState( obj )
+		
+		_instsByObj[inst.obj]=inst
+		_instsById[inst.id]=inst
+
+		_insts.Add( inst )
+	End
+
+	'ctor via ctor
+	Method AddInstance( obj:Object,args:Variant[] )
+		
+		AddInstance( obj,New Invocation( obj.DynamicType,"New",Null,args ) )
+	end
+
+	'ctor via method call
+	Method AddInstance( obj:Object,decl:String,inst:Variant,args:Variant[] )
+		
+		AddInstance( obj,New Invocation( decl,inst,args ) )
+	End
+
+	'ctor via function call
+	Method AddInstance( obj:Object,decl:String,args:Variant[] )
+		
+		AddInstance( obj,New Invocation( decl,Null,args ) )
+	End
+
+	#rem
+	'function/method call	
+	Method AddInstance( obj:Object,name:String,args:Variant[] )
+		
+		AddInstance( obj,New Invocation( name,args ) )
+	End
+	
+	#end
+	
+	Method JsonifyInstances:JsonObject()
+		
+		Local jobj:=New JsonObject
+		
+		Local jinsts:=New JsonArray( _insts.Length )
+		
+		For Local i:=0 Until jinsts.Length
+			
+			Local inst:=_insts[i]
+			Local jobj:=New JsonObject
+			
+			jobj["id"]=New JsonString( inst.id )
+			jobj["type"]=New JsonString( inst.obj.DynamicType.Name )
+			jobj["ctor"]=Jsonify( inst.ctor )
+			
+			Local state:=JsonifyState( inst.obj ),dstate:=New JsonObject
+			
+			For Local it:=Eachin state.All()
+				
+				Local x:=it.Value
+				Local y:=inst.initialState.GetValue( it.Key )
+				
+				If CompareJson( x,y )<>0 dstate[it.Key]=x
+			Next
+			
+			jobj["state"]=dstate
+			
+			jinsts[i]=jobj
+		Next
+
+		jobj["instances"]=jinsts
+		
+		Return jobj
+	End
+	
+	Method DejsonifyInstances( jobj:JsonObject )
+		
+		Local jinsts:=jobj.GetArray( "instances" )
+		
+		For Local i:=0 Until jinsts.Length
+			
+			Local obj:Object
+						
+			If i<_insts.Length
+				
+				obj=_insts[i].obj
+				
+			Else
+				Local jobj:=jinsts.GetObject( i )
+				
+				Local ctor:=Cast<Invocation>( Dejsonify( jobj["ctor"],Typeof<Invocation> ) )
+			
+				obj=Cast<Object>( ctor.Execute() )
+			Endif
+			
+			_dejsonified.Add( obj )
+		Next
+		
+		For Local i:=0 Until _dejsonified.Length
+			
+			Local jobj:=jinsts.GetObject( i )
+			
+			Local obj:=_dejsonified[i]
+			
+			DejsonifyState( obj,jobj.GetObject( "state" ),obj.DynamicType )
+		Next
+	End
+	
+	Method Jsonify:JsonValue( value:Variant )
+		
+		If Not value Return JsonValue.NullValue
+		
+		Local type:=value.Type
+		Assert( type )
+		
+		'handle primitive types
+		Select type
+		Case Typeof<Bool>
+			Return New JsonBool( Cast<Bool>( value ) )
+		Case Typeof<Int>
+			Return New JsonNumber( Cast<Int>( value ) )
+		Case Typeof<Float>
+			Return New JsonNumber( Cast<Float>( value ) )
+		Case Typeof<String>
+			Return New JsonString( Cast<String>( value ) )
+		Case Typeof<Bool[]>
+			Return JsonifyArray( Cast<Bool[]>( value ) )
+		Case Typeof<Int[]>
+			Return JsonifyArray( Cast<Int[]>( value ) )
+		Case Typeof<Float[]>
+			Return JsonifyArray( Cast<Float[]>( value ) )
+		Case Typeof<String[]>
+			Return JsonifyArray( Cast<String[]>( value ) )
+		End
+		
+		'handle enums+references
+		Select type.Kind
+		Case "Class"
+			Local obj:=Cast<Object>( value )
+			If Not obj Return JsonValue.NullValue
+			Local inst:=_instsByObj[obj]
+			If inst Return New JsonString( inst.id )
+		Case "Enum"
+			Return New JsonNumber( value.EnumValue )
+		End
+		
+		'try custom jsonifiers
+		For Local jext:=Eachin JsonifierExt.All
+			Local jvalue:=jext.Jsonify( value,Self )
+			If jvalue Return jvalue
+		Next
+		
+		RuntimeError( "TODO: No jsonifier found for type '"+type+"'" )
+		Return Null
+	End
+	
+	Method Dejsonify:Variant( jvalue:JsonValue,type:TypeInfo )
+		
+		'handle primitive types
+		Select type
+		Case Typeof<Bool>
+			Return jvalue.ToBool()
+		Case Typeof<Int>
+			Return Int( jvalue.ToNumber() )
+		Case Typeof<Float>
+			Return Float( jvalue.ToNumber() )
+		Case Typeof<String>
+			Return jvalue.ToString()
+		Case Typeof<Bool[]>
+			Return DejsonifyArray<Bool>( jvalue )
+		Case Typeof<Int[]>
+			Return DejsonifyArray<Int>( jvalue )
+		Case Typeof<Float[]>
+			Return DejsonifyArray<Float>( jvalue )
+		Case Typeof<String[]>
+			Return DejsonifyArray<String>( jvalue )
+		End
+		
+		'handle references
+		Select type.Kind
+		Case "Class"
+			If jvalue.IsNull
+				Return type.NullValue
+			Elseif jvalue.IsString
+				Local id:=Int( jvalue.ToString().Slice( 1 ) )
+				Assert( id>=0 And id<_dejsonified.Length,"Dejsonify error" )
+				Local obj:=_dejsonified[id]
+				Return obj
+			Endif
+		Case "Enum"
+			Return type.MakeEnum( jvalue.ToNumber() )
+		End
+		
+		'try custom jsonifiers
+		For Local jext:=Eachin JsonifierExt.All
+			Local value:=jext.Dejsonify( jvalue,type,Self )
+			If value Return value
+		Next
+		
+		RuntimeError( "No dejsonifier found for type '"+type+"'" )
+		Return Null
+	End
+	
+	Method JsonifyArray<C>:JsonArray( values:C[] )
+		
+		Local jvalues:=New JsonArray( values.Length )
+		
+		For Local i:=0 Until jvalues.Length
+			jvalues[i]=Jsonify( values[i] )
+		Next
+		
+		Return jvalues
+	End
+	
+	Method DejsonifyArray<C>:C[]( jvalue:JsonValue )
+		
+		Local jvalues:=jvalue.ToArray()
+		Local values:=New C[jvalues.Length]
+		
+		For Local i:=0 Until values.Length
+			values[i]=Cast<C>( Dejsonify( jvalues[i],Typeof<C> ) )
+		Next
+		
+		Return values
+	End
+	
+	Private
+	
+	Class Instance
+		Field obj:Object
+		Field id:String
+		Field ctor:Invocation
+		Field initialState:JsonObject
+	End
+	
+	Field _insts:=New Stack<Instance>
+	
+	Field _instsByObj:=New Map<Object,Instance>
+	Field _instsById:=New StringMap<Instance>
+	
+	Field _dejsonified:=New Stack<Object>
+	
+	Method JsonifyState:JsonObject( obj:Object )
+		
+		Local jobj:=New JsonObject
+		
+		JsonifyState( obj,jobj,obj.DynamicType )
+		
+		Return jobj
+	End
+	
+	Method JsonifyState( obj:Object,jobj:JsonObject,type:TypeInfo )
+		
+		If type.Kind<>"Class" Return
+		
+		If type.SuperType JsonifyState( obj,jobj,type.SuperType )
+		
+		For Local d:=Eachin type.GetDecls()
+			
+			If d.Kind<>"Property" Continue
+			'Note: Add DeclInfo.Access property so we can do public fields only?
+			If Not d.Gettable Or Not d.Settable Continue
+			
+			If Not Int( d.GetMetaValue( "jsonify" ) ) Continue
+			
+			jobj.SetValue( d.Name,Jsonify( d.Get( obj ) ) )
+		Next
+		
+	End
+	
+	Method DejsonifyState( obj:Object,jobj:JsonObject,type:TypeInfo  )
+		
+		If type.Kind<>"Class" Return
+		
+		If type.SuperType DejsonifyState( obj,jobj,type.SuperType )
+
+		For Local d:=Eachin type.GetDecls()
+			
+			If d.Kind<>"Property" Continue
+			'Note: Add DeclInfo.Access property so we can do public fields only?
+			If Not d.Gettable Or Not d.Settable Or Not jobj.Contains( d.Name ) Continue
+			
+			If Not Int( d.GetMetaValue( "jsonify" ) ) Continue
+			
+			d.Set( obj,Dejsonify( jobj.GetValue( d.Name ),d.Type ) )
+		Next
+	
+	End
+	
+End
+
+
+Class JsonifierExt
+	
+	Const All:=New Stack<JsonifierExt>
+	
+	Method New()
+		All.Add( Self )
+	End
+	
+	Method Jsonify:JsonValue( value:Variant,jsonifier:Jsonifier ) Abstract
+	
+	Method Dejsonify:Variant( jvalue:JsonValue,type:TypeInfo,jsonifier:Jsonifier ) Abstract
+End
+

+ 164 - 0
modules/mojo3d/scene/jsonifier/jsonifierexts.monkey2

@@ -0,0 +1,164 @@
+Namespace mojo3d.jsonifier
+
+Class StdJsonifierExt Extends JsonifierExt
+	
+	Const Instance:=New StdJsonifierExt
+
+	Method Jsonify:JsonValue( value:Variant,jsonifier:Jsonifier ) Override
+		
+		Select value.Type
+		Case Typeof<Vec2i>
+			Local v:=Cast<Vec2i>( value )
+			Return jsonifier.JsonifyArray( New Int[]( v.x,v.y ) )
+		Case Typeof<Vec2f>
+			Local v:=Cast<Vec2f>( value )
+			Return jsonifier.JsonifyArray( New Float[]( v.x,v.y ) )
+		Case Typeof<Recti>
+			Local v:=Cast<Recti>( value )
+			Return jsonifier.JsonifyArray( new Int[]( v.min.x,v.min.y,v.max.x,v.max.y ) )
+		Case Typeof<Rectf>
+			Local v:=Cast<Rectf>( value )
+			Return jsonifier.JsonifyArray( New Float[]( v.min.x,v.min.y,v.max.x,v.max.y ) )
+		Case Typeof<Vec3f>
+			Local v:=Cast<Vec3f>( value )
+			Return jsonifier.JsonifyArray( New Float[]( v.x,v.y,v.z ) )
+		Case Typeof<Boxf>
+			Local v:=Cast<Boxf>( value )
+			Return jsonifier.JsonifyArray( New Float[]( v.min.x,v.min.y,v.min.z,v.max.x,v.max.y,v.max.z ) )
+		Case Typeof<AffineMat4f>
+			Local v:=Cast<AffineMat4f>( value )
+			Return jsonifier.JsonifyArray( New Float[]( v.m.i.x,v.m.i.y,v.m.i.z, v.m.j.x,v.m.j.y,v.m.j.z, v.m.k.x,v.m.k.y,v.m.k.z, v.t.x,v.t.y,v.t.z ) )
+		Case Typeof<Color>
+			Local v:=Cast<Color>( value )
+			Return jsonifier.JsonifyArray( New Float[]( v.r,v.g,v.b,v.a ) )
+		End
+		
+		Return Null
+	End
+
+	Method Dejsonify:Variant( jvalue:JsonValue,type:TypeInfo,jsonifier:Jsonifier ) Override
+		
+		Select type
+		Case Typeof<Vec2i>
+			Local v:=jsonifier.DejsonifyArray<Int>( jvalue )
+			Return New Vec2i( v[0],v[1] )
+		Case Typeof<Vec2f>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New Vec2f( v[0],v[1] )
+		Case Typeof<Recti>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New Recti( v[0],v[1],v[2],v[3] )
+		Case Typeof<Rectf>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New Rectf( v[0],v[1],v[2],v[3] )
+		Case Typeof<Vec3f>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New Vec3f( v[0],v[1],v[2] )
+		Case Typeof<Boxf>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New Boxf( v[0],v[1],v[2],v[3],v[4],v[5] )
+		Case Typeof<AffineMat4f>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New AffineMat4f( v[0],v[1],v[2], v[3],v[4],v[5], v[6],v[7],v[8], v[9],v[10],v[11] )
+		Case Typeof<Color>
+			Local v:=jsonifier.DejsonifyArray<Float>( jvalue )
+			Return New Color( v[0],v[1],v[2],v[3] )
+		End
+		
+		Return Null
+	End
+	
+End
+
+Class InvocationJsonifierExt Extends JsonifierExt
+	
+	Const Instance:=New InvocationJsonifierExt
+	
+	Method Jsonify:JsonValue( value:Variant,jsonifier:Jsonifier ) Override
+		
+		Select value.Type
+		Case Typeof<Invocation>
+			
+			Local v:=Cast<Invocation>( value )
+			
+			Local jobj:=New JsonObject
+			
+'			jobj.SetString( "scope",v.Scope.Name )
+'			jobj.SetString( "decl",v.Decl.Name )
+
+			Local decl:=v.Scope.Name
+			If decl.EndsWith( " Extension" ) decl=decl.Slice( 0,-10 )
+			decl+="."+v.Decl.Name
+			
+			jobj.SetString( "decl",decl )
+			jobj.SetString( "type",v.Decl.Type )
+			If v.Inst jobj.SetValue( "inst",jsonifier.Jsonify( v.Inst ) )
+			jobj.SetValue( "args",jsonifier.JsonifyArray( v.Args ) )
+			
+			Return jobj
+		End
+		
+		Return Null
+	End
+	
+	Method Dejsonify:Variant( jvalue:JsonValue,type:TypeInfo,jsonifier:Jsonifier ) Override
+		
+		Select type
+		Case Typeof<Invocation>
+			
+			Local jobj:=Cast<JsonObject>( jvalue )
+			
+'			Local scope:=TypeInfo.GetType( jobj.GetString( "scope" ) )
+'			Local dname:=jobj.GetString( "decl" )
+
+			Local dname:=jobj.GetString( "decl" )
+			Local dtype:=jobj.GetString( "type" )
+			Local jinst:=jobj.Contains( "inst" ) ? jobj.GetValue( "inst" ) Else JsonValue.NullValue
+			Local jargs:=jobj.GetArray( "args" )
+
+			Local i:=dname.FindLast( "." )
+			Local dscope:=dname.Slice( 0,i )
+			dname=dname.Slice( i+1 )
+			
+			Local scope:=TypeInfo.GetType( dscope )
+			Local decl:DeclInfo
+			
+			For Local tdecl:=Eachin scope.GetDecls( dname )
+				If String(tdecl.Type)<>dtype Continue
+				decl=tdecl
+				Exit
+			Next
+			
+			If Not decl
+				For Local type:=Eachin reflection.GetTypeExtensions( scope )
+					For Local tdecl:=Eachin type.GetDecls( dname )
+						If String(tdecl.Type)<>dtype Continue
+						scope=type
+						decl=tdecl
+						Exit
+					Next
+					If decl Exit
+				Next
+				Assert( decl )
+			Endif
+			
+			Local type:=dname="New" ? scope Else decl.Type.ReturnType
+			
+			Local inst:=jsonifier.Dejsonify( jinst,type )'Typeof<Object> )
+			
+			Local args:=New Variant[jargs.Length]
+			For Local i:=0 Until args.Length
+				args[i]=jsonifier.Dejsonify( jargs[i],decl.Type.ParamTypes[i] )
+			Next
+			
+			Local ctor:=New Invocation( scope,decl,inst,args )
+			
+			Return ctor
+		End
+		
+		Return Null
+	End
+	
+End
+
+

+ 425 - 0
modules/mojo3d/scene/jsonifier/test.monkey2

@@ -0,0 +1,425 @@
+Namespace test
+
+#Reflect test
+
+#Import "<std>"
+
+#Import "jsonifier"
+#Import "invocation"
+#Import "jsonifierexts"
+#Import "comparejson"
+
+Using std..
+Using jsonifier..
+
+Global editing:=True
+Global jsonifier:=New Jsonifier
+
+Class Component
+	
+	'simple contructor
+	Method New( entity:Entity )
+		
+		_entity=entity
+		
+		_entity.AddComponent( Self )
+	End
+
+	'copy contructor
+	Method New( component:Component,entity:Entity )
+		
+		Self.New( entity )
+	End
+	
+	Property Entity:Entity()
+		
+		Return _entity
+	End
+	
+	Protected
+	
+	Method OnCopy:Component( entity:Entity ) Abstract
+	
+	Method SaveInitialState()
+		
+		If editing jsonifier.AddInstance( Self,New Variant[]( _entity ) )
+	End
+	
+	Method SaveInitialState( component:Component )
+		
+		If editing jsonifier.AddInstance( Self,New Variant[]( component,_entity ) )
+	End
+	
+	Private
+	
+	Field _entity:Entity
+	
+End
+
+Class Behaviour Extends Component
+	
+	'simple contructor
+	Method New( entity:Entity )
+		
+		Super.New( entity )
+		
+		Color=graphics.Color.White
+			
+		SaveInitialState()
+	End
+	
+	'copy constructor
+	Method New( behaviour:Behaviour,entity:Entity )
+		
+		Super.New( entity )
+		
+		Color=behaviour.Color
+		
+		SaveInitialState( behaviour )
+	End
+	
+	Property Color:Color()
+		
+		Return _color
+		
+	Setter( color:Color )
+		
+		_color=color
+	End
+	
+	Internal
+	
+	Method OnCopy:Behaviour( entity:Entity ) Override
+		
+		Return New Behaviour( Self,entity )
+	End
+	
+	Private
+	
+	Field _color:Color
+End
+
+Class Entity
+	
+	'simple ctor
+	Method New( parent:Entity )
+		
+		_parent=parent
+		
+		If _parent _parent._children.Add( Self )
+	End
+	
+	'copy ctor
+	Method New( entity:Entity,parent:Entity )
+		
+		Self.New( parent )
+	End
+	
+	Property Visible:Bool()
+		
+		Return _visible
+	
+	Setter( visible:Bool )
+		
+		_visible=visible
+	End
+	
+	Method Copy:Entity( parent:Entity ) Virtual
+		
+		Local copy:=OnCopy( parent )
+		
+		CopyTo( copy )
+		
+		Return copy
+	End
+	
+	Method AddComponent<T>:T()
+		
+		Local component:=New T( Self )
+		
+		Return component
+	End
+	
+	Protected
+	
+	Method OnCopy:Entity( parent:Entity ) Virtual
+		
+		Return New Entity( Self,parent )
+	End
+	
+	Method CopyTo( copy:Entity )
+		
+		For Local child:=Eachin _children
+			
+			child.CopyTo( child.OnCopy( copy ) )
+		Next
+		
+		For Local c:=Eachin _components
+			
+			c.OnCopy( copy )
+		Next
+	End
+	
+	Method SaveInitialState()
+		
+		If editing jsonifier.AddInstance( Self,New Variant[]( _parent ) )
+	End
+
+	Method SaveInitialState( entity:Entity )
+		
+		If editing jsonifier.AddInstance( Self,New Variant[]( entity,_parent ) )
+	End
+	
+	Private
+	
+	Field _parent:Entity
+	
+	Field _children:=New Stack<Entity>
+	
+	Field _visible:Bool
+	
+	Field _components:=New Stack<Component>
+	
+	Method AddComponent( component:Component )
+		
+		_components.Add( component )
+	End
+	
+End
+
+Class Camera Extends Entity
+	
+	Method New( parent:Entity )
+
+		Super.New( parent )
+		
+		FOV=90
+		
+		SaveInitialState()
+		
+		Visible=True
+	End
+	
+	Method New( camera:Camera,parent:Entity )
+		
+		Super.New( camera,parent )
+		
+		FOV=camera.FOV
+		
+		SaveInitialState( camera )
+		
+		Visible=True
+	End
+	
+	Property FOV:Float()
+	
+		Return _fov
+	
+	Setter( fov:Float )
+		
+		_fov=fov
+	End
+	
+	Method Copy:Camera( parent:Entity ) Override
+		
+		Local camera:=OnCopy( parent )
+		
+		CopyTo( camera )
+		
+		Return camera
+	End
+
+	Protected
+		
+	Method OnCopy:Camera( parent:Entity ) Override
+		
+		Return New Camera( Self,parent )
+	End
+	
+	Private
+	
+	Field _fov:Float
+	
+End
+
+Class Light Extends Entity
+	
+	Method New( parent:Entity )
+		
+		Super.New( parent )
+		
+		SaveInitialState()
+		
+		Visible=True
+	End
+
+	Method New( light:Light,parent:Entity )
+		
+		Super.New( parent )
+		
+		SaveInitialState( light )
+		
+		Visible=True
+	End
+
+	Method Copy:Light( parent:Entity ) Override
+		
+		Local light:=OnCopy( parent )
+		
+		CopyTo( light )
+		
+		Return light
+	End
+
+	Protected
+		
+	Method OnCopy:Light( parent:Entity ) Override
+		
+		Return New Light( Self,parent )
+	End
+	
+End
+
+Class Model Extends Entity
+	
+	Method New( parent:Entity )
+		
+		Super.New( parent )
+		
+		Mesh=""
+		
+		SaveInitialState()
+		
+		Visible=True
+	End
+	
+	Method New( model:Model,parent:Entity )
+		
+		Super.New( parent )
+		
+		Mesh=model.Mesh
+		
+		SaveInitialState( model )
+		
+		Visible=True
+	End
+	
+	Property Mesh:String()
+		
+		Return _mesh
+		
+	Setter( mesh:String )
+		
+		_mesh=mesh
+	End
+	
+	Function Load:Model( path:String,parent:Entity )
+		
+		Local model:=New Model( parent,True )
+		
+		model.Mesh="<"+path+">"
+		
+		If editing jsonifier.AddInstance( model,"Load",New Variant[]( path,parent ) )
+		
+		Return model
+	End
+	
+	Method Copy:Model( parent:Entity ) Override
+		
+		Local model:=OnCopy( parent )
+		
+		CopyTo( model )
+		
+		Return model
+	End
+
+	Protected
+		
+	Method OnCopy:Model( parent:Entity ) Override
+		
+		Return New Model( Self,parent )
+	End
+	
+	Private
+	
+	Field _mesh:String
+	
+	Method New( parent:Entity,loading:Bool )
+		
+		Super.New( parent )
+	End
+
+End
+
+Function CreateScene()
+	
+	Print "CreateScene"
+
+	jsonifier=New Jsonifier
+	
+	Local model1:=Model.Load( "model1.png",Null )
+	
+	Local behavour1:=New Behaviour( model1 )
+	
+	Local model2:=model1.Copy( Null )
+	
+End
+
+Function CreateScene2()
+	
+	Print "CreateScene"
+
+	jsonifier=New Jsonifier
+	
+	Local camera:=New Camera( Null )
+	
+	Local light:=New Light( Null )
+	
+	Local root:=Model.Load( "blah.txt",Null )
+	
+	For Local i:=0 Until 3
+		
+		Local model:=New Model( root )
+		
+		Local component:=New Behaviour( model )
+	Next
+	
+	Local copy:=root.Copy( Null )
+	
+End
+
+Function SaveScene:JsonObject()
+	
+	Print "SaveScene"
+
+	Local jobj:=jsonifier.JsonifyInstances()
+	
+	Return jobj
+End
+
+Function LoadScene( jobj:JsonObject )
+	
+	Print "LoadScene"
+	
+	jsonifier=New Jsonifier
+	
+	jsonifier.DejsonifyInstances( jobj )
+End
+
+Function Main()
+	
+	CreateScene()
+	
+	Local saved1:=SaveScene()
+	
+	LoadScene( saved1 )
+	
+	Local saved2:=SaveScene()
+	
+	If CompareJson( saved1,saved2 )=0
+		Print saved1.ToJson()+"~nSuccess!"
+	Else
+		Print "saved1:~n"+saved1.ToJson()+"~nsaved2:~n"+saved2.ToJson()+"~nError!"
+	Endif
+	
+End

+ 16 - 2
modules/mojo3d/render/material.monkey2 → modules/mojo3d/scene/material.monkey2

@@ -125,7 +125,7 @@ Class Material Extends Resource
 	Protected
 	Protected
 	
 	
 	Method New()
 	Method New()
-
+		
 		_uniforms=New UniformBlock( 3,True )
 		_uniforms=New UniformBlock( 3,True )
 		_blendMode=BlendMode.Opaque
 		_blendMode=BlendMode.Opaque
 		_cullMode=CullMode.Back
 		_cullMode=CullMode.Back
@@ -134,7 +134,7 @@ Class Material Extends Resource
 	End		
 	End		
 	
 	
 	Method New( material:Material )
 	Method New( material:Material )
-
+		
 		_uniforms=New UniformBlock( material._uniforms )
 		_uniforms=New UniformBlock( material._uniforms )
 
 
 		_blendMode=material._blendMode
 		_blendMode=material._blendMode
@@ -143,6 +143,20 @@ Class Material Extends Resource
 		TextureMatrix=material.TextureMatrix
 		TextureMatrix=material.TextureMatrix
 	End
 	End
 	
 	
+	Method AddInstance( args:Variant[] )
+		
+		Local scene:=Scene.GetCurrent()
+		
+		If scene.Editing scene.Jsonifier.AddInstance( Self,args )
+	End
+	
+	Method AddInstance( material:Material )
+		
+		Local scene:=Scene.GetCurrent()
+		
+		If scene.Editing scene.Jsonifier.AddInstance( Self,New Variant[]( material ) )
+	End
+	
 	Private
 	Private
 	
 	
 	Field _name:String
 	Field _name:String

+ 15 - 1
modules/mojo3d/render/materials/pbrmaterial.monkey2 → modules/mojo3d/scene/materials/pbrmaterial.monkey2

@@ -65,19 +65,25 @@ Class PbrMaterial Extends Material
 	End
 	End
 	
 	
 	Method New( color:Color,metalness:Float=1.0,roughness:Float=1.0,boned:Bool=False )
 	Method New( color:Color,metalness:Float=1.0,roughness:Float=1.0,boned:Bool=False )
+		
 		Self.New( boned )
 		Self.New( boned )
 		
 		
 		ColorFactor=color
 		ColorFactor=color
 		MetalnessFactor=metalness
 		MetalnessFactor=metalness
 		RoughnessFactor=roughness
 		RoughnessFactor=roughness
+		
+		AddInstance( New Variant[]( color,metalness,roughness,boned ) )
 	End
 	End
 	
 	
 	Method New( material:PbrMaterial )
 	Method New( material:PbrMaterial )
+		
 		Super.New( material )
 		Super.New( material )
 		
 		
 		_textured=material._textured
 		_textured=material._textured
 		_bumpmapped=material._bumpmapped
 		_bumpmapped=material._bumpmapped
 		_boned=material._boned
 		_boned=material._boned
+		
+		AddInstance( material )
 	End
 	End
 	
 	
 	#rem monkeydoc Creates a copy of the pbr material.
 	#rem monkeydoc Creates a copy of the pbr material.
@@ -170,7 +176,7 @@ Class PbrMaterial Extends Material
 	End
 	End
 	
 	
 	'***** factors *****
 	'***** factors *****
-
+	[jsonify=1]
 	Property ColorFactor:Color()
 	Property ColorFactor:Color()
 	
 	
 		Return Uniforms.GetColor( "ColorFactor" )
 		Return Uniforms.GetColor( "ColorFactor" )
@@ -180,6 +186,7 @@ Class PbrMaterial Extends Material
 		Uniforms.SetColor( "ColorFactor",color )
 		Uniforms.SetColor( "ColorFactor",color )
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property EmissiveFactor:Color()
 	Property EmissiveFactor:Color()
 	
 	
 		Return Uniforms.GetColor( "EmissiveFactor" )
 		Return Uniforms.GetColor( "EmissiveFactor" )
@@ -189,6 +196,7 @@ Class PbrMaterial Extends Material
 		Uniforms.SetColor( "EmissiveFactor",color )
 		Uniforms.SetColor( "EmissiveFactor",color )
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property MetalnessFactor:Float()
 	Property MetalnessFactor:Float()
 	
 	
 		Return Uniforms.GetFloat( "MetalnessFactor" )
 		Return Uniforms.GetFloat( "MetalnessFactor" )
@@ -198,6 +206,7 @@ Class PbrMaterial Extends Material
 		Uniforms.SetFloat( "MetalnessFactor",factor )
 		Uniforms.SetFloat( "MetalnessFactor",factor )
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property RoughnessFactor:Float()
 	Property RoughnessFactor:Float()
 	
 	
 		Return Uniforms.GetFloat( "RoughnessFactor" )
 		Return Uniforms.GetFloat( "RoughnessFactor" )
@@ -223,6 +232,11 @@ Class PbrMaterial Extends Material
 		
 		
 		Local material:=New PbrMaterial
 		Local material:=New PbrMaterial
 		
 		
+		Local scene:=Scene.GetCurrent()
+		If scene.Editing 
+			scene.Jsonifier.AddInstance( material,"mojo3d.PbrMaterial.Load",New Variant[]( path,textureFlags ) )
+		Endif
+		
 		Local texture:=LoadTexture( path,"color",textureFlags )
 		Local texture:=LoadTexture( path,"color",textureFlags )
 		If texture
 		If texture
 			material.ColorTexture=texture
 			material.ColorTexture=texture

+ 0 - 0
modules/mojo3d/render/materials/spritematerial.monkey2 → modules/mojo3d/scene/materials/spritematerial.monkey2


+ 0 - 0
modules/mojo3d/render/materials/watermaterial.monkey2 → modules/mojo3d/scene/materials/watermaterial.monkey2


+ 17 - 0
modules/mojo3d/geometry/mesh.monkey2 → modules/mojo3d/scene/mesh.monkey2

@@ -75,6 +75,21 @@ Class Mesh Extends Resource
 		Return _bounds
 		Return _bounds
 	End
 	End
 	
 	
+	#rem monkeydoc Compacts the mesh.
+	
+	Compacts all internal data used by the mesh so they occupy as little memory as possible.
+	
+	#end
+	Method Compact()
+		
+		_vertices.Compact()
+		_materials.Compact()
+		
+		For Local material:=Eachin _materials
+			material.indices.Compact()
+		Next
+	End
+	
 	#rem monkeydoc Clears the mesh.
 	#rem monkeydoc Clears the mesh.
 	
 	
 	Removes all vertices and primitives from the mesh, and resets the number of logical materials to '1'.
 	Removes all vertices and primitives from the mesh, and resets the number of logical materials to '1'.
@@ -90,6 +105,8 @@ Class Mesh Extends Resource
 		InvalidateVertices()
 		InvalidateVertices()
 	End
 	End
 	
 	
+	#rem monkeydoc Clear the mesh vertices.
+	#end
 	Method ClearVertices()
 	Method ClearVertices()
 		
 		
 		ResizeVertices( 0 )
 		ResizeVertices( 0 )

+ 59 - 19
modules/mojo3d/geometry/meshprims.monkey2 → modules/mojo3d/scene/meshprims.monkey2

@@ -3,6 +3,18 @@ Namespace mojo3d
 
 
 Private
 Private
 
 
+Function Editing:Bool()
+	
+	Return Scene.GetCurrent().Editing
+End
+
+Function AddInstance( instance:Mesh,ctor:String,args:Variant[] )
+	
+	Local scene:=Scene.GetCurrent()
+	
+	If scene?.Editing scene.Jsonifier.AddInstance( instance,ctor,args )
+End
+
 Struct TerrainData
 Struct TerrainData
 	
 	
 	Field heightMap:Pixmap
 	Field heightMap:Pixmap
@@ -58,7 +70,7 @@ Class Mesh Extension
 	
 	
 	Function CreateRect:Mesh( rect:Rectf )
 	Function CreateRect:Mesh( rect:Rectf )
 
 
-		Local data:=New Mesh( 
+		Local mesh:=New Mesh( 
 			New Vertex3f[](
 			New Vertex3f[](
 				New Vertex3f( rect.min.x,rect.max.y,0 ),
 				New Vertex3f( rect.min.x,rect.max.y,0 ),
 				New Vertex3f( rect.max.x,rect.max.y,0 ),
 				New Vertex3f( rect.max.x,rect.max.y,0 ),
@@ -67,10 +79,12 @@ Class Mesh Extension
 			New UInt[](
 			New UInt[](
 				0,1,2,
 				0,1,2,
 				0,2,3 ) )
 				0,2,3 ) )
+				
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateRect",New Variant[]( rect ) )
 		
 		
-		data.UpdateTangents()
+		mesh.UpdateTangents()
 		
 		
-		Return data
+		Return mesh
 	End
 	End
 
 
 	Function CreateBox:Mesh( box:Boxf,xsegs:Int=1,ysegs:Int=1,zsegs:Int=1 )
 	Function CreateBox:Mesh( box:Boxf,xsegs:Int=1,ysegs:Int=1,zsegs:Int=1 )
@@ -139,11 +153,13 @@ Class Mesh Extension
 			v0+=zsegs+1
 			v0+=zsegs+1
 		Next
 		Next
 		
 		
-		Local data:=New Mesh( vertices,indices )
+		Local mesh:=New Mesh( vertices,indices )
+		
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateBox",New Variant[]( box,xsegs,ysegs,zsegs ) )
 		
 		
-		data.UpdateTangents()
+		mesh.UpdateTangents()
 		
 		
-		Return data
+		Return mesh
 	End
 	End
 
 
 	Function CreateSphere:Mesh( radius:float,hsegs:Int=24,vsegs:Int=12 )
 	Function CreateSphere:Mesh( radius:float,hsegs:Int=24,vsegs:Int=12 )
@@ -191,11 +207,13 @@ Class Mesh Extension
 			vdata[i].normal=vdata[i].position.Normalize()
 			vdata[i].normal=vdata[i].position.Normalize()
 		Next
 		Next
 		
 		
-		Local data:=New Mesh( vertices.ToArray(),indices.ToArray() )
+		Local mesh:=New Mesh( vertices.ToArray(),indices.ToArray() )
 		
 		
-		data.UpdateTangents()
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateSphere",New Variant[]( radius,hsegs,vsegs ) )
+		
+		mesh.UpdateTangents()
 		
 		
-		Return data
+		Return mesh
 	End
 	End
 	
 	
 	Function CreateTorus:Mesh( outerRadius:Float,innerRadius:Float,outerSegs:Int=24,innerSegs:Int=12 )
 	Function CreateTorus:Mesh( outerRadius:Float,innerRadius:Float,outerSegs:Int=24,innerSegs:Int=12 )
@@ -246,11 +264,13 @@ Class Mesh Extension
 			Next
 			Next
 		Next
 		Next
 		
 		
-		Local data:=New Mesh( vertices,indices )
+		Local mesh:=New Mesh( vertices,indices )
+		
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateTorus",New Variant[]( outerRadius,innerRadius,outerSegs,innerSegs ) )
 		
 		
-		data.UpdateTangents()
+		mesh.UpdateTangents()
 		
 		
-		Return data
+		Return mesh
 	End
 	End
 	
 	
 	Function CreateCylinder:Mesh( radius:Float,length:Float,axis:Axis,segs:Int )
 	Function CreateCylinder:Mesh( radius:Float,length:Float,axis:Axis,segs:Int )
@@ -295,6 +315,8 @@ Class Mesh Extension
 		
 		
 		Local mesh:=New Mesh( vertices.ToArray(),triangles.ToArray() )
 		Local mesh:=New Mesh( vertices.ToArray(),triangles.ToArray() )
 		
 		
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateCylinder",New Variant[]( radius,length,axis,segs ) )
+		
 		Select axis
 		Select axis
 		Case Axis.X
 		Case Axis.X
 			mesh.TransformVertices( New AffineMat4f( 0,1,0, 1,0,0, 0,0,1, 0,0,0 ) )
 			mesh.TransformVertices( New AffineMat4f( 0,1,0, 1,0,0, 0,0,1, 0,0,0 ) )
@@ -383,6 +405,8 @@ Class Mesh Extension
 		
 		
 		Local mesh:=New Mesh( vertices.ToArray(),triangles.ToArray() )
 		Local mesh:=New Mesh( vertices.ToArray(),triangles.ToArray() )
 		
 		
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateCapsule",New Variant[]( radius,length,axis,segs ) )
+		
 		Select axis
 		Select axis
 		Case Axis.X
 		Case Axis.X
 			mesh.TransformVertices( New AffineMat4f( 0,1,0, 1,0,0, 0,0,1, 0,0,0 ) )
 			mesh.TransformVertices( New AffineMat4f( 0,1,0, 1,0,0, 0,0,1, 0,0,0 ) )
@@ -431,6 +455,8 @@ Class Mesh Extension
 		
 		
 		Local mesh:=New Mesh( vertices.ToArray(),triangles.ToArray() )
 		Local mesh:=New Mesh( vertices.ToArray(),triangles.ToArray() )
 		
 		
+		If Editing() AddInstance( mesh,"mojo3d.Mesh.CreateCone",New Variant[]( radius,length,axis,segs ) )
+		
 		Select axis
 		Select axis
 		Case Axis.X
 		Case Axis.X
 			mesh.TransformVertices( New AffineMat4f( 0,1,0, 1,0,0, 0,0,1, 0,0,0 ) )
 			mesh.TransformVertices( New AffineMat4f( 0,1,0, 1,0,0, 0,0,1, 0,0,0 ) )
@@ -497,49 +523,63 @@ Class Model Extension
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateBox( box,xsegs,ysegs,zsegs )
 		Local mesh:=mojo3d.Mesh.CreateBox( box,xsegs,ysegs,zsegs )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+		
+		Return model
 	End
 	End
 	
 	
 	Function CreateSphere:Model( radius:Float,hsegs:Int,vsegs:Int,material:Material,parent:Entity=Null )
 	Function CreateSphere:Model( radius:Float,hsegs:Int,vsegs:Int,material:Material,parent:Entity=Null )
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateSphere( radius,hsegs,vsegs )
 		Local mesh:=mojo3d.Mesh.CreateSphere( radius,hsegs,vsegs )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+
+		Return model
 	End
 	End
 	
 	
 	Function CreateTorus:Model( outerRadius:Float,innerRadius:Float,outerSegs:Int,innerSegs:Int,material:Material,parent:Entity=Null )
 	Function CreateTorus:Model( outerRadius:Float,innerRadius:Float,outerSegs:Int,innerSegs:Int,material:Material,parent:Entity=Null )
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateTorus( outerRadius,innerRadius,outerSegs,innerSegs )
 		Local mesh:=mojo3d.Mesh.CreateTorus( outerRadius,innerRadius,outerSegs,innerSegs )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+		
+		Return model
 	End
 	End
 	
 	
 	Function CreateCylinder:Model( radius:Float,length:Float,axis:Axis,segs:Int,material:Material,parent:Entity=null )
 	Function CreateCylinder:Model( radius:Float,length:Float,axis:Axis,segs:Int,material:Material,parent:Entity=null )
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateCylinder( radius,length,axis,segs )
 		Local mesh:=mojo3d.Mesh.CreateCylinder( radius,length,axis,segs )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+
+		Return model
 	End
 	End
 	
 	
 	Function CreateCapsule:Model( radius:Float,length:Float,axis:Axis,segs:Int,material:Material,parent:Entity=null )
 	Function CreateCapsule:Model( radius:Float,length:Float,axis:Axis,segs:Int,material:Material,parent:Entity=null )
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateCapsule( radius,length,axis,segs )
 		Local mesh:=mojo3d.Mesh.CreateCapsule( radius,length,axis,segs )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+
+		Return model
 	End
 	End
 	
 	
 	Function CreateCone:Model( radius:Float,length:Float,axis:Axis,segs:Int,material:Material,parent:Entity=null )
 	Function CreateCone:Model( radius:Float,length:Float,axis:Axis,segs:Int,material:Material,parent:Entity=null )
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateCone( radius,length,axis,segs )
 		Local mesh:=mojo3d.Mesh.CreateCone( radius,length,axis,segs )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+
+		Return model
 	End
 	End
 	
 	
 	Function CreateTerrain:Model( heightMap:Pixmap,bounds:Boxf,material:Material,parent:Entity=Null )
 	Function CreateTerrain:Model( heightMap:Pixmap,bounds:Boxf,material:Material,parent:Entity=Null )
 		
 		
 		Local mesh:=mojo3d.Mesh.CreateTerrain( heightMap,bounds )
 		Local mesh:=mojo3d.Mesh.CreateTerrain( heightMap,bounds )
 		
 		
-		Return New Model( mesh,material,parent )
+		Local model:=New Model( mesh,material,parent )
+
+		Return model
 	End
 	End
 	
 	
 End
 End

+ 0 - 0
modules/mojo3d/render/posteffect.monkey2 → modules/mojo3d/scene/posteffect.monkey2


+ 111 - 0
modules/mojo3d/scene/scene.monkey2

@@ -21,6 +21,14 @@ Class Scene
 		_envColor=Color.White
 		_envColor=Color.White
 		
 		
 		_world=New World( Self )
 		_world=New World( Self )
+		
+		Local type:=TypeInfo.GetType( "mojo3d.Scene" )
+		If type And type.Kind="Class"
+			_jsonifier=New Jsonifier
+			_jsonifier.AddInstance( Self,New Variant[0] )
+		Endif
+		
+		_editing=False
 	End
 	End
 	
 	
 	#rem monkeydoc The sky texture.
 	#rem monkeydoc The sky texture.
@@ -32,6 +40,7 @@ Class Scene
 	This must currently be a valid cubemap texture.
 	This must currently be a valid cubemap texture.
 	
 	
 	#end
 	#end
+'	[jsonify=1]
 	Property SkyTexture:Texture()
 	Property SkyTexture:Texture()
 		
 		
 		Return _skyTexture
 		Return _skyTexture
@@ -52,6 +61,7 @@ Class Scene
 	This must currently be a valid cubemap texture.
 	This must currently be a valid cubemap texture.
 	
 	
 	#end
 	#end
+'	[jsonify=1]
 	Property EnvTexture:Texture()
 	Property EnvTexture:Texture()
 		
 		
 		Return _envTexture
 		Return _envTexture
@@ -64,6 +74,7 @@ Class Scene
 	#rem monkey The environment color.
 	#rem monkey The environment color.
 	
 	
 	#end
 	#end
+	[jsonify=1]
 	Property EnvColor:Color()
 	Property EnvColor:Color()
 		
 		
 		Return _envColor
 		Return _envColor
@@ -80,6 +91,7 @@ Class Scene
 	The clear color is only used if there is no sky texture.
 	The clear color is only used if there is no sky texture.
 	
 	
 	#end
 	#end
+	[jsonify=1]
 	Property ClearColor:Color()
 	Property ClearColor:Color()
 		
 		
 		Return _clearColor
 		Return _clearColor
@@ -89,6 +101,7 @@ Class Scene
 		_clearColor=color
 		_clearColor=color
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property FogColor:Color()
 	Property FogColor:Color()
 		
 		
 		Return _fogColor
 		Return _fogColor
@@ -98,6 +111,7 @@ Class Scene
 		_fogColor=color
 		_fogColor=color
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property FogNear:Float()
 	Property FogNear:Float()
 		
 		
 		Return _fogNear
 		Return _fogNear
@@ -107,6 +121,7 @@ Class Scene
 		_fogNear=near
 		_fogNear=near
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property FogFar:Float()
 	Property FogFar:Float()
 		
 		
 		Return _fogFar
 		Return _fogFar
@@ -116,6 +131,7 @@ Class Scene
 		_fogFar=far
 		_fogFar=far
 	End
 	End
 	
 	
+	[jsonify=1]
 	Property ShadowAlpha:Float()
 	Property ShadowAlpha:Float()
 		
 		
 		Return _shadowAlpha
 		Return _shadowAlpha
@@ -127,6 +143,7 @@ Class Scene
 	
 	
 	#rem monkeydoc Scene update rate.
 	#rem monkeydoc Scene update rate.
 	#end
 	#end
+	[jsonify=1]
 	Property UpdateRate:Float()
 	Property UpdateRate:Float()
 		
 		
 		Return _updateRate
 		Return _updateRate
@@ -138,6 +155,7 @@ Class Scene
 	
 	
 	#rem monkeydoc Ambient diffuse lighting.
 	#rem monkeydoc Ambient diffuse lighting.
 	#end
 	#end
+	[jsonify=1]
 	Property AmbientLight:Color()
 	Property AmbientLight:Color()
 		
 		
 		Return _ambientDiffuse
 		Return _ambientDiffuse
@@ -154,6 +172,7 @@ Class Scene
 	Must have length 4.
 	Must have length 4.
 		
 		
 	#end
 	#end
+	[jsonify=1]
 	Property CSMSplits:Float[]()
 	Property CSMSplits:Float[]()
 		
 		
 		Return _csmSplits
 		Return _csmSplits
@@ -164,6 +183,60 @@ Class Scene
 		_csmSplits=splits.Slice( 0 )
 		_csmSplits=splits.Slice( 0 )
 	End
 	End
 	
 	
+	Property Editing:Bool()
+		
+		Return _editing
+	
+	Setter( editing:Bool )
+		
+		If editing And Not _jsonifier RuntimeError( "Scene is not editable" )
+		
+		_editing=editing
+	End
+	
+	Property Jsonifier:Jsonifier()
+		
+		Return _jsonifier
+	End
+	
+	Method PauseEditing()
+		
+		_editingPaused+=1
+	End
+	
+	Method ResumeEditing:Bool()
+		
+		_editingPaused-=1
+		
+		Return Editing
+	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 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.
 	#rem monkeydoc Adds a post effect to the scene.
 	#end
 	#end
 	Method AddPostEffect( postEffect:PostEffect )
 	Method AddPostEffect( postEffect:PostEffect )
@@ -235,6 +308,19 @@ Class Scene
 		Return _rootEntities.ToArray()
 		Return _rootEntities.ToArray()
 	End
 	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 Sets the current scene.
 	#rem monkeydoc Sets the current scene.
 	
 	
 	All newly created entities (including entites created using Entity.Copy]]) are automatically added to the current scene.
 	All newly created entities (including entites created using Entity.Copy]]) are automatically added to the current scene.
@@ -257,6 +343,25 @@ Class Scene
 		Return _current
 		Return _current
 	End
 	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
+		
+		SetCurrent( scene )
+		
+		scene.Jsonifier.DejsonifyInstances( jobj )
+		
+		Return scene
+	End
+	
 	Internal
 	Internal
 
 
 	Property PostEffects:Stack<PostEffect>()
 	Property PostEffects:Stack<PostEffect>()
@@ -319,6 +424,12 @@ Class Scene
 	
 	
 	Field _world:World
 	Field _world:World
 	
 	
+	Field _jsonifier:Jsonifier
+	
+	Field _editing:Bool
+	
+	Field _editingPaused:=0
+	
 	Method Update( elapsed:Float )
 	Method Update( elapsed:Float )
 		
 		
 		For Local e:=Eachin _rootEntities
 		For Local e:=Eachin _rootEntities

+ 0 - 0
modules/mojo3d/geometry/util3d.monkey2 → modules/mojo3d/scene/util3d.monkey2


+ 8 - 1
modules/mojo3d/tests/cubes.monkey2

@@ -1,5 +1,7 @@
 Namespace myapp
 Namespace myapp
 
 
+#Reflect mojo3d
+
 #Import "<std>"
 #Import "<std>"
 #Import "<mojo>"
 #Import "<mojo>"
 #Import "<mojo3d>"
 #Import "<mojo3d>"
@@ -24,13 +26,16 @@ Class MyWindow Extends Window
 		
 		
 		Print opengl.glGetString( opengl.GL_VERSION )
 		Print opengl.glGetString( opengl.GL_VERSION )
 		
 		
-		_scene=Scene.GetCurrent()
+		_scene=New Scene
+		
+		_scene.Editing=True
 		
 		
 		_scene.ClearColor=Color.Sky
 		_scene.ClearColor=Color.Sky
 		
 		
 		'create camera
 		'create camera
 		'
 		'
 		_camera=New Camera( Self )
 		_camera=New Camera( Self )
+		_camera.Name="Camera"
 		_camera.Near=.1
 		_camera.Near=.1
 		_camera.Far=1000
 		_camera.Far=1000
 		_camera.Move( 0,10,-10 )
 		_camera.Move( 0,10,-10 )
@@ -56,6 +61,8 @@ Class MyWindow Extends Window
 		Next
 		Next
 		
 		
 		cube.Destroy()
 		cube.Destroy()
+		
+		_scene.Save( "cubes-scene.mojo3d" )
 	End
 	End
 	
 	
 	Method OnRender( canvas:Canvas ) Override
 	Method OnRender( canvas:Canvas ) Override

+ 100 - 0
modules/mojo3d/tests/loadscene.monkey2

@@ -0,0 +1,100 @@
+Namespace myapp3d
+
+#Reflect mojo3d
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+
+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 CreateScene()
+		
+		_scene.AmbientLight = _scene.ClearColor * 0.25
+		_scene.FogColor = _scene.ClearColor
+		_scene.FogFar = 1.0
+		_scene.FogFar = 200.0
+
+		'create camera
+		_camera=New Camera
+		_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:=New PbrMaterial( Color.Red, 0.05, 0.2 )
+		_donut=Model.CreateTorus( 2,.5,48,24,donutMaterial )
+		_donut.Move( 0,2.5,0 )
+		Local rb:=_donut.AddComponent<RotateBehaviour>()
+		rb.Speed=New Vec3f( .2,.4,.6 )
+	End
+	
+	Method OnCreateWindow() Override
+		
+		Local path:=CurrentDir()+"test-scene.mojo3d"
+		
+		_scene=New Scene
+		
+		_scene.Editing=True
+		
+		Print "Creating scene"
+		
+		CreateScene()
+		
+		Print "Saving scene to "+path
+			
+		_scene.Save( path )
+		
+		Print "Loading scene from "+path
+			
+		_scene=Scene.Load( path )
+			
+		_camera=Cast<Camera>( _scene.FindEntity( "Camera" ) )
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+		
+		RequestRender()
+		
+		_scene.Update()
+		
+		_camera.Render( canvas )
+		
+		canvas.DrawText( "FPS="+App.FPS,0,0 )
+	End
+	
+End
+
+Function Main()
+
+	New AppInstance
+	
+	New MyWindow
+	
+	App.Run()
+End