2
0
Эх сурвалжийг харах

Merge branch 'master' of github.com:okamstudio/godot

Anton Yabchinskiy 10 жил өмнө
parent
commit
16746f157f
100 өөрчлөгдсөн 1174 нэмэгдсэн , 206 устгасан
  1. 69 68
      bin/tests/test_string.cpp
  2. 90 1
      core/bind/core_bind.cpp
  3. 20 0
      core/bind/core_bind.h
  4. 13 5
      core/event_queue.cpp
  5. 1 0
      core/global_constants.cpp
  6. 4 0
      core/io/file_access_pack.cpp
  7. 1 0
      core/io/file_access_pack.h
  8. 2 2
      core/math/geometry.h
  9. 1 0
      core/os/dir_access.h
  10. 22 2
      core/os/os.h
  11. 20 34
      core/ustring.cpp
  12. 1 1
      core/ustring.h
  13. 5 5
      core/variant_call.cpp
  14. 10 6
      core/variant_op.cpp
  15. BIN
      demos/2d/area_input/box_area.png
  16. BIN
      demos/2d/area_input/circle_area.png
  17. 4 0
      demos/2d/area_input/engine.cfg
  18. 16 0
      demos/2d/area_input/input.gd
  19. BIN
      demos/2d/area_input/input.scn
  20. 11 0
      demos/2d/fog_of_war/.fscache
  21. 12 0
      demos/2d/fog_of_war/engine.cfg
  22. BIN
      demos/2d/fog_of_war/floor.png
  23. 86 0
      demos/2d/fog_of_war/fog.gd
  24. BIN
      demos/2d/fog_of_war/fog.png
  25. BIN
      demos/2d/fog_of_war/fog.scn
  26. 29 0
      demos/2d/fog_of_war/fog.xml
  27. BIN
      demos/2d/fog_of_war/icon.png
  28. 1 0
      demos/2d/fog_of_war/icon.png.flags
  29. BIN
      demos/2d/fog_of_war/tile_edit.scn
  30. 43 0
      demos/2d/fog_of_war/troll.gd
  31. BIN
      demos/2d/fog_of_war/troll.png
  32. BIN
      demos/2d/fog_of_war/troll.scn
  33. 26 0
      demos/2d/hdr/beach_cave.gd
  34. BIN
      demos/2d/hdr/beach_cave.scn
  35. 13 0
      demos/2d/hdr/engine.cfg
  36. BIN
      demos/2d/hdr/ocean_beach.png
  37. 1 0
      demos/2d/hdr/ocean_beach.png.flags
  38. BIN
      demos/2d/hdr/ocean_cave.png
  39. 1 0
      demos/2d/hdr/ocean_cave.png.flags
  40. BIN
      demos/2d/isometric/dungeon.scn
  41. BIN
      demos/2d/isometric_light/cubio.scn
  42. 4 0
      demos/2d/isometric_light/engine.cfg
  43. BIN
      demos/2d/isometric_light/faceNormal.png
  44. BIN
      demos/2d/isometric_light/floor_shader.res
  45. BIN
      demos/2d/isometric_light/light2.png
  46. BIN
      demos/2d/isometric_light/map.scn
  47. BIN
      demos/2d/isometric_light/tileset_scene.scn
  48. BIN
      demos/2d/isometric_light/torch.scn
  49. BIN
      demos/2d/isometric_light/torch_light.png
  50. BIN
      demos/2d/isometric_light/wall_shader.res
  51. BIN
      demos/2d/light_mask/burano.png
  52. 8 0
      demos/2d/light_mask/engine.cfg
  53. BIN
      demos/2d/light_mask/lightmask.scn
  54. BIN
      demos/2d/light_mask/splat.png
  55. BIN
      demos/2d/lights_shadows/bg.png
  56. BIN
      demos/2d/lights_shadows/caster.png
  57. 8 0
      demos/2d/lights_shadows/engine.cfg
  58. BIN
      demos/2d/lights_shadows/light.png
  59. BIN
      demos/2d/lights_shadows/light_shadows.scn
  60. BIN
      demos/2d/lights_shadows/spot.png
  61. BIN
      demos/2d/normalmaps/diffuse.jpg
  62. BIN
      demos/2d/normalmaps/diffuse.png
  63. 4 0
      demos/2d/normalmaps/engine.cfg
  64. BIN
      demos/2d/normalmaps/light.png
  65. BIN
      demos/2d/normalmaps/normal.png
  66. BIN
      demos/2d/normalmaps/normal_material.res
  67. BIN
      demos/2d/normalmaps/normalmap.scn
  68. 14 10
      demos/2d/platformer/stage.xml
  69. BIN
      demos/2d/sdf_font/KaushanScript-Regular.otf
  70. 4 0
      demos/2d/sdf_font/engine.cfg
  71. BIN
      demos/2d/sdf_font/font.fnt
  72. BIN
      demos/2d/sdf_font/sdf.scn
  73. BIN
      demos/2d/sprite_shaders/cubio.png
  74. 4 0
      demos/2d/sprite_shaders/engine.cfg
  75. BIN
      demos/2d/sprite_shaders/sprite_shaders.scn
  76. BIN
      demos/2d/texscreen/OpenCV_Chessboard.png
  77. BIN
      demos/2d/texscreen/bubble.png
  78. 17 0
      demos/2d/texscreen/bubbles.gd
  79. BIN
      demos/2d/texscreen/bubbles.scn
  80. BIN
      demos/2d/texscreen/burano.png
  81. 4 0
      demos/2d/texscreen/engine.cfg
  82. 37 0
      demos/2d/texscreen/lens.gd
  83. BIN
      demos/2d/texscreen/lens.scn
  84. BIN
      demos/gui/drag_and_drop/drag_and_drop.scn
  85. 24 0
      demos/gui/drag_and_drop/drag_drop_script.gd
  86. 4 0
      demos/gui/drag_and_drop/engine.cfg
  87. 177 0
      demos/misc/window_management/control.gd
  88. 19 0
      demos/misc/window_management/engine.cfg
  89. BIN
      demos/misc/window_management/icon.png
  90. 1 0
      demos/misc/window_management/icon.png.flags
  91. 79 0
      demos/misc/window_management/observer/observer.gd
  92. BIN
      demos/misc/window_management/observer/observer.scn
  93. BIN
      demos/misc/window_management/window_management.scn
  94. 25 24
      demos/viewport/gui_in_3d/gui_3d.gd
  95. BIN
      demos/viewport/gui_in_3d/gui_3d.scn
  96. 26 3
      doc/base/classes.xml
  97. 1 1
      drivers/etc1/rg_etc1.cpp
  98. 199 44
      drivers/gles2/rasterizer_gles2.cpp
  99. 5 0
      drivers/gles2/rasterizer_gles2.h
  100. 8 0
      drivers/gles2/shader_compiler_gles2.cpp

+ 69 - 68
bin/tests/test_string.cpp

@@ -519,12 +519,13 @@ bool test_28() {
 	char output_format[] = "\tTest:\t%ls => %ls (%s)\n";
 	char output_format[] = "\tTest:\t%ls => %ls (%s)\n";
 	String format, output;
 	String format, output;
 	Array args;
 	Array args;
+	bool error;
 	
 	
 	// %%
 	// %%
 	format = "fish %% frog";
 	format = "fish %% frog";
 	args.clear();
 	args.clear();
-	output = format.sprintf(args);
-	success = (output == String("fish % frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish % frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -534,8 +535,8 @@ bool test_28() {
 	format = "fish %d frog";
 	format = "fish %d frog";
 	args.clear();
 	args.clear();
 	args.push_back(5);
 	args.push_back(5);
-	output = format.sprintf(args);
-	success = (output == String("fish 5 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 5 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -543,8 +544,8 @@ bool test_28() {
 	format = "fish %05d frog";
 	format = "fish %05d frog";
 	args.clear();
 	args.clear();
 	args.push_back(5);
 	args.push_back(5);
-	output = format.sprintf(args);
-	success = (output == String("fish 00005 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 00005 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -552,8 +553,8 @@ bool test_28() {
 	format = "fish %5d frog";
 	format = "fish %5d frog";
 	args.clear();
 	args.clear();
 	args.push_back(5);
 	args.push_back(5);
-	output = format.sprintf(args);
-	success = (output == String("fish     5 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish     5 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -561,8 +562,8 @@ bool test_28() {
 	format = "fish %-5d frog";
 	format = "fish %-5d frog";
 	args.clear();
 	args.clear();
 	args.push_back(5);
 	args.push_back(5);
-	output = format.sprintf(args);
-	success = (output == String("fish 5     frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 5     frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -570,8 +571,8 @@ bool test_28() {
 	format = "fish %+d frog";
 	format = "fish %+d frog";
 	args.clear();
 	args.clear();
 	args.push_back(5);
 	args.push_back(5);
-	output = format.sprintf(args);
-	success = (output == String("fish +5 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish +5 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -579,8 +580,8 @@ bool test_28() {
 	format = "fish %d frog";
 	format = "fish %d frog";
 	args.clear();
 	args.clear();
 	args.push_back(-5);
 	args.push_back(-5);
-	output = format.sprintf(args);
-	success = (output == String("fish -5 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish -5 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -588,8 +589,8 @@ bool test_28() {
 	format = "fish %x frog";
 	format = "fish %x frog";
 	args.clear();
 	args.clear();
 	args.push_back(45);
 	args.push_back(45);
-	output = format.sprintf(args);
-	success = (output == String("fish 2d frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 2d frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -597,8 +598,8 @@ bool test_28() {
 	format = "fish %X frog";
 	format = "fish %X frog";
 	args.clear();
 	args.clear();
 	args.push_back(45);
 	args.push_back(45);
-	output = format.sprintf(args);
-	success = (output == String("fish 2D frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 2D frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -606,8 +607,8 @@ bool test_28() {
 	format = "fish %o frog";
 	format = "fish %o frog";
 	args.clear();
 	args.clear();
 	args.push_back(99);
 	args.push_back(99);
-	output = format.sprintf(args);
-	success = (output == String("fish 143 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 143 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -617,8 +618,8 @@ bool test_28() {
 	format = "fish %f frog";
 	format = "fish %f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish 99.990000 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 99.990000 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -626,8 +627,8 @@ bool test_28() {
 	format = "fish %11f frog";
 	format = "fish %11f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish   99.990000 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish   99.990000 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -635,8 +636,8 @@ bool test_28() {
 	format = "fish %-11f frog";
 	format = "fish %-11f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish 99.990000   frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 99.990000   frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -644,8 +645,8 @@ bool test_28() {
 	format = "fish %f frog";
 	format = "fish %f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99);
 	args.push_back(99);
-	output = format.sprintf(args);
-	success = (output == String("fish 99.000000 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 99.000000 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -653,8 +654,8 @@ bool test_28() {
 	format = "fish %+f frog";
 	format = "fish %+f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish +99.990000 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish +99.990000 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -662,8 +663,8 @@ bool test_28() {
 	format = "fish %.1f frog";
 	format = "fish %.1f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish 100.0 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 100.0 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -671,8 +672,8 @@ bool test_28() {
 	format = "fish %.12f frog";
 	format = "fish %.12f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish 99.990000000000 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 99.990000000000 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -680,8 +681,8 @@ bool test_28() {
 	format = "fish %.f frog";
 	format = "fish %.f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish 100 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish 100 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -691,8 +692,8 @@ bool test_28() {
 	format = "fish %s frog";
 	format = "fish %s frog";
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == String("fish cheese frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish cheese frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -700,8 +701,8 @@ bool test_28() {
 	format = "fish %10s frog";
 	format = "fish %10s frog";
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == String("fish     cheese frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish     cheese frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -709,8 +710,8 @@ bool test_28() {
 	format = "fish %-10s frog";
 	format = "fish %-10s frog";
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == String("fish cheese     frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish cheese     frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -720,8 +721,8 @@ bool test_28() {
 	format = "fish %c frog";
 	format = "fish %c frog";
 	args.clear();
 	args.clear();
 	args.push_back("A");
 	args.push_back("A");
-	output = format.sprintf(args);
-	success = (output == String("fish A frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish A frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -729,8 +730,8 @@ bool test_28() {
 	format = "fish %c frog";
 	format = "fish %c frog";
 	args.clear();
 	args.clear();
 	args.push_back(65);
 	args.push_back(65);
-	output = format.sprintf(args);
-	success = (output == String("fish A frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish A frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -741,8 +742,8 @@ bool test_28() {
 	args.clear();
 	args.clear();
 	args.push_back(10);
 	args.push_back(10);
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == String("fish     cheese frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish     cheese frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -751,8 +752,8 @@ bool test_28() {
 	args.clear();
 	args.clear();
 	args.push_back(10);
 	args.push_back(10);
 	args.push_back(99);
 	args.push_back(99);
-	output = format.sprintf(args);
-	success = (output == String("fish         99 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish         99 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -762,8 +763,8 @@ bool test_28() {
 	args.push_back(10);
 	args.push_back(10);
 	args.push_back(3);
 	args.push_back(3);
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == String("fish     99.990 frog"));
+	output = format.sprintf(args, &error);
+	success = (output == String("fish     99.990 frog") && !error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -773,8 +774,8 @@ bool test_28() {
 	format = "fish %s %s frog";
 	format = "fish %s %s frog";
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "not enough arguments for format string" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -783,8 +784,8 @@ bool test_28() {
 	args.clear();
 	args.clear();
 	args.push_back("hello");
 	args.push_back("hello");
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "not all arguments converted during string formatting" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -792,8 +793,8 @@ bool test_28() {
 	format = "fish %10";
 	format = "fish %10";
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "incomplete format" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -801,8 +802,8 @@ bool test_28() {
 	format = "fish %&f frog";
 	format = "fish %&f frog";
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "unsupported format character" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -810,8 +811,8 @@ bool test_28() {
 	format = "fish %2.2.2f frog";
 	format = "fish %2.2.2f frog";
 	args.clear();
 	args.clear();
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "too many decimal points in format" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -820,8 +821,8 @@ bool test_28() {
 	args.clear();
 	args.clear();
 	args.push_back("cheese");
 	args.push_back("cheese");
 	args.push_back(99.99);
 	args.push_back(99.99);
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "* wants number" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -829,8 +830,8 @@ bool test_28() {
 	format = "fish %c frog";
 	format = "fish %c frog";
 	args.clear();
 	args.clear();
 	args.push_back("sc");
 	args.push_back("sc");
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "%c requires number or single-character string" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 
@@ -838,8 +839,8 @@ bool test_28() {
 	format = "fish %c frog";
 	format = "fish %c frog";
 	args.clear();
 	args.clear();
 	args.push_back(Array());
 	args.push_back(Array());
-	output = format.sprintf(args);
-	success = (output == "");
+	output = format.sprintf(args, &error);
+	success = (output == "%c requires number or single-character string" && error);
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
 	if (!success) state = false;
 	if (!success) state = false;
 
 

+ 90 - 1
core/bind/core_bind.cpp

@@ -176,6 +176,76 @@ bool _OS::is_video_mode_fullscreen(int p_screen) const {
 
 
 }
 }
 
 
+
+int _OS::get_screen_count() const {
+	return OS::get_singleton()->get_screen_count();
+}
+
+int _OS::get_current_screen() const {
+	return OS::get_singleton()->get_current_screen();
+}
+
+void _OS::set_current_screen(int p_screen) {
+	OS::get_singleton()->set_current_screen(p_screen);
+}
+
+Point2 _OS::get_screen_position(int p_screen) const {
+	return OS::get_singleton()->get_screen_position(p_screen);
+}
+
+Size2 _OS::get_screen_size(int p_screen) const {
+	return OS::get_singleton()->get_screen_size(p_screen);
+}
+
+Point2 _OS::get_window_position() const {
+	return OS::get_singleton()->get_window_position();
+}
+
+void _OS::set_window_position(const Point2& p_position) {
+	OS::get_singleton()->set_window_position(p_position);
+}
+
+Size2 _OS::get_window_size() const {
+	return OS::get_singleton()->get_window_size();
+}
+
+void _OS::set_window_size(const Size2& p_size) {
+	OS::get_singleton()->set_window_size(p_size);
+}
+
+void _OS::set_window_fullscreen(bool p_enabled) {
+	OS::get_singleton()->set_window_fullscreen(p_enabled);
+}
+
+bool _OS::is_window_fullscreen() const {
+	return OS::get_singleton()->is_window_fullscreen();
+}
+
+void _OS::set_window_resizable(bool p_enabled) {
+	OS::get_singleton()->set_window_resizable(p_enabled);
+}
+
+bool _OS::is_window_resizable() const {
+	return OS::get_singleton()->is_window_resizable();
+}
+
+void _OS::set_window_minimized(bool p_enabled) {
+	OS::get_singleton()->set_window_minimized(p_enabled);
+}
+
+bool _OS::is_window_minimized() const {
+	return OS::get_singleton()->is_window_minimized();
+}
+
+void _OS::set_window_maximized(bool p_enabled) {
+	OS::get_singleton()->set_window_maximized(p_enabled);
+}
+
+bool _OS::is_window_maximized() const {
+	return OS::get_singleton()->is_window_maximized();
+}
+
+
 void _OS::set_use_file_access_save_and_swap(bool p_enable) {
 void _OS::set_use_file_access_save_and_swap(bool p_enable) {
 
 
 	FileAccess::set_backup_save(p_enable);
 	FileAccess::set_backup_save(p_enable);
@@ -186,7 +256,6 @@ bool _OS::is_video_mode_resizable(int p_screen) const {
 	OS::VideoMode vm;
 	OS::VideoMode vm;
 	vm = OS::get_singleton()->get_video_mode(p_screen);
 	vm = OS::get_singleton()->get_video_mode(p_screen);
 	return vm.resizable;
 	return vm.resizable;
-
 }
 }
 
 
 Array _OS::get_fullscreen_mode_list(int p_screen) const {
 Array _OS::get_fullscreen_mode_list(int p_screen) const {
@@ -637,6 +706,26 @@ void _OS::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0));
 	ObjectTypeDB::bind_method(_MD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0));
 	ObjectTypeDB::bind_method(_MD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0));
 	ObjectTypeDB::bind_method(_MD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0));
 
 
+
+	ObjectTypeDB::bind_method(_MD("get_screen_count"),&_OS::get_screen_count);
+	ObjectTypeDB::bind_method(_MD("get_current_screen"),&_OS::get_current_screen);
+	ObjectTypeDB::bind_method(_MD("set_current_screen"),&_OS::set_current_screen);
+	ObjectTypeDB::bind_method(_MD("get_screen_position"),&_OS::get_screen_position,DEFVAL(0));
+	ObjectTypeDB::bind_method(_MD("get_screen_size"),&_OS::get_screen_size,DEFVAL(0));
+	ObjectTypeDB::bind_method(_MD("get_window_position"),&_OS::get_window_position);
+	ObjectTypeDB::bind_method(_MD("set_window_position"),&_OS::set_window_position);
+	ObjectTypeDB::bind_method(_MD("get_window_size"),&_OS::get_window_size);
+	ObjectTypeDB::bind_method(_MD("set_window_size"),&_OS::set_window_size);
+	ObjectTypeDB::bind_method(_MD("set_window_fullscreen","enabled"),&_OS::set_window_fullscreen);
+	ObjectTypeDB::bind_method(_MD("is_window_fullscreen"),&_OS::is_window_fullscreen);
+	ObjectTypeDB::bind_method(_MD("set_window_resizable","enabled"),&_OS::set_window_resizable);
+	ObjectTypeDB::bind_method(_MD("is_window_resizable"),&_OS::is_window_resizable);
+	ObjectTypeDB::bind_method(_MD("set_window_minimized", "enabled"),&_OS::set_window_minimized);
+	ObjectTypeDB::bind_method(_MD("is_window_minimized"),&_OS::is_window_minimized);
+	ObjectTypeDB::bind_method(_MD("set_window_maximized", "enabled"),&_OS::set_window_maximized);
+	ObjectTypeDB::bind_method(_MD("is_window_maximized"),&_OS::is_window_maximized);
+
+
 	ObjectTypeDB::bind_method(_MD("set_iterations_per_second","iterations_per_second"),&_OS::set_iterations_per_second);
 	ObjectTypeDB::bind_method(_MD("set_iterations_per_second","iterations_per_second"),&_OS::set_iterations_per_second);
 	ObjectTypeDB::bind_method(_MD("get_iterations_per_second"),&_OS::get_iterations_per_second);
 	ObjectTypeDB::bind_method(_MD("get_iterations_per_second"),&_OS::get_iterations_per_second);
 	ObjectTypeDB::bind_method(_MD("set_target_fps","target_fps"),&_OS::set_target_fps);
 	ObjectTypeDB::bind_method(_MD("set_target_fps","target_fps"),&_OS::set_target_fps);

+ 20 - 0
core/bind/core_bind.h

@@ -108,6 +108,26 @@ public:
 	bool is_video_mode_resizable(int p_screen=0) const;
 	bool is_video_mode_resizable(int p_screen=0) const;
 	Array get_fullscreen_mode_list(int p_screen=0) const;
 	Array get_fullscreen_mode_list(int p_screen=0) const;
 
 
+
+	virtual int get_screen_count() const;
+	virtual int get_current_screen() const;
+	virtual void set_current_screen(int p_screen);
+	virtual Point2 get_screen_position(int p_screen=0) const;
+	virtual Size2 get_screen_size(int p_screen=0) const;
+	virtual Point2 get_window_position() const;
+	virtual void set_window_position(const Point2& p_position);
+	virtual Size2 get_window_size() const;
+	virtual void set_window_size(const Size2& p_size);
+	virtual void set_window_fullscreen(bool p_enabled);
+	virtual bool is_window_fullscreen() const;
+	virtual void set_window_resizable(bool p_enabled);
+	virtual bool is_window_resizable() const;
+	virtual void set_window_minimized(bool p_enabled);
+	virtual bool is_window_minimized() const;
+	virtual void set_window_maximized(bool p_enabled);
+	virtual bool is_window_maximized() const;
+
+
 	Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
 	Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
 	bool native_video_is_playing();
 	bool native_video_is_playing();
 	void native_video_pause();
 	void native_video_pause();

+ 13 - 5
core/event_queue.cpp

@@ -56,28 +56,36 @@ Error EventQueue::push_call(uint32_t p_instance_ID, const StringName& p_method,
 	
 	
 	buffer_end+=sizeof(Event);
 	buffer_end+=sizeof(Event);
 	
 	
-	if (args==1) {
+	if (args>=1) {
 	
 	
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		buffer_end+=sizeof(Variant);
 		buffer_end+=sizeof(Variant);
 		*v=p_arg1;
 		*v=p_arg1;
-	} else if (args==2) {
+	}
+
+	if (args>=2) {
 	
 	
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		buffer_end+=sizeof(Variant);
 		buffer_end+=sizeof(Variant);
 		*v=p_arg2;
 		*v=p_arg2;
-	} else if (args==3) {
+	}
+
+	if (args>=3) {
 	
 	
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		buffer_end+=sizeof(Variant);
 		buffer_end+=sizeof(Variant);
 		*v=p_arg3;
 		*v=p_arg3;
 		
 		
-	} else if (args==4) {
+	}
+
+	if (args>=4) {
 	
 	
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		buffer_end+=sizeof(Variant);
 		buffer_end+=sizeof(Variant);
 		*v=p_arg4;
 		*v=p_arg4;
-	} else if (args==5) {
+	}
+
+	if (args>=5) {
 	
 	
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		Variant * v = memnew_placement( &event_buffer[ buffer_end ], Variant );
 		buffer_end+=sizeof(Variant);
 		buffer_end+=sizeof(Variant);

+ 1 - 0
core/global_constants.cpp

@@ -313,6 +313,7 @@ static _GlobalConstant _global_constants[]={
 	BIND_GLOBAL_CONSTANT( KEY_MASK_ALT   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_ALT   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_META   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_META   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_CTRL   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_CTRL   ),
+	BIND_GLOBAL_CONSTANT( KEY_MASK_CMD   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_KPAD   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_KPAD   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_GROUP_SWITCH   ),
 	BIND_GLOBAL_CONSTANT( KEY_MASK_GROUP_SWITCH   ),
 
 

+ 4 - 0
core/io/file_access_pack.cpp

@@ -362,6 +362,10 @@ bool DirAccessPack::current_is_dir() const{
 
 
 	return cdir;
 	return cdir;
 }
 }
+bool DirAccessPack::current_is_hidden() const{
+
+	return false;
+}
 void DirAccessPack::list_dir_end() {
 void DirAccessPack::list_dir_end() {
 
 
 	list_dirs.clear();
 	list_dirs.clear();

+ 1 - 0
core/io/file_access_pack.h

@@ -208,6 +208,7 @@ public:
 	virtual bool list_dir_begin();
 	virtual bool list_dir_begin();
 	virtual String get_next();
 	virtual String get_next();
 	virtual bool current_is_dir() const;
 	virtual bool current_is_dir() const;
+	virtual bool current_is_hidden() const;
 	virtual void list_dir_end();
 	virtual void list_dir_end();
 
 
 	virtual int get_drive_count();
 	virtual int get_drive_count();

+ 2 - 2
core/math/geometry.h

@@ -519,9 +519,9 @@ public:
 
 
 	    bool s_ab = (b.x-a.x)*as_y-(b.y-a.y)*as_x > 0;
 	    bool s_ab = (b.x-a.x)*as_y-(b.y-a.y)*as_x > 0;
 
 
-	    if((c.x-a.x)*as_y-(c.y-a.y)*as_x > 0 == s_ab) return false;
+	    if(((c.x-a.x)*as_y-(c.y-a.y)*as_x > 0) == s_ab) return false;
 
 
-	    if((c.x-b.x)*(s.y-b.y)-(c.y-b.y)*(s.x-b.x) > 0 != s_ab) return false;
+	    if(((c.x-b.x)*(s.y-b.y)-(c.y-b.y)*(s.x-b.x) > 0) != s_ab) return false;
 
 
 	    return true;
 	    return true;
 	}
 	}

+ 1 - 0
core/os/dir_access.h

@@ -78,6 +78,7 @@ public:
 	virtual String get_next(bool* p_is_dir); // compatibility
 	virtual String get_next(bool* p_is_dir); // compatibility
 	virtual String get_next()=0;
 	virtual String get_next()=0;
 	virtual bool current_is_dir() const=0;
 	virtual bool current_is_dir() const=0;
+	virtual bool current_is_hidden() const=0;
 	
 	
 	virtual void list_dir_end()=0; ///< 
 	virtual void list_dir_end()=0; ///< 
 	
 	

+ 22 - 2
core/os/os.h

@@ -73,7 +73,7 @@ public:
 		bool fullscreen;
 		bool fullscreen;
 		bool resizable;
 		bool resizable;
 		float get_aspect() const { return (float)width/(float)height; }
 		float get_aspect() const { return (float)width/(float)height; }
-		VideoMode(int p_width=640,int p_height=480,bool p_fullscreen=false, bool p_resizable = true) { width=p_width; height=p_height; fullscreen=p_fullscreen; resizable = p_resizable; }
+		VideoMode(int p_width=640,int p_height=480,bool p_fullscreen=false, bool p_resizable = true) {width=p_width; height=p_height; fullscreen=p_fullscreen; resizable = p_resizable; }
 	};
 	};
 protected:
 protected:
 friend class Main;
 friend class Main;
@@ -149,7 +149,27 @@ public:
 	virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0)=0;
 	virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0)=0;
 	virtual VideoMode get_video_mode(int p_screen=0) const=0;
 	virtual VideoMode get_video_mode(int p_screen=0) const=0;
 	virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const=0;
 	virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const=0;
-	
+
+
+	virtual int get_screen_count() const{ return 1; }
+	virtual int get_current_screen() const { return 0; }
+	virtual void set_current_screen(int p_screen) { }
+	virtual Point2 get_screen_position(int p_screen=0)  { return Point2(); }
+	virtual Size2 get_screen_size(int p_screen=0) const { return get_window_size(); }
+	virtual Point2 get_window_position() const { return Vector2(); }
+	virtual void set_window_position(const Point2& p_position) {}
+	virtual Size2 get_window_size() const=0;
+	virtual void set_window_size(const Size2 p_size){}
+	virtual void set_window_fullscreen(bool p_enabled) {}
+	virtual bool is_window_fullscreen() const { return true; }
+	virtual void set_window_resizable(bool p_enabled) {}
+	virtual bool is_window_resizable() const { return false; }
+	virtual void set_window_minimized(bool p_enabled) {}
+	virtual bool is_window_minimized() const { return false; }
+	virtual void set_window_maximized(bool p_enabled) {}
+	virtual bool is_window_maximized() const { return true; }
+
+
 	virtual void set_iterations_per_second(int p_ips);
 	virtual void set_iterations_per_second(int p_ips);
 	virtual int get_iterations_per_second() const;
 	virtual int get_iterations_per_second() const;
 
 

+ 20 - 34
core/ustring.cpp

@@ -3550,8 +3550,8 @@ String String::lpad(int min_length, const String& character) const {
 // sprintf is implemented in GDScript via:
 // sprintf is implemented in GDScript via:
 //   "fish %s pie" % "frog"
 //   "fish %s pie" % "frog"
 //   "fish %s %d pie" % ["frog", 12]
 //   "fish %s %d pie" % ["frog", 12]
-String String::sprintf(const Array& values) const {
-
+// In case of an error, the string returned is the error description and "error" is true.
+String String::sprintf(const Array& values, bool* error) const {
 	String formatted;
 	String formatted;
 	CharType* self = (CharType*)c_str();
 	CharType* self = (CharType*)c_str();
 	int num_items = values.size();
 	int num_items = values.size();
@@ -3564,6 +3564,7 @@ String String::sprintf(const Array& values) const {
 	bool left_justified;
 	bool left_justified;
 	bool show_sign;
 	bool show_sign;
 
 
+	*error = true;
 
 
 	for (; *self; self++) {
 	for (; *self; self++) {
 		const CharType c = *self;
 		const CharType c = *self;
@@ -3580,13 +3581,11 @@ String String::sprintf(const Array& values) const {
 				case 'x': // Hexadecimal (lowercase)
 				case 'x': // Hexadecimal (lowercase)
 				case 'X': { // Hexadecimal (uppercase)
 				case 'X': { // Hexadecimal (uppercase)
 					if (value_index >= values.size()) {
 					if (value_index >= values.size()) {
-						ERR_EXPLAIN("not enough arguments for format string");
-						ERR_FAIL_V("");
+						return "not enough arguments for format string";
 					}
 					}
 
 
 					if (!values[value_index].is_num()) {
 					if (!values[value_index].is_num()) {
-						ERR_EXPLAIN("a number is required");
-						ERR_FAIL_V("");
+						return "a number is required";
 					}
 					}
 					
 					
 					int64_t value = values[value_index];
 					int64_t value = values[value_index];
@@ -3622,13 +3621,11 @@ String String::sprintf(const Array& values) const {
 				}
 				}
 				case 'f': { // Float
 				case 'f': { // Float
 					if (value_index >= values.size()) {
 					if (value_index >= values.size()) {
-						ERR_EXPLAIN("not enough arguments for format string");
-						ERR_FAIL_V("");
+						return "not enough arguments for format string";
 					}
 					}
 
 
 					if (!values[value_index].is_num()) {
 					if (!values[value_index].is_num()) {
-						ERR_EXPLAIN("a number is required");
-						ERR_FAIL_V("");
+						return "a number is required";
 					}
 					}
 
 
 					double value = values[value_index];
 					double value = values[value_index];
@@ -3657,8 +3654,7 @@ String String::sprintf(const Array& values) const {
 				}
 				}
 				case 's': { // String
 				case 's': { // String
 					if (value_index >= values.size()) {
 					if (value_index >= values.size()) {
-						ERR_EXPLAIN("not enough arguments for format string");
-						ERR_FAIL_V("");
+						return "not enough arguments for format string";
 					}
 					}
 
 
 					String str = values[value_index];
 					String str = values[value_index];
@@ -3676,8 +3672,7 @@ String String::sprintf(const Array& values) const {
 				}
 				}
 				case 'c': {
 				case 'c': {
 					if (value_index >= values.size()) {
 					if (value_index >= values.size()) {
-						ERR_EXPLAIN("not enough arguments for format string");
-						ERR_FAIL_V("");
+						return "not enough arguments for format string";
 					}
 					}
 
 
 					// Convert to character.
 					// Convert to character.
@@ -3685,22 +3680,18 @@ String String::sprintf(const Array& values) const {
 					if (values[value_index].is_num()) {
 					if (values[value_index].is_num()) {
 						int value = values[value_index];
 						int value = values[value_index];
 						if (value < 0) {
 						if (value < 0) {
-							ERR_EXPLAIN("unsigned byte integer is lower than maximum")
-							ERR_FAIL_V("");
+							return "unsigned byte integer is lower than maximum";
 						} else if (value > 255) {
 						} else if (value > 255) {
-							ERR_EXPLAIN("unsigned byte integer is greater than maximum")
-							ERR_FAIL_V("");
+							return "unsigned byte integer is greater than maximum";
 						}
 						}
 						str = chr(values[value_index]);
 						str = chr(values[value_index]);
 					} else if (values[value_index].get_type() == Variant::STRING) {
 					} else if (values[value_index].get_type() == Variant::STRING) {
 						str = values[value_index];
 						str = values[value_index];
 						if (str.length() != 1) {
 						if (str.length() != 1) {
-							ERR_EXPLAIN("%c requires number or single-character string");
-							ERR_FAIL_V("");
+							return "%c requires number or single-character string";
 						}
 						}
 					} else {
 					} else {
-						ERR_EXPLAIN("%c requires number or single-character string");
-						ERR_FAIL_V("");
+						return "%c requires number or single-character string";
 					}
 					}
 
 
 					// Padding.
 					// Padding.
@@ -3741,8 +3732,7 @@ String String::sprintf(const Array& values) const {
 				}
 				}
 				case '.': { // Float separtor.
 				case '.': { // Float separtor.
 					if (in_decimals) {
 					if (in_decimals) {
-						ERR_EXPLAIN("too many decimal points in format");
-						ERR_FAIL_V("");
+						return "too many decimal points in format";
 					}
 					}
 					in_decimals = true;
 					in_decimals = true;
 					min_decimals = 0; // We want to add the value manually.
 					min_decimals = 0; // We want to add the value manually.
@@ -3751,13 +3741,11 @@ String String::sprintf(const Array& values) const {
 
 
 				case '*': { // Dyanmic width, based on value.
 				case '*': { // Dyanmic width, based on value.
 					if (value_index >= values.size()) {
 					if (value_index >= values.size()) {
-						ERR_EXPLAIN("not enough arguments for format string");
-						ERR_FAIL_V("");
+						return "not enough arguments for format string";
 					}
 					}
 
 
 					if (!values[value_index].is_num()) {
 					if (!values[value_index].is_num()) {
-						ERR_EXPLAIN("* wants number");
-						ERR_FAIL_V("");
+						return "* wants number";
 					}
 					}
 
 
 					int size = values[value_index];
 					int size = values[value_index];
@@ -3773,8 +3761,7 @@ String String::sprintf(const Array& values) const {
 				}
 				}
 
 
 				default: {
 				default: {
-					ERR_EXPLAIN("unsupported format character");
-  					ERR_FAIL_V("");
+					return "unsupported format character";
   				}
   				}
 			}
 			}
 		} else { // Not in format string.
 		} else { // Not in format string.
@@ -3796,14 +3783,13 @@ String String::sprintf(const Array& values) const {
 	}
 	}
 
 
 	if (in_format) {
 	if (in_format) {
-		ERR_EXPLAIN("incomplete format");
-  		ERR_FAIL_V("");
+		return "incomplete format";
 	}
 	}
 
 
 	if (value_index != values.size()) {
 	if (value_index != values.size()) {
-		ERR_EXPLAIN("not all arguments converted during string formatting");
-  		ERR_FAIL_V("");
+		return "not all arguments converted during string formatting";
 	}
 	}
 
 
+	*error = false;
 	return formatted;
 	return formatted;
 }
 }

+ 1 - 1
core/ustring.h

@@ -130,7 +130,7 @@ public:
 	String pad_zeros(int p_digits) const;
 	String pad_zeros(int p_digits) const;
 	String lpad(int min_length,const String& character=" ") const;
 	String lpad(int min_length,const String& character=" ") const;
 	String rpad(int min_length,const String& character=" ") const;
 	String rpad(int min_length,const String& character=" ") const;
-	String sprintf(const Array& values) const;
+	String sprintf(const Array& values, bool* error) const;
 	static String num(double p_num,int p_decimals=-1);
 	static String num(double p_num,int p_decimals=-1);
 	static String num_scientific(double p_num);
 	static String num_scientific(double p_num);
 	static String num_real(double p_num);
 	static String num_real(double p_num);

+ 5 - 5
core/variant_call.cpp

@@ -511,7 +511,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 	VCALL_LOCALMEM1(ColorArray,append_array);
 	VCALL_LOCALMEM1(ColorArray,append_array);
 
 
 #define VCALL_PTR0(m_type,m_method)\
 #define VCALL_PTR0(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
 #define VCALL_PTR0R(m_type,m_method)\
 #define VCALL_PTR0R(m_type,m_method)\
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(); }
 #define VCALL_PTR1(m_type,m_method)\
 #define VCALL_PTR1(m_type,m_method)\
@@ -519,7 +519,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 #define VCALL_PTR1R(m_type,m_method)\
 #define VCALL_PTR1R(m_type,m_method)\
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); }
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0]); }
 #define VCALL_PTR2(m_type,m_method)\
 #define VCALL_PTR2(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
 #define VCALL_PTR2R(m_type,m_method)\
 #define VCALL_PTR2R(m_type,m_method)\
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1]); }
 #define VCALL_PTR3(m_type,m_method)\
 #define VCALL_PTR3(m_type,m_method)\
@@ -531,7 +531,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 #define VCALL_PTR4R(m_type,m_method)\
 #define VCALL_PTR4R(m_type,m_method)\
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3]); }
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3]); }
 #define VCALL_PTR5(m_type,m_method)\
 #define VCALL_PTR5(m_type,m_method)\
-static void _call_##m_type##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
+static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
 #define VCALL_PTR5R(m_type,m_method)\
 #define VCALL_PTR5R(m_type,m_method)\
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
 static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Variant** p_args) { r_ret=reinterpret_cast<m_type*>(p_self._data._ptr)->m_method(*p_args[0],*p_args[1],*p_args[2],*p_args[3],*p_args[4]); }
 
 
@@ -685,7 +685,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 	VCALL_PTR0R( InputEvent, is_pressed );
 	VCALL_PTR0R( InputEvent, is_pressed );
 	VCALL_PTR1R( InputEvent, is_action );
 	VCALL_PTR1R( InputEvent, is_action );
 	VCALL_PTR0R( InputEvent, is_echo );
 	VCALL_PTR0R( InputEvent, is_echo );
-	//VCALL_PTR2( InputEvent, set_as_action );
+    VCALL_PTR2( InputEvent, set_as_action );
 
 
 	struct ConstructData {
 	struct ConstructData {
 
 
@@ -1496,7 +1496,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
 	ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_pressed,varray());
 	ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_pressed,varray());
 	ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action,STRING,"action",varray());
 	ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action,STRING,"action",varray());
 	ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_echo,varray());
 	ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_echo,varray());
-	//ADDFUNC2(INPUT_EVENT,NIL,InputEvent,set_as_action,STRING,"action",BOOL,"pressed",varray());
+    ADDFUNC2(INPUT_EVENT,NIL,InputEvent,set_as_action,STRING,"action",BOOL,"pressed",varray());
 
 
 	/* REGISTER CONSTRUCTORS */
 	/* REGISTER CONSTRUCTORS */
 
 

+ 10 - 6
core/variant_op.cpp

@@ -741,18 +741,22 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
 				_RETURN( p_a._data._int % p_b._data._int );
 				_RETURN( p_a._data._int % p_b._data._int );
 				
 				
 			} else if (p_a.type==STRING) {
 			} else if (p_a.type==STRING) {
-				const String *str=reinterpret_cast<const String*>(p_a._data._mem);
+				const String* format=reinterpret_cast<const String*>(p_a._data._mem);
 
 
+				String result;
+				bool error;
 				if (p_b.type==ARRAY) {
 				if (p_b.type==ARRAY) {
 					// e.g. "frog %s %d" % ["fish", 12]
 					// e.g. "frog %s %d" % ["fish", 12]
-					const Array *arr=reinterpret_cast<const Array*>(p_b._data._mem);
-					_RETURN(str->sprintf(*arr));
+					const Array* args=reinterpret_cast<const Array*>(p_b._data._mem);
+					result=format->sprintf(*args, &error);
 				} else {
 				} else {
 					// e.g. "frog %d" % 12
 					// e.g. "frog %d" % 12
-					Array arr;
-					arr.push_back(p_b);
-					_RETURN(str->sprintf(arr));
+					Array args;
+					args.push_back(p_b);
+					result=format->sprintf(args, &error);
 				}
 				}
+				r_valid = !error;
+				_RETURN(result);
 			}
 			}
 
 
 			r_valid=false;
 			r_valid=false;

BIN
demos/2d/area_input/box_area.png


BIN
demos/2d/area_input/circle_area.png


+ 4 - 0
demos/2d/area_input/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="Area 2D Input Events"
+main_scene="res://input.scn"

+ 16 - 0
demos/2d/area_input/input.gd

@@ -0,0 +1,16 @@
+
+extends Area2D
+
+#virtual from CollisionObject2D (also available as signal)
+func _input_event(viewport, event, shape_idx):
+	#convert event to local coordinates
+	if (event.type==InputEvent.MOUSE_MOTION):
+		event = make_input_local( event )
+		get_node("label").set_text(str(event.pos))
+		
+#virtual from CollisionObject2D (also available as signal)
+func _mouse_exit():
+		get_node("label").set_text("")
+		
+
+

BIN
demos/2d/area_input/input.scn


+ 11 - 0
demos/2d/fog_of_war/.fscache

@@ -0,0 +1,11 @@
+::res://::1422910453
+floor.png::ImageTexture::1422910453::
+fog.gd::GDScript::1422910025::
+fog.png::ImageTexture::1422908128::
+fog.scn::PackedScene::1422909435::
+fog.xml::TileSet::1422909324::
+icon.png::ImageTexture::1422811193::
+tile_edit.scn::PackedScene::1422909313::
+troll.gd::GDScript::1422909940::
+troll.png::ImageTexture::1418669358::
+troll.scn::PackedScene::1418669358::

+ 12 - 0
demos/2d/fog_of_war/engine.cfg

@@ -0,0 +1,12 @@
+[application]
+
+name="Fog of War"
+main_scene="res://fog.scn"
+icon="icon.png"
+
+[input]
+
+move_up=[key(Up)]
+move_bottom=[key(Down)]
+move_left=[key(Left)]
+move_right=[key(Right)]

BIN
demos/2d/fog_of_war/floor.png


+ 86 - 0
demos/2d/fog_of_war/fog.gd

@@ -0,0 +1,86 @@
+
+extends TileMap
+
+# member variables here, example:
+# var a=2
+# var b="textvar"
+
+# boundarys for the fog rectangle
+var x_min = -20 # left start tile
+var x_max = 20 # right end tile
+var y_min = -20 # top start tile
+var y_max = 20 # bottom end tile
+
+var position # players position
+
+# iteration variables
+var x
+var y
+
+# variable to check if player moved
+var x_old
+var y_old
+
+# array to build up the visible area like a square
+# first value determines the width/height of the tip
+# here it would be 2*2 + 1 = 5 tiles wide/high
+# second value determines the total squares size
+# here it would be 5*2 + 1 = 10 tiles wide/high
+var l = range(2,5)
+
+# process that runs in realtime
+func _fixed_process(delta):
+	position = get_node("../troll").get_pos()
+	
+	# calculate the corresponding tile
+	# from the players position
+	x = int(position.x/get_cell_size().x)
+	# switching from positive to negative tile positions
+	# causes problems because of rounding problems
+	if position.x < 0:
+		x -= 1 # correct negative values
+	
+	y = int(position.y/get_cell_size().y)
+	if position.y < 0:
+		y -= 1
+		
+	# check if the player moved one tile further
+	if (x_old != x) or (y_old != y):
+		
+		# create the transparent part (visited area)
+		var end = l.size()-1
+		var start = 0
+		for steps in range(l.size()):
+			for m in range(x-l[end]-1,x+l[end]+2):
+				for n in range(y-l[start]-1,y+l[start]+2):
+					if get_cell(m,n) != 0:
+						set_cell(m,n,1,0,0)
+			end -= 1
+			start += 1
+	
+		# create the actual and active visible part
+		var end = l.size()-1
+		var start = 0
+		for steps in range(l.size()):
+			for m in range(x-l[end],x+l[end]+1):
+				for n in range(y-l[start],y+l[start]+1):
+					set_cell(m,n,-1)
+			end -= 1
+			start += 1
+		
+	x_old = x
+	y_old = y
+	
+	pass
+
+func _ready():
+	# Initalization here
+	
+	# create a square filled with the 100% opaque fog
+	for x in range(x_min,x_max):
+		for y in range(y_min,y_max):
+			set_cell(x,y,0,0,0)
+	set_fixed_process(true)
+	pass
+
+

BIN
demos/2d/fog_of_war/fog.png


BIN
demos/2d/fog_of_war/fog.scn


+ 29 - 0
demos/2d/fog_of_war/fog.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<resource_file type="TileSet" subresource_count="3" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">
+	<ext_resource path="res://floor.png" type="Texture"></ext_resource>
+	<ext_resource path="res://fog.png" type="Texture"></ext_resource>
+	<main_resource>
+		<string name="0/name"> "fog opaque" </string>
+		<resource name="0/texture" resource_type="Texture" path="res://fog.png">  </resource>
+		<vector2 name="0/tex_offset"> -48, -48 </vector2>
+		<vector2 name="0/shape_offset"> 0, 0 </vector2>
+		<rect2 name="0/region"> 0, 0, 144, 144 </rect2>
+		<array name="0/shapes" len="0" shared="false">
+		</array>
+		<string name="1/name"> "fog transparent" </string>
+		<resource name="1/texture" resource_type="Texture" path="res://fog.png">  </resource>
+		<vector2 name="1/tex_offset"> -48, -48 </vector2>
+		<vector2 name="1/shape_offset"> 0, 0 </vector2>
+		<rect2 name="1/region"> 144, 0, 144, 144 </rect2>
+		<array name="1/shapes" len="0" shared="false">
+		</array>
+		<string name="2/name"> "floor" </string>
+		<resource name="2/texture" resource_type="Texture" path="res://floor.png">  </resource>
+		<vector2 name="2/tex_offset"> 0, 0 </vector2>
+		<vector2 name="2/shape_offset"> 0, 0 </vector2>
+		<rect2 name="2/region"> 0, 0, 0, 0 </rect2>
+		<array name="2/shapes" len="0" shared="false">
+		</array>
+
+	</main_resource>
+</resource_file>

BIN
demos/2d/fog_of_war/icon.png


+ 1 - 0
demos/2d/fog_of_war/icon.png.flags

@@ -0,0 +1 @@
+gen_mipmaps=true

BIN
demos/2d/fog_of_war/tile_edit.scn


+ 43 - 0
demos/2d/fog_of_war/troll.gd

@@ -0,0 +1,43 @@
+
+extends KinematicBody2D
+
+# This is a simple collision demo showing how
+# the kinematic cotroller works.
+# move() will allow to move the node, and will
+# always move it to a non-colliding spot, 
+# as long as it starts from a non-colliding spot too.
+
+
+#pixels / second
+const MOTION_SPEED=160
+
+func _fixed_process(delta):
+
+	var motion = Vector2()
+	
+	if (Input.is_action_pressed("move_up")):
+		motion+=Vector2(0,-1)
+	if (Input.is_action_pressed("move_bottom")):
+		motion+=Vector2(0,1)
+	if (Input.is_action_pressed("move_left")):
+		motion+=Vector2(-1,0)
+	if (Input.is_action_pressed("move_right")):
+		motion+=Vector2(1,0)
+	
+	motion = motion.normalized() * MOTION_SPEED * delta
+	motion = move(motion)
+	
+	#make character slide nicely through the world	
+	var slide_attempts = 4
+	while(is_colliding() and slide_attempts>0):
+		motion = get_collision_normal().slide(motion)
+		motion=move(motion)
+		slide_attempts-=1
+	
+
+func _ready():
+	# Initalization here
+	set_fixed_process(true)
+	pass
+
+

BIN
demos/2d/fog_of_war/troll.png


BIN
demos/2d/fog_of_war/troll.scn


+ 26 - 0
demos/2d/hdr/beach_cave.gd

@@ -0,0 +1,26 @@
+
+extends Node2D
+
+# member variables here, example:
+# var a=2
+# var b="textvar"
+const CAVE_LIMIT=1000
+
+func _input(ev):
+	if (ev.type==InputEvent.MOUSE_MOTION and ev.button_mask&1):
+		var rel_x = ev.relative_x
+		var cavepos = get_node("cave").get_pos()
+		cavepos.x+=rel_x
+		if (cavepos.x<-CAVE_LIMIT):
+			cavepos.x=-CAVE_LIMIT
+		elif (cavepos.x>0):
+			cavepos.x=0
+		get_node("cave").set_pos(cavepos)
+			
+
+func _ready():
+	set_process_input(true)
+	# Initialization here
+	pass
+
+

BIN
demos/2d/hdr/beach_cave.scn


+ 13 - 0
demos/2d/hdr/engine.cfg

@@ -0,0 +1,13 @@
+[application]
+
+name="HDR for 2D"
+main_scene="res://beach_cave.scn"
+
+[display]
+
+width=1080
+height=720
+
+[rasterizer]
+
+blur_buffer_size=128

BIN
demos/2d/hdr/ocean_beach.png


+ 1 - 0
demos/2d/hdr/ocean_beach.png.flags

@@ -0,0 +1 @@
+tolinear=true

BIN
demos/2d/hdr/ocean_cave.png


+ 1 - 0
demos/2d/hdr/ocean_cave.png.flags

@@ -0,0 +1 @@
+tolinear=true

BIN
demos/2d/isometric/dungeon.scn


BIN
demos/2d/isometric_light/cubio.scn


+ 4 - 0
demos/2d/isometric_light/engine.cfg

@@ -9,6 +9,10 @@ down=[key(S), key(Down)]
 left=[key(Left), key(A)]
 left=[key(Left), key(A)]
 right=[key(Right), key(D)]
 right=[key(Right), key(D)]
 
 
+[rasterizer]
+
+shadow_filter=0
+
 [render]
 [render]
 
 
 default_clear_color=#ff000000
 default_clear_color=#ff000000

BIN
demos/2d/isometric_light/faceNormal.png


BIN
demos/2d/isometric_light/floor_shader.res


BIN
demos/2d/isometric_light/light2.png


BIN
demos/2d/isometric_light/map.scn


BIN
demos/2d/isometric_light/tileset_scene.scn


BIN
demos/2d/isometric_light/torch.scn


BIN
demos/2d/isometric_light/torch_light.png


BIN
demos/2d/isometric_light/wall_shader.res


BIN
demos/2d/light_mask/burano.png


+ 8 - 0
demos/2d/light_mask/engine.cfg

@@ -0,0 +1,8 @@
+[application]
+
+name="Using Lights As Mask"
+main_scene="res://lightmask.scn"
+
+[rasterizer]
+
+shadow_filter=3

BIN
demos/2d/light_mask/lightmask.scn


BIN
demos/2d/light_mask/splat.png


BIN
demos/2d/lights_shadows/bg.png


BIN
demos/2d/lights_shadows/caster.png


+ 8 - 0
demos/2d/lights_shadows/engine.cfg

@@ -0,0 +1,8 @@
+[application]
+
+name="2D Lighting"
+main_scene="res://light_shadows.scn"
+
+[rasterizer]
+
+shadow_filter=2

BIN
demos/2d/lights_shadows/light.png


BIN
demos/2d/lights_shadows/light_shadows.scn


BIN
demos/2d/lights_shadows/spot.png


BIN
demos/2d/normalmaps/diffuse.jpg


BIN
demos/2d/normalmaps/diffuse.png


+ 4 - 0
demos/2d/normalmaps/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="2D Normal Mapping"
+main_scene="res://normalmap.scn"

BIN
demos/2d/normalmaps/light.png


BIN
demos/2d/normalmaps/normal.png


BIN
demos/2d/normalmaps/normal_material.res


BIN
demos/2d/normalmaps/normalmap.scn


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 14 - 10
demos/2d/platformer/stage.xml


BIN
demos/2d/sdf_font/KaushanScript-Regular.otf


+ 4 - 0
demos/2d/sdf_font/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="Signed Distance Field Font"
+main_scene="res://sdf.scn"

BIN
demos/2d/sdf_font/font.fnt


BIN
demos/2d/sdf_font/sdf.scn


BIN
demos/2d/sprite_shaders/cubio.png


+ 4 - 0
demos/2d/sprite_shaders/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="2D Shaders for Sprites"
+main_scene="res://sprite_shaders.scn"

BIN
demos/2d/sprite_shaders/sprite_shaders.scn


BIN
demos/2d/texscreen/OpenCV_Chessboard.png


BIN
demos/2d/texscreen/bubble.png


+ 17 - 0
demos/2d/texscreen/bubbles.gd

@@ -0,0 +1,17 @@
+
+extends Control
+
+# member variables here, example:
+# var a=2
+# var b="textvar"
+
+const MAX_BUBBLES=10
+
+func _ready():
+	# Initialization here
+	for i in range(MAX_BUBBLES):
+		var bubble = preload("res://lens.scn").instance()
+		add_child(bubble)
+	pass
+
+

BIN
demos/2d/texscreen/bubbles.scn


BIN
demos/2d/texscreen/burano.png


+ 4 - 0
demos/2d/texscreen/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="Glass Bubbles (Texscreen)"
+main_scene="res://bubbles.scn"

+ 37 - 0
demos/2d/texscreen/lens.gd

@@ -0,0 +1,37 @@
+
+extends BackBufferCopy
+
+# member variables here, example:
+# var a=2
+# var b="textvar"
+const MOTION_SPEED=150
+
+var vsize;
+var dir;
+
+func _process(delta):
+	var pos = get_pos() + dir * delta * MOTION_SPEED
+	
+	if (pos.x<0):
+		dir.x=abs(dir.x)
+	elif (pos.x>vsize.x):
+		dir.x=-abs(dir.x)
+
+	if (pos.y<0):
+		dir.y=abs(dir.y)
+	elif (pos.y>vsize.y):
+		dir.y=-abs(dir.y)
+		
+	set_pos(pos)
+
+func _ready():
+	vsize = get_viewport_rect().size
+	var pos = vsize * Vector2(randf(),randf());
+	set_pos(pos);
+	dir = Vector2(randf()*2.0-1,randf()*2.0-1).normalized()
+	set_process(true)
+	
+	# Initialization here
+	pass
+
+

BIN
demos/2d/texscreen/lens.scn


BIN
demos/gui/drag_and_drop/drag_and_drop.scn


+ 24 - 0
demos/gui/drag_and_drop/drag_drop_script.gd

@@ -0,0 +1,24 @@
+
+extends ColorPickerButton
+
+
+#virtual function
+func get_drag_data(pos):
+	
+	#use another colorpicker as drag preview
+	var cpb = ColorPickerButton.new()
+	cpb.set_color( get_color() )
+	cpb.set_size(Vector2(50,50))
+	set_drag_preview(cpb)
+	#return color as drag data
+	return get_color()
+
+#virtual function	
+func can_drop_data(pos, data):
+	return typeof(data)==TYPE_COLOR
+
+#virtual function
+func drop_data(pos, data):
+	set_color(data)
+		
+

+ 4 - 0
demos/gui/drag_and_drop/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="Drag &amp; Drop (GUI)"
+main_scene="res://drag_and_drop.scn"

+ 177 - 0
demos/misc/window_management/control.gd

@@ -0,0 +1,177 @@
+
+extends Control
+
+func _fixed_process(delta):
+
+	var modetext = "Mode:\n"
+	
+	if(OS.is_window_fullscreen()):
+		modetext += "Fullscreen\n"
+	else:
+		modetext += "Windowed\n"
+		
+	if(!OS.is_window_resizable()):
+		modetext += "FixedSize\n"
+	
+	if(OS.is_window_minimized()):
+		modetext += "Minimized\n"
+	
+	if(OS.is_window_maximized()):
+		modetext += "Maximized\n"
+	
+	if(Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED):
+		modetext += "MouseGrab\n"
+		get_node("Label_MouseGrab_KeyInfo").show()
+	else:
+		get_node("Label_MouseGrab_KeyInfo").hide()
+	
+	get_node("Label_Mode").set_text(modetext)
+	
+	get_node("Label_Position").set_text( str("Position:\n", OS.get_window_position() ) )
+	
+	get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) )
+	
+	get_node("Label_MousePosition").set_text(str("Mouse Position:\n", Input.get_mouse_pos() ) )
+	
+	get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) )
+	
+	get_node("Label_Screen_Current").set_text( str("Screen:\n", OS.get_current_screen() ) )
+	
+	get_node("Label_Screen0_Resolution").set_text( str("Screen0 Resolution:\n", OS.get_screen_size() ) )
+	
+	get_node("Label_Screen0_Position").set_text(str("Screen0 Position:\n",OS.get_screen_position() ) )
+	
+	if(OS.get_screen_count() > 1):
+		get_node("Button_Screen0").show()
+		get_node("Button_Screen1").show()
+		get_node("Label_Screen1_Resolution").show()
+		get_node("Label_Screen1_Position").show()
+		get_node("Label_Screen1_Resolution").set_text( str("Screen1 Resolution:\n", OS.get_screen_size(1) ) )
+		get_node("Label_Screen1_Position").set_text( str("Screen1 Position:\n", OS.get_screen_position(1) ) )
+	else:
+		get_node("Button_Screen0").hide()
+		get_node("Button_Screen1").hide()
+		get_node("Label_Screen1_Resolution").hide()
+		get_node("Label_Screen1_Position").hide()
+		
+	get_node("Button_Fullscreen").set_pressed( OS.is_window_fullscreen() )
+	get_node("Button_FixedSize").set_pressed( !OS.is_window_resizable() )
+	get_node("Button_Minimized").set_pressed( OS.is_window_minimized() )
+	get_node("Button_Maximized").set_pressed( OS.is_window_maximized() )
+	get_node("Button_Mouse_Grab").set_pressed( Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED )
+
+
+func check_wm_api():
+	var s = ""
+	if( !OS.has_method("get_screen_count") ):
+		s += " - get_screen_count()\n"
+	
+	if( !OS.has_method("get_current_screen") ):
+		s += " - get_current_screen()\n"
+	
+	if( !OS.has_method("set_current_screen") ):
+		s += " - set_current_screen()\n"
+	
+	if( !OS.has_method("get_screen_position") ):
+		s += " - get_screen_position()\n"
+	
+	if( !OS.has_method("get_screen_size") ):
+		s += " - get_screen_size()\n"
+	
+	if( !OS.has_method("get_window_position") ):
+		s += " - get_window_position()\n"
+	
+	if( !OS.has_method("set_window_position") ):
+		s += " - set_window_position()\n"
+	
+	if( !OS.has_method("get_window_size") ):
+		s += " - get_window_size()\n"
+	
+	if( !OS.has_method("set_window_size") ):
+		s += " - set_window_size()\n"
+	
+	if( !OS.has_method("set_window_fullscreen") ):
+		s += " - set_window_fullscreen()\n"
+	
+	if( !OS.has_method("is_window_fullscreen") ):
+		s += " - is_window_fullscreen()\n"
+	
+	if( !OS.has_method("set_window_resizable") ):
+		s += " - set_window_resizable()\n"
+	
+	if( !OS.has_method("is_window_resizable") ):
+		s += " - is_window_resizable()\n"
+	
+	if( !OS.has_method("set_window_minimized") ):
+		s += " - set_window_minimized()\n"
+	
+	if( !OS.has_method("is_window_minimized") ):
+		s += " - is_window_minimized()\n"
+	
+	if( !OS.has_method("set_window_maximized") ):
+		s += " - set_window_maximized()\n"
+	
+	if( !OS.has_method("is_window_maximized") ):
+		s += " - is_window_maximized()\n"
+	
+	if( s.length() == 0 ):
+		return true
+	else:
+		var text = get_node("ImplementationDialog/Text").get_text()
+		get_node("ImplementationDialog/Text").set_text( text + s )
+		get_node("ImplementationDialog").show()
+		return false
+
+
+func _ready():
+	if( check_wm_api() ):
+		set_fixed_process(true)
+
+
+func _on_Button_MoveTo_pressed():
+	OS.set_window_position( Vector2(100,100) )
+
+
+func _on_Button_Resize_pressed():
+	OS.set_window_size( Vector2(1024,768) )
+
+
+func _on_Button_Screen0_pressed():
+	OS.set_current_screen(0)
+
+
+func _on_Button_Screen1_pressed():
+	OS.set_current_screen(1)
+
+
+func _on_Button_Fullscreen_pressed():
+	if(OS.is_window_fullscreen()):
+		OS.set_window_fullscreen(false)
+	else:
+		OS.set_window_fullscreen(true)
+
+
+func _on_Button_FixedSize_pressed():
+	if(OS.is_window_resizable()):
+		OS.set_window_resizable(false)
+	else:
+		OS.set_window_resizable(true)
+
+
+func _on_Button_Minimized_pressed():
+	if(OS.is_window_minimized()):
+		OS.set_window_minimized(false)
+	else:
+		OS.set_window_minimized(true)
+
+
+func _on_Button_Maximized_pressed():
+	if(OS.is_window_maximized()):
+		OS.set_window_maximized(false)
+	else:
+		OS.set_window_maximized(true)
+
+
+func _on_Button_Mouse_Grab_pressed():
+	var observer = get_node("../Observer")
+	observer.state = observer.STATE_GRAB

+ 19 - 0
demos/misc/window_management/engine.cfg

@@ -0,0 +1,19 @@
+[application]
+
+name="window_management"
+main_scene="res://window_management.scn"
+icon="icon.png"
+
+[display]
+
+fullscreen=false
+resizable=true
+width=800
+height=600
+
+[input]
+
+move_forward=[key(W)]
+move_backwards=[key(S)]
+move_left=[key(A)]
+move_right=[key(D)]

BIN
demos/misc/window_management/icon.png


+ 1 - 0
demos/misc/window_management/icon.png.flags

@@ -0,0 +1 @@
+gen_mipmaps=false

+ 79 - 0
demos/misc/window_management/observer/observer.gd

@@ -0,0 +1,79 @@
+
+extends Spatial
+
+var r_pos = Vector2()
+var state
+
+const STATE_MENU=0
+const STATE_GRAB=1
+
+func direction(vector):
+	var v = get_node("Camera").get_global_transform().basis * vector
+	v = v.normalized()
+	
+	return v
+
+
+func impulse(event, action):
+	if(event.is_action(action) && event.is_pressed() && !event.is_echo()):
+		return true
+	else:
+		return false
+
+
+func _fixed_process(delta):
+	
+	if(state != STATE_GRAB):
+		return
+	
+	if(Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED):
+		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
+	
+	var dir = Vector3() 
+	var cam = get_global_transform()
+	var org = get_translation()
+	
+	if (Input.is_action_pressed("move_forward")):
+		dir += direction(Vector3(0,0,-1))
+	if (Input.is_action_pressed("move_backwards")):
+		dir += direction(Vector3(0,0,1))
+	if (Input.is_action_pressed("move_left")):
+		dir += direction(Vector3(-1,0,0))
+	if (Input.is_action_pressed("move_right")):
+		dir += direction(Vector3(1,0,0))
+	
+	dir = dir.normalized()
+	
+	move(dir * 10 * delta)
+	var d = delta * 0.1
+	
+	var yaw = get_transform().rotated(Vector3(0,1,0), d * r_pos.x)
+	set_transform(yaw)
+	
+	var cam = get_node("Camera")
+	var pitch = cam.get_transform().rotated(Vector3(1,0,0), d * r_pos.y)
+	cam.set_transform(pitch)
+	
+	r_pos.x = 0.0
+	r_pos.y = 0.0
+
+
+func _input( event ):
+	if(event.type == InputEvent.MOUSE_MOTION):
+		r_pos = event.relative_pos
+	
+	if(impulse(event, "ui_cancel")):
+		if(state == STATE_GRAB):
+			Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
+			state = STATE_MENU
+		else:
+			Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
+			state = STATE_GRAB
+
+
+func _ready():
+	set_fixed_process(true)
+	set_process_input(true)
+	
+	state = STATE_MENU
+

BIN
demos/misc/window_management/observer/observer.scn


BIN
demos/misc/window_management/window_management.scn


+ 25 - 24
demos/viewport/gui_in_3d/gui_3d.gd

@@ -7,38 +7,39 @@ extends Spatial
 
 
 var prev_pos=null
 var prev_pos=null
 
 
-func _input(ev):
-	if (ev.type in [InputEvent.MOUSE_BUTTON,InputEvent.MOUSE_MOTION]):
-		var pos = ev.pos
-		var rfrom = get_node("camera").project_ray_origin(pos)
-		var rnorm = get_node("camera").project_ray_normal(pos)
+
+func _input( ev ):
+	#all other (non-mouse) events
+	if (not ev.type in [InputEvent.MOUSE_BUTTON,InputEvent.MOUSE_MOTION,InputEvent.SCREEN_DRAG,InputEvent.SCREEN_TOUCH]):	
+		get_node("viewport").input(ev)
 		
 		
-		#simple collision test against aligned plane
-		#for game UIs of this kind consider more complex collision against plane
-		var p = Plane(Vector3(0,0,1),0).intersects_ray(rfrom,rnorm)
-		if (p==null):
-			return
-			
-		pos.x=(p.x+1.5)*100
-		pos.y=(-p.y+0.75)*100
-		ev.pos=pos
-		ev.global_pos=pos
-		if (prev_pos==null):
-			prev_pos=pos
-		if (ev.type==InputEvent.MOUSE_MOTION):
-			ev.relative_pos=pos-prev_pos
+	
+#mouse events for area
+func _on_area_input_event( camera, ev, click_pos, click_normal, shape_idx ):
+	
+	#use click pos (click in 3d space, convert to area space
+	var pos = get_node("area").get_global_transform().affine_inverse() * click_pos
+	#convert to 2D
+	pos = Vector2(pos.x,pos.y)
+	#convert to viewport coordinate system		
+	pos.x=(pos.x+1.5)*100
+	pos.y=(-pos.y+0.75)*100
+	#set to event
+	ev.pos=pos
+	ev.global_pos=pos
+	if (prev_pos==null):
 		prev_pos=pos
 		prev_pos=pos
+	if (ev.type==InputEvent.MOUSE_MOTION):
+		ev.relative_pos=pos-prev_pos
+	prev_pos=pos
 		
 		
 	get_node("viewport").input(ev)
 	get_node("viewport").input(ev)
-		
-		
+	
 	
 	
 
 
 func _ready():
 func _ready():
 	# Initalization here
 	# Initalization here
-	get_node("quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, get_node("viewport").get_render_target_texture() )
+	get_node("area/quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, get_node("viewport").get_render_target_texture() )
 	set_process_input(true)
 	set_process_input(true)
-	
 	pass
 	pass
 
 
-

BIN
demos/viewport/gui_in_3d/gui_3d.scn


+ 26 - 3
doc/base/classes.xml

@@ -257,13 +257,14 @@
 		<method name="lerp"  >
 		<method name="lerp"  >
 			<return type="float">
 			<return type="float">
 			</return>
 			</return>
-			<argument index="0" name="a" type="float">
+			<argument index="0" name="from" type="float">
 			</argument>
 			</argument>
-			<argument index="1" name="b" type="float">
+			<argument index="1" name="to" type="float">
 			</argument>
 			</argument>
-			<argument index="2" name="c" type="float">
+			<argument index="2" name="weight" type="float">
 			</argument>
 			</argument>
 			<description>
 			<description>
+			Linear interpolates between two values by a normalized value.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="dectime"  >
 		<method name="dectime"  >
@@ -276,6 +277,7 @@
 			<argument index="2" name="step" type="float">
 			<argument index="2" name="step" type="float">
 			</argument>
 			</argument>
 			<description>
 			<description>
+			Decreases time by a specified amount.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="randomize"  >
 		<method name="randomize"  >
@@ -421,6 +423,7 @@
 			<argument index="1" name="funcname" type="String">
 			<argument index="1" name="funcname" type="String">
 			</argument>
 			</argument>
 			<description>
 			<description>
+			Returns a reference to the specified function
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="convert"  >
 		<method name="convert"  >
@@ -475,6 +478,7 @@
 			<argument index="1" name="..." type="var">
 			<argument index="1" name="..." type="var">
 			</argument>
 			</argument>
 			<description>
 			<description>
+			Print one or more arguments to the console with a tab between each argument.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="printerr"  >
 		<method name="printerr"  >
@@ -499,6 +503,24 @@
 			Print one or more arguments to strings in the best way possible to console. No newline is added at the end.
 			Print one or more arguments to strings in the best way possible to console. No newline is added at the end.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="var2str"  >
+			<return type="String">
+			</return>
+			<argument index="0" name="var" type="var">
+			</argument>
+			<description>
+			Converts the value of a variable to a String.
+			</description>
+		</method>
+		<method name="str2var:var"  >
+			<return type="String">
+			</return>
+			<argument index="0" name="str" type="String">
+			</argument>
+			<description>
+			Converts the value of a String to a variable.
+			</description>
+		</method>
 		<method name="range"  >
 		<method name="range"  >
 			<return type="Array">
 			<return type="Array">
 			</return>
 			</return>
@@ -544,6 +566,7 @@
 			<argument index="0" name="var:var" type="var">
 			<argument index="0" name="var:var" type="var">
 			</argument>
 			</argument>
 			<description>
 			<description>
+			Hashes the variable passed and returns an integer.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="print_stack"  >
 		<method name="print_stack"  >

+ 1 - 1
drivers/etc1/rg_etc1.cpp

@@ -2367,7 +2367,7 @@ found_perfect_match:
       int dr = best_results[1].m_block_color_unscaled.r - best_results[0].m_block_color_unscaled.r;
       int dr = best_results[1].m_block_color_unscaled.r - best_results[0].m_block_color_unscaled.r;
       int dg = best_results[1].m_block_color_unscaled.g - best_results[0].m_block_color_unscaled.g;
       int dg = best_results[1].m_block_color_unscaled.g - best_results[0].m_block_color_unscaled.g;
       int db = best_results[1].m_block_color_unscaled.b - best_results[0].m_block_color_unscaled.b;
       int db = best_results[1].m_block_color_unscaled.b - best_results[0].m_block_color_unscaled.b;
-      RG_ETC1_ASSERT(best_use_color4 || (rg_etc1::minimum(dr, dg, db) >= cETC1ColorDeltaMin) && (rg_etc1::maximum(dr, dg, db) <= cETC1ColorDeltaMax));
+      RG_ETC1_ASSERT(best_use_color4 || ((rg_etc1::minimum(dr, dg, db) >= cETC1ColorDeltaMin) && (rg_etc1::maximum(dr, dg, db) <= cETC1ColorDeltaMax)));
            
            
       if (best_use_color4)
       if (best_use_color4)
       {
       {

+ 199 - 44
drivers/gles2/rasterizer_gles2.cpp

@@ -989,8 +989,14 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
 
 
 	if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
 	if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
 		glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
 		glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
-	else
-		glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+	else {
+		if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
+			glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+		} else {
+			glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+
+		}
+	}
 
 
 	if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
 	if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
 
 
@@ -1283,8 +1289,14 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) {
 
 
 	if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
 	if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
 		glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
 		glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
-	else
-		glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+	else{
+		if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
+			glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+		} else {
+			glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+
+		}
+	}
 
 
 	if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
 	if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
 
 
@@ -4276,7 +4288,7 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
 
 
 void RasterizerGLES2::clear_viewport(const Color& p_color) {
 void RasterizerGLES2::clear_viewport(const Color& p_color) {
 
 
-	if (current_rt) {
+	if (current_rt || using_canvas_bg) {
 
 
 		glScissor( 0, 0, viewport.width, viewport.height );
 		glScissor( 0, 0, viewport.width, viewport.height );
 	} else {
 	} else {
@@ -4599,6 +4611,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
 		if (fragment_flags.uses_texpixel_size) {
 		if (fragment_flags.uses_texpixel_size) {
 			enablers.push_back("#define USE_TEXPIXEL_SIZE\n");
 			enablers.push_back("#define USE_TEXPIXEL_SIZE\n");
 		}
 		}
+		if (light_flags.uses_shadow_color) {
+			enablers.push_back("#define USE_LIGHT_SHADOW_COLOR\n");
+		}
 
 
 		if (vertex_flags.uses_worldvec) {
 		if (vertex_flags.uses_worldvec) {
 			enablers.push_back("#define USE_WORLD_VEC\n");
 			enablers.push_back("#define USE_WORLD_VEC\n");
@@ -6932,7 +6947,7 @@ void RasterizerGLES2::_draw_tex_bg() {
 
 
 	RID texture;
 	RID texture;
 
 
-	if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+	if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
 		texture=current_env->bg_param[VS::ENV_BG_PARAM_TEXTURE];
 		texture=current_env->bg_param[VS::ENV_BG_PARAM_TEXTURE];
 	} else {
 	} else {
 		texture=current_env->bg_param[VS::ENV_BG_PARAM_CUBEMAP];
 		texture=current_env->bg_param[VS::ENV_BG_PARAM_CUBEMAP];
@@ -6949,25 +6964,20 @@ void RasterizerGLES2::_draw_tex_bg() {
 
 
 	copy_shader.set_conditional(CopyShaderGLES2::USE_ENERGY,true);
 	copy_shader.set_conditional(CopyShaderGLES2::USE_ENERGY,true);
 
 
-	if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+	if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
 		copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,false);
 		copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,false);
 
 
 	} else {
 	} else {
 		copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,true);
 		copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,true);
 	}
 	}
 
 
-	if (current_env->bg_mode==VS::ENV_BG_CUBEMAP_RGBE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
-		copy_shader.set_conditional(CopyShaderGLES2::USE_RGBE,true);
-	} else {
-		copy_shader.set_conditional(CopyShaderGLES2::USE_RGBE,false);
-	}
 
 
 	copy_shader.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA,true);
 	copy_shader.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA,true);
 
 
 
 
 	copy_shader.bind();
 	copy_shader.bind();
 
 
-	if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+	if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
 		glUniform1i( copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
 		glUniform1i( copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
 	} else {
 	} else {
 		glUniform1i( copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE_CUBE),0);
 		glUniform1i( copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE_CUBE),0);
@@ -6994,7 +7004,7 @@ void RasterizerGLES2::_draw_tex_bg() {
 		Vector3( 0, 0, 0)
 		Vector3( 0, 0, 0)
 	};
 	};
 
 
-	if (current_env->bg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) {
+	if (current_env->bg_mode==VS::ENV_BG_TEXTURE) {
 
 
 		//regular texture
 		//regular texture
 		//adjust aspect
 		//adjust aspect
@@ -7064,7 +7074,7 @@ void RasterizerGLES2::end_scene() {
 	if (framebuffer.active) {
 	if (framebuffer.active) {
 
 
 		//detect when to use the framebuffer object
 		//detect when to use the framebuffer object
-		if (texscreen_used || framebuffer.scale!=1) {
+		if (using_canvas_bg || texscreen_used || framebuffer.scale!=1) {
 			use_fb=true;
 			use_fb=true;
 		} else if (current_env) {
 		} else if (current_env) {
 			use_fb=false;
 			use_fb=false;
@@ -7116,6 +7126,7 @@ void RasterizerGLES2::end_scene() {
 
 
 		switch(current_env->bg_mode) {
 		switch(current_env->bg_mode) {
 
 
+			case VS::ENV_BG_CANVAS:
 			case VS::ENV_BG_KEEP: {
 			case VS::ENV_BG_KEEP: {
 				//copy from framebuffer if framebuffer
 				//copy from framebuffer if framebuffer
 				glClear(GL_DEPTH_BUFFER_BIT);
 				glClear(GL_DEPTH_BUFFER_BIT);
@@ -7128,7 +7139,7 @@ void RasterizerGLES2::end_scene() {
 					bgcolor = current_env->bg_param[VS::ENV_BG_PARAM_COLOR];
 					bgcolor = current_env->bg_param[VS::ENV_BG_PARAM_COLOR];
 				else
 				else
 					bgcolor = Globals::get_singleton()->get("render/default_clear_color");
 					bgcolor = Globals::get_singleton()->get("render/default_clear_color");
-				bgcolor = _convert_color(bgcolor);
+			bgcolor = _convert_color(bgcolor);
 				float a = use_fb ? float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW]) : 1.0;
 				float a = use_fb ? float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW]) : 1.0;
 				glClearColor(bgcolor.r,bgcolor.g,bgcolor.b,a);
 				glClearColor(bgcolor.r,bgcolor.g,bgcolor.b,a);
 				_glClearDepth(1.0);
 				_glClearDepth(1.0);
@@ -7136,9 +7147,7 @@ void RasterizerGLES2::end_scene() {
 
 
 			} break;
 			} break;
 			case VS::ENV_BG_TEXTURE:
 			case VS::ENV_BG_TEXTURE:
-			case VS::ENV_BG_CUBEMAP:
-			case VS::ENV_BG_TEXTURE_RGBE:
-			case VS::ENV_BG_CUBEMAP_RGBE: {
+			case VS::ENV_BG_CUBEMAP: {
 
 
 
 
 				glClear(GL_DEPTH_BUFFER_BIT);
 				glClear(GL_DEPTH_BUFFER_BIT);
@@ -7357,8 +7366,12 @@ void RasterizerGLES2::end_scene() {
 		_debug_shadows();
 		_debug_shadows();
 	}
 	}
 //	_debug_luminances();
 //	_debug_luminances();
-	_debug_samplers();
+//	_debug_samplers();
 
 
+	if (using_canvas_bg) {
+		using_canvas_bg=false;
+		glColorMask(1,1,1,1); //don't touch alpha
+	}
 
 
 }
 }
 void RasterizerGLES2::end_shadow_map() {
 void RasterizerGLES2::end_shadow_map() {
@@ -7827,8 +7840,26 @@ void RasterizerGLES2::flush_frame() {
 
 
 /* CANVAS API */
 /* CANVAS API */
 
 
+void RasterizerGLES2::begin_canvas_bg() {
+
+	if (framebuffer.active) {
+		using_canvas_bg=true;
+		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo);
+		glViewport( 0,0,viewport.width , viewport.height );
+	} else {
+		using_canvas_bg=false;
+	}
+
+}
+
 void RasterizerGLES2::canvas_begin() {
 void RasterizerGLES2::canvas_begin() {
 
 
+
+	if (using_canvas_bg) {
+		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo);
+		glColorMask(1,1,1,0); //don't touch alpha
+	}
+
 	glDisable(GL_CULL_FACE);
 	glDisable(GL_CULL_FACE);
 	glDisable(GL_DEPTH_TEST);
 	glDisable(GL_DEPTH_TEST);
 	glDisable(GL_SCISSOR_TEST);
 	glDisable(GL_SCISSOR_TEST);
@@ -8531,6 +8562,7 @@ RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) {
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
 		glDrawBuffer(GL_NONE);
 		glDrawBuffer(GL_NONE);
 #endif
 #endif
+
 	} else {
 	} else {
 		// We'll use a RGBA texture into which we pack the depth info
 		// We'll use a RGBA texture into which we pack the depth info
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0,
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0,
@@ -8539,6 +8571,7 @@ RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) {
 		// Attach the RGBA texture to FBO color attachment point
 		// Attach the RGBA texture to FBO color attachment point
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
 				       GL_TEXTURE_2D, cls->depth, 0);
 				       GL_TEXTURE_2D, cls->depth, 0);
+		cls->rgba=cls->depth;
 
 
 		// Allocate 16-bit depth buffer
 		// Allocate 16-bit depth buffer
 		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
 		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
@@ -8554,7 +8587,7 @@ RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) {
 	//printf("errnum: %x\n",status);
 	//printf("errnum: %x\n",status);
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
 	if (read_depth_supported) {
 	if (read_depth_supported) {
-		glDrawBuffer(GL_BACK);
+		//glDrawBuffer(GL_BACK);
 	}
 	}
 #endif
 #endif
 	glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
 	glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
@@ -8563,7 +8596,7 @@ RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) {
 
 
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
 	if (read_depth_supported) {
 	if (read_depth_supported) {
-		glDrawBuffer(GL_BACK);
+		//glDrawBuffer(GL_BACK);
 	}
 	}
 #endif
 #endif
 
 
@@ -8817,10 +8850,14 @@ void RasterizerGLES2::canvas_debug_viewport_shadows(CanvasLight* p_lights_with_s
 	int h = 10;
 	int h = 10;
 	int w = viewport.width;
 	int w = viewport.width;
 	int ofs = h;
 	int ofs = h;
+
+	//print_line(" debug lights ");
 	while(light) {
 	while(light) {
 
 
+	//	print_line("debug light");
 		if (light->shadow_buffer.is_valid()) {
 		if (light->shadow_buffer.is_valid()) {
 
 
+	//		print_line("sb is valid");
 			CanvasLightShadow * sb = canvas_light_shadow_owner.get(light->shadow_buffer);
 			CanvasLightShadow * sb = canvas_light_shadow_owner.get(light->shadow_buffer);
 			if (sb) {
 			if (sb) {
 				glActiveTexture(GL_TEXTURE0);
 				glActiveTexture(GL_TEXTURE0);
@@ -9099,8 +9136,11 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 	canvas_use_modulate=p_modulate!=Color(1,1,1,1);
 	canvas_use_modulate=p_modulate!=Color(1,1,1,1);
 	canvas_modulate=p_modulate;
 	canvas_modulate=p_modulate;
 	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
 	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+	canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD,false);
+
 
 
 	bool reset_modulate=false;
 	bool reset_modulate=false;
+	bool prev_distance_field=false;
 
 
 	while(p_item_list) {
 	while(p_item_list) {
 
 
@@ -9116,12 +9156,22 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 			canvas_use_modulate=p_modulate!=Color(1,1,1,1);
 			canvas_use_modulate=p_modulate!=Color(1,1,1,1);
 			canvas_modulate=p_modulate;
 			canvas_modulate=p_modulate;
 			canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
 			canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate);
+			canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD,false);
+			prev_distance_field=false;
 			rebind_shader=true;
 			rebind_shader=true;
 			reset_modulate=true;
 			reset_modulate=true;
 
 
 
 
 		}
 		}
 
 
+		if (prev_distance_field!=ci->distance_field) {
+
+			canvas_shader.set_conditional(CanvasShaderGLES2::USE_DISTANCE_FIELD,ci->distance_field);
+			prev_distance_field=ci->distance_field;
+			rebind_shader=true;
+		}
+
+
 		if (current_clip!=ci->final_clip_owner) {
 		if (current_clip!=ci->final_clip_owner) {
 
 
 			current_clip=ci->final_clip_owner;
 			current_clip=ci->final_clip_owner;
@@ -9138,6 +9188,40 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 			}
 			}
 		}
 		}
 
 
+		if (ci->copy_back_buffer && framebuffer.active && framebuffer.scale==1) {
+
+			Rect2 rect;
+			int x,y,w,h;
+
+			if (ci->copy_back_buffer->full) {
+
+				x = viewport.x;
+				y = window_size.height-(viewport.height+viewport.y);
+				w = viewport.width;
+				h = viewport.height;
+			} else {
+				x = viewport.x+ci->copy_back_buffer->screen_rect.pos.x;
+				y = window_size.height-(viewport.y+ci->copy_back_buffer->screen_rect.pos.y+ci->copy_back_buffer->screen_rect.size.y);
+				w = ci->copy_back_buffer->screen_rect.size.x;
+				h = ci->copy_back_buffer->screen_rect.size.y;
+			}
+			glActiveTexture(GL_TEXTURE0+max_texture_units-1);
+			glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
+
+#ifdef GLEW_ENABLED
+			glReadBuffer(GL_COLOR_ATTACHMENT0);
+#endif
+			glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,w,h);
+//			if (current_clip) {
+//			//	print_line(" a clip ");
+//			}
+
+			canvas_texscreen_used=true;
+			glActiveTexture(GL_TEXTURE0);
+		}
+
+
+
 
 
 		//begin rect
 		//begin rect
 		CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci;
 		CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci;
@@ -9179,7 +9263,9 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 			_canvas_item_setup_shader_uniforms(material,shader_cache);
 			_canvas_item_setup_shader_uniforms(material,shader_cache);
 		}
 		}
 
 
-		if (material && material->unshaded) {
+		bool unshaded = material && material->shading_mode==VS::CANVAS_ITEM_SHADING_UNSHADED;
+
+		if (unshaded) {
 			canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,Color(1,1,1,1));
 			canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,Color(1,1,1,1));
 			reset_modulate=true;
 			reset_modulate=true;
 		} else if (reset_modulate) {
 		} else if (reset_modulate) {
@@ -9236,13 +9322,15 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 
 		canvas_opacity = ci->final_opacity;
 		canvas_opacity = ci->final_opacity;
 
 
-		_canvas_item_render_commands<false>(ci,current_clip,reclip);
 
 
-		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && (!material || !material->unshaded)) {
+		if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT)))
+			_canvas_item_render_commands<false>(ci,current_clip,reclip);
+
+		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && !unshaded) {
 
 
 			CanvasLight *light = p_light;
 			CanvasLight *light = p_light;
 			bool light_used=false;
 			bool light_used=false;
-			bool subtract=false;
+			VS::CanvasLightMode mode=VS::CANVAS_LIGHT_MODE_ADD;
 
 
 
 
 			while(light) {
 			while(light) {
@@ -9251,21 +9339,28 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 
 					//intersects this light
 					//intersects this light
 
 
-					if (!light_used || subtract!=light->subtract) {
+					if (!light_used || mode!=light->mode) {
 
 
-						subtract=light->subtract;
+						mode=light->mode;
 
 
-						if (subtract) {
+						switch(mode) {
 
 
-							glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
-							glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+							case VS::CANVAS_LIGHT_MODE_ADD: {
+								glBlendEquation(GL_FUNC_ADD);
+								glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 
 
-						} else {
-
-							glBlendEquation(GL_FUNC_ADD);
-							glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+							} break;
+							case VS::CANVAS_LIGHT_MODE_SUB: {
+								glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+								glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+							} break;
+							case VS::CANVAS_LIGHT_MODE_MIX: {
+								glBlendEquation(GL_FUNC_ADD);
+								glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 
+							} break;
 						}
 						}
+
 					}
 					}
 
 
 					if (!light_used) {
 					if (!light_used) {
@@ -9303,7 +9398,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 
 
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX,light->light_shader_xform);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX,light->light_shader_xform);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos);
-					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,light->color);
+					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,Color(light->color.r*light->energy,light->color.g*light->energy,light->color.b*light->energy,light->color.a));
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse());
 					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse());
 
 
@@ -9783,9 +9878,9 @@ void RasterizerGLES2::free(const RID& p_rid) {
 		glDeleteFramebuffers(1,&cls->fbo);
 		glDeleteFramebuffers(1,&cls->fbo);
 		glDeleteRenderbuffers(1,&cls->rbo);
 		glDeleteRenderbuffers(1,&cls->rbo);
 		glDeleteTextures(1,&cls->depth);
 		glDeleteTextures(1,&cls->depth);
-		if (!read_depth_supported) {
-			glDeleteTextures(1,&cls->rgba);
-		}
+		//if (!read_depth_supported) {
+		//	glDeleteTextures(1,&cls->rgba);
+		//}
 
 
 		canvas_light_shadow_owner.free(p_rid);
 		canvas_light_shadow_owner.free(p_rid);
 		memdelete(cls);
 		memdelete(cls);
@@ -9904,7 +9999,7 @@ bool RasterizerGLES2::ShadowBuffer::init(int p_size,bool p_use_depth) {
 	//printf("errnum: %x\n",status);
 	//printf("errnum: %x\n",status);
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
 	if (p_use_depth) {
 	if (p_use_depth) {
-		glDrawBuffer(GL_BACK);
+		//glDrawBuffer(GL_BACK);
 	}
 	}
 #endif
 #endif
 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -9913,7 +10008,7 @@ bool RasterizerGLES2::ShadowBuffer::init(int p_size,bool p_use_depth) {
 
 
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
 	if (p_use_depth) {
 	if (p_use_depth) {
-		glDrawBuffer(GL_BACK);
+		//glDrawBuffer(GL_BACK);
 	}
 	}
 #endif
 #endif
 
 
@@ -10291,6 +10386,62 @@ void RasterizerGLES2::_update_blur_buffer() {
 
 
 }
 }
 #endif
 #endif
+
+
+bool RasterizerGLES2::_test_depth_shadow_buffer() {
+
+
+	int size=16;
+
+	GLuint fbo;
+	GLuint rbo;
+	GLuint depth;
+
+	glActiveTexture(GL_TEXTURE0);
+
+	glGenFramebuffers(1, &fbo);
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+	// Create a render buffer
+	glGenRenderbuffers(1, &rbo);
+	glBindRenderbuffer(GL_RENDERBUFFER, rbo);
+
+	// Create a texture for storing the depth
+	glGenTextures(1, &depth);
+	glBindTexture(GL_TEXTURE_2D, depth);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	// Remove artifact on the edges of the shadowmap
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+
+
+	// We'll use a depth texture to store the depths in the shadow map
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size, size, 0,
+		     GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+#ifdef GLEW_ENABLED
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#endif
+
+	// Attach the depth texture to FBO depth attachment point
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+			       GL_TEXTURE_2D, depth, 0);
+
+
+	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+	glDeleteFramebuffers(1,&fbo);
+	glDeleteRenderbuffers(1,&rbo);
+	glDeleteTextures(1,&depth);
+
+	return status == GL_FRAMEBUFFER_COMPLETE;
+
+}
+
 void RasterizerGLES2::init() {
 void RasterizerGLES2::init() {
 
 
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
@@ -10363,7 +10514,7 @@ void RasterizerGLES2::init() {
 
 
 #ifdef GLEW_ENABLED
 #ifdef GLEW_ENABLED
 
 
-	read_depth_supported=true;
+
 	pvr_supported=false;
 	pvr_supported=false;
 	etc_supported=false;
 	etc_supported=false;
 	use_depth24 =true;
 	use_depth24 =true;
@@ -10381,7 +10532,10 @@ void RasterizerGLES2::init() {
 	use_anisotropic_filter=true;
 	use_anisotropic_filter=true;
 	float_linear_supported=true;
 	float_linear_supported=true;
 	float_supported=true;
 	float_supported=true;
-	use_rgba_shadowmaps=false;
+
+	read_depth_supported=_test_depth_shadow_buffer();
+	use_rgba_shadowmaps=!read_depth_supported;
+	//print_line("read depth support? "+itos(read_depth_supported));
 
 
 	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&anisotropic_level);
 	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&anisotropic_level);
 	anisotropic_level=MIN(anisotropic_level,float(GLOBAL_DEF("rasterizer/anisotropic_filter_level",4.0)));
 	anisotropic_level=MIN(anisotropic_level,float(GLOBAL_DEF("rasterizer/anisotropic_filter_level",4.0)));
@@ -10504,6 +10658,7 @@ void RasterizerGLES2::init() {
 	shadow_mat_ptr = material_owner.get(shadow_material);
 	shadow_mat_ptr = material_owner.get(shadow_material);
 	overdraw_material = create_overdraw_debug_material();
 	overdraw_material = create_overdraw_debug_material();
 	copy_shader.set_conditional(CopyShaderGLES2::USE_8BIT_HDR,!use_fp16_fb);
 	copy_shader.set_conditional(CopyShaderGLES2::USE_8BIT_HDR,!use_fp16_fb);
+	canvas_shader.set_conditional(CanvasShaderGLES2::USE_DEPTH_SHADOWS,read_depth_supported);
 
 
 	canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false));
 	canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false));
 
 
@@ -10521,7 +10676,7 @@ void RasterizerGLES2::init() {
 	glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
 	glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
 
 
 
 
-
+	using_canvas_bg=false;
 	_update_framebuffer();
 	_update_framebuffer();
 	DEBUG_TEST_ERROR("Initializing");
 	DEBUG_TEST_ERROR("Initializing");
 }
 }

+ 5 - 0
drivers/gles2/rasterizer_gles2.h

@@ -677,6 +677,7 @@ class RasterizerGLES2 : public Rasterizer {
 			bg_param[VS::ENV_BG_PARAM_ENERGY]=1.0;
 			bg_param[VS::ENV_BG_PARAM_ENERGY]=1.0;
 			bg_param[VS::ENV_BG_PARAM_SCALE]=1.0;
 			bg_param[VS::ENV_BG_PARAM_SCALE]=1.0;
 			bg_param[VS::ENV_BG_PARAM_GLOW]=0.0;
 			bg_param[VS::ENV_BG_PARAM_GLOW]=0.0;
+			bg_param[VS::ENV_BG_PARAM_CANVAS_MAX_LAYER]=0;
 
 
 			for(int i=0;i<VS::ENV_FX_MAX;i++)
 			for(int i=0;i<VS::ENV_FX_MAX;i++)
 				fx_enabled[i]=false;
 				fx_enabled[i]=false;
@@ -1258,6 +1259,7 @@ class RasterizerGLES2 : public Rasterizer {
 	void _process_hdr();
 	void _process_hdr();
 	void _draw_tex_bg();
 	void _draw_tex_bg();
 
 
+	bool using_canvas_bg;
 	Size2 window_size;
 	Size2 window_size;
 	VS::ViewportRect viewport;
 	VS::ViewportRect viewport;
 	double last_time;
 	double last_time;
@@ -1286,6 +1288,7 @@ class RasterizerGLES2 : public Rasterizer {
 	void _copy_screen_quad();
 	void _copy_screen_quad();
 	void _copy_to_texscreen();
 	void _copy_to_texscreen();
 
 
+	bool _test_depth_shadow_buffer();
 
 
 	Vector3 chunk_vertex;
 	Vector3 chunk_vertex;
 	Vector3 chunk_normal;
 	Vector3 chunk_normal;
@@ -1600,6 +1603,8 @@ public:
 
 
 	/* CANVAS API */
 	/* CANVAS API */
 
 
+	virtual void begin_canvas_bg();
+
 	virtual void canvas_begin();
 	virtual void canvas_begin();
 	virtual void canvas_disable_blending();
 	virtual void canvas_disable_blending();
 
 

+ 8 - 0
drivers/gles2/shader_compiler_gles2.cpp

@@ -266,6 +266,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 					uses_normal=true;
 					uses_normal=true;
 				}
 				}
 
 
+				if (vnode->name==vname_shadow) {
+					uses_shadow_color=true;
+				}
 
 
 			}
 			}
 
 
@@ -616,6 +619,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	uses_texpixel_size=false;
 	uses_texpixel_size=false;
 	uses_worldvec=false;
 	uses_worldvec=false;
 	vertex_code_writes_vertex=false;
 	vertex_code_writes_vertex=false;
+	uses_shadow_color=false;
 	uniforms=r_uniforms;
 	uniforms=r_uniforms;
 	flags=&r_flags;
 	flags=&r_flags;
 	r_flags.use_color_interp=false;
 	r_flags.use_color_interp=false;
@@ -651,6 +655,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.uses_normal=uses_normal;
 	r_flags.uses_normal=uses_normal;
 	r_flags.uses_texpixel_size=uses_texpixel_size;
 	r_flags.uses_texpixel_size=uses_texpixel_size;
 	r_flags.uses_worldvec=uses_worldvec;
 	r_flags.uses_worldvec=uses_worldvec;
+	r_flags.uses_shadow_color=uses_shadow_color;
 	r_code_line=code;
 	r_code_line=code;
 	r_globals_line=global_code;
 	r_globals_line=global_code;
 
 
@@ -827,7 +832,9 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	mode_replace_table[5]["LIGHT_VEC"]="light_vec";
 	mode_replace_table[5]["LIGHT_VEC"]="light_vec";
 	mode_replace_table[5]["LIGHT_HEIGHT"]="light_height";
 	mode_replace_table[5]["LIGHT_HEIGHT"]="light_height";
 	mode_replace_table[5]["LIGHT_COLOR"]="light";
 	mode_replace_table[5]["LIGHT_COLOR"]="light";
+	mode_replace_table[5]["LIGHT_UV"]="light_uv";
 	mode_replace_table[5]["LIGHT"]="light_out";
 	mode_replace_table[5]["LIGHT"]="light_out";
+	mode_replace_table[5]["SHADOW"]="shadow_color";
 	mode_replace_table[5]["SCREEN_UV"]="screen_uv";
 	mode_replace_table[5]["SCREEN_UV"]="screen_uv";
 	mode_replace_table[5]["POINT_COORD"]="gl_PointCoord";
 	mode_replace_table[5]["POINT_COORD"]="gl_PointCoord";
 	mode_replace_table[5]["TIME"]="time";
 	mode_replace_table[5]["TIME"]="time";
@@ -857,5 +864,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	vname_normal="NORMAL";
 	vname_normal="NORMAL";
 	vname_texpixel_size="TEXTURE_PIXEL_SIZE";
 	vname_texpixel_size="TEXTURE_PIXEL_SIZE";
 	vname_world_vec="WORLD_VERTEX";
 	vname_world_vec="WORLD_VERTEX";
+	vname_shadow="SHADOW";
 
 
 }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно