Explorar o código

Merge pull request #79 from blitz-research/develop

Develop up
abakobo %!s(int64=8) %!d(string=hai) anos
pai
achega
b121c211a0
Modificáronse 77 ficheiros con 2003 adicións e 819 borrados
  1. 2 0
      .gitignore
  2. 2 2
      ABOUT.HTML
  3. 9 1
      VERSIONS.TXT
  4. 7 3
      bin/env_windows.txt
  5. BIN=BIN
      bin/mx2cc_linux
  6. BIN=BIN
      bin/mx2cc_macos
  7. BIN=BIN
      bin/mx2cc_windows.exe
  8. 3 1
      modules/assimp/assimp/MARKS_FIXES.TXT
  9. 4 0
      modules/assimp/assimp/contrib/zlib/gzguts.h
  10. 25 7
      modules/jni/jni.monkey2
  11. 91 25
      modules/jni/native/jni_glue.cpp
  12. 11 4
      modules/jni/native/jni_glue.h
  13. 1 0
      modules/mojo/app/style.monkey2
  14. 7 5
      modules/mojo3d-loaders/loaders/assimp.monkey2
  15. 4 4
      modules/mojo3d-loaders/tests/assets/castle/CASTLE1.X
  16. BIN=BIN
      modules/mojo3d-loaders/tests/assets/castle/stone2.jpg
  17. BIN=BIN
      modules/mojo3d-loaders/tests/assets/miramar-skybox.jpg
  18. 4 1
      modules/mojo3d-loaders/tests/castle.monkey2
  19. 6 1
      modules/mojo3d-physics/physics/collider.monkey2
  20. 187 96
      modules/mojo3d-physics/physics/rigidbody.monkey2
  21. 14 14
      modules/mojo3d-physics/physics/world.monkey2
  22. 0 0
      modules/mojo3d-physics/tests/assets/dummy.txt
  23. 210 0
      modules/mojo3d-physics/tests/fpsthing.monkey2
  24. 128 0
      modules/mojo3d-physics/tests/qcollide.monkey2
  25. 5 58
      modules/mojo3d-physics/tests/shapes.monkey2
  26. 14 12
      modules/mojo3d-physics/tests/util.monkey2
  27. 3 3
      modules/mojo3d/graphics/animator.monkey2
  28. 1 1
      modules/mojo3d/graphics/deferredrenderer.monkey2
  29. 63 63
      modules/mojo3d/graphics/entity.monkey2
  30. 167 170
      modules/mojo3d/graphics/entityexts.monkey2
  31. 11 5
      modules/mojo3d/graphics/gltf2loader.monkey2
  32. 6 3
      modules/mojo3d/graphics/mesh.monkey2
  33. 1 1
      modules/mojo3d/graphics/model.monkey2
  34. 7 7
      modules/mojo3d/graphics/renderer.monkey2
  35. 3 3
      modules/mojo3d/graphics/spritebuffer.monkey2
  36. 1 0
      modules/mojo3d/tests/cubetest.monkey2
  37. 3 2
      modules/mojo3d/tests/ducks.monkey2
  38. 10 5
      modules/monkey/monkey.monkey2
  39. 1 3
      modules/monkey/native/bbstring.h
  40. 9 0
      modules/monkey/native/bbstring.mm
  41. 3 0
      modules/sdl2/makefile_windows.monkey2
  42. 10 5
      modules/std/audio/load_wav.monkey2
  43. 9 11
      modules/std/filesystem/filesystem.monkey2
  44. 5 1
      modules/std/requesters/native/requesters_linux.cpp
  45. 34 7
      products/android/Monkey2Game/app/src/main/java/com/monkey2/lib/Monkey2Activity.java
  46. 5 5
      scripts/common.bat
  47. 12 12
      scripts/common.sh
  48. 2 0
      scripts/updatemods.bat
  49. 1 1
      scripts/updatemx2cc.sh
  50. 3 2
      src/createrelease/createrelease.monkey2
  51. 1 1
      src/mx2cc/mx2.monkey2
  52. 2 2
      src/mx2cc/mx2cc.monkey2
  53. 7 4
      src/mx2cc/test.monkey2
  54. 10 2
      src/mx2cc/value.monkey2
  55. 0 197
      src/ted2/bin/t.txt
  56. BIN=BIN
      src/ted2/bin/tmp.zip
  57. 62 4
      src/ted2go/MainWindow.monkey2
  58. 5 1
      src/ted2go/Prefs.monkey2
  59. 9 12
      src/ted2go/Ted2.monkey2
  60. BIN=BIN
      src/ted2go/assets/themes/hollow_assets/checkbox_icons.png
  61. BIN=BIN
      src/ted2go/assets/themes/hollow_assets/dialog_skin.png
  62. BIN=BIN
      src/ted2go/assets/themes/hollow_assets/progressbar_icons.png
  63. BIN=BIN
      src/ted2go/assets/themes/hollow_assets/tabclose_icons.png
  64. BIN=BIN
      src/ted2go/assets/themes/hollow_assets/treeview_icons.png
  65. BIN=BIN
      src/ted2go/assets/themes/irc/blink.png
  66. BIN=BIN
      src/ted2go/assets/themes/irc/important.png
  67. BIN=BIN
      src/ted2go/assets/themes/irc/notice.png
  68. BIN=BIN
      src/ted2go/assets/themes/prime_assets/button_skin.png
  69. BIN=BIN
      src/ted2go/assets/themes/prime_assets/square.png
  70. BIN=BIN
      src/ted2go/assets/themes/prime_assets/tabbutton_skin.png
  71. 474 0
      src/ted2go/assets/themes/theme-hollow.json
  72. 28 19
      src/ted2go/assets/themes/theme-prime-base.json
  73. 2 1
      src/ted2go/assets/themes/theme-smooth.json
  74. 1 0
      src/ted2go/assets/themes/themes.json
  75. 6 1
      src/ted2go/dialog/PrefsDialog.monkey2
  76. 67 1
      src/ted2go/dialog/UpdateModulesDialog.monkey2
  77. 225 30
      src/ted2go/view/IRCView.monkey2

+ 2 - 0
.gitignore

@@ -52,3 +52,5 @@ Monkey2 (Linux)
 
 
 /src/c2mx2/LLVM
 /src/c2mx2/LLVM
 /src/mx23d
 /src/mx23d
+
+/modules/mojo3d-physics/tests/assets/E1M1_clean.obj

+ 2 - 2
ABOUT.HTML

@@ -45,7 +45,7 @@ a:hover{
 
 
 <body>
 <body>
 
 
-<h1>Monkey2 v1.1.05b</h1>
+<h1>Monkey2 v1.1.06</h1>
 
 
 <p>Welcome to monkey2, an open source, user friendly, cross platform programming language by Mark Sibly.
 <p>Welcome to monkey2, an open source, user friendly, cross platform programming language by Mark Sibly.
 
 
@@ -171,7 +171,7 @@ Christian Leth Jeppesen!,
 Rene Damm,
 Rene Damm,
 Richard McLoughlin,
 Richard McLoughlin,
 Kennie,
 Kennie,
- ussell King,
+Russell King,
 gcmartijn,
 gcmartijn,
 Darryl,
 Darryl,
 Michael Hauck,
 Michael Hauck,

+ 9 - 1
VERSIONS.TXT

@@ -1,10 +1,18 @@
 
 
-***** Monkey2 v1.1.05c *****
+***** Monkey2 v1.1.06 *****
 
 
 * App no longer renders when minimized/inactive.
 * App no longer renders when minimized/inactive.
 
 
 * Added 'Internal' decl visibility to mx2cc, which means a decl is only visible to other decls within the same module.
 * Added 'Internal' decl visibility to mx2cc, which means a decl is only visible to other decls within the same module.
 
 
+* Namespace mojo3d now uses degrees. Namespaces monkey.math and std.geom still use radians.
+
+* Mx2cc now tries to make docs for type extensions. No way to link to 'em yet. 
+
+* Entity Position, Basis, Scale, Matrix etc properties are now in *world* space. Use LocalPosition, LocalBasis etc for local space versions. Ditto SetPosition, Setbasis, SetScale etc methods.
+
+* Added subclasses for RigidBody: StaticBody, DynamicBody and KinematicBody, use these with New instead of RigidBody.
+
 
 
 ***** Monkey2 v1.1.05b *****
 ***** Monkey2 v1.1.05b *****
 
 

+ 7 - 3
bin/env_windows.txt

@@ -37,11 +37,15 @@ MX2_CPP_OPTS_WINDOWS_RELEASE=-O3 -DNDEBUG
 
 
 MX2_USE_MSVC=0
 MX2_USE_MSVC=0
 
 
+'https://en.wikipedia.org/wiki/Microsoft_Windows_SDK
+'
+MX2_WINDOWS_KIT=10.0.15063.0
+
 PATH=${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC\bin;${PATH}
 PATH=${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC\bin;${PATH}
 
 
-INCLUDE=${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC\INCLUDE;${ProgramFiles(x86)}\Windows Kits\10\include\10.0.10586.0\ucrt;${ProgramFiles(x86)}\Windows Kits\10\include\10.0.10586.0\um;${ProgramFiles(x86)}\Windows Kits\10\include\10.0.10586.0\shared;
+INCLUDE=${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC\INCLUDE;${ProgramFiles(x86)}\Windows Kits\10\include\${MX2_WINDOWS_KIT}\ucrt;${ProgramFiles(x86)}\Windows Kits\10\include\${MX2_WINDOWS_KIT}\um;${ProgramFiles(x86)}\Windows Kits\10\include\${MX2_WINDOWS_KIT}\shared;
 
 
-LIB=${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC\LIB;${ProgramFiles(x86)}\Windows Kits\10\lib\10.0.10586.0\ucrt\x86;${ProgramFiles(x86)}\Windows Kits\10\lib\10.0.10586.0\um\x86;
+LIB=${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC\LIB;${ProgramFiles(x86)}\Windows Kits\10\lib\${MX2_WINDOWS_KIT}\ucrt\x86;${ProgramFiles(x86)}\Windows Kits\10\lib\${MX2_WINDOWS_KIT}\um\x86;
 
 
 'Linker options
 'Linker options
 MX2_LD_OPTS_MSVC=
 MX2_LD_OPTS_MSVC=
@@ -99,7 +103,7 @@ MX2_ANDROID_APP_ABI=armeabi-v7a x86
 
 
 'Controls APP_PLATFORM in Application.mk for NDK
 'Controls APP_PLATFORM in Application.mk for NDK
 '
 '
-MX2_ANDROID_APP_PLATFORM=10
+MX2_ANDROID_APP_PLATFORM=android-14
 
 
 
 
 '***** RASPBIAN *****
 '***** RASPBIAN *****

BIN=BIN
bin/mx2cc_linux


BIN=BIN
bin/mx2cc_macos


BIN=BIN
bin/mx2cc_windows.exe


+ 3 - 1
modules/assimp/assimp/MARKS_FIXES.TXT

@@ -1,4 +1,6 @@
 
 
 Tweaked include/assimp.config.h to #define some stuff like BUILD_DLL etc.
 Tweaked include/assimp.config.h to #define some stuff like BUILD_DLL etc.
 
 
-Changed pushpack1.h to use __MINGW32__ instead of HOST_MINGW
+Changed pushpack1.h to use __MINGW32__ instead of HOST_MINGW
+
+Added #include <unistd.h> to gzguts.h in zlib for LSEEK fix.

+ 4 - 0
modules/assimp/assimp/contrib/zlib/gzguts.h

@@ -27,6 +27,10 @@
 #endif
 #endif
 #include <fcntl.h>
 #include <fcntl.h>
 
 
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
 #ifdef _WIN32
 #ifdef _WIN32
 #  include <stddef.h>
 #  include <stddef.h>
 #endif
 #endif

+ 25 - 7
modules/jni/jni.monkey2

@@ -10,27 +10,30 @@ Extern
 
 
 Struct _jclass
 Struct _jclass
 End
 End
-
 Alias jclass:_jclass Ptr
 Alias jclass:_jclass Ptr
 
 
 Struct _jobject
 Struct _jobject
 End
 End
-
 Alias jobject:_jobject Ptr
 Alias jobject:_jobject Ptr
 
 
 Struct _jstring
 Struct _jstring
 End
 End
-
 Alias jstring:_jstring Ptr
 Alias jstring:_jstring Ptr
 
 
-Struct _jfieldID
+Struct _jarray
+End
+Alias jarray:_jarray Ptr
+
+Struct _jobjectArray
 End
 End
+Alias jobjectArray:_jobjectArray Ptr
 
 
+Struct _jfieldID
+End
 Alias jfieldID:_jfieldID Ptr
 Alias jfieldID:_jfieldID Ptr
 
 
 Struct _jmethodID
 Struct _jmethodID
 End
 End
-
 Alias jmethodID:_jmethodID Ptr
 Alias jmethodID:_jmethodID Ptr
 
 
 Class JNIEnv Extends Void
 Class JNIEnv Extends Void
@@ -48,8 +51,15 @@ Class JNIEnv Extends Void
 	'fields...
 	'fields...
 	'
 	'
 	Method GetFieldID:jfieldID( clazz:jclass,name:CString,sig:CString )
 	Method GetFieldID:jfieldID( clazz:jclass,name:CString,sig:CString )
-	
+		
+	Method GetBooleanField:Bool( obj:jobject,fieldID:jfieldID )
+		
+	Method GetIntField:Int( obj:jobject,fieldID:jfieldID )
+		
 	Method GetObjectField:jobject( obj:jobject,fieldID:jfieldID )
 	Method GetObjectField:jobject( obj:jobject,fieldID:jfieldID )
+
+	Method GetStringField:String( obj:jobject,fieldID:jfieldID ) Extension="bbJNI::GetStringField"
+		
 	
 	
 	'static fields...
 	'static fields...
 	
 	
@@ -65,10 +75,12 @@ Class JNIEnv Extends Void
 	
 	
 	Method CallBooleanMethod:Bool( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallBooleanMethod"
 	Method CallBooleanMethod:Bool( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallBooleanMethod"
 
 
-	Method CallStringMethod:String( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStringMethod"
+	Method CallIntMethod:Int( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallIntMethod"
 
 
 	Method CallObjectMethod:jobject( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallObjectMethod"
 	Method CallObjectMethod:jobject( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallObjectMethod"
 	
 	
+	Method CallStringMethod:String( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStringMethod"
+
 	'static methods...
 	'static methods...
 	'
 	'
 	Method GetStaticMethodID:jmethodID( clazz:jclass,name:CString,sig:CString )
 	Method GetStaticMethodID:jmethodID( clazz:jclass,name:CString,sig:CString )
@@ -77,6 +89,8 @@ Class JNIEnv Extends Void
 
 
 	Method CallStaticBooleanMethod:Bool( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticBooleanMethod"
 	Method CallStaticBooleanMethod:Bool( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticBooleanMethod"
 
 
+	Method CallStaticIntMethod:int( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticIntMethod"
+
 	Method CallStaticStringMethod:String( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticStringMethod"
 	Method CallStaticStringMethod:String( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticStringMethod"
 	
 	
 	Method CallStaticObjectMethod:jobject( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticObjectMethod"
 	Method CallStaticObjectMethod:jobject( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticObjectMethod"
@@ -87,6 +101,10 @@ Class JNIEnv Extends Void
 		
 		
 	Method NewObject:jobject( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::NewObject"
 	Method NewObject:jobject( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::NewObject"
 		
 		
+	Method NewObjectArray:jobjectArray( length:Int,clazz:jclass,init:jobject )
+		
+	Method SetObjectArrayElement( jarray:jobjectArray,index:Int,value:jobject )
+		
 	'refs...
 	'refs...
 	'
 	'
 	Method NewGlobalRef:jobject( obj:jobject )
 	Method NewGlobalRef:jobject( obj:jobject )

+ 91 - 25
modules/jni/native/jni_glue.cpp

@@ -3,30 +3,6 @@
 
 
 namespace bbJNI{
 namespace bbJNI{
 
 
-	bbString JStringToString( JNIEnv *env,jstring jstr ){
-	
-		const char *cstr=env->GetStringUTFChars( jstr,0 );
-		
-		bbString str=bbString::fromCString( cstr );
-		
-		env->ReleaseStringUTFChars( jstr,cstr );
-		
-		return str;
-	}
-	
-	jstring StringToJString( JNIEnv *env,bbString str ){
-	
-		int n=str.utf8Length()+1;
-		
-		char *buf=new char[n];
-		
-		str.toCString( buf,n );
-		
-		jstring jstr=env->NewStringUTF( buf );
-		
-		return jstr;
-	}
-
 	jvalue *makeArgs( JNIEnv *env,bbArray<bbVariant> args ){
 	jvalue *makeArgs( JNIEnv *env,bbArray<bbVariant> args ){
 	
 	
 		jvalue *jargs=new jvalue[args.length()];
 		jvalue *jargs=new jvalue[args.length()];
@@ -53,6 +29,12 @@ namespace bbJNI{
 				
 				
 				jarg->i=val;
 				jarg->i=val;
 			
 			
+			}else if( type==bbGetType<jobject>() ){
+			
+				jobject jobj=arg.get<jobject>();
+			
+				jarg->l=jobj;
+			
 			}else if( type==bbGetType<bbString>() ){
 			}else if( type==bbGetType<bbString>() ){
 			
 			
 				bbString str=arg.get<bbString>();
 				bbString str=arg.get<bbString>();
@@ -66,7 +48,39 @@ namespace bbJNI{
 				jstring jstr=env->NewStringUTF( buf );
 				jstring jstr=env->NewStringUTF( buf );
 				
 				
 				jarg->l=jstr;
 				jarg->l=jstr;
+/*				
+			}else if( type==bbGetType<bbArray<bbBool>>() ){
+			
+				bbArray<bbBool> arr=arg.get<bbArray<bbBool>>();
+				
+				jbooleanArray jarr=env->NewBooleanArray( arr.length() );
+				
+				jboolean *jdata=env->GetBooleanArrayElements( jarr,0 );
+				
+				memcpy( jdata,arr.data(),arr.length()*sizeof(bbBool) );
+				
+				env->ReleaseBooleanArrayElements( jarr,jdata,0 );
+				
+				jarg->l=(jobject)jarr;
+				
+			}else if( type==bbGetType<bbArray<bbInt>>() ){
+
+				bbArray<bbInt> arr=arg.get<bbArray<bbInt>>();
+				
+				jintArray jarr=env->NewIntArray( arr.length() );
+				
+				jint *jdata=env->GetIntArrayElements( jarr,0 );
+				
+				memcpy( jdata,arr.data(),arr.length()*sizeof(bbInt) );
+				
+				env->ReleaseIntArrayElements( jarr,jdata,0 );
+				
+				jarg->l=(jobject)jarr;
+			
+			}else if( type==bbGetType<bbArray<jobject>>() ){
 			
 			
+			}else if( type==bbGetType<bbArray<bbString>>() ){
+*/			
 			}else{
 			}else{
 			
 			
 				bbRuntimeError( "Can't evaluate JNI method param of typ:"+type->toString() );
 				bbRuntimeError( "Can't evaluate JNI method param of typ:"+type->toString() );
@@ -78,6 +92,37 @@ namespace bbJNI{
 		return jargs;
 		return jargs;
 	}
 	}
 	
 	
+	bbString JStringToString( JNIEnv *env,jstring jstr ){
+	
+		const char *cstr=env->GetStringUTFChars( jstr,0 );
+		
+		bbString str=bbString::fromCString( cstr );
+		
+		env->ReleaseStringUTFChars( jstr,cstr );
+		
+		return str;
+	}
+	
+	jstring StringToJString( JNIEnv *env,bbString str ){
+	
+		int n=str.utf8Length()+1;
+		
+		char *buf=new char[n];
+		
+		str.toCString( buf,n );
+		
+		jstring jstr=env->NewStringUTF( buf );
+		
+		return jstr;
+	}
+	
+	bbString GetStringField( JNIEnv *env,jobject obj,jfieldID fieldID ){
+	
+		jstring jstr=(jstring)env->GetObjectField( obj,fieldID );
+		
+		return JStringToString( env,jstr );
+	}
+
 	void CallVoidMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args ){
 	void CallVoidMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args ){
 		
 		
 		jvalue *jargs=makeArgs( env,args );
 		jvalue *jargs=makeArgs( env,args );
@@ -98,6 +143,17 @@ namespace bbJNI{
 		return r;
 		return r;
 	}
 	}
 
 
+	bbInt CallIntMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args ){
+		
+		jvalue *jargs=makeArgs( env,args );
+		
+		bbInt r=env->CallIntMethodA( obj,methodID,jargs );
+		
+		delete[] jargs;
+		
+		return r;
+	}
+
 	bbString CallStringMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args ){
 	bbString CallStringMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args ){
 		
 		
 		jvalue *jargs=makeArgs( env,args );
 		jvalue *jargs=makeArgs( env,args );
@@ -140,6 +196,17 @@ namespace bbJNI{
 		return r;
 		return r;
 	}
 	}
 	
 	
+	bbInt CallStaticIntMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args ){
+		
+		jvalue *jargs=makeArgs( env,args );
+		
+		bbInt r=env->CallStaticIntMethodA( clazz,methodID,jargs );
+		
+		delete[] jargs;
+		
+		return r;
+	}
+	
 	bbString CallStaticStringMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args ){
 	bbString CallStaticStringMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args ){
 		
 		
 		jvalue *jargs=makeArgs( env,args );
 		jvalue *jargs=makeArgs( env,args );
@@ -174,4 +241,3 @@ namespace bbJNI{
 	}
 	}
 	
 	
 }
 }
-

+ 11 - 4
modules/jni/native/jni_glue.h

@@ -5,11 +5,20 @@
 
 
 namespace bbJNI{
 namespace bbJNI{
 
 
+	bbString JStringToString( JNIEnv *env,jstring jstr );
+	
+	jstring StringToJString( JNIEnv *env,bbString str );
+	
+	
+	bbString GetStringField( JNIEnv *env,jobject obj,jfieldID fieldID );
+
 
 
 	void CallVoidMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 	void CallVoidMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 	
 	
 	bbBool CallBooleanMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 	bbBool CallBooleanMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 
 
+	bbInt CallIntMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
+
 	bbString CallStringMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 	bbString CallStringMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 
 
 	jobject CallObjectMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 	jobject CallObjectMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
@@ -19,6 +28,8 @@ namespace bbJNI{
 	
 	
 	bbBool CallStaticBooleanMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	bbBool CallStaticBooleanMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 
 
+	bbInt CallStaticIntMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
+
 	bbString CallStaticStringMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	bbString CallStaticStringMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 
 
 	jobject CallStaticObjectMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	jobject CallStaticObjectMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
@@ -27,8 +38,4 @@ namespace bbJNI{
 	jobject NewObject( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	jobject NewObject( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	
 	
 
 
-	bbString JStringToString( JNIEnv *env,jstring jstr );
-	
-	jstring StringToJString( JNIEnv *env,bbString str );
-
 }
 }

+ 1 - 0
modules/mojo/app/style.monkey2

@@ -6,6 +6,7 @@ Namespace mojo.app
 Class Style
 Class Style
 
 
 	Method New()
 	Method New()
+		_font=App.DefaultFont		
 	End
 	End
 	
 	
 	Method New( style:Style )
 	Method New( style:Style )

+ 7 - 5
modules/mojo3d-loaders/loaders/assimp.monkey2

@@ -55,6 +55,8 @@ Class AssimpLoader
 			
 			
 			Local aimesh:=_scene.mMeshes[i]
 			Local aimesh:=_scene.mMeshes[i]
 			
 			
+			If i=0 mesh.AddMaterials( 1 )
+			
 			LoadMesh( aimesh,mesh,Null,False )
 			LoadMesh( aimesh,mesh,Null,False )
 		Next
 		Next
 		
 		
@@ -73,7 +75,7 @@ Class AssimpLoader
 			
 			
 			Local aimesh:=_scene.mMeshes[i]
 			Local aimesh:=_scene.mMeshes[i]
 			
 			
-			If i mesh.AddMaterials( 1 )
+			mesh.AddMaterials( 1 )
 				
 				
 			LoadMesh( aimesh,mesh,Null,False )
 			LoadMesh( aimesh,mesh,Null,False )
 			
 			
@@ -234,9 +236,9 @@ Class AssimpLoader
 		Local rot:=matrix.m.Scale( 1/scl.x,1/scl.y,1/scl.z )
 		Local rot:=matrix.m.Scale( 1/scl.x,1/scl.y,1/scl.z )
 		Local pos:=matrix.t
 		Local pos:=matrix.t
 
 
-		model.Position=pos
-		model.Basis=rot
-		model.Scale=scl
+		model.LocalPosition=pos
+		model.LocalBasis=rot
+		model.LocalScale=scl
 		
 		
 		_nodes[ node.mName.data ]=model
 		_nodes[ node.mName.data ]=model
 		_entityIds[ node.mName.data ]=_entities.Length
 		_entityIds[ node.mName.data ]=_entities.Length
@@ -255,7 +257,7 @@ Class AssimpLoader
 			
 			
 			Local aimesh:=_scene.mMeshes[ node.mMeshes[i] ]
 			Local aimesh:=_scene.mMeshes[ node.mMeshes[i] ]
 			
 			
-			If i mesh.AddMaterials( 1 )
+			mesh.AddMaterials( 1 )
 			
 			
 			LoadMesh( aimesh,mesh,model,boned )
 			LoadMesh( aimesh,mesh,model,boned )
 			
 			

+ 4 - 4
modules/mojo3d-loaders/tests/assets/castle/CASTLE1.X

@@ -11,7 +11,7 @@ Material x3ds_mat_castlestone {
 0.898039, 0.898039, 0.898039;;
 0.898039, 0.898039, 0.898039;;
 0.000000, 0.000000, 0.000000;;
 0.000000, 0.000000, 0.000000;;
 TextureFilename {
 TextureFilename {
-"CASTLEST.JPG";
+"castlest.jpg";
 }
 }
 }
 }
 
 
@@ -21,7 +21,7 @@ Material x3ds_mat_Material__3 {
 0.898039, 0.898039, 0.898039;;
 0.898039, 0.898039, 0.898039;;
 0.000000, 0.000000, 0.000000;;
 0.000000, 0.000000, 0.000000;;
 TextureFilename {
 TextureFilename {
-"OLDBRIC.JPG";
+"oldbric.jpg";
 }
 }
 }
 }
 
 
@@ -31,7 +31,7 @@ Material x3ds_mat_shingle {
 0.898039, 0.898039, 0.898039;;
 0.898039, 0.898039, 0.898039;;
 0.000000, 0.000000, 0.000000;;
 0.000000, 0.000000, 0.000000;;
 TextureFilename {
 TextureFilename {
-"SHINGLE.JPG";
+"shingle.jpg";
 }
 }
 }
 }
 
 
@@ -41,7 +41,7 @@ Material x3ds_mat_Material__8 {
 0.898039, 0.898039, 0.898039;;
 0.898039, 0.898039, 0.898039;;
 0.000000, 0.000000, 0.000000;;
 0.000000, 0.000000, 0.000000;;
 TextureFilename {
 TextureFilename {
-"GOTHIC3.JPG";
+"gothic3.jpg";
 }
 }
 }
 }
 
 

BIN=BIN
modules/mojo3d-loaders/tests/assets/castle/stone2.jpg


BIN=BIN
modules/mojo3d-loaders/tests/assets/miramar-skybox.jpg


+ 4 - 1
modules/mojo3d-loaders/tests/castle.monkey2

@@ -9,6 +9,8 @@ Namespace myapp
 
 
 #Import "assets/"
 #Import "assets/"
 
 
+#Import "../../mojo3d/tests/assets/miramar-skybox.jpg"
+
 #Import "util"
 #Import "util"
 
 
 Using std..
 Using std..
@@ -55,7 +57,6 @@ Class MyWindow Extends Window
 		'create model
 		'create model
 		'		
 		'		
 		_model=Model.Load( "asset::castle/CASTLE1.X" )
 		_model=Model.Load( "asset::castle/CASTLE1.X" )
-'		_model=Model.Load( "asset::HOUSE.3DS" )
 '		_model=Model.Load( "desktop::Temple.3DS" )
 '		_model=Model.Load( "desktop::Temple.3DS" )
 '		_model=Model.Load( "desktop::FairyHouse/FairyHouse.3DS" )
 '		_model=Model.Load( "desktop::FairyHouse/FairyHouse.3DS" )
 		
 		
@@ -92,6 +93,8 @@ Class MyWindow Extends Window
 End
 End
 
 
 Function Main()
 Function Main()
+	
+	Print RealPath( "desktop::hello.png" )
 
 
 	New AppInstance
 	New AppInstance
 	
 	

+ 6 - 1
modules/mojo3d-physics/physics/collider.monkey2

@@ -21,6 +21,11 @@ Class Collider
 		_btshape.setMargin( margin )
 		_btshape.setMargin( margin )
 	End
 	End
 
 
+	Method CalculateLocalInertia:Vec3f( mass:Float )
+		
+		Return _btshape.calculateLocalInertia( mass )
+	End
+
 	Property btShape:btCollisionShape()
 	Property btShape:btCollisionShape()
 	
 	
 		Return _btshape
 		Return _btshape
@@ -155,7 +160,7 @@ Class MeshCollider Extends ConcaveCollider
 		
 		
 		Local shape:=New btBvhTriangleMeshShape( _btmesh,True,True )
 		Local shape:=New btBvhTriangleMeshShape( _btmesh,True,True )
 		
 		
-		CreateInternalEdgeInfo( shape )
+		'CreateInternalEdgeInfo( shape )
 		
 		
 		_btshape=shape
 		_btshape=shape
 	End
 	End

+ 187 - 96
modules/mojo3d-physics/physics/rigidbody.monkey2

@@ -22,10 +22,10 @@ Class KinematicMotionState Extends bbKinematicMotionState
 	
 	
 	Method GetWorldTransform:btTransform() Override
 	Method GetWorldTransform:btTransform() Override
 		
 		
-		Return _entity.WorldMatrix
+		Return _entity.Matrix
 	End
 	End
 	
 	
-	Private
+Private
 	
 	
 	Field _entity:Entity
 	Field _entity:Entity
 End
 End
@@ -34,35 +34,27 @@ End
 #end
 #end
 Class RigidBody
 Class RigidBody
 	
 	
-	#rem monkeydoc Creates a new rigid body.
-	#end
-	Method New( mass:Float,collider:Collider,entity:Entity,kinematic:Bool=False,collGroup:Int=1,collMask:Int=1 )
+	Method Init( collider:Collider,entity:Entity,mass:Float,collGroup:Int,collMask:Int,btmotion:btMotionState )
 		
 		
-		_mass=mass
+		Local inertia:btVector3=collider ? collider.CalculateLocalInertia( mass ) Else Null
+
+		_world=World.GetDefault()
 		_collider=collider
 		_collider=collider
 		_entity=entity
 		_entity=entity
-		_kinematic=kinematic
+		_mass=mass
 		_collGroup=collGroup
 		_collGroup=collGroup
 		_collMask=collMask
 		_collMask=collMask
-		
-		_world=World.GetDefault()
-		
-		If _kinematic
-			_btmotion=New KinematicMotionState( _entity )
-		Else
-			_btmotion=New btDefaultMotionState( _entity.WorldMatrix )
-		Endif
+		_btmotion=btmotion
 
 
-		Local inertia:btVector3=_collider ? _collider.btShape.calculateLocalInertia( _mass ) Else New btVector3( 0,0,0 )
-		
-		_btbody=New btRigidBody( _mass,_btmotion,_collider.btShape,inertia )
+		_btbody=New btRigidBody( mass,btmotion,collider.btShape,inertia )
 		
 		
-		If _kinematic 
-			_btbody.setCollisionFlags( _btbody.getCollisionFlags() | btCollisionObject.CF_KINEMATIC_OBJECT )
-			_btbody.setActivationState( DISABLE_DEACTIVATION )
-		Endif
-		
-		If Cast<MeshCollider>( _collider ) _btbody.setCollisionFlags( _btbody.getCollisionFlags() | btCollisionObject.CF_CUSTOM_MATERIAL_CALLBACK )
+		_btbody.setFriction( 1 )
+		_btbody.setRollingFriction( 1 )
+		_btbody.setRestitution( 0 )
+
+		'If Cast<MeshCollider>( _collider ) _btbody.setCollisionFlags( _btbody.getCollisionFlags() | btCollisionObject.CF_CUSTOM_MATERIAL_CALLBACK )
+			
+		If Not _entity Return
 
 
 		_entity.Shown+=Lambda()
 		_entity.Shown+=Lambda()
 		
 		
@@ -74,33 +66,19 @@ Class RigidBody
 			_world.Remove( Self )
 			_world.Remove( Self )
 		End
 		End
 		
 		
-		_entity.Copied+=Lambda( copy:Entity )
-		
-			Local body:=New RigidBody( Mass,Collider,copy )
-			
-			body.LinearVelocity=LinearVelocity
-			body.Restitution=Restitution
-			body.Friction=Friction
-			body.RollingFriction=RollingFriction
-		End
-		
 		If _entity.Visible _world.Add( Self )
 		If _entity.Visible _world.Add( Self )
-			
-		Restitution=0
-		Friction=1
-		RollingFriction=0
 	End
 	End
 
 
-	Property Mass:Float()
-		
-		Return _mass
-	End
-	
 	Property Collider:Collider()
 	Property Collider:Collider()
 		
 		
 		Return _collider
 		Return _collider
 	End
 	End
 	
 	
+	Property Entity:Entity()
+	
+		Return _entity
+	End
+	
 	Property CollisionGroup:Short()
 	Property CollisionGroup:Short()
 		
 		
 		Return _collGroup
 		Return _collGroup
@@ -111,18 +89,22 @@ Class RigidBody
 		Return _collMask
 		Return _collMask
 	End
 	End
 	
 	
-	Property Entity:Entity()
+	Property Friction:Float()
 	
 	
-		Return _entity
+		Return _btbody.getFriction()
+	
+	Setter( friction:Float )
+	
+		_btbody.setFriction( friction )
 	End
 	End
 	
 	
-	Property LinearVelocity:Vec3f()
+	Property RollingFriction:Float()
 	
 	
-		Return _btbody.getLinearVelocity()
+		Return _btbody.getRollingFriction()
 	
 	
-	Setter( velocity:Vec3f )
+	Setter( friction:Float )
 	
 	
-		_btbody.setLinearVelocity( velocity )
+		_btbody.setRollingFriction( friction )
 	End
 	End
 	
 	
 	Property Restitution:Float()
 	Property Restitution:Float()
@@ -134,22 +116,154 @@ Class RigidBody
 		_btbody.setRestitution( restitution )
 		_btbody.setRestitution( restitution )
 	End
 	End
 	
 	
-	Property Friction:Float()
+	Property btBody:btRigidBody()
 	
 	
-		Return _btbody.getFriction()
+		Return _btbody
+	End
+
+Protected
+
+	Field _world:World
+	Field _mass:Float	
+	Field _collider:Collider
+	Field _entity:Entity
+	Field _collGroup:Int
+	Field _collMask:Int
 	
 	
-	Setter( friction:Float )
+	Field _btmotion:btMotionState
+	Field _btbody:btRigidBody
+	Field _seq:Int
 	
 	
-		_btbody.setFriction( friction )
+	Method OnValidate() Virtual
 	End
 	End
 	
 	
-	Property RollingFriction:Float()
+	Method OnUpdate() Virtual
+	End
 	
 	
-		Return _btbody.getRollingFriction()
+Internal
+		
+	Method Validate()
+		
+		If _entity OnValidate()
+	End
 	
 	
-	Setter( friction:Float )
+	Method Update()
+		
+		If _entity OnUpdate()
+	End
 	
 	
-		_btbody.setRollingFriction( friction )
+End
+
+Class StaticBody Extends RigidBody
+	
+	Method New( collider:Collider,entity:Entity,collGroup:Int=1,collMask:Int=1 )
+		
+		Init( collider,entity,0,collGroup,collMask,Null )
+		
+		If entity entity.Copied+=Lambda( copy:Entity )
+		
+			Local body:=New StaticBody( collider,copy,collGroup,collMask )
+			
+			body.Friction=Friction
+			body.RollingFriction=RollingFriction
+			body.Restitution=Restitution
+		End
+		
+	End
+	
+Protected
+	
+	Method OnValidate() Override
+		
+		If _seq=_entity.Seq Return
+		
+		_btbody.setWorldTransform( _entity.Matrix )
+	End
+	
+	Method OnUpdate() Override
+		
+		_seq=_entity.Seq
+	End
+
+End
+
+Class KinematicBody Extends RigidBody
+	
+	Method New( collider:Collider,entity:Entity,collGroup:Int=1,collMask:Int=1 )
+
+		Init( collider,entity,0,collGroup,collMask,entity ? New KinematicMotionState( entity ) Else Null )
+
+		_btbody.setCollisionFlags( _btbody.getCollisionFlags() | btCollisionObject.CF_KINEMATIC_OBJECT )
+		_btbody.setActivationState( DISABLE_DEACTIVATION )
+		
+		If entity entity.Copied+=Lambda( copy:Entity )
+		
+			Local body:=New KinematicBody( collider,copy,collGroup,collMask )
+
+			body.Friction=Friction
+			body.RollingFriction=RollingFriction
+			body.Restitution=Restitution
+		End
+
+	End
+	
+Protected
+	
+	Method OnValidate() Override
+	End
+	
+	Method OnUpdate() Override
+	End
+	
+End
+
+Class DynamicBody Extends RigidBody
+
+	Method New( collider:Collider,entity:Entity,mass:Float=1,collGroup:Int=1,collMask:Int=1 )
+		
+		Init( collider,entity,mass,collGroup,collMask,entity ? New btDefaultMotionState( entity.Matrix ) Else null )
+			
+		If entity entity.Copied+=Lambda( copy:Entity )
+		
+			Local body:=New DynamicBody( collider,copy,mass,collGroup,collMask )
+
+			body.Gravity=Gravity
+			body.Friction=Friction
+			body.RollingFriction=RollingFriction
+			body.Restitution=Restitution
+		End
+	End
+	
+	Property Mass:Float()
+		
+		Return _mass
+	End
+	
+	Property Gravity:Vec3f()
+		
+		Return _btbody.getGravity()
+	
+	Setter( gravity:Vec3f )
+		
+		_btbody.setGravity( gravity )
+	End
+	
+	Property LinearVelocity:Vec3f()
+	
+		Return _btbody.getLinearVelocity()
+	
+	Setter( velocity:Vec3f )
+	
+		_btbody.setLinearVelocity( velocity )
+	End
+	
+	Property AngularVelocity:Vec3f()
+		
+		Return _btbody.getAngularVelocity()
+	
+	Setter( velocity:Vec3f )
+		
+		_btbody.setAngularVelocity( velocity )
 	End
 	End
 	
 	
 	Method ApplyForce( force:Vec3f,relativePos:Vec3f )
 	Method ApplyForce( force:Vec3f,relativePos:Vec3f )
@@ -172,65 +286,42 @@ Class RigidBody
 		_btbody.applyImpulse( impulse,relativePos )
 		_btbody.applyImpulse( impulse,relativePos )
 	End
 	End
 	
 	
-	Method ApplyTorqueImpulse( torque:Vec3f )
-		
-		_btbody.applyTorqueImpulse( torque )
-	End
-	
 	Method ApplyCentralImpulse( impulse:Vec3f )
 	Method ApplyCentralImpulse( impulse:Vec3f )
 		
 		
 		_btbody.applyCentralImpulse( impulse )
 		_btbody.applyCentralImpulse( impulse )
 	End
 	End
 	
 	
-	Function Get:RigidBody( btobject:btCollisionObject )
+	Method ApplyTorqueImpulse( torque:Vec3f )
 		
 		
-		Return Cast<RigidBody>( handle_to_object( btobject.getUserPointer() ) )
+		_btbody.applyTorqueImpulse( torque )
 	End
 	End
-
-	Internal
 	
 	
-	Property btBody:btRigidBody()
+Protected
 	
 	
-		Return _btbody
-	End
-	
-	Method Validate()
+	Method OnValidate() Override
+		
+		If _seq=_entity.Seq Return
+		
+		_btbody.clearForces()
+		
+		_btbody.setLinearVelocity( New Vec3f( 0 ) )
 		
 		
-		If _kinematic Or _seq=_entity.Seq Return
+		_btbody.setAngularVelocity( New Vec3f( 0 ) )
 		
 		
-		_btbody.setWorldTransform( _entity.WorldMatrix )
+		_btbody.setWorldTransform( _entity.Matrix )
 		
 		
-		_btmotion.setWorldTransform( _entity.WorldMatrix )
+		_btmotion.setWorldTransform( _entity.Matrix )
 	End
 	End
 	
 	
-	Method Update()
+	Method OnUpdate() Override
 		
 		
-		If _kinematic Return
-	
 		Local tform:=_btmotion.getWorldTransform()
 		Local tform:=_btmotion.getWorldTransform()
 		
 		
-		_entity.WorldPosition=tform.getOrigin()
+		_entity.Position=tform.getOrigin()
 		
 		
-		_entity.WorldBasis=tform.getBasis()
+		_entity.Basis=tform.getBasis()
 		
 		
 		_seq=_entity.Seq
 		_seq=_entity.Seq
 	End
 	End
-	
-Private
-
-	Field _self:RigidBody
 
 
-	Field _mass:Float	
-	Field _collider:Collider
-	Field _entity:Entity
-	Field _kinematic:Bool
-	Field _collGroup:Int
-	Field _collMask:Int
-	Field _world:World
-	Field _seq:Int
-	
-	Field _btmotion:btMotionState
-	Field _btbody:btRigidBody
-	
 End
 End
-

+ 14 - 14
modules/mojo3d-physics/physics/world.monkey2

@@ -21,22 +21,22 @@ Class RaycastResult
 	Method New()
 	Method New()
 	End
 	End
 	
 	
-	Method New( btresult:btCollisionWorld.ClosestRayResultCallback )
-		time=btresult.m_closestHitFraction
-		body=Cast<RigidBody>( handle_to_object( btresult.m_collisionObject.getUserPointer() ) )
-		point=btresult.m_hitPointWorld
-		normal=btresult.m_hitNormalWorld
+	Method New( btresult:btCollisionWorld.ClosestRayResultCallback Ptr )
+		time=btresult->m_closestHitFraction
+		body=Cast<RigidBody>( handle_to_object( btresult->m_collisionObject.getUserPointer() ) )
+		point=btresult->m_hitPointWorld
+		normal=btresult->m_hitNormalWorld
 	End
 	End
 	
 	
-	Method New( btresult:btCollisionWorld.ClosestConvexResultCallback )
+	Method New( btresult:btCollisionWorld.ClosestConvexResultCallback Ptr )
 		
 		
-		Local castFrom:=Cast<Vec3f>( btresult.m_convexFromWorld )
-		Local castTo:=Cast<Vec3f>( btresult.m_convexToWorld )
+		Local castFrom:=Cast<Vec3f>( btresult->m_convexFromWorld )
+		Local castTo:=Cast<Vec3f>( btresult->m_convexToWorld )
 		
 		
-		time=btresult.m_closestHitFraction
-		body=Cast<RigidBody>( handle_to_object( btresult.m_hitCollisionObject.getUserPointer() ) )
-		point=(castTo-castFrom) * btresult.m_closestHitFraction + castFrom
-		normal=btresult.m_hitNormalWorld
+		time=btresult->m_closestHitFraction
+		body=Cast<RigidBody>( handle_to_object( btresult->m_hitCollisionObject.getUserPointer() ) )
+		point=(castTo-castFrom) * btresult->m_closestHitFraction + castFrom
+		normal=btresult->m_hitNormalWorld
 	End
 	End
 	
 	
 End
 End
@@ -92,7 +92,7 @@ Class World
 		
 		
 		If Not btresult.hasHit() Return Null
 		If Not btresult.hasHit() Return Null
 		
 		
-		Return New RaycastResult( btresult )
+		Return New RaycastResult( Varptr btresult )
 	End
 	End
 	
 	
 	Method ConvexSweep:RaycastResult( collider:ConvexCollider,castFrom:AffineMat4f,castTo:AffineMat4f )
 	Method ConvexSweep:RaycastResult( collider:ConvexCollider,castFrom:AffineMat4f,castTo:AffineMat4f )
@@ -103,7 +103,7 @@ Class World
 		
 		
 		If Not btresult.hasHit() Return Null
 		If Not btresult.hasHit() Return Null
 		
 		
-		Return New RaycastResult( btresult )
+		Return New RaycastResult( Varptr btresult )
 		
 		
 	End
 	End
 	
 	

+ 0 - 0
modules/mojo3d-physics/tests/assets/dummy.txt


+ 210 - 0
modules/mojo3d-physics/tests/fpsthing.monkey2

@@ -0,0 +1,210 @@
+Namespace myapp
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+#Import "<mojo3d-loaders>"
+#Import "<mojo3d-physics>"
+
+#Import "assets/"
+
+#Import "../../mojo3d/tests/assets/miramar-skybox.jpg"
+
+#Import "../../mojo3d-loaders/tests/assets/castle/@/castle"
+
+#Import "util"
+
+#Import "qcollide"
+
+Using std..
+Using mojo..
+Using mojo3d..
+
+Const GRAVITY:=30	'coz reality sux!
+
+Class Player
+	
+	Field _model:Model
+	
+	Field _collider:ConvexCollider
+	
+	Field _paused:Bool
+	
+	Field _onground:Bool
+	
+	Field _yvel:Float
+	
+	Method New( radius:Float=.5,height:Float=1 )
+		
+		_model=Model.CreateCapsule( radius,height,Axis.Y,12,New PbrMaterial( Color.Sky ) )
+
+'		_model.Move( 0,0,0 )
+		
+		_collider=New CapsuleCollider( radius,height,Axis.Y )
+		
+		_collider.Margin=.01
+	End
+	
+	Method Update()
+		
+		Local src:=_model.Position
+		
+		Move()
+		
+		If _paused Return
+		
+		Local qresult:=qcollide.QCollide( _collider,src,_model.Position )
+
+		_model.Position=qresult.position
+		
+		src=_model.Position
+		
+		If _onground _yvel=-_collider.Margin
+			
+		_yvel-=GRAVITY/60.0/60.0
+
+		_model.MoveY( _yvel )
+
+		qresult=qcollide.QCollide( _collider,src,_model.Position )
+
+		_model.Position=qresult.position
+		
+		_yvel=_model.Position.y-src.y
+		
+		_onground=qresult.onground
+	End
+	
+	Method Move()
+		
+		If Keyboard.KeyDown( Key.Left )
+			
+			_model.RotateY( 2.5 )
+			
+		Else If Keyboard.KeyDown( Key.Right )
+			
+			_model.RotateY( -2.5 )
+		Endif
+
+		If _paused
+			
+			If Keyboard.KeyDown( Key.Up )
+				
+				_model.MoveY( .25 )
+				
+			Else If Keyboard.KeyDown( Key.Down )
+				
+				_model.MoveY( -.25 )
+				
+			Endif
+		Endif
+		
+		If Keyboard.KeyDown( Key.A )
+			
+			_model.MoveZ( .15 )
+			
+		Else If Keyboard.KeyDown( Key.Z )
+			
+			_model.MoveZ( -.15 )
+		Endif
+		
+		If Keyboard.KeyHit( Key.Space )
+			
+			_onground=False
+			
+			_yvel=.25
+		Endif
+		
+	End
+	
+End
+
+Class MyWindow Extends Window
+	
+	Field _scene:Scene
+	
+	Field _camera:Camera
+	
+	Field _light:Light
+	
+	Field _castle:Model
+	
+	Field _player:Player
+	
+	Field _sphere:SphereCollider
+	
+	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
+
+		Super.New( title,width,height,flags )
+		
+		
+		Print New Vec3f( 0,1,0 ).Cross( New Vec3f( 0,1,0 ) )
+		
+		_scene=Scene.GetCurrent()
+		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
+		
+		'create light
+		'
+		_light=New Light
+		_light.Rotate( 60,60,0 )	'aim directional light 'down' - Pi/2=90 degrees.
+		_light.ShadowsEnabled=False
+		
+		'Load castle
+		'
+		Local sz:=50
+		
+'		_castle=Model.Load( "asset::E1M1_clean.obj" )	'On the off chance you've got this...have no idea of license issues though.
+		_castle=Model.Load( "asset::castle/CASTLE1.X" )
+
+		_castle.Mesh.FitVertices( New Boxf( -sz,sz ),True )
+		
+		Local collider:=New MeshCollider( _castle.Mesh )
+		
+		Local body:=New StaticBody( collider,_castle,1,1 )
+		
+		'create player
+		'
+		_player=New Player( .75,.5 )
+		
+		'create camera
+		'
+		_camera=New Camera
+		_camera.Near=.1
+		_camera.Far=200
+		
+		_sphere=New SphereCollider( .2 )
+
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+		
+		RequestRender()
+		
+		If Keyboard.KeyHit( Key.Enter ) _player._paused=Not _player._paused
+		
+		_player.Update()
+
+		World.GetDefault().Update()
+		
+		Local src:=_player._model.Matrix * New Vec3f( 0,1,0 )
+		
+		Local dst:=_player._model.Matrix * New Vec3f( 0,1.5,-2.5 )
+		
+		_camera.Position=dst
+		
+		_camera.PointAt( _player._model.Position+New Vec3f( 0,1.5,0 ) )
+		
+		_scene.Render( canvas,_camera )
+		
+'		canvas.DrawText( "position="+_player._model.Position+", Rx="+_player._model.Rx+", Width="+Width+", Height="+Height+", FPS="+App.FPS,0,0 )
+	End
+	
+End
+
+Function Main()
+	
+	New AppInstance
+	
+	New MyWindow
+	
+	App.Run()
+End

+ 128 - 0
modules/mojo3d-physics/tests/qcollide.monkey2

@@ -0,0 +1,128 @@
+
+Namespace qcollide
+
+Private
+
+Function F:String( f:Float )
+	If f>=0 
+		Local i:Int=Floor( f*100+.5 )
+		Return String( i / 100 ) + "." + ("00"+String( i Mod 100 )).Slice( -2 )
+	Else
+		Local i:Int=Floor( -f*100+.5 )
+		Return "-"+String( i / 100 ) + "." + ("00"+String( i Mod 100 )).Slice( -2 )
+	Endif
+End
+
+Function V:String( V:Vec3f )
+	'Return String(V)
+	Return "("+F(V.x)+","+F(V.y)+","+F(V.z)+")"
+End
+
+Function P:String( P:Planef )
+	Return "("+F(P.n.x)+","+F(P.n.y)+","+F(P.n.z)+","+F(P.d)+")"
+End
+
+Public
+
+Struct QResult
+	Field position:Vec3f
+	Field onground:Bool
+End
+
+Function QCollide:QResult( collider:ConvexCollider,src:Vec3f,dst:Vec3f )
+	
+	Local start:=src
+	
+	Local plane0:Planef,plane1:Planef,state:=0,casts:=0
+	
+	Local qresult:QResult
+	
+	Local debug:=""
+	
+	Repeat
+
+		If dst.Distance( src )<.001 Exit
+		
+		casts+=1
+		
+		Local cresult:=World.GetDefault().ConvexSweep( collider,src,dst )
+		If Not cresult Exit
+
+'		debug+=", "
+		
+		If cresult.normal.y>.7071 qresult.onground=True
+			
+		Local plane:=New Planef( cresult.point,cresult.normal )
+
+		plane.d-=collider.Margin
+		
+		Local tline:=New Linef( src,dst-src )
+		
+		Local t:=plane.TIntersect( tline )
+		
+		If t>=1 dst=tline * t ; Exit
+		
+		If t>0 src=tline * t
+		
+		Select state
+
+		Case 0
+			
+			dst=plane.Nearest( dst )
+			
+'			debug+="A "+P( plane )
+				
+			plane0=plane
+				
+			state=1
+		
+		Case 1
+
+			Local v:=plane0.n.Cross( plane.n )
+			
+			If v.Length>.0001
+				
+				Local groove:=New Linef( src,v )
+				
+'				Local d0:=plane0.Distance( dst )
+				
+				dst=groove.Nearest( dst )
+				
+'				debug+="B "+P( plane )+" d0="+F(d0)+" sd0="+F(plane0.Distance(src))+" dd0="+F(plane0.Distance(dst))
+				
+				plane1=plane
+				
+				state=2
+			
+			Else
+				
+'				debug+="C "+P( plane )
+
+				dst=plane.Nearest( dst )
+
+				plane0=plane
+				
+				state=1
+			
+			Endif
+				
+		Case 2
+
+'			Local d0:=plane0.Distance( dst )
+'			Local d1:=plane1.Distance( dst )
+'			debug+="D "+P( plane )+" d0="+F(d0)+" d1="+F(d1)
+				
+			dst=src
+			
+			Exit
+		End
+
+	Forever
+	
+'	If casts>2 Print debug.Slice( 2 )+" casts="+casts
+
+	qresult.position=dst
+	
+	Return qresult
+
+End

+ 5 - 58
modules/mojo3d-physics/tests/shapes.monkey2

@@ -14,37 +14,6 @@ Using std..
 Using mojo..
 Using mojo..
 Using mojo3d..
 Using mojo3d..
 
 
-Function Randomize( model:Model )
-	
-	Local vertices:=model.Mesh.GetVertices()
-	
-	Local indices:=model.Mesh.GetAllIndices()
-	
-	Local mesh:=New Mesh
-	
-	mesh.AddVertices( vertices )
-	
-	mesh.AddMaterials( 9 )
-	
-	Local materials:=New Material[10]
-	
-	For Local i:=0 Until 10
-
-		materials[i]=New PbrMaterial( New Color( Rnd(),Rnd(),Rnd() ) )
-	
-	Next
-	
-	For Local i:=0 Until indices.Length Step 3
-		
-		mesh.AddTriangles( New UInt[]( indices[i],indices[i+1],indices[i+2] ),Rnd(10) )
-	
-	Next
-	
-	model.Mesh=mesh
-	
-	model.Materials=materials
-End
-
 Class MyWindow Extends Window
 Class MyWindow Extends Window
 	
 	
 	Field _scene:Scene
 	Field _scene:Scene
@@ -55,8 +24,6 @@ Class MyWindow Extends Window
 	
 	
 	Field _ground:Model
 	Field _ground:Model
 	
 	
-	Field _sphere:Model
-	
 	Field _collider:SphereCollider
 	Field _collider:SphereCollider
 	
 	
 	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
 	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
@@ -74,8 +41,8 @@ Class MyWindow Extends Window
 		_camera.Far=60
 		_camera.Far=60
 		_camera.Move( 0,10,-10 )
 		_camera.Move( 0,10,-10 )
 		
 		
-		New RigidBody( 0,New SphereCollider( 1 ),_camera,True )
-
+		New KinematicBody( New SphereCollider( 1 ),_camera )
+		
 		'create fog
 		'create fog
 		'		
 		'		
 		Local fog:=New FogEffect
 		Local fog:=New FogEffect
@@ -86,7 +53,7 @@ Class MyWindow Extends Window
 		'create light
 		'create light
 		'
 		'
 		_light=New Light
 		_light=New Light
-		_light.RotateX( Pi/2 )	'aim directional light 'down' - Pi/2=90 degrees.
+		_light.RotateX( 90 )	'aim directional light 'down'.
 		
 		
 		'create ground
 		'create ground
 		'
 		'
@@ -94,19 +61,10 @@ Class MyWindow Extends Window
 		
 		
 		_ground=Model.CreateBox( groundBox,16,16,16,New PbrMaterial( Color.Green ) )
 		_ground=Model.CreateBox( groundBox,16,16,16,New PbrMaterial( Color.Green ) )
 		
 		
-'		Randomize( _ground )
-		
-'		Local collider:Collider=New MeshCollider( _ground.Mesh )	'UGH - FIXME!
 		Local collider:Collider=New BoxCollider( groundBox )
 		Local collider:Collider=New BoxCollider( groundBox )
 		
 		
-		Local body:=New RigidBody( 0,collider,_ground )
+		Local body:=New StaticBody( collider,_ground )
 
 
-		_sphere=Model.CreateSphere( .5,24,12,New PbrMaterial( Color.White ) )
-		
-		_collider=New SphereCollider( .5 )
-		
-'		Return
-		
 		'create some meshes/colliders
 		'create some meshes/colliders
 		
 		
 		Local meshes:=New Mesh[5]
 		Local meshes:=New Mesh[5]
@@ -139,7 +97,7 @@ Class MyWindow Extends Window
 				Local model:=New Model( mesh,material )
 				Local model:=New Model( mesh,material )
 				model.Move( x,10,z )
 				model.Move( x,10,z )
 				
 				
-				Local body:=New RigidBody( 1,colliders[i],model )
+				Local body:=New DynamicBody( colliders[i],model )
 				
 				
 			Next
 			Next
 		
 		
@@ -152,17 +110,6 @@ Class MyWindow Extends Window
 		RequestRender()
 		RequestRender()
 		
 		
 		util.Fly( _camera,Self )
 		util.Fly( _camera,Self )
-		
-'		Local cresult:=World.GetDefault().ConvexSweep( _collider,_camera.Position,_camera.Position+_camera.Basis.k * 100 )
-
-		Local cresult:=World.GetDefault().ConvexSweep( _collider,_camera.Position+_camera.Basis.k * 2,_camera.Position+_camera.Basis.k * 100 )
-		
-		'Local cresult:=World.GetDefault().RayCast( _camera.Position,_camera.Position+_camera.Basis.k * 100 )
-		
-		If cresult 
-			Print "pos="+cresult.point
-			_sphere.Position=cresult.point'+cresult.normal
-		Endif
 			
 			
 		World.GetDefault().Update()
 		World.GetDefault().Update()
 		
 		

+ 14 - 12
modules/mojo3d-physics/tests/util.monkey2

@@ -2,30 +2,32 @@
 Namespace util
 Namespace util
 
 
 Function Fly( entity:Entity,view:View )
 Function Fly( entity:Entity,view:View )
+	
+	Const rspeed:=2.0
 
 
 	If Keyboard.KeyDown( Key.Up )
 	If Keyboard.KeyDown( Key.Up )
-		entity.RotateX( .05 )
+		entity.RotateX( rspeed )
 	Else If Keyboard.KeyDown( Key.Down )
 	Else If Keyboard.KeyDown( Key.Down )
-		entity.RotateX( -.05 )
+		entity.RotateX( -rspeed )
 	Endif
 	Endif
 	
 	
-	If Keyboard.KeyDown( Key.Left )
-		entity.RotateY( .025,True )
-	Else If Keyboard.KeyDown( Key.Right )
-		entity.RotateY( -.025,True )
-	Endif
-
 	If Keyboard.KeyDown( Key.Q )
 	If Keyboard.KeyDown( Key.Q )
-		entity.RotateZ( .01 )
+		entity.RotateZ( rspeed )
 	Else If Keyboard.KeyDown( Key.W )
 	Else If Keyboard.KeyDown( Key.W )
-		entity.RotateZ( -.01 )
+		entity.RotateZ( -rspeed )
 	Endif
 	Endif
 	
 	
+	If Keyboard.KeyDown( Key.Left )
+		entity.RotateY( rspeed,True )
+	Else If Keyboard.KeyDown( Key.Right )
+		entity.RotateY( -rspeed,True )
+	Endif
+
 	If Mouse.ButtonDown( MouseButton.Left )
 	If Mouse.ButtonDown( MouseButton.Left )
 		If Mouse.X<view.Width/3
 		If Mouse.X<view.Width/3
-			entity.RotateY( .1,True )
+			entity.RotateY( rspeed,True )
 		Else If Mouse.X>view.Width/3*2
 		Else If Mouse.X>view.Width/3*2
-			entity.RotateY( -.1,True )
+			entity.RotateY( -rspeed,True )
 		Else
 		Else
 			entity.Move( New Vec3f( 0,0,.1 ) )
 			entity.Move( New Vec3f( 0,0,.1 ) )
 		Endif
 		Endif

+ 3 - 3
modules/mojo3d/graphics/animator.monkey2

@@ -39,9 +39,9 @@ Class Animator
 			Local channel:=animation.Channels[i]
 			Local channel:=animation.Channels[i]
 			If Not channel continue
 			If Not channel continue
 			
 			
-			_entities[i].Position=channel.GetPosition( time )
-			_entities[i].Basis=New Mat3f( channel.GetRotation( time ) )
-			_entities[i].Scale=channel.GetScale( time )
+			_entities[i].LocalPosition=channel.GetPosition( time )
+			_entities[i].LocalBasis=New Mat3f( channel.GetRotation( time ) )
+			_entities[i].LocalScale=channel.GetScale( time )
 		End
 		End
 		
 		
 	End
 	End

+ 1 - 1
modules/mojo3d/graphics/deferredrenderer.monkey2

@@ -43,7 +43,7 @@ Class DeferredRenderer Extends Renderer
 	
 	
 		_uniforms.SetVec4f( "LightColor",light.Color )
 		_uniforms.SetVec4f( "LightColor",light.Color )
 		_uniforms.SetFloat( "LightRange",light.Range )
 		_uniforms.SetFloat( "LightRange",light.Range )
-		_uniforms.SetMat4f( "LightViewMatrix",_camera.InverseWorldMatrix * light.WorldMatrix )
+		_uniforms.SetMat4f( "LightViewMatrix",_camera.InverseMatrix * light.Matrix )
 		
 		
 		_uniforms.SetMat4f( "InverseProjectionMatrix",-_camera.ProjectionMatrix )
 		_uniforms.SetMat4f( "InverseProjectionMatrix",-_camera.ProjectionMatrix )
 		
 		

+ 63 - 63
modules/mojo3d/graphics/entity.monkey2

@@ -137,7 +137,7 @@ Class Entity
 	
 	
 	Setter( visible:Bool )
 	Setter( visible:Bool )
 		
 		
-		If _visible Show() Else Hide()
+		If visible Show() Else Hide()
 	End
 	End
 
 
 	#rem monkeydoc Entity animator.
 	#rem monkeydoc Entity animator.
@@ -151,136 +151,136 @@ Class Entity
 		_animator=animator
 		_animator=animator
 	End
 	End
 	
 	
-	'***** Local space properties *****
-
-	#rem monkeydoc Local transformation matrix.
+	'***** World space properties *****
 	
 	
-	The local matrix combines the local position, orientation and scale of the entity into a single affine 4x4 matrix.
+	#rem monkeydoc World space transformation matrix.
+	
+	The world matrix combines the world position, basis matrix and scale of the entity into a single affine 4x4 matrix.
 	
 	
 	#end
 	#end
 	Property Matrix:AffineMat4f()
 	Property Matrix:AffineMat4f()
 		
 		
-		If _dirty & Dirty.M
-			_M=New AffineMat4f( _r.Scale( _s ),_t )
-			_dirty&=~Dirty.M
+		If _dirty & Dirty.W
+			_W=_parent ? _parent.Matrix * LocalMatrix Else LocalMatrix
+			_dirty&=~Dirty.W
 		Endif
 		Endif
 		
 		
-		Return _M
+		Return _W
 	End
 	End
-
-	#rem monkeydoc Local position.
+	
+	#rem monkeydoc Inverse world space transformation matrix.
+	#end
+	Property InverseMatrix:AffineMat4f()
+		
+		If _dirty & Dirty.IW
+			_IW=-Matrix
+			_dirty&=~Dirty.IW
+		Endif
+		
+		Return _IW
+	End
+	
+	#rem monkeydoc World space position.
 	#end
 	#end
 	Property Position:Vec3f()
 	Property Position:Vec3f()
-
-		Return _t
+		
+		Return Matrix.t
 		
 		
 	Setter( position:Vec3f )
 	Setter( position:Vec3f )
 		
 		
-		_t=position
+		_t=_parent ? _parent.InverseMatrix * position Else position
 		
 		
 		Invalidate()
 		Invalidate()
 	End
 	End
 	
 	
-	#rem monkeydoc Local basis matrix.
-	
-	A basis matrix is a 3x3 matrix representation of an orientation.
+	#rem monkeydoc World space basis matrix.
 
 
+	A basis matrix is a 3x3 matrix representation of an orientation.
+	
 	A basis matrix is orthogonal (ie: the i,j,k members are perpendicular to each other) and normalized (ie: the i,j,k members all have unit length).
 	A basis matrix is orthogonal (ie: the i,j,k members are perpendicular to each other) and normalized (ie: the i,j,k members all have unit length).
 	
 	
 	#end
 	#end
 	Property Basis:Mat3f()
 	Property Basis:Mat3f()
 		
 		
-		Return _r
+		Return _parent ? _parent.Basis * _r Else _r
 	
 	
 	Setter( basis:Mat3f )
 	Setter( basis:Mat3f )
 		
 		
-		_r=basis
+		_r=_parent ? ~_parent.Basis * basis Else basis
 		
 		
 		Invalidate()
 		Invalidate()
 	End
 	End
-
-	#rem monkeydoc Local scale.
+	
+	#rem monkeydoc World space scale.
 	#end	
 	#end	
 	Property Scale:Vec3f()
 	Property Scale:Vec3f()
 		
 		
-		Return _s
+		Return _parent ? _s * _parent.Scale Else _s
 	
 	
 	Setter( scale:Vec3f )
 	Setter( scale:Vec3f )
 		
 		
-		_s=scale
+		_s=_parent ? scale / _parent.Scale Else scale
 		
 		
 		Invalidate()
 		Invalidate()
 	End
 	End
 	
 	
-	'***** World space properties *****
-	
-	#rem monkeydoc World transformation matrix.
-	
-	The world matrix combines the world position, basis matrix and scale of the entity into a single affine 4x4 matrix.
+	'***** Local space properties *****
+
+	#rem monkeydoc Local space transformation matrix.
 	
 	
-	#end
-	Property WorldMatrix:AffineMat4f()
-		
-		If _dirty & Dirty.W
-			_W=_parent ? _parent.WorldMatrix * Matrix Else Matrix
-			_dirty&=~Dirty.W
-		Endif
-		
-		Return _W
-	End
+	The local matrix combines the local position, orientation and scale of the entity into a single affine 4x4 matrix.
 	
 	
-	#rem monkeydoc Inverse world matrix.
 	#end
 	#end
-	Property InverseWorldMatrix:AffineMat4f()
+	Property LocalMatrix:AffineMat4f()
 		
 		
-		If _dirty & Dirty.IW
-			_IW=-WorldMatrix
-			_dirty&=~Dirty.IW
+		If _dirty & Dirty.M
+			_M=New AffineMat4f( _r.Scale( _s ),_t )
+			_dirty&=~Dirty.M
 		Endif
 		Endif
 		
 		
-		Return _IW
+		Return _M
 	End
 	End
-	
-	#rem monkeydoc World position.
+
+	#rem monkeydoc Local space position.
 	#end
 	#end
-	Property WorldPosition:Vec3f()
-		
-		Return WorldMatrix.t
+	Property LocalPosition:Vec3f()
+
+		Return _t
 		
 		
 	Setter( position:Vec3f )
 	Setter( position:Vec3f )
 		
 		
-		_t=_parent ? _parent.InverseWorldMatrix * position Else position
+		_t=position
 		
 		
 		Invalidate()
 		Invalidate()
 	End
 	End
 	
 	
-	#rem monkeydoc World basis matrix.
-
-	A basis matrix is a 3x3 matrix representation of an orientation.
+	#rem monkeydoc Local space basis matrix.
 	
 	
+	A basis matrix is a 3x3 matrix representation of an orientation.
+
 	A basis matrix is orthogonal (ie: the i,j,k members are perpendicular to each other) and normalized (ie: the i,j,k members all have unit length).
 	A basis matrix is orthogonal (ie: the i,j,k members are perpendicular to each other) and normalized (ie: the i,j,k members all have unit length).
 	
 	
 	#end
 	#end
-	Property WorldBasis:Mat3f()
+	Property LocalBasis:Mat3f()
 		
 		
-		Return _parent ? _parent.WorldBasis * _r Else _r
+		Return _r
 	
 	
 	Setter( basis:Mat3f )
 	Setter( basis:Mat3f )
 		
 		
-		_r=_parent ? ~_parent.WorldBasis * basis Else basis
+		_r=basis
 		
 		
 		Invalidate()
 		Invalidate()
 	End
 	End
-	
-	#rem monkeydoc World scale.
+
+	#rem monkeydoc Local space scale.
 	#end	
 	#end	
-	Property WorldScale:Vec3f()
+	Property LocalScale:Vec3f()
 		
 		
-		Return _parent ? Scale * _parent.WorldScale Else _s
+		Return _s
 	
 	
 	Setter( scale:Vec3f )
 	Setter( scale:Vec3f )
 		
 		
-		_s=_parent ? scale / _parent.WorldScale Else scale
+		_s=scale
 		
 		
 		Invalidate()
 		Invalidate()
 	End
 	End
@@ -301,7 +301,7 @@ Class Entity
 		Next
 		Next
 	End
 	End
 	
 	
-	#rem monkeydoc Hides the entity and all of its children
+	#rem monkeydoc Shows the entity and all of its children
 	#end
 	#end
 	Method Show()
 	Method Show()
 		
 		
@@ -324,8 +324,8 @@ Class Entity
 		Wend
 		Wend
 		
 		
 		If _visible 
 		If _visible 
-			OnHide()
 			_visible=False
 			_visible=False
+			OnHide()
 		Endif
 		Endif
 
 
 		If _parent
 		If _parent

+ 167 - 170
modules/mojo3d/graphics/entityexts.monkey2

@@ -13,7 +13,7 @@ Public
 #end
 #end
 Class Entity Extension
 Class Entity Extension
 
 
-	#rem monkeydoc Local rotation in degrees.
+	#rem monkeydoc Local space rotation in degrees.
 	#end
 	#end
 	Property Rotation:Vec3f()
 	Property Rotation:Vec3f()
 		
 		
@@ -24,18 +24,90 @@ Class Entity Extension
 		Basis=Mat3f.Rotation( rotation * DegreesToRadians )
 		Basis=Mat3f.Rotation( rotation * DegreesToRadians )
 	End
 	End
 	
 	
-	#rem monkeydoc World rotation in degrees.
+	#rem monkeydoc Local space rotation in degrees.
 	#end
 	#end
-	Property WorldRotation:Vec3f()
+	Property LocalRotation:Vec3f()
 		
 		
-		Return WorldBasis.GetRotation() * RadiansToDegrees
+		Return LocalBasis.GetRotation() * RadiansToDegrees
 	
 	
 	Setter( rotation:Vec3f )
 	Setter( rotation:Vec3f )
 		
 		
-		WorldBasis=Mat3f.Rotation( rotation * DegreesToRadians )
+		Basis=Mat3f.Rotation( rotation * DegreesToRadians )
 	End
 	End
 	
 	
-	#rem monkeydoc X coordinate of local position.
+	#Rem monkeydoc World space rotation around the X axis in degrees.
+	#End
+	Property Rx:Float()
+		
+		Return Rotation.x
+		
+	Setter( rx:Float )
+		
+		Local r:=Rotation
+		Rotation=New Vec3f( rx,r.y,r.z )
+	End
+
+	#Rem monkeydoc World space rotation around the Y axis in degrees.
+	#End
+	Property Ry:Float()
+		
+		Return Rotation.y
+		
+	Setter( ry:Float )
+		
+		Local r:=Rotation
+		Rotation=New Vec3f( r.x,ry,r.z )
+	End
+
+	#Rem monkeydoc World space rotation around the Z axis in degrees.
+	#End
+	Property Rz:Float()
+		
+		Return Rotation.z
+		
+	Setter( rz:Float )
+		
+		Local r:=Rotation
+		Rotation=New Vec3f( r.x,r.y,rz )
+	End
+	
+	#Rem monkeydoc Local space rotation around the X axis in degrees.
+	#End
+	Property LocalRx:Float()
+		
+		Return LocalRotation.x
+		
+	Setter( rx:Float )
+		
+		Local r:=LocalRotation
+		LocalRotation=New Vec3f( rx,r.y,r.z )
+	End
+
+	#Rem monkeydoc Local space rotation around the Y axis in degrees.
+	#End
+	Property LocalRy:Float()
+		
+		Return LocalRotation.y
+		
+	Setter( ry:Float )
+		
+		Local r:=LocalRotation
+		LocalRotation=New Vec3f( r.x,ry,r.z )
+	End
+
+	#Rem monkeydoc Local space rotation around the Z axis in degrees.
+	#End
+	Property LocalRz:Float()
+		
+		Return LocalRotation.z
+		
+	Setter( rz:Float )
+		
+		Local r:=LocalRotation
+		LocalRotation=New Vec3f( r.x,r.y,rz )
+	End
+
+	#rem monkeydoc World space X coordinate.
 	#end
 	#end
 	Property X:Float()
 	Property X:Float()
 		
 		
@@ -47,7 +119,7 @@ Class Entity Extension
 		Position=New Vec3f( x,v.y,v.z )
 		Position=New Vec3f( x,v.y,v.z )
 	End
 	End
 	
 	
-	#rem monkeydoc Y coordinate of local position.
+	#rem monkeydoc World space Y coordinate.
 	#end
 	#end
 	Property Y:Float()
 	Property Y:Float()
 	
 	
@@ -59,7 +131,7 @@ Class Entity Extension
 		Position=New Vec3f( v.x,y,v.z )
 		Position=New Vec3f( v.x,y,v.z )
 	End
 	End
 
 
-	#rem monkeydoc Z coordinate of local position.
+	#rem monkeydoc World space Z coordinate.
 	#end
 	#end
 	Property Z:Float()
 	Property Z:Float()
 	
 	
@@ -71,115 +143,43 @@ Class Entity Extension
 		Position=New Vec3f( v.x,v.y,z )
 		Position=New Vec3f( v.x,v.y,z )
 	End
 	End
 	
 	
-	#rem monkeydoc X coordinate of world position.
+	#rem monkeydoc Local space X coordinate.
 	#end
 	#end
-	Property WorldX:Float()
+	Property LocalX:Float()
 		
 		
-		Return WorldPosition.x
+		Return LocalPosition.x
 		
 		
 	Setter( x:Float )
 	Setter( x:Float )
 
 
-		Local v:=WorldPosition		
-		WorldPosition=New Vec3f( x,v.y,v.z )
+		Local v:=LocalPosition		
+		LocalPosition=New Vec3f( x,v.y,v.z )
 	End
 	End
 	
 	
-	#rem monkeydoc Y coordinate of world position.
+	#rem monkeydoc Local space Y coordinate.
 	#end
 	#end
-	Property WorldY:Float()
+	Property LocalY:Float()
 	
 	
-		Return WorldPosition.y
+		Return LocalPosition.y
 	
 	
 	Setter( y:Float )
 	Setter( y:Float )
 		
 		
-		Local v:=WorldPosition		
-		WorldPosition=New Vec3f( v.x,y,v.z )
+		Local v:=LocalPosition		
+		LocalPosition=New Vec3f( v.x,y,v.z )
 	End
 	End
 
 
-	#rem monkeydoc Z coordinate of world position.
+	#rem monkeydoc Local space Z coordinate.
 	#end
 	#end
-	Property WorldZ:Float()
+	Property LocalZ:Float()
 	
 	
-		Return WorldPosition.z
+		Return LocalPosition.z
 	
 	
 	Setter( z:Float )
 	Setter( z:Float )
 		
 		
-		Local v:=WorldPosition		
-		WorldPosition=New Vec3f( v.x,v.y,z )
-	End
-	
-	#Rem monkeydoc Rotation around the X axis in degrees.
-	#End
-	Property Rx:Float()
-		
-		Return Rotation.x
-		
-	Setter( rx:Float )
-		
-		Local r:=Rotation
-		Rotation=New Vec3f( rx,r.y,r.z )
-	End
-
-	#Rem monkeydoc Rotation around the Y axis in degrees.
-	#End
-	Property Ry:Float()
-		
-		Return Rotation.y
-		
-	Setter( ry:Float )
-		
-		Local r:=Rotation
-		Rotation=New Vec3f( r.x,ry,r.z )
-	End
-
-	#Rem monkeydoc Rotation around the X axis in degrees.
-	#End
-	Property Rz:Float()
-		
-		Return Rotation.z
-		
-	Setter( rz:Float )
-		
-		Local r:=Rotation
-		Rotation=New Vec3f( r.x,r.y,rz )
-	End
-
-	#Rem monkeydoc Rotation around the X axis in degrees.
-	#End
-	Property WorldRx:Float()
-		
-		Return WorldRotation.x
-		
-	Setter( rx:Float )
-		
-		Local r:=WorldRotation
-		WorldRotation=New Vec3f( rx,r.y,r.z )
-	End
-
-	#Rem monkeydoc Rotation around the Y axis in degrees.
-	#End
-	Property WorldRy:Float()
-		
-		Return WorldRotation.y
-		
-	Setter( ry:Float )
-		
-		Local r:=WorldRotation
-		WorldRotation=New Vec3f( r.x,ry,r.z )
-	End
-
-	#Rem monkeydoc Rotation around the X axis in degrees.
-	#End
-	Property WorldRz:Float()
-		
-		Return WorldRotation.z
-		
-	Setter( rz:Float )
-		
-		Local r:=WorldRotation
-		WorldRotation=New Vec3f( r.x,r.y,rz )
+		Local v:=LocalPosition		
+		LocalPosition=New Vec3f( v.x,v.y,z )
 	End
 	End
 	
 	
-	#rem monkeydoc Scale on the x axis.
+	#rem monkeydoc World space scale on the X axis.
 	#end
 	#end
 	Property Sx:Float()
 	Property Sx:Float()
 		
 		
@@ -191,7 +191,7 @@ Class Entity Extension
 		Scale=New Vec3f( sx,s.y,s.z )
 		Scale=New Vec3f( sx,s.y,s.z )
 	End
 	End
 	
 	
-	#rem monkeydoc Scale on the y axis.
+	#rem monkeydoc World space scale on the Y axis.
 	#end
 	#end
 	Property Sy:Float()
 	Property Sy:Float()
 		
 		
@@ -203,7 +203,7 @@ Class Entity Extension
 		Scale=New Vec3f( s.x,sy,s.z )
 		Scale=New Vec3f( s.x,sy,s.z )
 	End
 	End
 	
 	
-	#rem monkeydoc Scale on the z axis.
+	#rem monkeydoc World space scale on the Z axis.
 	#end
 	#end
 	Property Sz:Float()
 	Property Sz:Float()
 		
 		
@@ -212,123 +212,120 @@ Class Entity Extension
 	Setter( sz:Float )
 	Setter( sz:Float )
 		
 		
 		Local s:=Scale
 		Local s:=Scale
-		
 		Scale=New Vec3f( s.x,s.y,sz )
 		Scale=New Vec3f( s.x,s.y,sz )
 	End
 	End
 	
 	
-	#rem monkeydoc Scale on the x axis.
+	#rem monkeydoc Local space scale on the X axis.
 	#end
 	#end
-	Property WorldSx:Float()
+	Property LocalSx:Float()
 		
 		
-		Return WorldScale.x
+		Return LocalScale.x
 	
 	
 	Setter( sx:Float )
 	Setter( sx:Float )
 		
 		
-		Local s:=WorldScale
+		Local s:=LocalScale
 		
 		
-		WorldScale=New Vec3f( sx,s.y,s.z )
+		LocalScale=New Vec3f( sx,s.y,s.z )
 	End
 	End
 	
 	
-	#rem monkeydoc Scale on the y axis.
+	#rem monkeydoc Local space scale on the Y axis.
 	#end
 	#end
-	Property WorldSy:Float()
+	Property LocalSy:Float()
 		
 		
-		Return WorldScale.y
+		Return LocalScale.y
 	
 	
 	Setter( sy:Float )
 	Setter( sy:Float )
 		
 		
-		Local s:=WorldScale
-		
-		WorldScale=New Vec3f( s.x,sy,s.z )
+		Local s:=LocalScale
+		LocalScale=New Vec3f( s.x,sy,s.z )
 	End
 	End
 	
 	
-	#rem monkeydoc Scale on the z axis.
+	#rem monkeydoc Local space scale on the Z axis.
 	#end
 	#end
-	Property WorldSz:Float()
+	Property LocalSz:Float()
 		
 		
-		Return WorldScale.z
+		Return LocalScale.z
 	
 	
 	Setter( sz:Float )
 	Setter( sz:Float )
 		
 		
-		Local s:=WorldScale
-		
-		WorldScale=New Vec3f( s.x,s.y,sz )
+		Local s:=LocalScale
+		LocalScale=New Vec3f( s.x,s.y,sz )
 	End
 	End
 	
 	
-	#rem monkeydoc Sets entity basis matrix in local or world space.
+	#rem monkeydoc Sets entity position in local or world space.
 	#end
 	#end
-	Method SetBasis( basis:Mat3f,worldSpace:Bool=False )
+	Method SetPosition( position:Vec3f,localSpace:Bool=False )
 		
 		
-		If worldSpace WorldBasis=basis Else Basis=basis
+		If localSpace LocalPosition=position Else Position=position
 	End
 	End
 	
 	
-	#rem monkeydoc Gets entity basis matrix in local or world space.
-	#end
-	method GetBasis:Mat3f( worldSpace:Bool=False )
+	Method SetPosition( x:Float,y:Float,z:Float,localSpace:Bool=False )
 		
 		
-		Return worldSpace ? WorldBasis Else Basis
-	
+		SetPosition( New Vec3f( x,y,z ),localSpace )
 	End
 	End
-
-	#rem monkeydoc Sets entity position in local or world space.
+	
+	#rem monkeydoc Gets entity position in local or world space.
 	#end
 	#end
-	Method SetPosition( position:Vec3f,worldSpace:Bool=False )
+	Method GetPostition:Vec3f( localSpace:Bool=False )
 		
 		
-		If worldSpace WorldPosition=position Else Position=position
+		Return localSpace ? LocalPosition Else Position
 	End
 	End
 	
 	
-	Method SetPosition( x:Float,y:Float,z:Float,worldSpace:Bool=False )
+	#rem monkeydoc Sets entity basis matrix in local or world space.
+	#end
+	Method SetBasis( basis:Mat3f,localSpace:Bool=False )
 		
 		
-		SetPosition( New Vec3f( x,y,z ),worldSpace )
+		If localSpace LocalBasis=basis Else Basis=basis
 	End
 	End
 	
 	
-	#rem monkeydoc Gets entity position in local or world space.
+	#rem monkeydoc Gets entity basis matrix in local or world space.
 	#end
 	#end
-	Method GetPostition:Vec3f( worldSpace:Bool=False )
+	method GetBasis:Mat3f( localSpace:Bool=False )
 		
 		
-		Return worldSpace ? WorldPosition Else Position
-	End
+		Return localSpace ? LocalBasis Else Basis
 	
 	
+	End
+
 	#rem monkeydoc Sets entity rotation in euler angles in local or world space.
 	#rem monkeydoc Sets entity rotation in euler angles in local or world space.
 	#end
 	#end
-	Method SetRotation( rotation:Vec3f,worldSpace:Bool=False )
+	Method SetRotation( rotation:Vec3f,localSpace:Bool=False )
 		
 		
 		Local basis:=Mat3f.Rotation( rotation * DegreesToRadians )
 		Local basis:=Mat3f.Rotation( rotation * DegreesToRadians )
 		
 		
-		If worldSpace WorldBasis=basis Else Basis=basis
+		If localSpace LocalBasis=basis Else Basis=basis
 	End
 	End
 	
 	
-	Method SetRotation( rx:Float,ry:Float,rz:Float,worldSpace:Bool=False )
+	Method SetRotation( rx:Float,ry:Float,rz:Float,localSpace:Bool=False )
 		
 		
-		SetRotation( New Vec3f( rx,ry,rz ),worldSpace )
+		SetRotation( New Vec3f( rx,ry,rz ),localSpace )
 	End
 	End
 	
 	
 	#rem monkeydoc Gets entity rotation in euler angles in local or world space.
 	#rem monkeydoc Gets entity rotation in euler angles in local or world space.
 	#end
 	#end
-	Method GetRotation:Vec3f( worldSpace:Bool=False )
+	Method GetRotation:Vec3f( localSpace:Bool=False )
 		
 		
-		Local basis:=worldSpace ? WorldBasis Else Basis
+		Local basis:=localSpace ? LocalBasis Else Basis
 		
 		
 		Return basis.GetRotation() * RadiansToDegrees
 		Return basis.GetRotation() * RadiansToDegrees
 	End
 	End
 	
 	
 	#rem monkeydoc Sets entity scale in local or world space.
 	#rem monkeydoc Sets entity scale in local or world space.
 	#end
 	#end
-	Method SetScale( scale:Vec3f,worldSpace:Bool=False )
+	Method SetScale( scale:Vec3f,localSpace:Bool=False )
 		
 		
-		If worldSpace WorldScale=scale Else Scale=scale
+		If localSpace LocalScale=scale Else Scale=scale
 	End
 	End
 	
 	
-	Method SetScale( sx:Float,sy:Float,sz:Float,worldSpace:Bool=False )
+	Method SetScale( sx:Float,sy:Float,sz:Float,localSpace:Bool=False )
 		
 		
-		SetScale( New Vec3f( sx,sy,sz ),worldSpace )
+		SetScale( New Vec3f( sx,sy,sz ),localSpace )
 	End
 	End
 
 
 	#rem monkeydoc Gets entity scale in local or world space.
 	#rem monkeydoc Gets entity scale in local or world space.
 	#end
 	#end
-	Method GetScale:Vec3f( worldSpace:Bool=False )
+	Method GetScale:Vec3f( localSpace:Bool=False )
 		
 		
-		Return worldSpace ? WorldScale Else Scale
+		Return localSpace ? LocalScale Else Scale
 	End
 	End
 	
 	
 	#rem monkeydoc Moves the entity.
 	#rem monkeydoc Moves the entity.
@@ -336,9 +333,9 @@ Class Entity Extension
 	Moves the entity relative to its current orientation.
 	Moves the entity relative to its current orientation.
 	
 	
 	#end	
 	#end	
-	Method Move( tv:Vec3f,worldSpace:Bool=False )
+	Method Move( tv:Vec3f,localSpace:Bool=False )
 		
 		
-		If worldSpace WorldPosition+=tv Else Position+=Basis * tv
+		If localSpace LocalPosition+=tv Else Position+=Basis * tv
 	End
 	End
 	
 	
 	Method Move( tx:Float,ty:Float,tz:Float )
 	Method Move( tx:Float,ty:Float,tz:Float )
@@ -351,9 +348,9 @@ Class Entity Extension
 	Moves the entity relative to its current orientation.
 	Moves the entity relative to its current orientation.
 	
 	
 	#end	
 	#end	
-	Method MoveX( tx:Float,worldSpace:Bool=False )
+	Method MoveX( tx:Float,localSpace:Bool=False )
 		
 		
-		If worldSpace WorldX+=tx Else Position+=Basis.i * tx
+		If localSpace LocalX+=tx Else Position+=Basis.i * tx
 	End
 	End
 	
 	
 	#rem monkeydoc Moves the entity on the Y axis.
 	#rem monkeydoc Moves the entity on the Y axis.
@@ -361,9 +358,9 @@ Class Entity Extension
 	Moves the entity relative to its current orientation.
 	Moves the entity relative to its current orientation.
 	
 	
 	#end	
 	#end	
-	Method MoveY( ty:Float,worldSpace:Bool=False )
+	Method MoveY( ty:Float,localSpace:Bool=False )
 
 
-		If worldSpace WorldY+=ty Else Position+=Basis.j * ty
+		If localSpace LocalY+=ty Else Position+=Basis.j * ty
 	End
 	End
 	
 	
 	#rem monkeydoc Moves the entity on the Z axis.
 	#rem monkeydoc Moves the entity on the Z axis.
@@ -371,75 +368,75 @@ Class Entity Extension
 	Moves the entity relative to its current orientation.
 	Moves the entity relative to its current orientation.
 	
 	
 	#end	
 	#end	
-	Method MoveZ( tz:Float,worldSpace:Bool=False )
+	Method MoveZ( tz:Float,localSpace:Bool=False )
 
 
-		If worldSpace WorldZ+=tz Else Position+=Basis.k * tz
+		If localSpace LocalZ+=tz Else Position+=Basis.k * tz
 	End
 	End
 	
 	
 	#rem monkeydoc Rotates the entity.
 	#rem monkeydoc Rotates the entity.
 	
 	
 	Rotates the entity.
 	Rotates the entity.
 	
 	
-	If `postRotate` is true, the rotation is applied after the entity's world rotation.
+	If `localSpace` is false, the rotation is applied after the entity's world rotation.
 		
 		
-	If `postRotate` is false, the rotation is applied before the entity's local rotation.
+	If `localSpace` is true, the rotation is applied before the entity's local rotation.
 		
 		
 	#end
 	#end
-	Method Rotate( rv:Vec3f,postRotate:Bool=False )
+	Method Rotate( rv:Vec3f,localSpace:Bool=False )
 		
 		
 		Local basis:=Mat3f.Rotation( rv * DegreesToRadians )
 		Local basis:=Mat3f.Rotation( rv * DegreesToRadians )
 		
 		
-		If postRotate WorldBasis=basis*WorldBasis Else Basis*=basis
+		If localSpace LocalBasis*=basis Else Basis=basis*Basis
 	End
 	End
 	
 	
-	Method Rotate( rx:Float,ry:Float,rz:Float,postRotate:Bool=False )
+	Method Rotate( rx:Float,ry:Float,rz:Float,localSpace:Bool=False )
 		
 		
-		Rotate( New Vec3f( rx,ry,rz ),postRotate )
+		Rotate( New Vec3f( rx,ry,rz ),localSpace )
 	End
 	End
 	
 	
 	#rem monkeydoc Rotates the entity around the X axis.
 	#rem monkeydoc Rotates the entity around the X axis.
 	#end
 	#end
-	Method RotateX( rx:Float,postRotate:Bool=False )
+	Method RotateX( rx:Float,localSpace:Bool=False )
 		
 		
 		Local basis:=Mat3f.Pitch( rx * DegreesToRadians )
 		Local basis:=Mat3f.Pitch( rx * DegreesToRadians )
 		
 		
-		If postRotate WorldBasis=basis*WorldBasis Else Basis*=basis
+		If localSpace LocalBasis=basis*LocalBasis Else Basis*=basis
 	End
 	End
 
 
 	#rem monkeydoc Rotates the entity around the Y axis.
 	#rem monkeydoc Rotates the entity around the Y axis.
 	#end
 	#end
-	Method RotateY( ry:Float,postRotate:Bool=False )
+	Method RotateY( ry:Float,localSpace:Bool=False )
 
 
 		Local basis:=Mat3f.Yaw( ry * DegreesToRadians )
 		Local basis:=Mat3f.Yaw( ry * DegreesToRadians )
 		
 		
-		If postRotate WorldBasis=basis*WorldBasis Else Basis*=basis
+		If localSpace LocalBasis=basis*LocalBasis Else Basis*=basis
 	End
 	End
 
 
 	#rem monkeydoc Rotates the entity around the Z axis.
 	#rem monkeydoc Rotates the entity around the Z axis.
 	#end
 	#end
-	Method RotateZ( rz:Float,postRotate:Bool=False )
+	Method RotateZ( rz:Float,localSpace:Bool=False )
 
 
 		Local basis:=Mat3f.Roll( rz * DegreesToRadians )
 		Local basis:=Mat3f.Roll( rz * DegreesToRadians )
 		
 		
-		If postRotate WorldBasis=basis*WorldBasis Else Basis*=basis
+		If localSpace LocalBasis=basis*LocalBasis Else Basis*=basis
 	End
 	End
 
 
 	#rem monkeydoc Points the entity at a target.
 	#rem monkeydoc Points the entity at a target.
 	#end
 	#end
 	Method PointAt( target:Vec3f,up:Vec3f=New Vec3f( 0,1,0 ) )
 	Method PointAt( target:Vec3f,up:Vec3f=New Vec3f( 0,1,0 ) )
 		
 		
-		Local k:=(target-WorldPosition).Normalize()
+		Local k:=(target-LocalPosition).Normalize()
 		
 		
 		Local i:=up.Cross( k ).Normalize()
 		Local i:=up.Cross( k ).Normalize()
 		
 		
 		Local j:=k.Cross( i )
 		Local j:=k.Cross( i )
 		
 		
-		WorldBasis=New Mat3f( i,j,k )
+		LocalBasis=New Mat3f( i,j,k )
 	End
 	End
 	
 	
 	Method PointAt( target:Entity,up:Vec3f=New Vec3f( 0,1,0 ) )
 	Method PointAt( target:Entity,up:Vec3f=New Vec3f( 0,1,0 ) )
 		
 		
-		PointAt( target.WorldPosition )
+		PointAt( target.LocalPosition )
 	End
 	End
-
+	
 End
 End

+ 11 - 5
modules/mojo3d/graphics/gltf2loader.monkey2

@@ -225,13 +225,19 @@ Class Gltf2Loader
 					Next
 					Next
 				Endif
 				Endif
 				
 				
-				If materials And Not mesh.NumVertices mesh.AddMaterials( 1 )				
-				
 				mesh.AddVertices( vertices )
 				mesh.AddVertices( vertices )
 				
 				
-				mesh.AddTriangles( indices,mesh.NumMaterials-1 )
-				
-				If materials materials.Push( GetMaterial( prim.material ) )
+				If materials
+					
+					mesh.AddTriangles( indices,mesh.NumMaterials )
+
+					materials.Push( GetMaterial( prim.material ) )
+					
+				Else
+					
+					mesh.AddTriangles( indices,0 )
+					
+				Endif
 					
 					
 				Print "Added "+vcount+" vertices, "+icount+" indices."
 				Print "Added "+vcount+" vertices, "+icount+" indices."
 				
 				

+ 6 - 3
modules/mojo3d/graphics/mesh.monkey2

@@ -7,7 +7,7 @@ Class Mesh Extends Resource
 	
 	
 	#rem monkeydoc Creates a new mesh.
 	#rem monkeydoc Creates a new mesh.
 	
 	
-	Creates a new empty mesh with 1 logical material.
+	Creates a new empty mesh.
 	
 	
 	Meshes don't actual contain instances of materials. Instead, mesh triangles are added to 'logical' materials which are effectively just integer indices.
 	Meshes don't actual contain instances of materials. Instead, mesh triangles are added to 'logical' materials which are effectively just integer indices.
 	
 	
@@ -20,7 +20,6 @@ Class Mesh Extends Resource
 		_bounds=Boxf.EmptyBounds
 		_bounds=Boxf.EmptyBounds
 		_vbuffer=New VertexBuffer( Vertex3fFormat.Instance,0 )
 		_vbuffer=New VertexBuffer( Vertex3fFormat.Instance,0 )
 		_ibuffers=New Stack<IndexBuffer>
 		_ibuffers=New Stack<IndexBuffer>
-		AddMaterials( 1 )
 	End
 	End
 	
 	
 	Method New( mesh:Mesh )
 	Method New( mesh:Mesh )
@@ -135,11 +134,15 @@ Class Mesh Extends Resource
 	
 	
 	#rem monkeydoc Adds triangles to the mesh.
 	#rem monkeydoc Adds triangles to the mesh.
 	
 	
-	The `materialid` parameter must be greater than or equal to 0 and less than NumMaterials.
+	The `materialid` parameter must be greater than or equal to 0 and less or equal to [[NumMaterials]].
+	
+	If `materialid` is equal to NumMaterials, a new material is automatically added first.
 	
 	
 	#end
 	#end
 	Method AddTriangles( indices:UInt Ptr,count:Int,materialid:Int=0 )
 	Method AddTriangles( indices:UInt Ptr,count:Int,materialid:Int=0 )
 		
 		
+		If materialid=_ibuffers.Length AddMaterials( 1 )
+		
 		Local p:=_ibuffers[materialid].AddIndices( count )
 		Local p:=_ibuffers[materialid].AddIndices( count )
 		
 		
 		libc.memcpy( p,indices,count*4 )
 		libc.memcpy( p,indices,count*4 )

+ 1 - 1
modules/mojo3d/graphics/model.monkey2

@@ -156,7 +156,7 @@ Class Model Extends Entity
 			
 			
 			For Local i:=0 Until _bones.Length
 			For Local i:=0 Until _bones.Length
 				Local bone:=_bones[i]
 				Local bone:=_bones[i]
-				_boneMatrices[i]=New Mat4f( bone.entity.WorldMatrix * bone.offset )
+				_boneMatrices[i]=New Mat4f( bone.entity.Matrix * bone.offset )
 			Next
 			Next
 		End
 		End
 		
 		

+ 7 - 7
modules/mojo3d/graphics/renderer.monkey2

@@ -257,8 +257,8 @@ Class Renderer
 	
 	
 		_camera=camera
 		_camera=camera
 		
 		
-		Local envMat:=_camera.WorldMatrix.m
-		Local viewMat:=_camera.InverseWorldMatrix
+		Local envMat:=_camera.Matrix.m
+		Local viewMat:=_camera.InverseMatrix
 		Local projMat:=_camera.ProjectionMatrix
 		Local projMat:=_camera.ProjectionMatrix
 		Local invProjMat:=-projMat
 		Local invProjMat:=-projMat
 			
 			
@@ -314,7 +314,7 @@ Class Renderer
 		_device.DepthFunc=DepthFunc.LessEqual
 		_device.DepthFunc=DepthFunc.LessEqual
 		_device.RenderPass=1
 		_device.RenderPass=1
 		
 		
-		RenderRenderOps( _renderQueue.OpaqueOps,_camera.InverseWorldMatrix,_camera.ProjectionMatrix )
+		RenderRenderOps( _renderQueue.OpaqueOps,_camera.InverseMatrix,_camera.ProjectionMatrix )
 	End
 	End
 	
 	
 	'MX2_RENDERPASS 0
 	'MX2_RENDERPASS 0
@@ -326,7 +326,7 @@ Class Renderer
 		_device.DepthFunc=DepthFunc.Always
 		_device.DepthFunc=DepthFunc.Always
 		_device.RenderPass=0
 		_device.RenderPass=0
 
 
-		RenderRenderOps( _spriteQueue.OpaqueOps,_camera.InverseWorldMatrix,_camera.ProjectionMatrix )
+		RenderRenderOps( _spriteQueue.OpaqueOps,_camera.InverseMatrix,_camera.ProjectionMatrix )
 	End
 	End
 	
 	
 	'MX2_RENDERPASS 2
 	'MX2_RENDERPASS 2
@@ -351,8 +351,8 @@ Class Renderer
 		_device.CullMode=CullMode.Back
 		_device.CullMode=CullMode.Back
 		_device.RenderPass=2
 		_device.RenderPass=2
 
 
-		Local invLightMatrix:=light.InverseWorldMatrix
-		Local viewLight:=invLightMatrix * _camera.WorldMatrix
+		Local invLightMatrix:=light.InverseMatrix
+		Local viewLight:=invLightMatrix * _camera.Matrix
 		
 		
 		For Local i:=0 Until _csmSplits.Length-1
 		For Local i:=0 Until _csmSplits.Length-1
 			
 			
@@ -428,7 +428,7 @@ Class Renderer
 			
 			
 			Local model:=op.instance
 			Local model:=op.instance
 			
 			
-			Local modelMat:= model ? model.WorldMatrix Else New AffineMat4f
+			Local modelMat:= model ? model.Matrix Else New AffineMat4f
 			Local modelViewMat:=viewMatrix * modelMat
 			Local modelViewMat:=viewMatrix * modelMat
 			Local modelViewProjMat:=projMatrix * modelViewMat
 			Local modelViewProjMat:=projMatrix * modelViewMat
 			Local modelViewNormMat:=~-modelViewMat.m
 			Local modelViewNormMat:=~-modelViewMat.m

+ 3 - 3
modules/mojo3d/graphics/spritebuffer.monkey2

@@ -38,7 +38,7 @@ Class SpriteBuffer
 		Endif
 		Endif
 		
 		
 		sprites.Sort( Lambda:Int( x:Sprite,y:Sprite )
 		sprites.Sort( Lambda:Int( x:Sprite,y:Sprite )
-			Return camera.WorldPosition.Distance( y.WorldPosition ) <=> camera.WorldPosition.Distance( x.WorldPosition )
+			Return camera.Position.Distance( y.Position ) <=> camera.Position.Distance( x.Position )
 		End )
 		End )
 		
 		
 		Local cmaterial:=sprites[0].Material
 		Local cmaterial:=sprites[0].Material
@@ -53,7 +53,7 @@ Class SpriteBuffer
 				i0=i
 				i0=i
 			Endif
 			Endif
 			
 			
-			Local r:=camera.WorldBasis
+			Local r:=camera.Basis
 			
 			
 			Select sprite.Mode
 			Select sprite.Mode
 			Case SpriteMode.Upright
 			Case SpriteMode.Upright
@@ -61,7 +61,7 @@ Class SpriteBuffer
 				r.j=New Vec3f( 0,1,0 ) ; r.i=r.j.Cross( r.k ).Normalize()
 				r.j=New Vec3f( 0,1,0 ) ; r.i=r.j.Cross( r.k ).Normalize()
 			End
 			End
 			
 			
-			Local matrix:=New AffineMat4f( r.Scale( sprite.WorldScale ),sprite.WorldPosition )
+			Local matrix:=New AffineMat4f( r.Scale( sprite.Scale ),sprite.Position )
 			
 			
 			Local handle:=sprite.Handle
 			Local handle:=sprite.Handle
 			
 			

+ 1 - 0
modules/mojo3d/tests/cubetest.monkey2

@@ -1,3 +1,4 @@
+
 Namespace myapp
 Namespace myapp
 
 
 #Import "<std>"
 #Import "<std>"

+ 3 - 2
modules/mojo3d/tests/ducks.monkey2

@@ -73,7 +73,6 @@ Class MyWindow Extends Window
 		'		
 		'		
 		Local duck:=Model.Load( "asset::duck.gltf/Duck.gltf" )
 		Local duck:=Model.Load( "asset::duck.gltf/Duck.gltf" )
 		duck.Mesh.FitVertices( New Boxf( -1,1 ) )
 		duck.Mesh.FitVertices( New Boxf( -1,1 ) )
-		duck.Mesh.TransformVertices( Mat4f.Rotation( 0,Pi/2,0 ) )
 		
 		
 		Local root:=duck.Copy()
 		Local root:=duck.Copy()
 		root.Move( 0,10,0 )
 		root.Move( 0,10,0 )
@@ -91,6 +90,8 @@ Class MyWindow Extends Window
 				
 				
 				copy.Move( 0,0,6+m*16 )
 				copy.Move( 0,0,6+m*16 )
 				
 				
+				copy.Scale=New Vec3f( 1 )
+				
 				For Local j:=0 Until copy.Materials.Length
 				For Local j:=0 Until copy.Materials.Length
 				
 				
 					Local material:=Cast<PbrMaterial>( copy.Materials[j].Copy() )
 					Local material:=Cast<PbrMaterial>( copy.Materials[j].Copy() )
@@ -121,7 +122,7 @@ Class MyWindow Extends Window
 		
 		
 		For Local duck:=Eachin _ducks
 		For Local duck:=Eachin _ducks
 			
 			
-			duck.Rotate( 0,1,0 )
+			duck.RotateY( 1 )
 		Next
 		Next
 		
 		
 		util.Fly( _camera,Self )
 		util.Fly( _camera,Self )

+ 10 - 5
modules/monkey/monkey.monkey2

@@ -5,11 +5,6 @@ Namespace monkey
 #import "<liblog.a>"
 #import "<liblog.a>"
 #endif
 #endif
 
 
-#Import "types.monkey2"
-#Import "math.monkey2"
-#Import "debug.monkey2"
-#Import "gc.monkey2"
-
 #Import "native/bbtypes.cpp"
 #Import "native/bbtypes.cpp"
 #Import "native/bbassert.cpp"
 #Import "native/bbassert.cpp"
 #Import "native/bbmemory.cpp"
 #Import "native/bbmemory.cpp"
@@ -23,3 +18,13 @@ Namespace monkey
 #Import "native/bbvariant.cpp"
 #Import "native/bbvariant.cpp"
 #Import "native/bbtypeinfo.cpp"
 #Import "native/bbtypeinfo.cpp"
 #Import "native/bbdeclinfo.cpp"
 #Import "native/bbdeclinfo.cpp"
+
+#If __TARGET__="macos" Or __TARGET__="ios"
+#Import "native/bbstring.mm"
+#Endif
+
+#Import "types.monkey2"
+#Import "math.monkey2"
+#Import "debug.monkey2"
+#Import "gc.monkey2"
+

+ 1 - 3
modules/monkey/native/bbstring.h

@@ -252,9 +252,7 @@ class bbString{
 	void toWString( void *buf,int size )const;
 	void toWString( void *buf,int size )const;
 	
 	
 #if __OBJC__	
 #if __OBJC__	
-	NSString *ToNSString()const{
-		return [NSString stringWithUTF8String:c_str()];
-	}
+	NSString *ToNSString()const;
 #endif
 #endif
 	
 	
 	static bbString fromChar( int chr );
 	static bbString fromChar( int chr );

+ 9 - 0
modules/monkey/native/bbstring.mm

@@ -0,0 +1,9 @@
+
+#include "bbstring.h"
+
+bbString::bbString( NSString *str ):_rep( Rep::create( str.UTF8String ) ){
+}
+
+NSString *bbString::ToNSString()const{
+	return [NSString stringWithUTF8String:c_str()];
+}

+ 3 - 0
modules/sdl2/makefile_windows.monkey2

@@ -1,10 +1,13 @@
 
 
 Namespace sdl2
 Namespace sdl2
 
 
+
+
 #import "<libdsound.a>"
 #import "<libdsound.a>"
 #import "<libxinput.a>"
 #import "<libxinput.a>"
 #import "<libdinput8.a>"
 #import "<libdinput8.a>"
 
 
+#import "<libadvapi32.a>"
 #import "<libole32.a>"
 #import "<libole32.a>"
 #Import "<libshell32.a>"
 #Import "<libshell32.a>"
 #import "<liboleaut32.a>"
 #import "<liboleaut32.a>"

+ 10 - 5
modules/std/audio/load_wav.monkey2

@@ -44,16 +44,20 @@ Function ReadWAV:AudioData( stream:std.stream.Stream )
 		Local tag:=stream.ReadInt()
 		Local tag:=stream.ReadInt()
 		Local size:=stream.ReadInt()
 		Local size:=stream.ReadInt()
 		
 		
+		Local aligned_size:=size+(size&1)	'chunk size *including* 2 byte alignment of next chunk.
+		
 		Select tag
 		Select tag
 		Case $20746d66		'FMT
 		Case $20746d66		'FMT
 			
 			
 			Local fmt:=New FMT_Chunk
 			Local fmt:=New FMT_Chunk
 			Local fmt_sz:=sizeof( fmt )
 			Local fmt_sz:=sizeof( fmt )
 			
 			
-			If stream.Read( Varptr fmt,fmt_sz )<>fmt_sz Return Null
+			'read FMT chunk data
+			If fmt_sz>size Or stream.Read( Varptr fmt,fmt_sz )<>fmt_sz Return Null
 			
 			
-			Local n:=size-fmt_sz
-			If n>0 And stream.Skip( n )<>n Return Null
+			'skip to next chunk
+			Local n:=aligned_size-fmt_sz
+			If n And stream.Skip( n )<>n Return Null
 			
 			
 			If fmt.compType<>1 Return Null
 			If fmt.compType<>1 Return Null
 			
 			
@@ -85,11 +89,12 @@ Function ReadWAV:AudioData( stream:std.stream.Stream )
 		
 		
 		End
 		End
 		
 		
-		stream.Skip( size )
+		'skip to next chunk
+		If stream.Skip( aligned_size )<>aligned_size Return Null
 		
 		
 	Wend
 	Wend
 	
 	
-	Return null
+	Return Null
 
 
 End
 End
 
 

+ 9 - 11
modules/std/filesystem/filesystem.monkey2

@@ -44,10 +44,9 @@ Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
 
 
 Private
 Private
 
 
-Function FixRoot:String( path:String )
+Function FixPath:String( path:String )
 	
 	
 	Local root:=ExtractRootDir( path )
 	Local root:=ExtractRootDir( path )
-	
 	If Not root.EndsWith( "::" ) Return path
 	If Not root.EndsWith( "::" ) Return path
 	
 	
 	path=path.Slice( root.Length )
 	path=path.Slice( root.Length )
@@ -63,7 +62,7 @@ End
 
 
 Function FixFilePath:String( path:String )
 Function FixFilePath:String( path:String )
 	
 	
-	Return FixRoot( StripSlashes( path ) )
+	Return FixPath( StripSlashes( path ) )
 End
 End
 
 
 Public
 Public
@@ -137,6 +136,7 @@ Note that only the desktop and web targets have an assets directory. Other targe
 Function AssetsDir:String()
 Function AssetsDir:String()
 #If __TARGET__="macos"
 #If __TARGET__="macos"
 	Return AppDir()+"../Resources/"
 	Return AppDir()+"../Resources/"
+	'Return ExtractDir( AppDir() )+"/Resources/"	'enable me!
 #Else If __DESKTOP_TARGET__ Or __WEB_TARGET__
 #Else If __DESKTOP_TARGET__ Or __WEB_TARGET__
 	Return AppDir()+"assets/"
 	Return AppDir()+"assets/"
 #Else
 #Else
@@ -153,7 +153,7 @@ Note that only the desktop targets have a desktop directory. Other targets will
 #end
 #end
 Function DesktopDir:String()
 Function DesktopDir:String()
 #If __TARGET__="windows"
 #If __TARGET__="windows"
-	Return GetEnv( "USERPROFILE" )+"/Desktop/"
+	Return GetEnv( "USERPROFILE" ).Replace( "\","/" )+"/Desktop/"
 #Else If __DESKTOP_TARGET__
 #Else If __DESKTOP_TARGET__
  	Return GetEnv( "HOME" )+"/Desktop/"
  	Return GetEnv( "HOME" )+"/Desktop/"
  #Else
  #Else
@@ -169,10 +169,10 @@ Note that only the desktop targets have a home directory. Other targets will ret
 
 
 #end
 #end
 Function HomeDir:String()
 Function HomeDir:String()
-#If __DESKTOP_TARGET__
-	Return GetEnv( "USERPROFILE" )+"/"
+#If __TARGET__="windows"
+	Return GetEnv( "USERPROFILE" ).Replace( "\","/" )+"/"
 #Else if __DESKTOP_TARGET__
 #Else if __DESKTOP_TARGET__
-	Return GetEnv( "HOME" )+"/"+
+	Return GetEnv( "HOME" )+"/"
 #Else
 #Else
 	Return ""
 	Return ""
 #Endif
 #Endif
@@ -276,7 +276,7 @@ Then, any internal './' or '../' references in the path are collapsed.
 #end
 #end
 Function RealPath:String( path:String )
 Function RealPath:String( path:String )
 	
 	
-	path=FixRoot( path )
+	path=FixPath( path )
 	
 	
 	Local rpath:=ExtractRootDir( path )
 	Local rpath:=ExtractRootDir( path )
 	If rpath 
 	If rpath 
@@ -305,7 +305,7 @@ Function RealPath:String( path:String )
 	
 	
 	#rem Not working on macos!
 	#rem Not working on macos!
 	
 	
-	path=FixRoot( path )
+	path=FixPath( path )
 	
 	
 	Local buf:=New char_t[PATH_MAX]
 	Local buf:=New char_t[PATH_MAX]
 	
 	
@@ -332,8 +332,6 @@ This function will not strip slashes from a root directory path.
 #end
 #end
 Function StripSlashes:String( path:String )
 Function StripSlashes:String( path:String )
 	
 	
-	path=path.Replace( "\","/" )
-	
 	If Not path.EndsWith( "/" ) Return path
 	If Not path.EndsWith( "/" ) Return path
 	
 	
 	Local root:=ExtractRootDir( path )
 	Local root:=ExtractRootDir( path )

+ 5 - 1
modules/std/requesters/native/requesters_linux.cpp

@@ -38,7 +38,11 @@ bbString bbRequesters::RequestFile( bbString title,bbString exts,bbBool save,bbS
 
 
 	if( path=="" ) path=".";
 	if( path=="" ) path=".";
 		
 		
-	return tinyfd_openFileDialog( bbCString( title ),bbCString( path ),0,0,0,0 );
+	if( save ){
+		return tinyfd_saveFileDialog( bbCString( title ),bbCString( path ),0,0,0 );
+	}else{
+		return tinyfd_openFileDialog( bbCString( title ),bbCString( path ),0,0,0,0 );
+	}
 }
 }
 
 
 bbString bbRequesters::RequestDir( bbString title,bbString dir ){
 bbString bbRequesters::RequestDir( bbString title,bbString dir ){

+ 34 - 7
products/android/Monkey2Game/app/src/main/java/com/monkey2/lib/Monkey2Activity.java

@@ -3,15 +3,45 @@ package com.monkey2.lib;
 import android.os.Bundle;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.Looper;
 import android.util.Log;
 import android.util.Log;
+import android.content.Intent;
 import android.view.ViewGroup;
 import android.view.ViewGroup;
 
 
 import org.libsdl.app.SDLActivity;
 import org.libsdl.app.SDLActivity;
 
 
+import java.util.List;
+import java.util.LinkedList;
+
 public class Monkey2Activity extends SDLActivity {
 public class Monkey2Activity extends SDLActivity {
     private static final String TAG = "Monkey2Activity";
     private static final String TAG = "Monkey2Activity";
 
 
     public static Monkey2Activity mSingleton;
     public static Monkey2Activity mSingleton;
 
 
+    public static List<Delegate> mDelegates=new LinkedList<Delegate>();
+
+    public static class Delegate{
+
+        void onActivityResult( int requestCode,int resultCode,Intent data ){}
+    }
+
+    public static Monkey2Activity instance(){
+
+        return mSingleton;
+    }
+
+    public static ViewGroup layout(){
+
+        return mSingleton.mLayout;
+    }
+
+    public static void addDelegate( Delegate delegate ){
+
+        if( mDelegates.contains( delegate ) ) return;
+
+        mDelegates.add( delegate );
+    }
+
+    // ***** overrides *****
+
     protected void onCreate(Bundle savedInstanceState) {
     protected void onCreate(Bundle savedInstanceState) {
 
 
         super.onCreate(savedInstanceState);
         super.onCreate(savedInstanceState);
@@ -24,14 +54,11 @@ public class Monkey2Activity extends SDLActivity {
         super.onDestroy();
         super.onDestroy();
     }
     }
 
 
-    static public Monkey2Activity instance(){
+    protected void onActivityResult( int requestCode,int resultCode,Intent data ){
 
 
-        return mSingleton;
-    }
-
-    static public ViewGroup layout() {
+        for( Delegate delegate : mDelegates ){
 
 
-        return mSingleton.mLayout;
+            delegate.onActivityResult( requestCode,resultCode,data );
+        }
     }
     }
-
 }
 }

+ 5 - 5
scripts/common.bat

@@ -1,11 +1,11 @@
 
 
 set mx2cc=..\bin\mx2cc_windows.exe
 set mx2cc=..\bin\mx2cc_windows.exe
-set mx2cc_new=..\src\mx2cc\mx2cc.buildv1.1.05\windows_release\mx2cc.exe
-set mx2cc_raspbian_new=..\src\mx2cc\mx2cc.buildv1.1.05\raspbian_release\mx2cc
+set mx2cc_new=..\src\mx2cc\mx2cc.buildv1.1.06\windows_release\mx2cc.exe
+set mx2cc_raspbian_new=..\src\mx2cc\mx2cc.buildv1.1.06\raspbian_release\mx2cc
 
 
 set ted2=..\bin\ted2_windows
 set ted2=..\bin\ted2_windows
-set ted2_new=..\src\ted2\ted2.buildv1.1.05\windows_release
-set ted2go_new=..\src\ted2go\Ted2.buildv1.1.05\windows_release
+set ted2_new=..\src\ted2\ted2.buildv1.1.06\windows_release
+set ted2go_new=..\src\ted2go\Ted2.buildv1.1.06\windows_release
 
 
 set launcher="..\Monkey2 (Windows).exe"
 set launcher="..\Monkey2 (Windows).exe"
-set launcher_new=..\src\launcher\launcher.buildv1.1.05\windows_release\launcher.exe
+set launcher_new=..\src\launcher\launcher.buildv1.1.06\windows_release\launcher.exe

+ 12 - 12
scripts/common.sh

@@ -9,34 +9,34 @@ launcher_new=""
 if [ "$OSTYPE" = "linux-gnu" ]
 if [ "$OSTYPE" = "linux-gnu" ]
 then
 then
 	mx2cc="../bin/mx2cc_linux"
 	mx2cc="../bin/mx2cc_linux"
-	mx2cc_new="../src/mx2cc/mx2cc.buildv1.1.05/linux_release/mx2cc"
+	mx2cc_new="../src/mx2cc/mx2cc.buildv1.1.06/linux_release/mx2cc"
 	
 	
 	ted2="../bin/ted2_linux"
 	ted2="../bin/ted2_linux"
-	ted2_new="../src/ted2/ted2.buildv1.1.05/linux_release"
-	ted2go_new="../src/ted2go/Ted2.buildv1.1.05/linux_release"
+	ted2_new="../src/ted2/ted2.buildv1.1.06/linux_release"
+	ted2go_new="../src/ted2go/Ted2.buildv1.1.06/linux_release"
 	
 	
 	launcher="../Monkey2 (Linux)"
 	launcher="../Monkey2 (Linux)"
-	launcher_new="../src/launcher/launcher.buildv1.1.05/linux_release/launcher"
+	launcher_new="../src/launcher/launcher.buildv1.1.06/linux_release/launcher"
 	
 	
 elif [ "$OSTYPE" = "linux-gnueabihf" ]
 elif [ "$OSTYPE" = "linux-gnueabihf" ]
 then
 then
 	mx2cc="../bin/mx2cc_raspbian"
 	mx2cc="../bin/mx2cc_raspbian"
-	mx2cc_new="../src/mx2cc/mx2cc.buildv1.1.02/raspbian_release/mx2cc"
+	mx2cc_new="../src/mx2cc/mx2cc.buildv1.1.06/raspbian_release/mx2cc"
 	
 	
 	ted2="../bin/ted2_raspbian"
 	ted2="../bin/ted2_raspbian"
-	ted2_new="../src/ted2/ted2.buildv1.1.02/raspbian_release"
-	ted2go_new="../src/ted2go/Ted2.buildv1.1.02/raspbian_release"
+	ted2_new="../src/ted2/ted2.buildv1.1.06/raspbian_release"
+	ted2go_new="../src/ted2go/Ted2.buildv1.1.06/raspbian_release"
 	
 	
 	launcher="../Monkey2 (Raspbian)"
 	launcher="../Monkey2 (Raspbian)"
-	launcher_new="../src/launcher/launcher.buildv1.1.02/raspbian_release/launcher"
+	launcher_new="../src/launcher/launcher.buildv1.1.06/raspbian_release/launcher"
 else
 else
 	mx2cc="../bin/mx2cc_macos"
 	mx2cc="../bin/mx2cc_macos"
-	mx2cc_new="../src/mx2cc/mx2cc.buildv1.1.05/macos_release/mx2cc"
+	mx2cc_new="../src/mx2cc/mx2cc.buildv1.1.06/macos_release/mx2cc"
 	
 	
 	ted2="../bin/ted2_macos.app"
 	ted2="../bin/ted2_macos.app"
-	ted2_new="../src/ted2/ted2.buildv1.1.05/macos_release/ted2.app"
-	ted2go_new="../src/ted2go/Ted2.buildv1.1.05/macos_release/ted2.app"
+	ted2_new="../src/ted2/ted2.buildv1.1.06/macos_release/ted2.app"
+	ted2go_new="../src/ted2go/Ted2.buildv1.1.06/macos_release/ted2.app"
 	
 	
 	launcher="../Monkey2 (Macos).app"
 	launcher="../Monkey2 (Macos).app"
-	launcher_new="../src/launcher/launcher.buildv1.1.05/macos_release/launcher.app"
+	launcher_new="../src/launcher/launcher.buildv1.1.06/macos_release/launcher.app"
 fi
 fi

+ 2 - 0
scripts/updatemods.bat

@@ -1,6 +1,8 @@
 
 
 echo off
 echo off
 
 
+call common.bat
+
 echo.
 echo.
 echo ***** Updating modules *****
 echo ***** Updating modules *****
 echo.
 echo.

+ 1 - 1
scripts/updatemx2cc.sh

@@ -5,7 +5,7 @@ echo ""
 echo "***** Updating mx2cc *****"
 echo "***** Updating mx2cc *****"
 echo ""
 echo ""
 
 
-$mx2cc makemods -config=release
+$mx2cc makemods -config=release monkey libc miniz stb-image stb-image-write stb-vorbis std
 
 
 $mx2cc makeapp -apptype=console -config=release ../src/mx2cc/mx2cc.monkey2
 $mx2cc makeapp -apptype=console -config=release ../src/mx2cc/mx2cc.monkey2
 
 

+ 3 - 2
src/createrelease/createrelease.monkey2

@@ -5,9 +5,9 @@
 Using libc..
 Using libc..
 Using std..
 Using std..
 
 
-Const MX2CC_VERSION:="1.1.05"
+Const MX2CC_VERSION:="1.1.06"
 
 
-Const RELEASE_SUFFIX:="b"
+Const RELEASE_SUFFIX:=""
 
 
 Const OUTPUT:="Monkey2-v"+MX2CC_VERSION+RELEASE_SUFFIX
 Const OUTPUT:="Monkey2-v"+MX2CC_VERSION+RELEASE_SUFFIX
 
 
@@ -16,6 +16,7 @@ Const IGNORE:="
 src/c2mx2
 src/c2mx2
 src/createrelease
 src/createrelease
 modules/admob
 modules/admob
+modules/iap
 modules/linq
 modules/linq
 modules/gles30
 modules/gles30
 bin/ted2.state.json
 bin/ted2.state.json

+ 1 - 1
src/mx2cc/mx2.monkey2

@@ -50,4 +50,4 @@ Using libc
 ' 3) edit .sh and .bat files to use new version (common.sh, common.bat)
 ' 3) edit .sh and .bat files to use new version (common.sh, common.bat)
 ' 4) ./rebuildall
 ' 4) ./rebuildall
 '
 '
-Const MX2CC_VERSION:="1.1.05"
+Const MX2CC_VERSION:="1.1.06"

+ 2 - 2
src/mx2cc/mx2cc.monkey2

@@ -25,7 +25,7 @@ Const FORCE_MSVC:=False
 
 
 Global StartDir:String
 Global StartDir:String
 
 
-Const TestArgs:="mx2cc makemods"
+'Const TestArgs:="mx2cc makemods"
 
 
 'Const TestArgs:="mx2cc makedocs mojo3d"
 'Const TestArgs:="mx2cc makedocs mojo3d"
 
 
@@ -33,7 +33,7 @@ Const TestArgs:="mx2cc makemods"
 
 
 'Const TestArgs:="mx2cc makemods -config=debug monkey libc miniz stb-image stb-image-write stb-vorbis std"
 'Const TestArgs:="mx2cc makemods -config=debug monkey libc miniz stb-image stb-image-write stb-vorbis std"
 
 
-'Const TestArgs:="mx2cc makeapp -target=desktop -apptype=console -run src/mx2cc/test.monkey2"
+Const TestArgs:="mx2cc makeapp -target=desktop -apptype=console -run src/mx2cc/test.monkey2"
 
 
 'To build with old mx2cc...
 'To build with old mx2cc...
 '
 '

+ 7 - 4
src/mx2cc/test.monkey2

@@ -1,8 +1,11 @@
 
 
-#Import "test2
-
 Function Main()
 Function Main()
-	
-	Test()
 
 
+	Local i:=010
+	
+	Print i	
+	Print 010.10
+	
+	Print 1.0e+20
+	
 End
 End

+ 10 - 2
src/mx2cc/value.monkey2

@@ -233,6 +233,16 @@ Class LiteralValue Extends Value
 	
 	
 	Method New( type:Type,value:String )
 	Method New( type:Type,value:String )
 		Self.type=type
 		Self.type=type
+		
+		Local ptype:=TCast<PrimType>( type )
+		If ptype And ptype.IsNumeric
+			If ptype.IsIntegral
+				value=String( ULong( value ) )
+			Else If ptype.IsReal
+				value=String( Double( value ) )
+			Endif
+		Endif
+
 		Self.value=value
 		Self.value=value
 	End
 	End
 	
 	
@@ -250,11 +260,9 @@ Class LiteralValue Extends Value
 		'upcast to...
 		'upcast to...
 		Local ptype:=TCast<PrimType>( type )
 		Local ptype:=TCast<PrimType>( type )
 		If Not ptype Return New UpCastValue( type,Self )
 		If Not ptype Return New UpCastValue( type,Self )
-'		If Not ptype SemantError( "LiteralValue.UpCast()" )
 		
 		
 		Local ptype2:=TCast<PrimType>( Self.type )
 		Local ptype2:=TCast<PrimType>( Self.type )
 		If Not ptype2 Return New UpCastValue( type,Self )
 		If Not ptype2 Return New UpCastValue( type,Self )
-'		If Not ptype2 SemantError( "LiteralValue.UpCast()" )
 		
 		
 		Local result:=""
 		Local result:=""
 		
 		

+ 0 - 197
src/ted2/bin/t.txt

@@ -1,197 +0,0 @@
-GNU Wget 1.18, a non-interactive network retriever.
-Usage: wget [OPTION]... [URL]...
-
-Mandatory arguments to long options are mandatory for short options too.
-
-Startup:
-  -V,  --version                   display the version of Wget and exit
-  -h,  --help                      print this help
-  -b,  --background                go to background after startup
-  -e,  --execute=COMMAND           execute a `.wgetrc'-style command
-
-Logging and input file:
-  -o,  --output-file=FILE          log messages to FILE
-  -a,  --append-output=FILE        append messages to FILE
-  -d,  --debug                     print lots of debugging information
-  -q,  --quiet                     quiet (no output)
-  -v,  --verbose                   be verbose (this is the default)
-  -nv, --no-verbose                turn off verboseness, without being quiet
-       --report-speed=TYPE         output bandwidth as TYPE.  TYPE can be bits
-  -i,  --input-file=FILE           download URLs found in local or external FILE
-       --input-metalink=FILE       download files covered in local Metalink FILE
-  -F,  --force-html                treat input file as HTML
-  -B,  --base=URL                  resolves HTML input-file links (-i -F)
-                                     relative to URL
-       --config=FILE               specify config file to use
-       --no-config                 do not read any config file
-       --rejected-log=FILE         log reasons for URL rejection to FILE
-
-Download:
-  -t,  --tries=NUMBER              set number of retries to NUMBER (0 unlimits)
-       --retry-connrefused         retry even if connection is refused
-  -O,  --output-document=FILE      write documents to FILE
-  -nc, --no-clobber                skip downloads that would download to
-                                     existing files (overwriting them)
-  -c,  --continue                  resume getting a partially-downloaded file
-       --start-pos=OFFSET          start downloading from zero-based position OFFSET
-       --progress=TYPE             select progress gauge type
-       --show-progress             display the progress bar in any verbosity mode
-  -N,  --timestamping              don't re-retrieve files unless newer than
-                                     local
-       --no-if-modified-since      don't use conditional if-modified-since get
-                                     requests in timestamping mode
-       --no-use-server-timestamps  don't set the local file's timestamp by
-                                     the one on the server
-  -S,  --server-response           print server response
-       --spider                    don't download anything
-  -T,  --timeout=SECONDS           set all timeout values to SECONDS
-       --dns-timeout=SECS          set the DNS lookup timeout to SECS
-       --connect-timeout=SECS      set the connect timeout to SECS
-       --read-timeout=SECS         set the read timeout to SECS
-  -w,  --wait=SECONDS              wait SECONDS between retrievals
-       --waitretry=SECONDS         wait 1..SECONDS between retries of a retrieval
-       --random-wait               wait from 0.5*WAIT...1.5*WAIT secs between retrievals
-       --no-proxy                  explicitly turn off proxy
-  -Q,  --quota=NUMBER              set retrieval quota to NUMBER
-       --bind-address=ADDRESS      bind to ADDRESS (hostname or IP) on local host
-       --limit-rate=RATE           limit download rate to RATE
-       --no-dns-cache              disable caching DNS lookups
-       --restrict-file-names=OS    restrict chars in file names to ones OS allows
-       --ignore-case               ignore case when matching files/directories
-  -4,  --inet4-only                connect only to IPv4 addresses
-  -6,  --inet6-only                connect only to IPv6 addresses
-       --prefer-family=FAMILY      connect first to addresses of specified family,
-                                     one of IPv6, IPv4, or none
-       --user=USER                 set both ftp and http user to USER
-       --password=PASS             set both ftp and http password to PASS
-       --ask-password              prompt for passwords
-       --no-iri                    turn off IRI support
-       --local-encoding=ENC        use ENC as the local encoding for IRIs
-       --remote-encoding=ENC       use ENC as the default remote encoding
-       --unlink                    remove file before clobber
-       --metalink-over-http        use Metalink metadata from HTTP response headers
-       --preferred-location        preferred location for Metalink resources
-
-Directories:
-  -nd, --no-directories            don't create directories
-  -x,  --force-directories         force creation of directories
-  -nH, --no-host-directories       don't create host directories
-       --protocol-directories      use protocol name in directories
-  -P,  --directory-prefix=PREFIX   save files to PREFIX/..
-       --cut-dirs=NUMBER           ignore NUMBER remote directory components
-
-HTTP options:
-       --http-user=USER            set http user to USER
-       --http-password=PASS        set http password to PASS
-       --no-cache                  disallow server-cached data
-       --default-page=NAME         change the default page name (normally
-                                     this is 'index.html'.)
-  -E,  --adjust-extension          save HTML/CSS documents with proper extensions
-       --ignore-length             ignore 'Content-Length' header field
-       --header=STRING             insert STRING among the headers
-       --max-redirect              maximum redirections allowed per page
-       --proxy-user=USER           set USER as proxy username
-       --proxy-password=PASS       set PASS as proxy password
-       --referer=URL               include 'Referer: URL' header in HTTP request
-       --save-headers              save the HTTP headers to file
-  -U,  --user-agent=AGENT          identify as AGENT instead of Wget/VERSION
-       --no-http-keep-alive        disable HTTP keep-alive (persistent connections)
-       --no-cookies                don't use cookies
-       --load-cookies=FILE         load cookies from FILE before session
-       --save-cookies=FILE         save cookies to FILE after session
-       --keep-session-cookies      load and save session (non-permanent) cookies
-       --post-data=STRING          use the POST method; send STRING as the data
-       --post-file=FILE            use the POST method; send contents of FILE
-       --method=HTTPMethod         use method "HTTPMethod" in the request
-       --body-data=STRING          send STRING as data. --method MUST be set
-       --body-file=FILE            send contents of FILE. --method MUST be set
-       --content-disposition       honor the Content-Disposition header when
-                                     choosing local file names (EXPERIMENTAL)
-       --content-on-error          output the received content on server errors
-       --auth-no-challenge         send Basic HTTP authentication information
-                                     without first waiting for the server's
-                                     challenge
-
-HTTPS (SSL/TLS) options:
-       --secure-protocol=PR        choose secure protocol, one of auto, SSLv2,
-                                     SSLv3, TLSv1 and PFS
-       --https-only                only follow secure HTTPS links
-       --no-check-certificate      don't validate the server's certificate
-       --certificate=FILE          client certificate file
-       --certificate-type=TYPE     client certificate type, PEM or DER
-       --private-key=FILE          private key file
-       --private-key-type=TYPE     private key type, PEM or DER
-       --ca-certificate=FILE       file with the bundle of CAs
-       --ca-directory=DIR          directory where hash list of CAs is stored
-       --crl-file=FILE             file with bundle of CRLs
-       --pinnedpubkey=FILE/HASHES  Public key (PEM/DER) file, or any number
-                                   of base64 encoded sha256 hashes preceded by
-                                   'sha256//' and seperated by ';', to verify
-                                   peer against
-       --random-file=FILE          file with random data for seeding the SSL PRNG
-       --egd-file=FILE             file naming the EGD socket with random data
-
-HSTS options:
-       --no-hsts                   disable HSTS
-       --hsts-file                 path of HSTS database (will override default)
-
-FTP options:
-       --ftp-user=USER             set ftp user to USER
-       --ftp-password=PASS         set ftp password to PASS
-       --no-remove-listing         don't remove '.listing' files
-       --no-glob                   turn off FTP file name globbing
-       --no-passive-ftp            disable the "passive" transfer mode
-       --preserve-permissions      preserve remote file permissions
-       --retr-symlinks             when recursing, get linked-to files (not dir)
-
-FTPS options:
-       --ftps-implicit                 use implicit FTPS (default port is 990)
-       --ftps-resume-ssl               resume the SSL/TLS session started in the control connection when
-                                         opening a data connection
-       --ftps-clear-data-connection    cipher the control channel only; all the data will be in plaintext
-       --ftps-fallback-to-ftp          fall back to FTP if FTPS is not supported in the target server
-WARC options:
-       --warc-file=FILENAME        save request/response data to a .warc.gz file
-       --warc-header=STRING        insert STRING into the warcinfo record
-       --warc-max-size=NUMBER      set maximum size of WARC files to NUMBER
-       --warc-cdx                  write CDX index files
-       --warc-dedup=FILENAME       do not store records listed in this CDX file
-       --no-warc-compression       do not compress WARC files with GZIP
-       --no-warc-digests           do not calculate SHA1 digests
-       --no-warc-keep-log          do not store the log file in a WARC record
-       --warc-tempdir=DIRECTORY    location for temporary files created by the
-                                     WARC writer
-
-Recursive download:
-  -r,  --recursive                 specify recursive download
-  -l,  --level=NUMBER              maximum recursion depth (inf or 0 for infinite)
-       --delete-after              delete files locally after downloading them
-  -k,  --convert-links             make links in downloaded HTML or CSS point to
-                                     local files
-       --convert-file-only         convert the file part of the URLs only (usually known as the basename)
-       --backups=N                 before writing file X, rotate up to N backup files
-  -K,  --backup-converted          before converting file X, back up as X.orig
-  -m,  --mirror                    shortcut for -N -r -l inf --no-remove-listing
-  -p,  --page-requisites           get all images, etc. needed to display HTML page
-       --strict-comments           turn on strict (SGML) handling of HTML comments
-
-Recursive accept/reject:
-  -A,  --accept=LIST               comma-separated list of accepted extensions
-  -R,  --reject=LIST               comma-separated list of rejected extensions
-       --accept-regex=REGEX        regex matching accepted URLs
-       --reject-regex=REGEX        regex matching rejected URLs
-       --regex-type=TYPE           regex type (posix)
-  -D,  --domains=LIST              comma-separated list of accepted domains
-       --exclude-domains=LIST      comma-separated list of rejected domains
-       --follow-ftp                follow FTP links from HTML documents
-       --follow-tags=LIST          comma-separated list of followed HTML tags
-       --ignore-tags=LIST          comma-separated list of ignored HTML tags
-  -H,  --span-hosts                go to foreign hosts when recursive
-  -L,  --relative                  follow relative links only
-  -I,  --include-directories=LIST  list of allowed directories
-       --trust-server-names        use the name specified by the redirection
-                                     URL's last component
-  -X,  --exclude-directories=LIST  list of excluded directories
-  -np, --no-parent                 don't ascend to the parent directory
-
-Mail bug reports and suggestions to <[email protected]>

BIN=BIN
src/ted2/bin/tmp.zip


+ 62 - 4
src/ted2go/MainWindow.monkey2

@@ -11,6 +11,7 @@ Namespace ted2go
 
 
 #Import "assets/fonts/@/fonts"
 #Import "assets/fonts/@/fonts"
 
 
+#Import "assets/themes/irc/@/themes/irc"
 
 
 Global MainWindow:MainWindowInstance
 Global MainWindow:MainWindowInstance
 
 
@@ -57,13 +58,17 @@ Class MainWindowInstance Extends Window
 		End
 		End
 		
 		
 		'IRC tab
 		'IRC tab
+		
 		_ircView=New IRCView
 		_ircView=New IRCView
-		_ircView.introScreen.Text="Get live help from other Monkey 2 users"
+		_ircView.introScreen.Text="Hang out with other Monkey 2 users"
 		_ircView.introScreen.OnNickChange+=Lambda( nick:String )
 		_ircView.introScreen.OnNickChange+=Lambda( nick:String )
 			Prefs.IrcNickname=nick
 			Prefs.IrcNickname=nick
 		End
 		End
+		
 		SetupChatTab()
 		SetupChatTab()
 		
 		
+		If Prefs.IrcConnect Then _ircView.introScreen.Connect()
+		
 		'Build tab
 		'Build tab
 		
 		
 		_buildConsole=New ConsoleExt
 		_buildConsole=New ConsoleExt
@@ -367,6 +372,8 @@ Class MainWindowInstance Extends Window
 		_consolesTabView.AddTab( "Find",_findConsole,False )
 		_consolesTabView.AddTab( "Find",_findConsole,False )
 		_consolesTabView.AddTab( "Chat",_ircView,False )
 		_consolesTabView.AddTab( "Chat",_ircView,False )
 		
 		
+		_consolesTabView.CurrentChanged+=OnChatClicked
+		
 		_statusBar=New StatusBarView
 		_statusBar=New StatusBarView
 		
 		
 		_contentView=New DockingView
 		_contentView=New DockingView
@@ -506,13 +513,14 @@ Class MainWindowInstance Extends Window
 	End
 	End
 	
 	
 	Method Terminate()
 	Method Terminate()
-	
+		
 		_isTerminating=True
 		_isTerminating=True
 		SaveState()
 		SaveState()
 		_enableSaving=False
 		_enableSaving=False
 		OnForceStop() ' kill build process if started
 		OnForceStop() ' kill build process if started
 		ProcessReader.StopAll()
 		ProcessReader.StopAll()
-
+		If _ircView Then _ircView.Quit("Closing Ted2Go")
+		
 		App.Terminate()
 		App.Terminate()
 	End
 	End
 
 
@@ -956,7 +964,7 @@ Class MainWindowInstance Extends Window
 	Field _helpIdent:String
 	Field _helpIdent:String
 	
 	
 	Method OnRender( canvas:Canvas ) Override
 	Method OnRender( canvas:Canvas ) Override
-	
+		
 		If Not _inited
 		If Not _inited
 			_inited=True
 			_inited=True
 			OnInit()
 			OnInit()
@@ -969,6 +977,8 @@ Class MainWindowInstance Extends Window
 			SizeChanged()
 			SizeChanged()
 		Endif
 		Endif
 		
 		
+		UpdateIrcIcon()
+		
 		Rendered()
 		Rendered()
 		Rendered=Null
 		Rendered=Null
 	End
 	End
@@ -995,6 +1005,8 @@ Class MainWindowInstance Extends Window
 		
 		
 		If Not _ircView Return
 		If Not _ircView Return
 		
 		
+		_ircView.ircHandler.OnMessage+=Self.OnChatMessage
+		
 		Local intro:=_ircView.introScreen
 		Local intro:=_ircView.introScreen
 		
 		
 		If intro.IsConnected Return
 		If intro.IsConnected Return
@@ -1007,6 +1019,49 @@ Class MainWindowInstance Extends Window
 		
 		
 	End
 	End
 	
 	
+	Method OnChatClicked()
+		If _consolesTabView.CurrentView<>_ircView Then Return
+		
+		_consolesTabView.SetTabIcon( _ircView, Null )
+		_ircNotifyIcon=0
+	End
+	
+	Method OnChatMessage( message:IRCMessage, container:IRCMessageContainer, server:IRCServer )
+		If message.type<>"PRIVMSG" Or _consolesTabView.CurrentView=_ircView Then Return
+		
+		'Show notice icon
+		If message.text.Contains(server.nickname) Then
+			If _ircNotifyIcon<=1 Then _ircNotifyIcon=2
+	
+		Else
+			If _ircNotifyIcon<=0 Then _ircNotifyIcon=1
+		Endif
+		
+	End
+	
+	Method UpdateIrcIcon()
+		If _ircNotifyIcon<=0 Then Return
+		
+		Local time:Int=Int(Millisecs()*0.0025)
+		
+		If time=_ircIconBlink Then Return
+		_ircIconBlink=time
+		
+		If time Mod 2 Then
+			Select _ircNotifyIcon
+				
+				Case 1
+					_consolesTabView.SetTabIcon( _ircView, App.Theme.OpenImage( "irc/notice.png" ) )
+					
+				Case 2
+					_consolesTabView.SetTabIcon( _ircView, App.Theme.OpenImage( "irc/important.png" ) )
+			End
+		Else
+			_consolesTabView.SetTabIcon( _ircView, App.Theme.OpenImage( "irc/blink.png" ) )
+		Endif
+		
+	End
+	
 	Method LoadState( jobj:JsonObject )
 	Method LoadState( jobj:JsonObject )
 	
 	
 		If jobj.Contains( "browserSize" )
 		If jobj.Contains( "browserSize" )
@@ -1137,6 +1192,9 @@ Class MainWindowInstance Extends Window
 	Field _consolesTabView:TabView
 	Field _consolesTabView:TabView
 	Field _browsersTabView:TabView
 	Field _browsersTabView:TabView
 	
 	
+	Field _ircNotifyIcon:Int
+	Field _ircIconBlink:Int
+	
 	Field _forceStop:Action
 	Field _forceStop:Action
 
 
 	Field _tabMenu:Menu
 	Field _tabMenu:Menu

+ 5 - 1
src/ted2go/Prefs.monkey2

@@ -21,7 +21,8 @@ Class Prefs
 	Global IrcNickname:String
 	Global IrcNickname:String
 	Global IrcServer:="irc.freenode.net"
 	Global IrcServer:="irc.freenode.net"
 	Global IrcPort:=6667
 	Global IrcPort:=6667
-	Global IrcRooms:="#monkey2" '#monkey2Ui#monkey23D
+	Global IrcRooms:="#monkey2" '#mojox#mojo2d
+	Global IrcConnect:Bool=False
 	'
 	'
 	Global EditorToolBarVisible:=False
 	Global EditorToolBarVisible:=False
 	Global EditorGutterVisible:=True
 	Global EditorGutterVisible:=True
@@ -46,6 +47,8 @@ Class Prefs
 			IrcServer=Json_GetString( j2,"server",IrcServer )
 			IrcServer=Json_GetString( j2,"server",IrcServer )
 			IrcPort=Json_GetInt( j2,"port",IrcPort )
 			IrcPort=Json_GetInt( j2,"port",IrcPort )
 			IrcRooms=Json_GetString( j2,"rooms",IrcRooms )
 			IrcRooms=Json_GetString( j2,"rooms",IrcRooms )
+			IrcConnect=Json_GetBool( j2,"connect",IrcConnect )
+			
 		Endif
 		Endif
 		
 		
 		If json.Contains( "main" )
 		If json.Contains( "main" )
@@ -108,6 +111,7 @@ Class Prefs
 		j["server"]=New JsonString( IrcServer )
 		j["server"]=New JsonString( IrcServer )
 		j["port"]=New JsonNumber( IrcPort )
 		j["port"]=New JsonNumber( IrcPort )
 		j["rooms"]=New JsonString( IrcRooms )
 		j["rooms"]=New JsonString( IrcRooms )
+		j["connect"]=New JsonBool( IrcConnect )
 		
 		
 		j=New JsonObject
 		j=New JsonObject
 		json["completion"]=j
 		json["completion"]=j

+ 9 - 12
src/ted2go/Ted2.monkey2

@@ -127,18 +127,16 @@ Function Main()
 	Local root:=Prefs.MonkeyRootPath
 	Local root:=Prefs.MonkeyRootPath
 	If Not root Then root=AppDir()
 	If Not root Then root=AppDir()
 	
 	
-	' return real folder or empty string
-	Local path:=SetupMonkeyRootPath( root,True )
-	If Not path
-		libc.exit_( 1 )
-		Return
-	Endif
+	root=SetupMonkeyRootPath( root,True )
+	If Not root libc.exit_( 1 )
 	
 	
-	If path<>root
-		Prefs.MonkeyRootPath=path
+	If root<>Prefs.MonkeyRootPath
+		Prefs.MonkeyRootPath=root
 		Prefs.SaveLocalState()
 		Prefs.SaveLocalState()
 	Endif
 	Endif
 	
 	
+	ChangeDir( root )
+	
 	'load ted2 state
 	'load ted2 state
 	'
 	'
 	Local jobj:=JsonObject.Load( "bin/ted2.state.json" )
 	Local jobj:=JsonObject.Load( "bin/ted2.state.json" )
@@ -148,7 +146,8 @@ Function Main()
 	
 	
 	'initial theme
 	'initial theme
 	'
 	'
-	If Not jobj.Contains( "theme" ) jobj["theme"]=New JsonString( "theme-classic-dark" )
+	If Not jobj.Contains( "theme" ) jobj["theme"]=New JsonString( "theme-prime-blue" )
+
 	If Not jobj.Contains( "themeScale" ) jobj["themeScale"]=New JsonNumber( 1 )
 	If Not jobj.Contains( "themeScale" ) jobj["themeScale"]=New JsonNumber( 1 )
 	
 	
 	Local config:=New StringMap<String>
 	Local config:=New StringMap<String>
@@ -194,9 +193,7 @@ End
 Function SetupMonkeyRootPath:String( rootPath:String,searchMode:Bool )
 Function SetupMonkeyRootPath:String( rootPath:String,searchMode:Bool )
 	
 	
 #If __DESKTOP_TARGET__
 #If __DESKTOP_TARGET__
-	
-	ChangeDir( rootPath )
-	
+
 	If searchMode
 	If searchMode
 		' search for desired folder
 		' search for desired folder
 		Local found:=FindBinFolder( rootPath )
 		Local found:=FindBinFolder( rootPath )

BIN=BIN
src/ted2go/assets/themes/hollow_assets/checkbox_icons.png


BIN=BIN
src/ted2go/assets/themes/hollow_assets/dialog_skin.png


BIN=BIN
src/ted2go/assets/themes/hollow_assets/progressbar_icons.png


BIN=BIN
src/ted2go/assets/themes/hollow_assets/tabclose_icons.png


BIN=BIN
src/ted2go/assets/themes/hollow_assets/treeview_icons.png


BIN=BIN
src/ted2go/assets/themes/irc/blink.png


BIN=BIN
src/ted2go/assets/themes/irc/important.png


BIN=BIN
src/ted2go/assets/themes/irc/notice.png


BIN=BIN
src/ted2go/assets/themes/prime_assets/button_skin.png


BIN=BIN
src/ted2go/assets/themes/prime_assets/square.png


BIN=BIN
src/ted2go/assets/themes/prime_assets/tabbutton_skin.png


+ 474 - 0
src/ted2go/assets/themes/theme-hollow.json

@@ -0,0 +1,474 @@
+//Theme by @Hezkore
+//Inspired by gruvbox
+{
+	"extends":"ted2-default",
+	
+	"fonts":{
+	
+		"normal":"Roboto-Medium.ttf,16",
+		"fixedWidth":"RobotoMono-Medium.ttf,19",
+		"small":"Roboto-Medium.ttf,14",
+		"editor":"MesloLGSDZ-Bold.ttf,19"
+	},
+
+	"colors":{
+
+		"border": "#121111",
+
+		"transparent": "#0000",
+		"darkest": "#222020",
+		"darker": "#32302F",
+		"dark": "#3C3836",
+		"bright": "#504945",
+		"brighter": "#665C54",
+		"brightest": "#7C6F64",
+
+		"text-default": "#CECECE",
+		"text-highlight": "#FFFFFF",
+		"text-disabled": "#6F6F6F",
+		"text-background": "#969696",
+		
+		"textview-cursor":"textview-color1",
+		"textview-selection":"brightest",
+		"textview-cursor-line":"dark",
+		"textview-whitespaces":"bright",
+
+		"textview-color0":"#FF00FF", 	//When is this used?
+		"textview-color1": "#EBDAB4",	//identifiers
+		"textview-color2": "#FB4934",	//keywords
+		"textview-color3": "#B8BB26",	//strings
+		"textview-color4": "#B087D2",	//numbers
+		"textview-color5": "#6F665E",	//comment
+		"textview-color6": "#FABD2F",	//preproc
+		"textview-color7": "#8EC07C",
+		
+		"windowClearColor":"darkest",
+		"menu-shortcut":"text-background",
+
+		"statusbar": "darkest",
+		"statusbar-active": "darkest"
+	},
+	
+	"styles":{
+
+		"default":{
+			"font":"normal",
+			"textColor":"text-default",
+			"iconColor":"#ffff",
+			"states":{
+				"disabled":{
+					"textColor":"text-disabled",
+					"iconColor":"#8fff"
+				}
+			}
+		},
+
+		"CodeMapView":{
+			"extends":"TextView",
+			"margin":[ 4,0,0,0 ]
+		},
+
+		"GutterView":{
+			"padding":[ -16,0,16,0 ],
+			"extends":"TextView",
+			"textColor":"text-disabled",
+			"backgroundColor":"darkest",
+			"font":"editor"
+		},
+		
+		"DebugToolBar":{
+			"extends":"ToolBar",
+			"border":[ 1 ],
+			"borderColor":"darker",
+			"icons":"debug_icons.png"
+		},
+		
+		"HelpTextField":{
+			"extends":"TextField",
+			"skinColor":"darker"
+		},
+
+		"Hint":{
+			"font":"small",
+			"textColor":"text-default",
+			"backgroundColor":"border"
+		},
+
+		"ToolBarExt":{
+			"extends":"ToolBar",
+			"padding":[ 0 ],
+			"margin":[ 0 ],
+			"backgroundColor":"dark",
+			"border":[ 0 ]
+		},
+
+		"MainToolBar":{
+			"extends":"ToolBarExt"
+		},
+
+		"EditorToolBar":{
+			"extends":"ToolBarExt"
+		},
+
+		"SourceToolBar":{
+			"extends":"ToolBarExt",
+			"backgroundColor":"darker"
+		},
+
+		"TabViewArrowPrev":{
+			"extends":"Button",
+			"textColor":"text-background",
+			"padding":[ 8,4 ],
+			"margin":[ 2,0,2,0 ]
+		},
+
+		"TabViewArrowNext":{
+			"extends":"Button",
+			"textColor":"text-background",
+			"padding":[ 8,4 ],
+			"margin":[ 2,0,12,0 ]
+		},
+
+		"ProgressBar":{
+			"icons":"hollow_assets/progressbar_icons.png"
+		},
+
+		"StatusBar":{
+			"extends":"DockingView",
+			"padding":[ 0,8,0,8 ],
+			"border":[0,1,0,0],
+			"borderColor":"border",
+			"backgroundColor":"statusbar"
+		},
+		"StatusBarText":{
+			"extends":"Label",
+			"font":"small"
+		},
+		"StatusBarLineInfo":{
+			"extends":"Label",
+			"margin":[ 40,0,0,0 ],
+			"font":"small"
+		},
+		"StatusBarIns":{
+			"extends":"Label",
+			"font":"small"
+		},
+		"StatusBarProgress":{
+			"extends":"ProgressBar",
+			"margin":[ 6,0 ]
+		},
+
+		"CompletionDialog":{
+			"extends":"Dialog"
+		},
+		"CompletionDialogContent":{
+			"padding":[ 1 ]
+		},
+		
+		"ProjectTabView":{
+			"extends":"TabView",
+			"backgroundColor":"dark"
+		},
+		
+		"StatusBarButton":{
+			"extends":"ToolButton",
+			"padding":[ 0 ],
+			"skinColor":"transparent"
+		},
+		
+		"Label":{
+			"padding":[8,4]
+		},
+		
+		"Button":{
+			"extends":"Label",
+			"padding":[4,2],
+			"backgroundColor":"dark",
+			"textColor":"text-default",
+			
+			"states":{
+				"hover":{
+					"textColor":"text-highlight",
+					"backgroundColor":"bright"
+				},
+				"active":{
+					"textColor":"text-highlight",
+					"backgroundColor":"brighter"
+				},
+				"selected":{
+					"textColor":"text-highlight",
+					"backgroundColor":"brightest"
+				}
+			}
+		},
+
+		"ToolButton":{
+			"extends":"Button",
+			"backgroundColor":"dark",
+			"padding":[ 2,0 ],
+			"margin":[ 2,0 ],
+
+			"states":{
+				"hover":{
+					"backgroundColor":"bright"
+				},
+				"active":{
+					"backgroundColor":"brighter"
+				},
+				"selected":{
+					"backgroundColor":"brighter"
+				}
+			}
+		},
+		
+		"PushButton":{
+			"extends":"Button",
+			"margin":[4,4]
+		},
+		
+		"CheckButton":{
+			"extends":"Label"
+		},
+		
+		"CheckBox":{
+			"icons":"hollow_assets/checkbox_icons.png",
+			"iconColor":"textview-color7",
+			"margin":[0,0,0,0]
+		},
+		
+		"ScrollView":{
+		},
+		
+		"ScrollBar":{
+			"backgroundColor":"darker"
+		},
+		
+		"ScrollKnob":{
+			"padding":[ 6 ],
+			"border":[ 0 ],
+			"backgroundColor":"dark",
+			"states":{
+				"hover":{
+					"backgroundColor":"bright"
+				},
+				"active":{
+					"backgroundColor":"brighter"
+				}
+			}
+		},
+		
+		"TextView":{
+			"font":"editor",
+			"textColor":"textview-color7",
+			"backgroundColor":"darker"
+		},
+		
+		"TextViewContent":{
+			"padding":[4]
+		},
+		
+		"TextField":{
+			"font":"normal",
+			"padding":[ 2 ],
+			"margin":[ 2 ],
+			"backgroundColor":"darker"
+		},
+		
+		"DockingView":{
+		},
+		
+		"DockedView":{
+		},
+		
+		"DockKnob":{
+			"padding":[ 3 ],
+			"backgroundColor":"darkest",
+			"states":{
+				"hover":{
+					"backgroundColor":"bright"
+				},
+				"active":{
+					"backgroundColor":"brightest"
+				}
+			}
+		},
+		
+		"ToolBar":{
+			"padding":[ 2 ],
+			"backgroundColor":"darker"
+		},
+		
+		"Menu":{
+			"extends":"DockingView",
+			"padding":[ 0 ],
+			"skin":"hollow_assets/dialog_skin.png",
+			"skinColor":"dark"
+		},
+		
+		"MenuButton":{
+			"extends":"Label",
+			"padding":[8,3],
+			"textColor":"text-default",
+			"states":{
+				"hover":{
+					"textColor":"text-highlight",
+					"backgroundColor":"brightest"
+				},
+				"active":{
+					"backgroundColor":"brightest"
+				},
+				"selected":{
+					"backgroundColor":"brightest"
+				}
+			}
+		},
+		
+		"MenuBar":{
+			"extends":"ToolBar",
+			"backgroundColor":"border",
+			"border":[ 0,0,0,1 ],
+			"backgroundColor":"dark",
+			"margin":[ 0 ]
+		},
+		
+		"MenuSeparator":{
+			"padding":[ 0,0,0,1 ],
+			"backgroundColor":"dark",
+			"border":[ 8,8,7,7 ]
+		},
+
+		"TabView":{
+		},
+		
+		"TabBar":{
+			"extends":"ToolBar",
+			"padding":[ 0,0,0,0 ],
+			"backgroundColor":"windowClearColor"
+		},
+		
+		"TabButton":{
+			"extends":"Button",
+			"font":"small",
+			"padding":[10],
+			"textColor":"text-disabled",
+			"backgroundColor":"darkest",
+			"borderColor":"darkest",
+			"border":[0,2,0,0],
+			"states":{
+				"hover":{
+					"textColor":"text-background"
+				},
+				"active":{
+					"textColor":"text-background"
+				},
+				"selected":{
+					"borderColor":"textview-color7",
+					"backgroundColor":"darker",
+					"textColor":"text-default"
+				}
+			}
+		},
+		
+		"TabClose":{
+			"margin":[32,0,0,0 ],
+			"icons":"hollow_assets/tabclose_icons.png",
+			"iconColor":"text-disabled",
+			"states":{
+				"hover":{
+					"iconColor":"text-background"
+				},
+				"active":{
+					"iconColor":"text-highlight"
+				}
+			}
+		},
+		
+		"TableView":{
+			"extends":"DockingView"
+		},
+		
+		"TableHeader":{
+			"extends":"Label",
+			"textColor":"text-highlight",
+			"borderColor":"darker"
+		},
+		
+		"TableColumn":{
+		},
+		
+		"TreeView":{
+			"backgroundColor":"darker",
+			"icons":"hollow_assets/treeview_icons.png",
+			"iconColor":"text-background"
+		},
+		
+		"TreeViewContent":{
+			"padding":[3]
+		},
+
+		"TreeViewNode":{
+			"font":"small",
+			"textColor":"text-background",
+			"padding":[0,2,0,2],
+			"states":{
+				"hover":{
+					"textColor":"text-default"
+				},
+				"selected":{
+					"textColor":"text-default"
+				}
+			}
+		},
+		
+		"ListView":{
+			"backgroundColor":"dark"
+		},
+		
+		"ListViewContent":{
+			"padding":[2]
+		},
+		
+		"ListViewItem":{
+			"padding":[1],
+			"states":{
+				"hover":{
+					"backgroundColor":"darker"
+				},
+				"selected":{
+					"backgroundColor":"darker",
+					"textColor":"text-highlight"
+				}
+			}
+		},
+		
+		"FileBrowser":{
+			"extends":"TreeView"
+		},
+		
+		"HtmlView":{
+		},
+		
+		"Console":{
+			"backgroundColor":"darker"
+		},
+		
+		"Dialog":{
+			"skin":"hollow_assets/dialog_skin.png",
+			"skinColor":"bright"
+		},
+		
+		"DialogTitle":{
+			"extends":"Label",
+			"backgroundColor":"brightest"
+		
+		},
+		
+		"DialogContent":{
+			"padding":[ 8,8,8,4 ]
+		},
+		
+		"DialogActions":{
+			"padding":[ 8,4,8,4 ]
+		}
+	}
+}

+ 28 - 19
src/ted2go/assets/themes/theme-prime-base.json

@@ -40,7 +40,7 @@
 		"textview-color4": "#6C71C4",	//numbers
 		"textview-color4": "#6C71C4",	//numbers
 		"textview-color5": "#606060",	//comment
 		"textview-color5": "#606060",	//comment
 		"textview-color6": "#E74C31",	//preproc
 		"textview-color6": "#E74C31",	//preproc
-		"textview-color7": "#FF00FF",	//When is this used?
+		"textview-color7": "#3298DB",
 		
 		
 		"windowClearColor":"bright",
 		"windowClearColor":"bright",
 		"menu-shortcut":"text-background",
 		"menu-shortcut":"text-background",
@@ -111,8 +111,21 @@
 
 
 		"ToolButton":{
 		"ToolButton":{
 			"extends":"Button",
 			"extends":"Button",
+			"backgroundColor":"dark",
 			"padding":[ 2,0 ],
 			"padding":[ 2,0 ],
-			"margin":[ 2,0 ]
+			"margin":[ 2,0 ],
+
+			"states":{
+				"hover":{
+					"backgroundColor":"bright"
+				},
+				"active":{
+					"backgroundColor":"brighter"
+				},
+				"selected":{
+					"backgroundColor":"brighter"
+				}
+			}
 		},
 		},
 
 
 		"TabViewArrowPrev":{
 		"TabViewArrowPrev":{
@@ -180,21 +193,20 @@
 		"Button":{
 		"Button":{
 			"extends":"Label",
 			"extends":"Label",
 			"padding":[4,2],
 			"padding":[4,2],
-			"skin":"prime_assets/square.png",
-			"skinColor":"darker",
+			"backgroundColor":"darker",
 			
 			
 			"states":{
 			"states":{
 				"hover":{
 				"hover":{
 					"textColor":"accent",
 					"textColor":"accent",
-					"skinColor":"dark"
+					"backgroundColor":"dark"
 				},
 				},
 				"active":{
 				"active":{
 					"textColor":"accent",
 					"textColor":"accent",
-					"skinColor":"dark"
+					"backgroundColor":"dark"
 				},
 				},
 				"selected":{
 				"selected":{
 					"textColor":"accent",
 					"textColor":"accent",
-					"skinColor":"dark"
+					"backgroundColor":"dark"
 				}
 				}
 			}
 			}
 		},
 		},
@@ -222,22 +234,22 @@
 		},
 		},
 		
 		
 		"ScrollKnob":{
 		"ScrollKnob":{
-			"padding":[ 4 ],
+			"padding":[ 6 ],
 			"border":[ 0 ],
 			"border":[ 0 ],
-			"skin":"prime_assets/square.png",
-			"skinColor":"brightest",
+			"backgroundColor":"brightest",
 			"states":{
 			"states":{
 				"hover":{
 				"hover":{
-					"skinColor":"brighter"
+					"backgroundColor":"brighter"
 				},
 				},
 				"active":{
 				"active":{
-					"skinColor":"brightest"
+					"backgroundColor":"brightest"
 				}
 				}
 			}
 			}
 		},
 		},
 		
 		
 		"TextView":{
 		"TextView":{
 			"font":"editor",
 			"font":"editor",
+			"textColor":"textview-color7",
 			"backgroundColor":"dark"
 			"backgroundColor":"dark"
 		},
 		},
 		
 		
@@ -247,10 +259,9 @@
 		
 		
 		"TextField":{
 		"TextField":{
 			"font":"normal",
 			"font":"normal",
-			"padding":[ 2 ],
+			"padding":[ 4 ],
 			"margin":[ 2 ],
 			"margin":[ 2 ],
-			"skin":"prime_assets/square.png",
-			"skinColor":"darker"
+			"backgroundColor":"darker"
 		},
 		},
 		
 		
 		"DockingView":{
 		"DockingView":{
@@ -325,24 +336,22 @@
 		},
 		},
 		
 		
 		"TabButton":{
 		"TabButton":{
-            "skinColor":"brighter",
+            "backgroundColor":"brighter",
 			"extends":"Button",
 			"extends":"Button",
 			"font":"small",
 			"font":"small",
 			"padding":[14,12,14,12],
 			"padding":[14,12,14,12],
 			"border":[0,0,0,4],
 			"border":[0,0,0,4],
 			"borderColor":"accentDark",
 			"borderColor":"accentDark",
-			"skin":"prime_assets/square.png",
 			"textColor":"text-background",
 			"textColor":"text-background",
 			"states":{
 			"states":{
 				"hover":{
 				"hover":{
-					"skinColor":"bright",
 					"textColor":"text-default"
 					"textColor":"text-default"
 				},
 				},
 				"active":{
 				"active":{
 					"textColor":"text-default"
 					"textColor":"text-default"
 				},
 				},
 				"selected":{
 				"selected":{
-					"skinColor":"brightest",
+					"backgroundColor":"brightest",
 					"textColor":"text-highlight",
 					"textColor":"text-highlight",
 					"borderColor":"accent"
 					"borderColor":"accent"
 				}
 				}

+ 2 - 1
src/ted2go/assets/themes/theme-smooth.json

@@ -61,7 +61,8 @@
 		},
 		},
 
 
 		"GutterView":{
 		"GutterView":{
-			"border":[0],
+			"border":[0,0,1,0],
+			"borderColor":"textview-whitespaces",
 			"extends":"TextView",
 			"extends":"TextView",
 			"textColor":"text-disabled"
 			"textColor":"text-disabled"
 		},
 		},

+ 1 - 0
src/ted2go/assets/themes/themes.json

@@ -4,6 +4,7 @@
 	"Monkey 1":"theme-monkey1",
 	"Monkey 1":"theme-monkey1",
 	"Blitzed":"theme-blitzed",
 	"Blitzed":"theme-blitzed",
 	"Basic Blue":"theme-Basic-Blue",
 	"Basic Blue":"theme-Basic-Blue",
+	"Hollow":"theme-hollow",
 	"Prime - Red":"theme-prime-red",
 	"Prime - Red":"theme-prime-red",
 	"Prime - Blue":"theme-prime-blue",
 	"Prime - Blue":"theme-prime-blue",
 	"Smooth":"theme-smooth",
 	"Smooth":"theme-smooth",

+ 6 - 1
src/ted2go/dialog/PrefsDialog.monkey2

@@ -75,6 +75,7 @@ Class PrefsDialog Extends DialogExt
 	Field _chatServer:TextField
 	Field _chatServer:TextField
 	Field _chatPort:TextField
 	Field _chatPort:TextField
 	Field _chatRooms:TextField
 	Field _chatRooms:TextField
+	Field _chatAutoConnect:CheckButton
 	
 	
 	Method OnApply()
 	Method OnApply()
 	
 	
@@ -109,6 +110,7 @@ Class PrefsDialog Extends DialogExt
 		Prefs.IrcServer=_chatServer.Text
 		Prefs.IrcServer=_chatServer.Text
 		Prefs.IrcPort=Int(_chatPort.Text)
 		Prefs.IrcPort=Int(_chatPort.Text)
 		Prefs.IrcRooms=_chatRooms.Text
 		Prefs.IrcRooms=_chatRooms.Text
+		Prefs.IrcConnect=_chatAutoConnect.Checked
 		
 		
 		App.ThemeChanged()
 		App.ThemeChanged()
 		
 		
@@ -293,11 +295,13 @@ Class PrefsDialog Extends DialogExt
 	
 	
 	Method GetChatDock:DockingView()
 	Method GetChatDock:DockingView()
 		
 		
-		Local chatTable:=New TableView( 2,4 )
+		Local chatTable:=New TableView( 2,5 )
 		_chatNick=New TextField( Prefs.IrcNickname )
 		_chatNick=New TextField( Prefs.IrcNickname )
 		_chatServer=New TextField( Prefs.IrcServer )
 		_chatServer=New TextField( Prefs.IrcServer )
 		_chatPort=New TextField( ""+Prefs.IrcPort )
 		_chatPort=New TextField( ""+Prefs.IrcPort )
 		_chatRooms=New TextField( Prefs.IrcRooms )
 		_chatRooms=New TextField( Prefs.IrcRooms )
+		_chatAutoConnect=New CheckButton( "Auto connect at start" )
+		_chatAutoConnect.Checked=Prefs.IrcConnect
 		chatTable[0,0]=New Label( "Nickname" )
 		chatTable[0,0]=New Label( "Nickname" )
 		chatTable[1,0]=_chatNick
 		chatTable[1,0]=_chatNick
 		chatTable[0,1]=New Label( "Server" )
 		chatTable[0,1]=New Label( "Server" )
@@ -306,6 +310,7 @@ Class PrefsDialog Extends DialogExt
 		chatTable[1,2]=_chatPort
 		chatTable[1,2]=_chatPort
 		chatTable[0,3]=New Label( "Rooms" )
 		chatTable[0,3]=New Label( "Rooms" )
 		chatTable[1,3]=_chatRooms
 		chatTable[1,3]=_chatRooms
+		chatTable[0,4]=_chatAutoConnect
 		
 		
 		Local docker:=New DockingView
 		Local docker:=New DockingView
 		docker.AddView( New Label( " " ),"top" )
 		docker.AddView( New Label( " " ),"top" )

+ 67 - 1
src/ted2go/dialog/UpdateModulesDialog.monkey2

@@ -1,4 +1,3 @@
-
 Namespace ted2go
 Namespace ted2go
 
 
 
 
@@ -163,7 +162,73 @@ Class UpdateModulesDialog Extends DialogExt
 	
 	
 	Global _modsNames:=New StringStack
 	Global _modsNames:=New StringStack
 	
 	
+	#rem MARK WAS HERE!!!!!
+	
+	EnumModules code lifted from mx2cc.monkey2
+	
+	This sorts modules into dependancy order.
+	
+	#end
+	Function EnumModules( out:StringStack,cur:String,deps:StringMap<StringStack> )
+		If out.Contains( cur ) Return
+		
+		For Local dep:=Eachin deps[cur]
+			EnumModules( out,dep,deps )
+		Next
+		
+		out.Push( cur )
+	End
+	
+	Function EnumModules:String[]()
+	
+		Local mods:=New StringMap<StringStack>
+		
+		Local modsPath:=MainWindow.ModsPath
+	
+		For Local f:=Eachin LoadDir( modsPath )
+		
+			Local dir:=modsPath+f+"/"
+			If GetFileType( dir )<>FileType.Directory Continue
+			
+			Local str:=LoadString( dir+"module.json" )
+			If Not str Continue
+			
+			Local obj:=JsonObject.Parse( str )
+			If Not obj 
+				Print "Error parsing json:"+dir+"module.json"
+				Continue
+			Endif
+			
+			Local name:=obj["module"].ToString()
+			If name<>f Continue
+			
+			Local deps:=New StringStack
+			If name<>"monkey" deps.Push( "monkey" )
+			
+			Local jdeps:=obj["depends"]
+			If jdeps
+				For Local dep:=Eachin jdeps.ToArray()
+					deps.Push( dep.ToString() )
+				Next
+			Endif
+			
+			mods[name]=deps
+		Next
+		
+		Local out:=New StringStack
+		For Local cur:=Eachin mods.Keys
+			EnumModules( out,cur,mods )
+		Next
+		
+		Return out.ToArray()
+	End
 	
 	
+	Function GetModulesNames( out:StringStack )
+		
+		out.AddAll( EnumModules() )
+	End
+
+#rem	
 	Function GetModulesNames( out:StringStack )
 	Function GetModulesNames( out:StringStack )
 	
 	
 		Local modsPath:=MainWindow.ModsPath
 		Local modsPath:=MainWindow.ModsPath
@@ -179,6 +244,7 @@ Class UpdateModulesDialog Extends DialogExt
 			Endif
 			Endif
 		Next
 		Next
 	End
 	End
+#end
 	
 	
 	Function ShowMessage( title:String,msg:String,okButton:String="  OK  " )
 	Function ShowMessage( title:String,msg:String,okButton:String="  OK  " )
 		
 		

+ 225 - 30
src/ted2go/view/IRCView.monkey2

@@ -3,8 +3,6 @@
 
 
 Namespace ted2go
 Namespace ted2go
 
 
-#Import "assets/"
-
 '=MODULE=
 '=MODULE=
 
 
 'This class is the main class
 'This class is the main class
@@ -56,12 +54,12 @@ Class IRCServer Extends IRCMessageContainer
 	Field serverPort:Int
 	Field serverPort:Int
 	Field sendBuffer:DataBuffer
 	Field sendBuffer:DataBuffer
 	Field receiveBuffer:DataBuffer=New DataBuffer(512)
 	Field receiveBuffer:DataBuffer=New DataBuffer(512)
-	Field fiberSleep:Float=0.26 'Lower value gets internet messages faster but uses more CPU
+	Field fiberSleep:Float=0.35 'Lower value gets internet messages faster but uses more CPU
 	Field updateFiber:Fiber 'Fiber for updating internet mesages
 	Field updateFiber:Fiber 'Fiber for updating internet mesages
 	Field socket:Socket
 	Field socket:Socket
 	Field stream:SocketStream
 	Field stream:SocketStream
 	Field nickname:String
 	Field nickname:String
-	Field realname:String="KoreIRC"
+	Field realname:String="KoreIRC 1.0"
 	Field messageContainers:=New List<IRCMessageContainer>
 	Field messageContainers:=New List<IRCMessageContainer>
 	Field skipContainers:=New String[]("chanserv","nickserv","services","*") 'Make sure these are lower case!
 	Field skipContainers:=New String[]("chanserv","nickserv","services","*") 'Make sure these are lower case!
 	
 	
@@ -386,10 +384,10 @@ Class IRCServer Extends IRCMessageContainer
 					Endif
 					Endif
 					
 					
 				Case "NICK" 'Changing names
 				Case "NICK" 'Changing names
-					'Update local name
+					'Was local name?
 					Local wasSelf:Bool
 					Local wasSelf:Bool
 					If GetNickname(fromUser)=nickname Then
 					If GetNickname(fromUser)=nickname Then
-						wasSelf=true
+						wasSelf=True
 						nickname=msg
 						nickname=msg
 					Endif
 					Endif
 					
 					
@@ -399,8 +397,12 @@ Class IRCServer Extends IRCMessageContainer
 							If u.name=GetNickname(fromUser) Then
 							If u.name=GetNickname(fromUser) Then
 								u.name=msg
 								u.name=msg
 								container.SortUsers()
 								container.SortUsers()
-								TriggerOnMessage(msg,fromUser,msg,type,container)
-								parent.OnUserUpdate(container,Self)
+								
+								If Not wasSelf Then 
+									TriggerOnMessage(msg,fromUser,msg,type,container)
+									parent.OnUserUpdate(container,Self)
+								Endif
+								
 								Exit
 								Exit
 							Endif
 							Endif
 						Next
 						Next
@@ -464,11 +466,19 @@ Class IRCServer Extends IRCMessageContainer
 		nC.type=type
 		nC.type=type
 		messageContainers.AddLast(nC)
 		messageContainers.AddLast(nC)
 		parent.OnNewContainer(nC,Self)
 		parent.OnNewContainer(nC,Self)
+		
+		'Load history for chat rooms
+		If nC.name.StartsWith("#") Then nC.LoadHistory()
+		
 		Return nC
 		Return nC
 	End
 	End
 	
 	
 	'Remove a specific message container
 	'Remove a specific message container
 	Method RemoveMessageContainer(container:IRCMessageContainer)
 	Method RemoveMessageContainer(container:IRCMessageContainer)
+		
+		'Save history for chat rooms
+		If container.name.StartsWith("#") Then container.SaveHistory()
+		
 		messageContainers.Remove(container)
 		messageContainers.Remove(container)
 		If parent Then parent.OnRemoveContainer(container,Self)
 		If parent Then parent.OnRemoveContainer(container,Self)
 	End
 	End
@@ -507,6 +517,50 @@ Class IRCMessageContainer
 	Field gotUsers:Bool 'Have we gotten users before?
 	Field gotUsers:Bool 'Have we gotten users before?
 	Field messages:=New List<IRCMessage>
 	Field messages:=New List<IRCMessage>
 	
 	
+	Method LogPath:String()
+		
+		Return AppDir() + "/logs/" + parent.serverAddress + "/" + name + ".txt"
+		
+	End
+	
+	Method LoadHistory()
+		Local file:String=LoadString( Self.LogPath() )
+		If Not file Then Return
+		
+		Local lines:=file.Split( "~n" )
+		Local type:String
+		Local time:String
+		Local user:String
+		Local message:String
+		
+		For Local s:=Eachin lines
+			If Not s.Contains( ">" ) Or Not s.Contains( " " ) Or Not s.Contains( ":" ) Then Continue
+			
+			type=s.Split( ">" )[0]
+			time=s.Split( ">" )[1].Split( " " )[0]
+			user=s.Split( ">" )[1].Split( " " )[1].Split( ":" )[0]
+			message=s.Split( type + ">" + time + " " + user + ":" )[1]
+			
+			Self.AddMessage( message, user, Self.name, type.ToUpper() ).time=time
+		Next
+		
+	End
+	
+	Method SaveHistory()
+		Local log:String
+		
+		For Local m:=Eachin Self.messages
+			If m.type<>"PRIVMSG" And m.type<>"QUIT" And m.type<>"PART" And m.type<>"JOIN" And m.type<>"NICK" Then Continue
+			
+			log+=m.type+">"+m.time+" "+m.fromUser+":"+m.text+"~n"
+		Next
+		
+		If log.Length>2 Then
+			CreateFile( LogPath(), True )
+			SaveString( log, LogPath() )
+		Endif
+	End
+	
 	Method Remove() Virtual
 	Method Remove() Virtual
 		parent.messageContainers.Remove(Self)
 		parent.messageContainers.Remove(Self)
 	End
 	End
@@ -520,7 +574,7 @@ Class IRCMessageContainer
 	End
 	End
 	
 	
 	'Add a message to this container
 	'Add a message to this container
-	Method AddMessage(msg:String,fromUser:String="",toUser:String="",type:String="",hostname:string="")
+	Method AddMessage:IRCMessage(msg:String,fromUser:String="",toUser:String="",type:String="",hostname:string="")
 		Local nM:=New IRCMessage
 		Local nM:=New IRCMessage
 		nM.parent=Self
 		nM.parent=Self
 		nM.text=msg
 		nM.text=msg
@@ -529,6 +583,7 @@ Class IRCMessageContainer
 		nM.type=type
 		nM.type=type
 		nM.hostname=hostname
 		nM.hostname=hostname
 		messages.AddLast(nM)
 		messages.AddLast(nM)
+		Return nM
 	End
 	End
 	
 	
 	'Sort the userlist
 	'Sort the userlist
@@ -580,6 +635,75 @@ End
 
 
 '=IRC VIEW=
 '=IRC VIEW=
 
 
+'Highlighter for IRC history text
+Function IrcTextHighlighter:Int( text:String,colors:Byte[],sol:Int,eol:Int,state:Int )
+	Local i0:=sol
+	Local msgStep:Int
+	Local userColor:Int
+	Local userStart:Int
+	Local userEnd:Int
+	Local userDone:Bool
+	
+	While i0<eol
+		Local chr:=text[i0]
+		
+		If userDone Then 
+			colors[i0]=0
+		Else
+			colors[i0]=1
+		Endif
+		
+		'Reset
+		If chr=110 And msgStep=6 Then 'n
+			msgStep=0
+			userDone=False
+		Elseif msgStep=6 And chr<>110
+			msgStep=5
+		Endif
+		If chr=126 And msgStep=5 Then '~
+			msgStep=6
+		Endif
+		
+		'Detect username
+		If chr=9 And msgStep=2 Then 'Tab
+			userStart=i0
+			msgStep=3
+			userColor=0
+		Elseif msgStep=2 And chr<>9 Then
+			msgStep=5
+		Endif
+		If chr=32 And msgStep=4 Then 'Space after :
+			userEnd=i0-1
+			msgStep=5
+			userDone=True
+			For Local i1:Int=userStart Until userEnd
+				colors[i1]=2 + (userColor Mod 5)
+			Next
+		Elseif msgStep=4 And chr<>32 Then
+			msgStep=5
+		Endif
+		If chr=58 And msgStep=3 Then ':
+			msgStep=4
+		Endif
+		
+		If msgStep=3 Then userColor+=chr
+		
+		'Detect time
+		If chr=91 And msgStep=0 Then '[
+			msgStep=1
+		Endif
+		If msgStep=1 Then colors[i0]=1
+		
+		If chr=93 And msgStep=1 Then ']
+			msgStep=2
+		Endif
+		
+		i0+=1
+	Wend
+	
+	Return state
+End
+
 'This is a pre-made IRC client, ready to be used in any MojoX application
 'This is a pre-made IRC client, ready to be used in any MojoX application
 Class IRCView Extends DockingView
 Class IRCView Extends DockingView
 	Field ircHandler:IRC
 	Field ircHandler:IRC
@@ -598,6 +722,8 @@ Class IRCView Extends DockingView
 	Field selectedServer:IRCServer
 	Field selectedServer:IRCServer
 	Field selectedMessageContainer:IRCMessageContainer
 	Field selectedMessageContainer:IRCMessageContainer
 	
 	
+	Field maxHistory:Int=50
+	
 	Property Intro:IRCIntroView()
 	Property Intro:IRCIntroView()
 		Return introScreen
 		Return introScreen
 	End
 	End
@@ -615,6 +741,7 @@ Class IRCView Extends DockingView
 		
 		
 		'Chat history field
 		'Chat history field
 		historyField=New TextView
 		historyField=New TextView
+		historyField.Document.TextHighlighter=IrcTextHighlighter
 		historyField.ReadOnly=True
 		historyField.ReadOnly=True
 		historyField.WordWrap=True
 		historyField.WordWrap=True
 		chatScreen.ContentView=historyField
 		chatScreen.ContentView=historyField
@@ -859,7 +986,7 @@ Class IRCView Extends DockingView
 			selectedMessageContainer.AddMessage(selectedServer.nickname+": "+text)
 			selectedMessageContainer.AddMessage(selectedServer.nickname+": "+text)
 		Else
 		Else
 			'Yep, add PRIVMSG and send!
 			'Yep, add PRIVMSG and send!
-			selectedMessageContainer.AddMessage(selectedServer.nickname+": "+text)
+			selectedMessageContainer.AddMessage( text, selectedServer.nickname, selectedMessageContainer.name, "PRIVMSG" )
 			text="PRIVMSG "+selectedMessageContainer.name+" :"+text
 			text="PRIVMSG "+selectedMessageContainer.name+" :"+text
 		Endif
 		Endif
 		
 		
@@ -867,6 +994,23 @@ Class IRCView Extends DockingView
 		AddChatMessage(selectedMessageContainer.messages.Last)
 		AddChatMessage(selectedMessageContainer.messages.Last)
 	End
 	End
 	
 	
+	Method SaveAllHistory()
+		For Local s:IRCServer=Eachin Self.ircHandler.servers
+		For Local c:IRCMessageContainer=Eachin s.messageContainers
+			c.SaveHistory()
+		Next
+		Next
+	End
+	
+	Method Quit(message:String=Null)
+		SaveAllHistory()
+		
+		For Local s:IRCServer=Eachin Self.ircHandler.servers
+			s.SendString("QUIT :"+message)
+			s.Disconnect()
+		Next
+	End
+	
 	Method OnMessageIRC(message:IRCMessage,container:IRCMessageContainer,server:IRCServer)
 	Method OnMessageIRC(message:IRCMessage,container:IRCMessageContainer,server:IRCServer)
 		'For message information, visit: https://tools.ietf.org/html/rfc2812
 		'For message information, visit: https://tools.ietf.org/html/rfc2812
 		Local doNotify:Bool 'Should we notify the user?
 		Local doNotify:Bool 'Should we notify the user?
@@ -877,48 +1021,45 @@ Class IRCView Extends DockingView
 				
 				
 			Case "JOIN"
 			Case "JOIN"
 				If message.fromUser=server.nickname Then
 				If message.fromUser=server.nickname Then
+					UpdateHistory()
 					container.AddMessage("You are now talking in "+container.name)
 					container.AddMessage("You are now talking in "+container.name)
 				Else
 				Else
-					container.AddMessage(message.fromUser+" joined "+container.name)
+					container.AddMessage( message.text, message.fromUser, container.name, message.type)
 				Endif
 				Endif
 				
 				
 			Case "PART"
 			Case "PART"
-				If message.text Then
-					container.AddMessage(message.fromUser+" left "+container.name+" (reason: "+message.text+")")
-				Else
-					container.AddMessage(message.fromUser+" left "+container.name)
-				Endif
+				container.AddMessage( message.text, message.fromUser, container.name, message.type)
 				
 				
 			Case "QUIT"
 			Case "QUIT"
-				If message.text Then
-					container.AddMessage(message.fromUser+" quit (reason: "+message.text+")")
-				Else
-					container.AddMessage(message.fromUser+" quit")
-				Endif
+				container.AddMessage( message.text, message.fromUser, container.name, message.type)
 				
 				
 			Case "NICK"
 			Case "NICK"
-				If nicknameLabel.Text.Left(nicknameLabel.Text.Length-1) Then
-					container.AddMessage("You are now known as "+message.toUser)
-				Else
-					container.AddMessage(message.fromUser+" is now known as "+message.toUser)
+				Local wasSelf:Bool
+				If container=server And selectedMessageContainer Then
+					wasSelf=true
+					container=selectedMessageContainer
 				Endif
 				Endif
 				
 				
+				container.AddMessage( message.text, message.fromUser, message.toUser, message.type)
+				
+				If wasSelf Then UpdateUsers()
+				
 			Case "PRIVMSG"
 			Case "PRIVMSG"
-				container.AddMessage(message.fromUser+": "+message.text)
+				container.AddMessage( message.text, message.fromUser, container.name, message.type)
 				doNotify=True
 				doNotify=True
 			
 			
 			Case "NOTICE"
 			Case "NOTICE"
-				container.AddMessage("NOTICE >"+message.fromUser+"<: "+message.text)
+				container.AddMessage( message.text, message.fromUser, container.name, message.type)
 			
 			
 			Default
 			Default
-				container.AddMessage(message.fromUser+": "+message.text)
+				container.AddMessage( message.text, message.fromUser, container.name, message.type)
 				doNotify=True
 				doNotify=True
 		End
 		End
 		
 		
 		'Display message if we're in that container right now
 		'Display message if we're in that container right now
 		If container=selectedMessageContainer Then
 		If container=selectedMessageContainer Then
 			AddChatMessage(container.messages.Last)
 			AddChatMessage(container.messages.Last)
-		Elseif doNotify Then 'Notify user perhaps?
+		Elseif doNotify Then
 			Local node:TreeView.Node=GetMessageContainerNode(container.name,server.name)
 			Local node:TreeView.Node=GetMessageContainerNode(container.name,server.name)
 			If node Then node.Icon=App.Theme.OpenImage("irc/notice.png")
 			If node Then node.Icon=App.Theme.OpenImage("irc/notice.png")
 		Endif
 		Endif
@@ -1095,14 +1236,68 @@ Class IRCView Extends DockingView
 	
 	
 	Method UpdateHistory()
 	Method UpdateHistory()
 		historyField.Clear()
 		historyField.Clear()
+		
 		If Not selectedMessageContainer Then Return
 		If Not selectedMessageContainer Then Return
+		
+		'Limit message count
+		While selectedMessageContainer.messages.Count()>maxHistory
+			selectedMessageContainer.messages.Remove(selectedMessageContainer.messages.First)
+		Wend
+		
 		For Local m:=Eachin selectedMessageContainer.messages
 		For Local m:=Eachin selectedMessageContainer.messages
 			AddChatMessage(m)
 			AddChatMessage(m)
 		Next
 		Next
 	End
 	End
 	
 	
+	Function PadTime:String(timeStr:String)
+		If Not timeStr.Contains(":") Return timeStr
+		
+		Local t:=timeStr.Split(":")
+		If t[0].Length<=1 Then t[0]="0"+t[0]
+		If t[1].Length<=1 Then t[1]="0"+t[1]
+		
+		Return t[0]+":"+t[1]
+	End
+	
 	Method AddChatMessage(message:IRCMessage)
 	Method AddChatMessage(message:IRCMessage)
-		historyField.AppendText("["+message.time+"]~t"+message.text+"~n")
+		Local time:String="["+PadTime(message.time)+"]~t"
+		
+		Select message.type.ToUpper()
+			
+			Case "JOIN"
+				historyField.AppendText( time + message.fromUser + " joined " + message.toUser + "~n" )
+				
+			Case "PART"
+				If message.text Then
+					historyField.AppendText( time + message.fromUser + " left " + message.toUser + " (Reason " + message.text + ")~n" )
+				Else
+					historyField.AppendText( time + message.fromUser + " left " + message.toUser + "~n" )
+				Endif
+				
+			Case "QUIT"
+				If message.text Then
+					historyField.AppendText( time + message.fromUser + " quit (Reason '" + message.text + "')~n" )
+				Else
+					historyField.AppendText( time + message.fromUser + " quit~n" )
+				Endif
+				
+			Case "NICK"
+				historyField.AppendText( time + message.fromUser + " is now known as " + message.text + "~n" )
+				
+			Case "MODE"
+				'historyField.AppendText( time + message.fromUser + " sets MODE " + message.text + "~n" )
+				
+			Case "NOTICE"
+				historyField.AppendText( time + message.fromUser + ": <NOTICE> " + message.text + "~n" )
+				
+			Default
+				If message.fromUser Then
+					historyField.AppendText( time + message.fromUser + ": " + message.text + "~n" )
+				Else
+					historyField.AppendText( time + message.text + "~n" )
+				Endif
+		End
+		
 	End
 	End
 	
 	
 	Method OnRender(canvas:Canvas) Override
 	Method OnRender(canvas:Canvas) Override