From 6f0b4678e26c04abfc88c0226c803e78a108de98 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 29 May 2014 10:56:39 -0300 Subject: [PATCH] More 3D Improvements -=-=-=-=-=-=-=-=-=-= -Sprite3D and AnimatedSprite3D support. -Opaque pre-pass works, is compatible with shadows -Improved shadow map rendering (can differentiate between plain opaque and opaque with shaders/discard/etc) -Added option to use alpha discard in FixedMaterial -Improved Glow FX, many more options (three modes, Additive, Screen and SoftLight), strength and scale -Ability for Background (image or cubemap) to send to glow buffer -Dumb Deploy of clients now actually works in Android -Many Many rendering fixes, 3D is much more usable now. --- demos/3d/fixed_materials/fixed_materials.scn | Bin 5906 -> 6071 bytes demos/3d/platformer/stage.xml | 15 +- demos/3d/platformer/tiles.res | Bin 81540 -> 81468 bytes drivers/gles1/rasterizer_gles1.cpp | 81 ++ drivers/gles1/rasterizer_gles1.h | 28 + drivers/gles2/rasterizer_gles2.cpp | 365 ++++++++- drivers/gles2/rasterizer_gles2.h | 67 +- drivers/gles2/shader_compiler_gles2.cpp | 7 + drivers/gles2/shader_compiler_gles2.h | 1 + drivers/gles2/shader_gles2.cpp | 8 +- drivers/gles2/shaders/copy.glsl | 56 +- drivers/gles2/shaders/material.glsl | 20 +- platform/android/export/export.cpp | 74 +- platform/android/java_bind.cpp | 5 + platform/android/java_bind.h | 10 + platform/bb10/export/export.cpp | 8 +- platform/javascript/export/export.cpp | 8 +- platform/osx/export/export.cpp | 8 +- scene/3d/immediate_geometry.cpp | 102 +++ scene/3d/immediate_geometry.h | 41 + scene/3d/sprite_3d.cpp | 772 ++++++++++++++++++ scene/3d/sprite_3d.h | 191 +++++ scene/register_scene_types.cpp | 5 + scene/resources/environment.cpp | 15 + scene/resources/environment.h | 10 + scene/resources/material.cpp | 9 +- scene/resources/material.h | 2 + scene/resources/texture.cpp | 43 + scene/resources/texture.h | 2 + scene/scene_string_names.cpp | 2 + scene/scene_string_names.h | 4 + servers/visual/rasterizer.cpp | 6 + servers/visual/rasterizer.h | 22 + servers/visual/rasterizer_dummy.cpp | 80 ++ servers/visual/rasterizer_dummy.h | 29 + servers/visual/shader_language.cpp | 2 +- servers/visual/visual_server_raster.cpp | 77 ++ servers/visual/visual_server_raster.h | 15 + servers/visual/visual_server_wrap_mt.h | 16 + servers/visual_server.cpp | 49 ++ servers/visual_server.h | 43 +- tools/editor/editor_import_export.cpp | 2 +- tools/editor/editor_import_export.h | 6 +- tools/editor/editor_node.cpp | 7 +- tools/editor/editor_run_native.cpp | 14 +- tools/editor/editor_run_native.h | 4 + .../editor/fileserver/editor_file_server.cpp | 21 + .../editor/icons/icon_animated_sprite_3d.png | Bin 0 -> 753 bytes tools/editor/icons/icon_sprite_3d.png | Bin 0 -> 604 bytes tools/editor/project_export.cpp | 2 +- 50 files changed, 2261 insertions(+), 93 deletions(-) create mode 100644 platform/android/java_bind.cpp create mode 100644 platform/android/java_bind.h create mode 100644 scene/3d/immediate_geometry.cpp create mode 100644 scene/3d/immediate_geometry.h create mode 100644 scene/3d/sprite_3d.cpp create mode 100644 scene/3d/sprite_3d.h create mode 100644 tools/editor/icons/icon_animated_sprite_3d.png create mode 100644 tools/editor/icons/icon_sprite_3d.png diff --git a/demos/3d/fixed_materials/fixed_materials.scn b/demos/3d/fixed_materials/fixed_materials.scn index 210d4208ee824db465913bc68e56a77ae3488989..de14ccdb154e39791c6c8ea63c343791e9863a7a 100644 GIT binary patch delta 4302 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 delta 4180 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 C0n1YW diff --git a/demos/3d/platformer/stage.xml b/demos/3d/platformer/stage.xml index 1dc7d1e7ab21..fbb720c006ea 100644 --- a/demos/3d/platformer/stage.xml +++ b/demos/3d/platformer/stage.xml @@ -6,14 +6,19 @@ + False 4 0, 0, 0, 1 1 1 + 0.6 True 2 + 1.3 + 1.2 + 1 0 0.5 False @@ -150,8 +155,12 @@ False "zoom" 1 + "use_snap" + False "ofs" 1, 1 + "snap" + 10 "3D" @@ -165,15 +174,15 @@ "distance" 6.622579 "x_rot" - 1.570796 + 0.358295 "y_rot" - 0 + 0.45 "use_orthogonal" False "use_environment" False "pos" - 8.30511, 0.427271, 15.7846 + 9.41795, 2.98588, 13.6496 "distance" diff --git a/demos/3d/platformer/tiles.res b/demos/3d/platformer/tiles.res index 9270f4c49121cbb8508f11ab3aeceede993aae96..0ab7c92ef66763c970cc744ecfb629c6fc3e2f79 100644 GIT binary patch delta 15001 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 Uly+++aXzg1j*-T(jq delta 15144 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 diff --git a/drivers/gles1/rasterizer_gles1.cpp b/drivers/gles1/rasterizer_gles1.cpp index 60c88af508f3..9e13f12abef7 100644 --- a/drivers/gles1/rasterizer_gles1.cpp +++ b/drivers/gles1/rasterizer_gles1.cpp @@ -2165,6 +2165,74 @@ int RasterizerGLES1::multimesh_get_visible_instances(RID p_multimesh) const { } +/* IMMEDIATE API */ + + +RID RasterizerGLES1::immediate_create() { + + Immediate *im = memnew( Immediate ); + return immediate_owner.make_rid(im); + +} + +void RasterizerGLES1::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture){ + + +} +void RasterizerGLES1::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + +} +void RasterizerGLES1::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + +} +void RasterizerGLES1::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + +} +void RasterizerGLES1::immediate_color(RID p_immediate,const Color& p_color){ + + +} +void RasterizerGLES1::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + + +} +void RasterizerGLES1::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + + +} + +void RasterizerGLES1::immediate_end(RID p_immediate){ + + +} +void RasterizerGLES1::immediate_clear(RID p_immediate) { + + +} + +AABB RasterizerGLES1::immediate_get_aabb(RID p_immediate) const { + + return AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); +} + +void RasterizerGLES1::immediate_set_material(RID p_immediate,RID p_material) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + im->material=p_material; +} + +RID RasterizerGLES1::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + +} + /* PARTICLES API */ @@ -5327,6 +5395,12 @@ bool RasterizerGLES1::is_mesh(const RID& p_rid) const { return mesh_owner.owns(p_rid); } + +bool RasterizerGLES1::is_immediate(const RID& p_rid) const { + + return immediate_owner.owns(p_rid); +} + bool RasterizerGLES1::is_multimesh(const RID& p_rid) const { return multimesh_owner.owns(p_rid); @@ -5447,6 +5521,13 @@ void RasterizerGLES1::free(const RID& p_rid) { particles_owner.free(p_rid); memdelete(particles); + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + ERR_FAIL_COND(!immediate); + + immediate_owner.free(p_rid); + memdelete(immediate); } else if (particles_instance_owner.owns(p_rid)) { ParticlesInstance *particles_isntance = particles_instance_owner.get(p_rid); diff --git a/drivers/gles1/rasterizer_gles1.h b/drivers/gles1/rasterizer_gles1.h index dbb411c8a309..323d00a46766 100644 --- a/drivers/gles1/rasterizer_gles1.h +++ b/drivers/gles1/rasterizer_gles1.h @@ -371,6 +371,15 @@ class RasterizerGLES1 : public Rasterizer { mutable RID_Owner multimesh_owner; + + struct Immediate { + + RID material; + int empty; + }; + + mutable RID_Owner immediate_owner; + struct Particles : public Geometry { ParticleSystemSW data; // software particle system @@ -963,6 +972,23 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible); virtual int multimesh_get_visible_instances(RID p_multimesh) const; + /* IMMEDIATE API */ + + virtual RID immediate_create(); + virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID()); + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_normal(RID p_immediate,const Vector3& p_normal); + virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent); + virtual void immediate_color(RID p_immediate,const Color& p_color); + virtual void immediate_uv(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_end(RID p_immediate); + virtual void immediate_clear(RID p_immediate); + virtual AABB immediate_get_aabb(RID p_immediate) const; + virtual void immediate_set_material(RID p_immediate,RID p_material); + virtual RID immediate_get_material(RID p_immediate) const; + + /* PARTICLES API */ virtual RID particles_create(); @@ -1120,6 +1146,7 @@ public: virtual void add_mesh( const RID& p_mesh, const InstanceData *p_data); virtual void add_multimesh( const RID& p_multimesh, const InstanceData *p_data); + virtual void add_immediate( const RID& p_immediate, const InstanceData *p_data) {} virtual void add_particles( const RID& p_particle_instance, const InstanceData *p_data); virtual void end_scene(); @@ -1176,6 +1203,7 @@ public: virtual bool is_material(const RID& p_rid) const; virtual bool is_mesh(const RID& p_rid) const; virtual bool is_multimesh(const RID& p_rid) const; + virtual bool is_immediate(const RID& p_rid) const; virtual bool is_particles(const RID &p_beam) const; virtual bool is_light(const RID& p_rid) const; diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 472e92f23a0c..74a82e1a5ca9 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -2489,6 +2489,156 @@ int RasterizerGLES2::multimesh_get_visible_instances(RID p_multimesh) const { } +/* IMMEDIATE API */ + + +RID RasterizerGLES2::immediate_create() { + + Immediate *im = memnew( Immediate ); + return immediate_owner.make_rid(im); + +} + +void RasterizerGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + + Immediate::Chunk ic; + ic.texture=p_texture; + ic.primitive=p_rimitive; + im->chunks.push_back(ic); + im->mask=0; + im->building=true; + + +} +void RasterizerGLES2::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + Immediate::Chunk *c = &im->chunks.back()->get(); + + + if (c->vertices.empty() && im->chunks.size()==1) { + + im->aabb.pos=p_vertex; + im->aabb.size=Vector3(); + } else { + im->aabb.expand_to(p_vertex); + } + + if (im->mask&VS::ARRAY_FORMAT_NORMAL) + c->normals.push_back(chunk_normal); + if (im->mask&VS::ARRAY_FORMAT_TANGENT) + c->tangents.push_back(chunk_tangent); + if (im->mask&VS::ARRAY_FORMAT_COLOR) + c->colors.push_back(chunk_color); + if (im->mask&VS::ARRAY_FORMAT_TEX_UV) + c->uvs.push_back(chunk_uv); + if (im->mask&VS::ARRAY_FORMAT_TEX_UV2) + c->uvs2.push_back(chunk_uv2); + im->mask|=VS::ARRAY_FORMAT_VERTEX; + c->vertices.push_back(p_vertex); + +} + + +void RasterizerGLES2::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_NORMAL; + chunk_normal=p_normal; + +} +void RasterizerGLES2::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TANGENT; + chunk_tangent=p_tangent; + +} +void RasterizerGLES2::immediate_color(RID p_immediate,const Color& p_color){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_COLOR; + chunk_color=p_color; + +} +void RasterizerGLES2::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TEX_UV; + chunk_uv=tex_uv; + +} +void RasterizerGLES2::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TEX_UV2; + chunk_uv2=tex_uv; + +} + +void RasterizerGLES2::immediate_end(RID p_immediate){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->building=false; + +} +void RasterizerGLES2::immediate_clear(RID p_immediate) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + + im->chunks.clear(); +} + +AABB RasterizerGLES2::immediate_get_aabb(RID p_immediate) const { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,AABB()); + return im->aabb; +} + +void RasterizerGLES2::immediate_set_material(RID p_immediate,RID p_material) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + im->material=p_material; + +} + +RID RasterizerGLES2::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + +} + /* PARTICLES API */ @@ -3793,9 +3943,16 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const { //print_line("UCF: "+itos(p_shader->uniforms.size())); + int first_tex_index=0xFFFFF; + p_shader->first_texture=StringName(); + for(Map::Element *E=p_shader->uniforms.front();E;E=E->next()) { uniform_names.push_back("_"+String(E->key())); + if (E->get().type==ShaderLanguage::TYPE_TEXTURE && E->get().orderfirst_texture=E->key(); + first_tex_index=E->get().order; + } } if (p_shader->mode==VS::SHADER_MATERIAL) { @@ -3819,6 +3976,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const { if (flags.uses_screen_uv) { enablers.push_back("#define ENABLE_SCREEN_UV\n"); } + if (flags.uses_discard) { + enablers.push_back("#define ENABLE_DISCARD\n"); + } material_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, fragment_globals,uniform_names,enablers); } else { @@ -3827,6 +3987,8 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const { p_shader->valid=true; p_shader->has_alpha=flags.uses_alpha || flags.uses_texscreen; + p_shader->writes_vertex=flags.vertex_code_writes_vertex; + p_shader->uses_discard=flags.uses_discard; p_shader->has_texscreen=flags.uses_texscreen; p_shader->has_screen_uv=flags.uses_screen_uv; p_shader->can_zpass=!flags.uses_discard && !flags.vertex_code_writes_vertex; @@ -3887,16 +4049,19 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD RenderList *render_list=NULL; - bool has_alpha = m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX || (m->shader_cache && m->shader_cache->has_alpha) || m->flags[VS::MATERIAL_FLAG_ONTOP]; + bool has_base_alpha=(m->shader_cache && m->shader_cache->has_alpha); + bool has_blend_alpha=m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX || m->flags[VS::MATERIAL_FLAG_ONTOP]; + bool has_alpha = has_base_alpha || has_blend_alpha; if (shadow) { - if (has_alpha) + if (has_blend_alpha || (has_base_alpha && !m->hints[VS::MATERIAL_HINT_OPAQUE_PRE_PASS])) return; //bye - if (true) { - m = shadow_mat_ptr; //for now do this always + if (m->shader_cache && !m->shader_cache->writes_vertex && !m->shader_cache->uses_discard && !m->hints[VS::MATERIAL_HINT_OPAQUE_PRE_PASS]) { + //shader does not use discard and does not write a vertex position, use generic material + m = shadow_mat_ptr; if (m->last_pass!=frame) { if (m->shader.is_valid()) { @@ -3939,6 +4104,9 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD RenderList::Element *e = render_list->add_element(); + if (!e) + return; + e->geometry=p_geometry; e->geometry_cmp=p_geometry_cmp; e->material=m; @@ -3974,6 +4142,18 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD e->light_type=0xFF; // no lights! e->light=0xFFFF; + if (!shadow && !has_blend_alpha && has_alpha && m->hints[VS::MATERIAL_HINT_OPAQUE_PRE_PASS]) { + + //if nothing exists, add this element as opaque too + RenderList::Element *oe = opaque_render_list.add_element(); + + if (!oe) + return; + + memcpy(oe,e,sizeof(RenderList::Element)); + oe->additive_ptr=&oe->additive; + } + if (shadow || m->flags[VS::MATERIAL_FLAG_UNSHADED]) { e->light_type=0x7F; //unshaded is zero @@ -4098,6 +4278,17 @@ void RasterizerGLES2::add_multimesh( const RID& p_multimesh, const InstanceData } +void RasterizerGLES2::add_immediate( const RID& p_immediate, const InstanceData *p_data) { + + + Immediate *immediate = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!immediate); + + _add_geometry(immediate,p_data,immediate,NULL); + +} + + void RasterizerGLES2::add_particles( const RID& p_particle_instance, const InstanceData *p_data){ //print_line("adding particles"); @@ -4169,7 +4360,7 @@ _FORCE_INLINE_ void RasterizerGLES2::_update_material_shader_params(Material *p_ } -bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material *p_material,bool p_no_const_light) { +bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material *p_material,bool p_no_const_light,bool p_opaque_pass) { if (p_material->flags[VS::MATERIAL_FLAG_DOUBLE_SIDED]) { glDisable(GL_CULL_FACE); @@ -4196,11 +4387,19 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF_HQ,shadow_filter>SHADOW_FILTER_PCF5); //material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_ESM,true); + if (p_opaque_pass && p_material->hints[VS::MATERIAL_HINT_OPAQUE_PRE_PASS] && p_material->shader_cache && p_material->shader_cache->has_alpha) { + + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_CLIP_ALPHA,true); + } else { + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_CLIP_ALPHA,false); + + } + if (!shadow) { bool depth_test=!p_material->flags[VS::MATERIAL_FLAG_ONTOP]; - bool depth_write=!p_material->hints[VS::MATERIAL_HINT_NO_DEPTH_DRAW]; + bool depth_write=!p_material->hints[VS::MATERIAL_HINT_NO_DEPTH_DRAW] && (p_opaque_pass || !p_material->hints[VS::MATERIAL_HINT_NO_DEPTH_DRAW_FOR_ALPHA]); if (current_depth_mask!=depth_write) { current_depth_mask=depth_write; @@ -4276,6 +4475,10 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material if (t) { if (t->render_target) t->render_target->last_pass=frame; + if (E->key()==p_material->shader_cache->first_texture) { + tc0_idx=texcoord; + tc0_id_cache=t->tex_id; + } glBindTexture(t->target,t->tex_id); } else glBindTexture(GL_TEXTURE_2D,white_tex); //no texture @@ -5019,6 +5222,109 @@ void RasterizerGLES2::_render(const Geometry *p_geometry,const Material *p_mater }; } } break; + case Geometry::GEOMETRY_IMMEDIATE: { + + bool restore_tex=false; + const Immediate *im = static_cast( p_geometry ); + if (im->building) { + return; + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + for(const List::Element *E=im->chunks.front();E;E=E->next()) { + + const Immediate::Chunk &c=E->get(); + if (c.vertices.empty()) { + continue; + } + for(int i=0;itarget,t->tex_id); + restore_tex=true; + + + } else if (restore_tex) { + + glActiveTexture(GL_TEXTURE0+tc0_idx); + glBindTexture(GL_TEXTURE_2D,tc0_id_cache); + restore_tex=false; + } + + if (!c.normals.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_NORMAL); + glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, false,sizeof(Vector3),c.normals.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_NORMAL); + } + + if (!c.tangents.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_TANGENT); + glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, false,sizeof(Plane),c.tangents.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_TANGENT); + } + + if (!c.colors.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false,sizeof(Color),c.colors.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_COLOR); + _set_color_attrib(Color(1, 1, 1,1)); + } + + + if (!c.uvs.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false,sizeof(Vector2),c.uvs.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + if (!c.uvs2.empty()) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV2); + glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, false,sizeof(Vector2),c.uvs2.ptr()); + + } else { + + glDisableVertexAttribArray(VS::ARRAY_TEX_UV2); + } + + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false,sizeof(Vector3),c.vertices.ptr()); + glDrawArrays(gl_primitive[c.primitive],0,c.vertices.size()); + + + } + + + if (restore_tex) { + + glActiveTexture(GL_TEXTURE0+tc0_idx); + glBindTexture(GL_TEXTURE_2D,tc0_id_cache); + restore_tex=false; + } + + + } break; case Geometry::GEOMETRY_PARTICLES: { @@ -5275,8 +5581,10 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans if (desired_blend) { glEnable(GL_BLEND); + glColorMask(1,1,1,0); } else { glDisable(GL_BLEND); + glColorMask(1,1,1,1); } prev_blend=desired_blend; @@ -5337,7 +5645,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans if (material!=prev_material || rebind) { - rebind = _setup_material(e->geometry,material,additive); + rebind = _setup_material(e->geometry,material,additive,!p_alpha_pass); DEBUG_TEST_ERROR("Setup material"); _rinfo.mat_change_count++; @@ -5530,9 +5838,12 @@ void RasterizerGLES2::_process_glow_bloom() { _copy_screen_quad(); copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_COPY,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false); + copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false); int passes = current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_PASSES]; Vector2 psize(1.0/framebuffer.blur_size,1.0/framebuffer.blur_size); + float pscale = current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_SCALE]; + float pmag = current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_STRENGTH]; + for(int i=0;ibg_mode==VS::ENV_BG_TEXTURE || current_env->bg_mode==VS::ENV_BG_TEXTURE_RGBE) { @@ -5705,6 +6022,7 @@ void RasterizerGLES2::_draw_tex_bg() { if (current_env->fx_enabled[VS::ENV_FX_HDR]) nrg*=0.25; //go down a quarter for hdr copy_shader.set_uniform(CopyShaderGLES2::ENERGY,nrg); + copy_shader.set_uniform(CopyShaderGLES2::CUSTOM_ALPHA,float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW])); Vector3 vertices[4]={ Vector3(-1,-1,1), @@ -5774,6 +6092,7 @@ void RasterizerGLES2::_draw_tex_bg() { copy_shader.set_conditional(CopyShaderGLES2::USE_ENERGY,false); copy_shader.set_conditional(CopyShaderGLES2::USE_RGBE,false); copy_shader.set_conditional(CopyShaderGLES2::USE_CUBEMAP,false); + copy_shader.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA,false); } void RasterizerGLES2::end_scene() { @@ -5854,7 +6173,7 @@ void RasterizerGLES2::end_scene() { bgcolor = current_env->bg_param[VS::ENV_BG_PARAM_COLOR]; else bgcolor = Globals::get_singleton()->get("render/default_clear_color"); - float a = use_fb ? 0.0 : 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); _glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); @@ -5923,7 +6242,7 @@ void RasterizerGLES2::end_scene() { } alpha_render_list.sort_z(); - _render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,false,true); + _render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); glColorMask(1,1,1,1); // material_shader.set_conditional( MaterialShaderGLES2::USE_FOG,false); @@ -5953,7 +6272,12 @@ void RasterizerGLES2::end_scene() { _process_hdr(); } if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) { - _process_glow_bloom(); + _process_glow_bloom(); + int glow_transfer_mode=current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_BLEND_MODE]; + if (glow_transfer_mode==1) + copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,true); + if (glow_transfer_mode==2) + copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,true); } glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer); @@ -6024,6 +6348,8 @@ void RasterizerGLES2::end_scene() { copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false); copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,false); copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,false); + copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,false); + copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,false); material_shader.set_conditional(MaterialShaderGLES2::USE_HDR,false); @@ -6216,8 +6542,8 @@ void RasterizerGLES2::end_shadow_map() { //glDisable(GL_POLYGON_OFFSET_FILL); - if (!use_rgba_shadowmaps) - glColorMask(1, 1, 1, 1); + //if (!use_rgba_shadowmaps) + glColorMask(1, 1, 1, 1); DEBUG_TEST_ERROR("Drawing Shadow"); shadow=NULL; @@ -6950,6 +7276,10 @@ bool RasterizerGLES2::is_mesh(const RID& p_rid) const { return mesh_owner.owns(p_rid); } +bool RasterizerGLES2::is_immediate(const RID& p_rid) const { + + return immediate_owner.owns(p_rid); +} bool RasterizerGLES2::is_multimesh(const RID& p_rid) const { return multimesh_owner.owns(p_rid); @@ -7074,6 +7404,13 @@ void RasterizerGLES2::free(const RID& p_rid) { multimesh_owner.free(p_rid); memdelete(multimesh); + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + ERR_FAIL_COND(!immediate); + + immediate_owner.free(p_rid); + memdelete(immediate); } else if (particles_owner.owns(p_rid)) { Particles *particles = particles_owner.get(p_rid); @@ -8121,6 +8458,8 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo draw_next_frame=false; use_framebuffers=true; framebuffer.active=false; + tc0_id_cache=0; + tc0_idx=0; }; RasterizerGLES2::~RasterizerGLES2() { diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 673297dd5127..0fee8bf91830 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -173,8 +173,11 @@ class RasterizerGLES2 : public Rasterizer { bool can_zpass; bool has_texscreen; bool has_screen_uv; + bool writes_vertex; + bool uses_discard; Map uniforms; + StringName first_texture; SelfList dirty_list; @@ -190,6 +193,8 @@ class RasterizerGLES2 : public Rasterizer { can_zpass=true; has_texscreen=false; has_screen_uv=false; + writes_vertex=false; + uses_discard=false; } @@ -235,6 +240,7 @@ class RasterizerGLES2 : public Rasterizer { flags[VS::MATERIAL_FLAG_VISIBLE]=true; for(int i=0;i multimesh_owner; mutable SelfList::List _multimesh_dirty_list; + struct Immediate : public Geometry { + + struct Chunk { + + RID texture; + VS::PrimitiveType primitive; + Vector vertices; + Vector normals; + Vector tangents; + Vector colors; + Vector uvs; + Vector uvs2; + }; + + List chunks; + bool building; + int mask; + AABB aabb; + + Immediate() { type=GEOMETRY_IMMEDIATE; building=false;} + + }; + + mutable RID_Owner immediate_owner; + struct Particles : public Geometry { ParticleSystemSW data; // software particle system @@ -585,11 +616,15 @@ class RasterizerGLES2 : public Rasterizer { bg_param[VS::ENV_BG_PARAM_CUBEMAP]=RID(); bg_param[VS::ENV_BG_PARAM_ENERGY]=1.0; bg_param[VS::ENV_BG_PARAM_SCALE]=1.0; + bg_param[VS::ENV_BG_PARAM_GLOW]=0.0; for(int i=0;iname==vname_vertex && p_assign_left) { + vertex_code_writes_vertex=true; + } + } if (type==ShaderLanguage::SHADER_MATERIAL_FRAGMENT) { if (vnode->name==vname_discard) { @@ -644,5 +650,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { vname_binormal_interp="BINORMAL"; vname_var1_interp="VAR1"; vname_var2_interp="VAR2"; + vname_vertex="VERTEX"; } diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 2f4aa7647ee6..d683f5b4f301 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -61,6 +61,7 @@ private: StringName vname_binormal_interp; StringName vname_var1_interp; StringName vname_var2_interp; + StringName vname_vertex; Map *uniforms; diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index d665fddd2c00..bcd3e6ad4b91 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -315,6 +315,7 @@ ShaderGLES2::Version* ShaderGLES2::get_current_version() { for(int i=0;icustom_defines.size();i++) { strings.push_back(cc->custom_defines[i]); + DEBUG_PRINT("CD #"+itos(i)+": "+String(cc->custom_defines[i])); } } @@ -349,9 +350,11 @@ ShaderGLES2::Version* ShaderGLES2::get_current_version() { strings.push_back(vertex_code2.get_data()); #ifdef DEBUG_SHADER + + DEBUG_PRINT("\nVertex Code:\n\n"+String(code_string.get_data())); for(int i=0;i 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); + color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); + color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); + } + +#endif + +#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) color.rgb+=glow.rgb; #endif @@ -316,6 +335,9 @@ void main() { color.a=1.0; #endif +#ifdef USE_CUSTOM_ALPHA + color.a=custom_alpha; +#endif gl_FragColor = color; } diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl index 1794f18801d0..a919e3b1e29a 100644 --- a/drivers/gles2/shaders/material.glsl +++ b/drivers/gles2/shaders/material.glsl @@ -386,6 +386,7 @@ VERTEX_SHADER_CODE specular_interp=vec3(0.0); } } + #else #ifdef SHADELESS @@ -722,21 +723,28 @@ void main() { -#ifdef FRAGMENT_SHADER_CODE_USE_DISCARD - float discard_=0.0; +#if defined(ENABLE_DISCARD) + bool discard_=false; #endif FRAGMENT_SHADER_CODE -#ifdef FRAGMENT_SHADER_CODE_USE_DISCARD - if (discard_>0.0) { +#if defined(ENABLE_DISCARD) + if (discard_) { //easy to eliminate dead code discard; } #endif +#ifdef ENABLE_CLIP_ALPHA + if (diffuse.a<0.99) { + //used for doublepass and shadowmapping + discard; + } +#endif + float shadow_attenuation = 1.0; @@ -902,7 +910,10 @@ FRAGMENT_SHADER_CODE # if !defined(LIGHT_TYPE_DIRECTIONAL) && !defined(LIGHT_TYPE_OMNI) && !defined (LIGHT_TYPE_SPOT) //none +#ifndef SHADELESS diffuse.rgb=vec3(0.0,0.0,0.0); +#endif + # endif diffuse.rgb+=const_light_mult*emission; @@ -959,6 +970,7 @@ FRAGMENT_SHADER_CODE #ifdef USE_HDR diffuse.rgb*=0.25; #endif + gl_FragColor = diffuse; #endif } diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 3b6a62898e32..d1ee7087e7d6 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -189,6 +189,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { int orientation; String release_keystore; + String release_password; String release_username; struct APKExportData { @@ -241,11 +242,11 @@ public: virtual int get_device_count() const; virtual String get_device_name(int p_device) const; virtual String get_device_info(int p_device) const; - virtual Error run(int p_device); + virtual Error run(int p_device,bool p_dumb=false); virtual bool requieres_password(bool p_debug) const { return !p_debug; } virtual String get_binary_extension() const { return "apk"; } - virtual Error export_project(const String& p_path,bool p_debug,const String& p_password=""); + virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false); virtual bool can_export(String *r_error=NULL) const; @@ -285,6 +286,8 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant& release_keystore=p_value; else if (n=="keystore/release_user") release_username=p_value; + else if (n=="keystore/release_password") + release_password=p_value; else if (n=="apk_expansion/enable") apk_expansion=p_value; else if (n=="apk_expansion/SALT") @@ -343,6 +346,8 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret) r_ret=release_keystore; else if (n=="keystore/release_user") r_ret=release_username; + else if (n=="keystore/release_password") + r_ret=release_password; else if (n=="apk_expansion/enable") r_ret=apk_expansion; else if (n=="apk_expansion/SALT") @@ -968,7 +973,7 @@ Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String& -Error EditorExportPlatformAndroid::export_project(const String& p_path,bool p_debug,const String& p_password) { +Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_debug, bool p_dumb) { String src_apk; @@ -1088,34 +1093,51 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path,bool p_de ep.step("Adding Files..",1); - Error err=OK; Vector cl = cmdline.strip_edges().split(" "); - if (apk_expansion) { - String apkfname="main."+itos(version_code)+"."+package+".obb"; - String fullpath=p_path.get_base_dir().plus_file(apkfname); - FileAccess *pf = FileAccess::open(fullpath,FileAccess::WRITE); - if (!pf) { - EditorNode::add_io_error("Could not write expansion package file: "+apkfname); - return OK; + if (p_dumb) { + + String host = EditorSettings::get_singleton()->get("file_server/host"); + int port = EditorSettings::get_singleton()->get("file_server/post"); + String passwd = EditorSettings::get_singleton()->get("file_server/password"); + cl.push_back("-rfs"); + cl.push_back(host+":"+itos(port)); + if (passwd!="") { + cl.push_back("-rfs_pass"); + cl.push_back(passwd); } - err = save_pack(pf); - memdelete(pf); - cl.push_back("-main_pack"); - cl.push_back(apkfname); - cl.push_back("-main_pack_md5"); - cl.push_back(FileAccess::get_md5(fullpath)); - cl.push_back("-main_pack_cfg"); - cl.push_back(apk_expansion_salt+","+apk_expansion_pkey); + } else { + //all files - APKExportData ed; - ed.ep=&ep; - ed.apk=apk; + if (apk_expansion) { - err = export_project_files(save_apk_file,&ed,false); + String apkfname="main."+itos(version_code)+"."+package+".obb"; + String fullpath=p_path.get_base_dir().plus_file(apkfname); + FileAccess *pf = FileAccess::open(fullpath,FileAccess::WRITE); + if (!pf) { + EditorNode::add_io_error("Could not write expansion package file: "+apkfname); + return OK; + } + err = save_pack(pf); + memdelete(pf); + cl.push_back("-main_pack"); + cl.push_back(apkfname); + cl.push_back("-main_pack_md5"); + cl.push_back(FileAccess::get_md5(fullpath)); + cl.push_back("-main_pack_cfg"); + cl.push_back(apk_expansion_salt+","+apk_expansion_pkey); + + } else { + + APKExportData ed; + ed.ep=&ep; + ed.apk=apk; + + err = export_project_files(save_apk_file,&ed,false); + } } if (cl.size()) { @@ -1179,7 +1201,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path,bool p_de } else { keystore=release_keystore; - password=p_password; + password=release_password; user=release_username; ep.step("Signing Release APK..",103); @@ -1388,7 +1410,7 @@ void EditorExportPlatformAndroid::_device_poll_thread(void *ud) { } -Error EditorExportPlatformAndroid::run(int p_device) { +Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) { ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER); device_lock->lock(); @@ -1407,7 +1429,7 @@ Error EditorExportPlatformAndroid::run(int p_device) { ep.step("Exporting APK",0); String export_to=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport.apk"; - Error err = export_project(export_to,true); + Error err = export_project(export_to,true,p_dumb); if (err) { device_lock->unlock(); return err; diff --git a/platform/android/java_bind.cpp b/platform/android/java_bind.cpp new file mode 100644 index 000000000000..33ecfcffb699 --- /dev/null +++ b/platform/android/java_bind.cpp @@ -0,0 +1,5 @@ +#include "java_bind.h" + +JavaBind::JavaBind() +{ +} diff --git a/platform/android/java_bind.h b/platform/android/java_bind.h new file mode 100644 index 000000000000..ca6b4650d3f1 --- /dev/null +++ b/platform/android/java_bind.h @@ -0,0 +1,10 @@ +#ifndef JAVA_BIND_H +#define JAVA_BIND_H + +class JavaBind +{ +public: + JavaBind(); +}; + +#endif // JAVA_BIND_H diff --git a/platform/bb10/export/export.cpp b/platform/bb10/export/export.cpp index 0a19e71f0859..5edcf393969e 100644 --- a/platform/bb10/export/export.cpp +++ b/platform/bb10/export/export.cpp @@ -67,11 +67,11 @@ public: virtual int get_device_count() const; virtual String get_device_name(int p_device) const; virtual String get_device_info(int p_device) const; - virtual Error run(int p_device); + virtual Error run(int p_device,bool p_dumb=false); virtual bool requieres_password(bool p_debug) const { return !p_debug; } virtual String get_binary_extension() const { return "bar"; } - virtual Error export_project(const String& p_path,bool p_debug,const String& p_password=""); + virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false); virtual bool can_export(String *r_error=NULL) const; @@ -270,7 +270,7 @@ void EditorExportPlatformBB10::_fix_descriptor(Vector& p_descriptor) { -Error EditorExportPlatformBB10::export_project(const String& p_path,bool p_debug,const String& p_password) { +Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debug, bool p_dumb) { EditorProgress ep("export","Exporting for BlackBerry 10",104); @@ -632,7 +632,7 @@ void EditorExportPlatformBB10::_device_poll_thread(void *ud) { } -Error EditorExportPlatformBB10::run(int p_device) { +Error EditorExportPlatformBB10::run(int p_device, bool p_dumb) { ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER); diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index cd2e24216aed..928d12879987 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -77,11 +77,11 @@ public: virtual int get_device_count() const { return show_run?1:0; }; virtual String get_device_name(int p_device) const { return "Run in Browser"; } virtual String get_device_info(int p_device) const { return "Run exported HTML in the system's default browser."; } - virtual Error run(int p_device); + virtual Error run(int p_device,bool p_dumb=false); virtual bool requieres_password(bool p_debug) const { return false; } virtual String get_binary_extension() const { return "html"; } - virtual Error export_project(const String& p_path,bool p_debug,const String& p_password=""); + virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false); virtual bool can_export(String *r_error=NULL) const; @@ -194,7 +194,7 @@ struct JSExportData { -Error EditorExportPlatformJavaScript::export_project(const String& p_path,bool p_debug,const String& p_password) { +Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool p_debug, bool p_dumb) { String src_template; @@ -299,7 +299,7 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path,bool p } -Error EditorExportPlatformJavaScript::run(int p_device) { +Error EditorExportPlatformJavaScript::run(int p_device, bool p_dumb) { String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmp_export.html"; Error err = export_project(path,true,""); diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index f55e90179462..087a648700d3 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -57,11 +57,11 @@ public: virtual int get_device_count() const { return 0; }; virtual String get_device_name(int p_device) const { return String(); } virtual String get_device_info(int p_device) const { return String(); } - virtual Error run(int p_device); + virtual Error run(int p_device,bool p_dumb=false); virtual bool requieres_password(bool p_debug) const { return false; } virtual String get_binary_extension() const { return "zip"; } - virtual Error export_project(const String& p_path,bool p_debug,const String& p_password=""); + virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false); virtual bool can_export(String *r_error=NULL) const; @@ -245,7 +245,7 @@ void EditorExportPlatformOSX::_fix_plist(Vector& plist,const String& p_ } } -Error EditorExportPlatformOSX::export_project(const String& p_path,bool p_debug,const String& p_password) { +Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, bool p_dumb) { String src_pkg; @@ -437,7 +437,7 @@ Error EditorExportPlatformOSX::export_project(const String& p_path,bool p_debug, } -Error EditorExportPlatformOSX::run(int p_device) { +Error EditorExportPlatformOSX::run(int p_device, bool p_dumb) { return OK; } diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp new file mode 100644 index 000000000000..1459f2c36275 --- /dev/null +++ b/scene/3d/immediate_geometry.cpp @@ -0,0 +1,102 @@ +#include "immediate_geometry.h" + + +void ImmediateGeometry::begin(Mesh::PrimitiveType p_primitive,const Ref& p_texture) { + + VS::get_singleton()->immediate_begin(im,(VS::PrimitiveType)p_primitive,p_texture.is_valid()?p_texture->get_rid():RID()); + if (p_texture.is_valid()) + cached_textures.push_back(p_texture); + +} + +void ImmediateGeometry::set_normal(const Vector3& p_normal){ + + VS::get_singleton()->immediate_normal(im,p_normal); +} + +void ImmediateGeometry::set_tangent(const Plane& p_tangent){ + + VS::get_singleton()->immediate_tangent(im,p_tangent); + +} + +void ImmediateGeometry::set_color(const Color& p_color){ + + VS::get_singleton()->immediate_color(im,p_color); + +} + +void ImmediateGeometry::set_uv(const Vector2& p_uv){ + + VS::get_singleton()->immediate_uv(im,p_uv); + +} + +void ImmediateGeometry::set_uv2(const Vector2& p_uv2){ + + VS::get_singleton()->immediate_uv2(im,p_uv2); + +} + +void ImmediateGeometry::add_vertex(const Vector3& p_vertex){ + + VS::get_singleton()->immediate_vertex(im,p_vertex); + if (empty) { + aabb.pos=p_vertex; + aabb.size=Vector3(); + } else { + aabb.expand_to(p_vertex); + } +} + +void ImmediateGeometry::end(){ + + VS::get_singleton()->immediate_end(im); + +} + +void ImmediateGeometry::clear(){ + + VS::get_singleton()->immediate_clear(im); + empty=true; + cached_textures.clear(); + +} + +AABB ImmediateGeometry::get_aabb() const { + + return aabb; +} +DVector ImmediateGeometry::get_faces(uint32_t p_usage_flags) const { + + return DVector(); +} + +void ImmediateGeometry::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("begin","primitive","texture:Texture"),&ImmediateGeometry::begin); + ObjectTypeDB::bind_method(_MD("set_normal","normal"),&ImmediateGeometry::set_normal); + ObjectTypeDB::bind_method(_MD("set_tangent","tangent"),&ImmediateGeometry::set_tangent); + ObjectTypeDB::bind_method(_MD("set_color","color"),&ImmediateGeometry::set_color); + ObjectTypeDB::bind_method(_MD("set_uv","uv"),&ImmediateGeometry::set_uv); + ObjectTypeDB::bind_method(_MD("set_uv2","uv"),&ImmediateGeometry::set_uv2); + ObjectTypeDB::bind_method(_MD("add_vertex","color"),&ImmediateGeometry::add_vertex); + ObjectTypeDB::bind_method(_MD("end"),&ImmediateGeometry::end); + ObjectTypeDB::bind_method(_MD("clear"),&ImmediateGeometry::clear); + +} + +ImmediateGeometry::ImmediateGeometry() { + + im = VisualServer::get_singleton()->immediate_create(); + set_base(im); + empty=true; + +} + + +ImmediateGeometry::~ImmediateGeometry() { + + VisualServer::get_singleton()->free(im); + +} diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h new file mode 100644 index 000000000000..2db81134c6ce --- /dev/null +++ b/scene/3d/immediate_geometry.h @@ -0,0 +1,41 @@ +#ifndef IMMEDIATE_GEOMETRY_H +#define IMMEDIATE_GEOMETRY_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/mesh.h" + +class ImmediateGeometry : public GeometryInstance { + + OBJ_TYPE(ImmediateGeometry,GeometryInstance); + + + RID im; + List > cached_textures; + bool empty; + AABB aabb; +protected: + + static void _bind_methods(); +public: + + + void begin(Mesh::PrimitiveType p_primitive,const Ref& p_texture); + void set_normal(const Vector3& p_normal); + void set_tangent(const Plane& p_tangent); + void set_color(const Color& p_color); + void set_uv(const Vector2& tex_uv); + void set_uv2(const Vector2& tex_uv); + + void add_vertex(const Vector3& p_vertex); + + void end(); + void clear(); + + virtual AABB get_aabb() const; + virtual DVector get_faces(uint32_t p_usage_flags) const; + + ImmediateGeometry(); + ~ImmediateGeometry(); +}; + +#endif // IMMEDIATE_GEOMETRY_H diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp new file mode 100644 index 000000000000..21fdb9abd316 --- /dev/null +++ b/scene/3d/sprite_3d.cpp @@ -0,0 +1,772 @@ +#include "sprite_3d.h" +#include "scene/scene_string_names.h" +#include "core_string_names.h" + + +Color SpriteBase3D::_get_color_accum() { + + if (!color_dirty) + return color_accum; + + if (parent_sprite) + color_accum=parent_sprite->_get_color_accum(); + else + color_accum=Color(1,1,1,1); + + color_accum.r*=modulate.r; + color_accum.g*=modulate.g; + color_accum.b*=modulate.b; + color_accum.a*=modulate.a; + color_dirty=false; + return color_accum; +} + +void SpriteBase3D::_propagate_color_changed() { + + if (color_dirty) + return; + + color_dirty=true; + _queue_update(); + + for (List::Element *E=children.front();E;E=E->next()) { + + E->get()->_propagate_color_changed(); + } +} + +void SpriteBase3D::_notification(int p_what) { + + if (p_what==NOTIFICATION_ENTER_SCENE) { + + if (!pending_update) + _im_update(); + + Node *parent=get_parent(); + if (parent) { + + parent_sprite=parent->cast_to(); + if (parent_sprite) { + pI=parent_sprite->children.push_back(this); + } + } + } + + if (p_what==NOTIFICATION_EXIT_SCENE) { + + + if (parent_sprite) { + + parent_sprite->children.erase(pI); + pI=NULL; + parent_sprite=NULL; + } + } + +} + + +void SpriteBase3D::set_centered(bool p_center) { + + centered=p_center; + _queue_update(); + +} + +bool SpriteBase3D::is_centered() const { + + return centered; +} + +void SpriteBase3D::set_offset(const Point2& p_offset) { + + offset=p_offset; + _queue_update(); + +} +Point2 SpriteBase3D::get_offset() const { + + return offset; +} + +void SpriteBase3D::set_flip_h(bool p_flip) { + + hflip=p_flip; + _queue_update(); +} +bool SpriteBase3D::is_flipped_h() const { + + return hflip; +} + +void SpriteBase3D::set_flip_v(bool p_flip) { + + vflip=p_flip; + _queue_update(); +} +bool SpriteBase3D::is_flipped_v() const { + + return vflip; +} + + + +void SpriteBase3D::set_modulate(const Color& p_color) { + + modulate=p_color; + _propagate_color_changed(); + _queue_update(); +} + +Color SpriteBase3D::get_modulate() const{ + + return modulate; +} + + +void SpriteBase3D::set_pixel_size(float p_amount) { + + pixel_size=p_amount; + _queue_update(); +} +float SpriteBase3D::get_pixel_size() const { + + return pixel_size; +} + +void SpriteBase3D::set_opacity(float p_amount) { + + opacity=p_amount; + _queue_update(); +} +float SpriteBase3D::get_opacity() const { + + return opacity; +} + + +void SpriteBase3D::set_axis(Vector3::Axis p_axis) { + + axis=p_axis; + _queue_update(); +} +Vector3::Axis SpriteBase3D::get_axis() const { + + return axis; +} + + + +void SpriteBase3D::_im_update() { + + + _draw(); + + + pending_update=false; + + //texture->draw_rect_region(ci,dst_rect,src_rect,modulate); + +} + +void SpriteBase3D::_queue_update(){ + + if (pending_update) + return; + + pending_update=true; + call_deferred(SceneStringNames::get_singleton()->_im_update); +} + + +AABB SpriteBase3D::get_aabb() const { + + return aabb; +} +DVector SpriteBase3D::get_faces(uint32_t p_usage_flags) const { + + return DVector(); + +} + +void SpriteBase3D::set_draw_flag(DrawFlags p_flag,bool p_enable) { + + ERR_FAIL_INDEX(p_flag,FLAG_MAX); + flags[p_flag]=p_enable; + _queue_update(); +} + +bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const{ + ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false); + return flags[p_flag]; +} + +void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode){ + + ERR_FAIL_INDEX(p_mode,3); + alpha_cut=p_mode; + _queue_update(); + +} + +SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const{ + + return alpha_cut; +} + + +void SpriteBase3D::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_centered","centered"),&SpriteBase3D::set_centered); + ObjectTypeDB::bind_method(_MD("is_centered"),&SpriteBase3D::is_centered); + + ObjectTypeDB::bind_method(_MD("set_offset","offset"),&SpriteBase3D::set_offset); + ObjectTypeDB::bind_method(_MD("get_offset"),&SpriteBase3D::get_offset); + + ObjectTypeDB::bind_method(_MD("set_flip_h","flip_h"),&SpriteBase3D::set_flip_h); + ObjectTypeDB::bind_method(_MD("is_flipped_h"),&SpriteBase3D::is_flipped_h); + + ObjectTypeDB::bind_method(_MD("set_flip_v","flip_v"),&SpriteBase3D::set_flip_v); + ObjectTypeDB::bind_method(_MD("is_flipped_v"),&SpriteBase3D::is_flipped_v); + + + ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&SpriteBase3D::set_modulate); + ObjectTypeDB::bind_method(_MD("get_modulate"),&SpriteBase3D::get_modulate); + + ObjectTypeDB::bind_method(_MD("set_opacity","opacity"),&SpriteBase3D::set_opacity); + ObjectTypeDB::bind_method(_MD("get_opacity"),&SpriteBase3D::get_opacity); + + ObjectTypeDB::bind_method(_MD("set_pixel_size","pixel_size"),&SpriteBase3D::set_pixel_size); + ObjectTypeDB::bind_method(_MD("get_pixel_size"),&SpriteBase3D::get_pixel_size); + + ObjectTypeDB::bind_method(_MD("set_axis","axis"),&SpriteBase3D::set_axis); + ObjectTypeDB::bind_method(_MD("get_axis"),&SpriteBase3D::get_axis); + + ObjectTypeDB::bind_method(_MD("set_draw_flag","flag","enabled"),&SpriteBase3D::set_draw_flag); + ObjectTypeDB::bind_method(_MD("get_draw_flag","flag"),&SpriteBase3D::get_draw_flag); + + ObjectTypeDB::bind_method(_MD("set_alpha_cut_mode","mode"),&SpriteBase3D::set_alpha_cut_mode); + ObjectTypeDB::bind_method(_MD("get_alpha_cut_mode"),&SpriteBase3D::get_alpha_cut_mode); + + ObjectTypeDB::bind_method(_MD("get_item_rect"),&SpriteBase3D::get_item_rect); + + ObjectTypeDB::bind_method(_MD("_queue_update"),&SpriteBase3D::_queue_update); + ObjectTypeDB::bind_method(_MD("_im_update"),&SpriteBase3D::_im_update); + + + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "opacity",PROPERTY_HINT_RANGE,"0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "pixel_size",PROPERTY_HINT_RANGE,"0.0001,128,0.0001"), _SCS("set_pixel_size"),_SCS("get_pixel_size")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "axis",PROPERTY_HINT_ENUM,"X-Axis,Y-Axis,Z-Axis"), _SCS("set_axis"),_SCS("get_axis")); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "flags/transparent"), _SCS("set_draw_flag"),_SCS("get_draw_flag"),FLAG_TRANSPARENT); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "flags/shaded"), _SCS("set_draw_flag"),_SCS("get_draw_flag"),FLAG_SHADED); + ADD_PROPERTY( PropertyInfo( Variant::INT, "flags/alpha_cut",PROPERTY_HINT_ENUM,"Disabled,Discard,Opaque Pre-Pass"), _SCS("set_alpha_cut_mode"),_SCS("get_alpha_cut_mode")); + + + BIND_CONSTANT( FLAG_TRANSPARENT ); + BIND_CONSTANT( FLAG_SHADED ); + BIND_CONSTANT( FLAG_MAX ); + + BIND_CONSTANT( ALPHA_CUT_DISABLED ); + BIND_CONSTANT( ALPHA_CUT_DISCARD ); + BIND_CONSTANT( ALPHA_CUT_OPAQUE_PREPASS ); +} + + + + +SpriteBase3D::SpriteBase3D() { + + color_dirty=true; + centered=true; + hflip=false; + vflip=false; + parent_sprite=NULL; + pI=NULL; + + for(int i=0;i<4;i++) + flags[i]=i==FLAG_TRANSPARENT; + + axis=Vector3::AXIS_Z; + pixel_size=0.01; + modulate=Color(1,1,1,1); + pending_update=false; + opacity=1.0; + immediate = VisualServer::get_singleton()->immediate_create(); + set_base(immediate); +} + + +SpriteBase3D::~SpriteBase3D() { + + VisualServer::get_singleton()->free(immediate); +} + + +/////////////////////////////////////////// + + +void Sprite3D::_draw() { + + RID immediate = get_immediate(); + + VS::get_singleton()->immediate_clear(immediate); + if (!texture.is_valid()) + return; //no texuture no life + Vector2 tsize = texture->get_size(); + if (tsize.x==0 || tsize.y==0) + return; + + Size2i s; + Rect2i src_rect; + + if (region) { + + s=region_rect.size; + src_rect=region_rect; + } else { + s = texture->get_size(); + s=s/Size2i(hframes,vframes); + + src_rect.size=s; + src_rect.pos.x+=(frame%hframes)*s.x; + src_rect.pos.y+=(frame/hframes)*s.y; + + } + + Point2i ofs=get_offset(); + if (is_centered()) + ofs-=s/2; + + Rect2i dst_rect(ofs,s); + + + Rect2 final_rect; + Rect2 final_src_rect; + if (!texture->get_rect_region(dst_rect,src_rect,final_rect,final_src_rect)) + return; + + + if (final_rect.size.x==0 || final_rect.size.y==0) + return; + + Color color=_get_color_accum(); + color.a*=get_opacity(); + + float pixel_size=get_pixel_size(); + + Vector2 vertices[4]={ + + (final_rect.pos+Vector2(0,final_rect.size.y)) * pixel_size, + (final_rect.pos+final_rect.size) * pixel_size, + (final_rect.pos+Vector2(final_rect.size.x,0)) * pixel_size, + final_rect.pos * pixel_size, + + + }; + Vector2 uvs[4]={ + final_src_rect.pos / tsize, + (final_src_rect.pos+Vector2(final_src_rect.size.x,0)) / tsize, + (final_src_rect.pos+final_src_rect.size) / tsize, + (final_src_rect.pos+Vector2(0,final_src_rect.size.y)) / tsize, + }; + + if (is_flipped_h()) { + SWAP(uvs[0],uvs[1]); + SWAP(uvs[2],uvs[3]); + } + if (is_flipped_v()) { + + SWAP(uvs[0],uvs[3]); + SWAP(uvs[1],uvs[2]); + } + + + Vector3 normal; + int axis = get_axis(); + normal[axis]=1.0; + + RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED),get_draw_flag(FLAG_TRANSPARENT),get_alpha_cut_mode()==ALPHA_CUT_DISCARD,get_alpha_cut_mode()==ALPHA_CUT_OPAQUE_PREPASS); + VS::get_singleton()->immediate_set_material(immediate,mat); + + VS::get_singleton()->immediate_begin(immediate,VS::PRIMITIVE_TRIANGLE_FAN,texture->get_rid()); + + int x_axis = ((axis + 1) % 3); + int y_axis = ((axis + 2) % 3); + + AABB aabb; + + for(int i=0;i<4;i++) { + VS::get_singleton()->immediate_normal(immediate,normal); + VS::get_singleton()->immediate_color(immediate,color); + VS::get_singleton()->immediate_uv(immediate,uvs[i]); + + Vector3 vtx; + vtx[x_axis]=vertices[i][x_axis]; + vtx[y_axis]=vertices[i][y_axis]; + VS::get_singleton()->immediate_vertex(immediate,vtx); + if (i==0) { + aabb.pos=vtx; + aabb.size=Vector3(); + } else { + aabb.expand_to(vtx); + } + } + set_aabb(aabb); + VS::get_singleton()->immediate_end(immediate); + + +} + +void Sprite3D::set_texture(const Ref& p_texture) { + + if (p_texture==texture) + return; + if (texture.is_valid()) { + texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_queue_update); + } + texture=p_texture; + if (texture.is_valid()) { + texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites + texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_queue_update); + } + _queue_update(); + +} + +Ref Sprite3D::get_texture() const { + + return texture; +} + +void Sprite3D::set_region(bool p_region) { + + if (p_region==region) + return; + + region=p_region; + _queue_update(); +} + +bool Sprite3D::is_region() const{ + + return region; +} + +void Sprite3D::set_region_rect(const Rect2& p_region_rect) { + + bool changed=region_rect!=p_region_rect; + region_rect=p_region_rect; + if (region && changed) { + _queue_update(); + } +} + +Rect2 Sprite3D::get_region_rect() const { + + return region_rect; +} + +void Sprite3D::set_frame(int p_frame) { + + ERR_FAIL_INDEX(p_frame,vframes*hframes); + + if (frame != p_frame) + + frame=p_frame; +} + +int Sprite3D::get_frame() const { + + return frame; +} + +void Sprite3D::set_vframes(int p_amount) { + + ERR_FAIL_COND(p_amount<1); + vframes=p_amount; + _queue_update(); + _change_notify("frame"); +} +int Sprite3D::get_vframes() const { + + return vframes; +} + +void Sprite3D::set_hframes(int p_amount) { + + ERR_FAIL_COND(p_amount<1); + hframes=p_amount; + _queue_update(); + _change_notify("frame"); +} +int Sprite3D::get_hframes() const { + + return hframes; +} + +Rect2 Sprite3D::get_item_rect() const { + + if (texture.is_null()) + return Rect2(0,0,1,1); + //if (texture.is_null()) + // return CanvasItem::get_item_rect(); + + Size2i s; + + if (region) { + + s=region_rect.size; + } else { + s = texture->get_size(); + s=s/Point2(hframes,vframes); + } + + Point2i ofs=get_offset(); + if (is_centered()) + ofs-=s/2; + + if (s==Size2(0,0)) + s=Size2(1,1); + + return Rect2(ofs,s); +} + +void Sprite3D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_texture","texture:Texture"),&Sprite3D::set_texture); + ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&Sprite3D::get_texture); + + ObjectTypeDB::bind_method(_MD("set_region","enabled"),&Sprite3D::set_region); + ObjectTypeDB::bind_method(_MD("is_region"),&Sprite3D::is_region); + + ObjectTypeDB::bind_method(_MD("set_region_rect","rect"),&Sprite3D::set_region_rect); + ObjectTypeDB::bind_method(_MD("get_region_rect"),&Sprite3D::get_region_rect); + + ObjectTypeDB::bind_method(_MD("set_frame","frame"),&Sprite3D::set_frame); + ObjectTypeDB::bind_method(_MD("get_frame"),&Sprite3D::get_frame); + + ObjectTypeDB::bind_method(_MD("set_vframes","vframes"),&Sprite3D::set_vframes); + ObjectTypeDB::bind_method(_MD("get_vframes"),&Sprite3D::get_vframes); + + ObjectTypeDB::bind_method(_MD("set_hframes","hframes"),&Sprite3D::set_hframes); + ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite3D::get_hframes); + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); + ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); + +} + +Sprite3D::Sprite3D() { + + + region=false; + frame=0; + vframes=1; + hframes=1; + +} + +//////////////////////////////////////// + + +void AnimatedSprite3D::_draw() { + + RID immediate = get_immediate(); + VS::get_singleton()->immediate_clear(immediate); + + if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) { + return; + } + + Ref texture = frames->get_frame(frame); + if (!texture.is_valid()) + return; //no texuture no life + Vector2 tsize = texture->get_size(); + if (tsize.x==0 || tsize.y==0) + return; + + Size2i s=tsize; + Rect2i src_rect; + + src_rect.size=s; + + Point2i ofs=get_offset(); + if (is_centered()) + ofs-=s/2; + + Rect2i dst_rect(ofs,s); + + + Rect2 final_rect; + Rect2 final_src_rect; + if (!texture->get_rect_region(dst_rect,src_rect,final_rect,final_src_rect)) + return; + + + if (final_rect.size.x==0 || final_rect.size.y==0) + return; + + Color color=_get_color_accum(); + color.a*=get_opacity(); + + float pixel_size=get_pixel_size(); + + Vector2 vertices[4]={ + + (final_rect.pos+Vector2(0,final_rect.size.y)) * pixel_size, + (final_rect.pos+final_rect.size) * pixel_size, + (final_rect.pos+Vector2(final_rect.size.x,0)) * pixel_size, + final_rect.pos * pixel_size, + + + }; + Vector2 uvs[4]={ + final_src_rect.pos / tsize, + (final_src_rect.pos+Vector2(final_src_rect.size.x,0)) / tsize, + (final_src_rect.pos+final_src_rect.size) / tsize, + (final_src_rect.pos+Vector2(0,final_src_rect.size.y)) / tsize, + }; + + if (is_flipped_h()) { + SWAP(uvs[0],uvs[1]); + SWAP(uvs[2],uvs[3]); + } + if (is_flipped_v()) { + + SWAP(uvs[0],uvs[3]); + SWAP(uvs[1],uvs[2]); + } + + + Vector3 normal; + int axis = get_axis(); + normal[axis]=1.0; + + RID mat = VS::get_singleton()->material_2d_get(get_draw_flag(FLAG_SHADED),get_draw_flag(FLAG_TRANSPARENT),get_alpha_cut_mode()==ALPHA_CUT_DISCARD,get_alpha_cut_mode()==ALPHA_CUT_OPAQUE_PREPASS); + VS::get_singleton()->immediate_set_material(immediate,mat); + + VS::get_singleton()->immediate_begin(immediate,VS::PRIMITIVE_TRIANGLE_FAN,texture->get_rid()); + + int x_axis = ((axis + 1) % 3); + int y_axis = ((axis + 2) % 3); + + AABB aabb; + + for(int i=0;i<4;i++) { + VS::get_singleton()->immediate_normal(immediate,normal); + VS::get_singleton()->immediate_color(immediate,color); + VS::get_singleton()->immediate_uv(immediate,uvs[i]); + + Vector3 vtx; + vtx[x_axis]=vertices[i][x_axis]; + vtx[y_axis]=vertices[i][y_axis]; + VS::get_singleton()->immediate_vertex(immediate,vtx); + if (i==0) { + aabb.pos=vtx; + aabb.size=Vector3(); + } else { + aabb.expand_to(vtx); + } + } + set_aabb(aabb); + VS::get_singleton()->immediate_end(immediate); + +} + +void AnimatedSprite3D::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_sprite_frames","sprite_frames:SpriteFrames"),&AnimatedSprite3D::set_sprite_frames); + ObjectTypeDB::bind_method(_MD("get_sprite_frames:Texture"),&AnimatedSprite3D::get_sprite_frames); + ObjectTypeDB::bind_method(_MD("set_frame","frame"),&AnimatedSprite3D::set_frame); + ObjectTypeDB::bind_method(_MD("get_frame"),&AnimatedSprite3D::get_frame); + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + +} + + + + +void AnimatedSprite3D::set_sprite_frames(const Ref& p_sprite_frames) { + + + if (frames==p_sprite_frames) + return; + + if (frames.is_valid()) + frames->disconnect("changed",this,"_queue_update"); + frames=p_sprite_frames; + if (frames.is_valid()) + frames->connect("changed",this,"_queue_update"); + + if (!frames.is_valid() || frame >=frames->get_frame_count()) { + frame=0; + + } + _queue_update(); + +} + +Ref AnimatedSprite3D::get_sprite_frames() const{ + + return frames; +} + +void AnimatedSprite3D::set_frame(int p_frame){ + + if (frames.is_null()) + return; + + ERR_FAIL_INDEX(p_frame,frames->get_frame_count()); + + if (frame==p_frame) + return; + + frame=p_frame; + _queue_update(); + +} +int AnimatedSprite3D::get_frame() const{ + + return frame; +} + +Rect2 AnimatedSprite3D::get_item_rect() const { + + if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) { + return Rect2(0,0,1,1); + } + + Ref t = frames->get_frame(frame); + if (t.is_null()) + return Rect2(0,0,1,1); + Size2i s = t->get_size(); + + Point2i ofs=get_offset(); + if (is_centered()) + ofs-=s/2; + + if (s==Size2(0,0)) + s=Size2(1,1); + + return Rect2(ofs,s); +} + + + +AnimatedSprite3D::AnimatedSprite3D() { + + frame=0; +} + diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h new file mode 100644 index 000000000000..1330cd1c3078 --- /dev/null +++ b/scene/3d/sprite_3d.h @@ -0,0 +1,191 @@ +#ifndef SPRITE_3D_H +#define SPRITE_3D_H + +#include "scene/3d/visual_instance.h" +#include "scene/2d/animated_sprite.h" + + +class SpriteBase3D : public VisualInstance { + + OBJ_TYPE(SpriteBase3D,VisualInstance); +public: + + enum DrawFlags { + FLAG_TRANSPARENT, + FLAG_SHADED, + FLAG_MAX + + }; + + enum AlphaCutMode { + ALPHA_CUT_DISABLED, + ALPHA_CUT_DISCARD, + ALPHA_CUT_OPAQUE_PREPASS + }; + +private: + + + bool color_dirty; + Color color_accum; + + SpriteBase3D *parent_sprite; + List children; + List::Element *pI; + + bool centered; + Point2 offset; + + bool hflip; + bool vflip; + + + Color modulate; + float opacity; + + Vector3::Axis axis; + float pixel_size; + AABB aabb; + + RID immediate; + + bool flags[FLAG_MAX]; + AlphaCutMode alpha_cut; + bool pending_update; + void _im_update(); + + + void _propagate_color_changed(); + +protected: + + Color _get_color_accum(); + void _notification(int p_what); + static void _bind_methods(); + virtual void _draw()=0; + _FORCE_INLINE_ void set_aabb(const AABB& p_aabb) { aabb=p_aabb; } + _FORCE_INLINE_ RID& get_immediate() { return immediate; } + void _queue_update(); +public: + + void set_centered(bool p_center); + bool is_centered() const; + + void set_offset(const Point2& p_offset); + Point2 get_offset() const; + + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + + void set_region(bool p_region); + bool is_region() const; + + void set_region_rect(const Rect2& p_region_rect); + Rect2 get_region_rect() const; + + void set_modulate(const Color& p_color); + Color get_modulate() const; + + void set_opacity(float p_amount); + float get_opacity() const; + + void set_pixel_size(float p_amount); + float get_pixel_size() const; + + void set_axis(Vector3::Axis p_amount); + Vector3::Axis get_axis() const; + + void set_draw_flag(DrawFlags p_flag,bool p_enable); + bool get_draw_flag(DrawFlags p_flag) const; + + void set_alpha_cut_mode(AlphaCutMode p_mode); + AlphaCutMode get_alpha_cut_mode() const; + + virtual Rect2 get_item_rect() const=0; + + virtual AABB get_aabb() const; + virtual DVector get_faces(uint32_t p_usage_flags) const; + + SpriteBase3D(); + ~SpriteBase3D(); +}; + + +class Sprite3D : public SpriteBase3D { + + OBJ_TYPE(Sprite3D,SpriteBase3D); + Ref texture; + + + bool region; + Rect2 region_rect; + + int frame; + + int vframes; + int hframes; +protected: + virtual void _draw(); + static void _bind_methods(); +public: + + + + void set_texture(const Ref& p_texture); + Ref get_texture() const; + + void set_region(bool p_region); + bool is_region() const; + + void set_region_rect(const Rect2& p_region_rect); + Rect2 get_region_rect() const; + + void set_frame(int p_frame); + int get_frame() const; + + void set_vframes(int p_amount); + int get_vframes() const; + + void set_hframes(int p_amount); + int get_hframes() const; + + virtual Rect2 get_item_rect() const; + + Sprite3D(); +// ~Sprite3D(); +}; + +class AnimatedSprite3D : public SpriteBase3D { + + OBJ_TYPE(AnimatedSprite3D,SpriteBase3D); + Ref frames; + + + int frame; + +protected: + virtual void _draw(); + static void _bind_methods(); +public: + + + + void set_sprite_frames(const Ref& p_sprite_frames); + Ref get_sprite_frames() const; + + void set_frame(int p_frame); + int get_frame() const; + + + virtual Rect2 get_item_rect() const; + + AnimatedSprite3D(); +// ~AnimatedSprite3D(); +}; + +VARIANT_ENUM_CAST(SpriteBase3D::DrawFlags); +VARIANT_ENUM_CAST(SpriteBase3D::AlphaCutMode); +#endif // SPRITE_3D_H diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index b30ad2d71f85..f3d757b601eb 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -189,6 +189,8 @@ #include "scene/3d/multimesh_instance.h" #include "scene/3d/baked_light.h" #include "scene/3d/ray_cast.h" +#include "scene/3d/immediate_geometry.h" +#include "scene/3d/sprite_3d.h" #include "scene/3d/spatial_sample_player.h" #include "scene/3d/spatial_stream_player.h" #include "scene/3d/proximity_group.h" @@ -372,6 +374,9 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 0c55d22dbeb2..99447c0a0e7b 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -109,9 +109,13 @@ void Environment::_bind_methods() { ADD_PROPERTYI( PropertyInfo(Variant::OBJECT,"background/cubemap",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_CUBEMAP); ADD_PROPERTYI( PropertyInfo(Variant::REAL,"background/energy",PROPERTY_HINT_RANGE,"0,128,0.01"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_ENERGY); ADD_PROPERTYI( PropertyInfo(Variant::REAL,"background/scale",PROPERTY_HINT_RANGE,"0.001,16,0.001"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_SCALE); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"background/glow",PROPERTY_HINT_RANGE,"0.00,8,0.01"),_SCS("set_background_param"),_SCS("get_background_param"), BG_PARAM_GLOW); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"glow/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_GLOW); ADD_PROPERTYI( PropertyInfo(Variant::INT,"glow/blur_passes",PROPERTY_HINT_RANGE,"1,4,1"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLUR_PASSES); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"glow/blur_scale",PROPERTY_HINT_RANGE,"0.01,4,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLUR_SCALE); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"glow/blur_strength",PROPERTY_HINT_RANGE,"0.01,4,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLUR_STRENGTH); + ADD_PROPERTYI( PropertyInfo(Variant::INT,"glow/blur_blend_mode",PROPERTY_HINT_ENUM,"Additive,Screen,SoftLight"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLUR_BLEND_MODE); ADD_PROPERTYI( PropertyInfo(Variant::REAL,"glow/bloom",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLOOM); ADD_PROPERTYI( PropertyInfo(Variant::REAL,"glow/bloom_treshold",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GLOW_BLOOM_TRESHOLD); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"dof_blur/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_DOF_BLUR); @@ -180,6 +184,7 @@ void Environment::_bind_methods() { BIND_CONSTANT( BG_PARAM_TEXTURE ); BIND_CONSTANT( BG_PARAM_CUBEMAP ); BIND_CONSTANT( BG_PARAM_ENERGY ); + BIND_CONSTANT( BG_PARAM_GLOW ); BIND_CONSTANT( BG_PARAM_MAX ); @@ -193,7 +198,14 @@ void Environment::_bind_methods() { BIND_CONSTANT( FX_MAX ); + BIND_CONSTANT( FX_BLUR_BLEND_MODE_ADDITIVE ); + BIND_CONSTANT( FX_BLUR_BLEND_MODE_SCREEN ); + BIND_CONSTANT( FX_BLUR_BLEND_MODE_SOFTLIGHT ); + BIND_CONSTANT( FX_PARAM_GLOW_BLUR_PASSES ); + BIND_CONSTANT( FX_PARAM_GLOW_BLUR_SCALE ); + BIND_CONSTANT( FX_PARAM_GLOW_BLUR_STRENGTH ); + BIND_CONSTANT( FX_PARAM_GLOW_BLUR_BLEND_MODE ); BIND_CONSTANT( FX_PARAM_GLOW_BLOOM); BIND_CONSTANT( FX_PARAM_GLOW_BLOOM_TRESHOLD); BIND_CONSTANT( FX_PARAM_DOF_BLUR_PASSES ); @@ -229,11 +241,14 @@ Environment::Environment() { set_background_param(BG_PARAM_CUBEMAP,Ref()); set_background_param(BG_PARAM_ENERGY,1.0); set_background_param(BG_PARAM_SCALE,1.0); + set_background_param(BG_PARAM_GLOW,0.0); for(int i=0;ifixed_material_set_flag(material,(VS::FixedMaterialFlags)p_flag,p_value); } bool FixedMaterial::get_fixed_flag(FixedFlag p_flag) const { - ERR_FAIL_INDEX_V(p_flag,3,false); + ERR_FAIL_INDEX_V(p_flag,4,false); return fixed_flags[p_flag]; } @@ -419,6 +422,7 @@ void FixedMaterial::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_alpha" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_ALPHA); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_color_array" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_COLOR_ARRAY); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_point_size" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_POINT_SIZE); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/discard_alpha" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_DISCARD_ALPHA); ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/diffuse" ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_DIFFUSE); ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/specular", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPECULAR ); ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/emission", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_EMISSION ); @@ -457,6 +461,7 @@ void FixedMaterial::_bind_methods() { BIND_CONSTANT( FLAG_USE_ALPHA ); BIND_CONSTANT( FLAG_USE_COLOR_ARRAY ); BIND_CONSTANT( FLAG_USE_POINT_SIZE ); + BIND_CONSTANT( FLAG_DISCARD_ALPHA ); } diff --git a/scene/resources/material.h b/scene/resources/material.h index 1f2afb70b9cf..2057b3cac9f9 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -85,6 +85,7 @@ public: HINT_OPAQUE_PRE_PASS=VS::MATERIAL_HINT_OPAQUE_PRE_PASS, HINT_NO_SHADOW=VS::MATERIAL_HINT_NO_SHADOW, HINT_NO_DEPTH_DRAW=VS::MATERIAL_HINT_NO_DEPTH_DRAW, + HINT_NO_DEPTH_DRAW_FOR_ALPHA=VS::MATERIAL_HINT_NO_DEPTH_DRAW_FOR_ALPHA, HINT_MAX=VS::MATERIAL_HINT_MAX }; @@ -159,6 +160,7 @@ public: FLAG_USE_ALPHA=VS::FIXED_MATERIAL_FLAG_USE_ALPHA, FLAG_USE_COLOR_ARRAY=VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY, FLAG_USE_POINT_SIZE=VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE, + FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA }; private: diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 5402a28d9290..5b31ba1f1ba1 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -53,6 +53,13 @@ void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate); } +bool Texture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const { + + r_rect=p_rect; + r_src_rect=p_src_rect; + + return true; +} void Texture::_bind_methods() { @@ -609,6 +616,42 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate); } +bool AtlasTexture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const { + + Rect2 rc=region; + + if (!atlas.is_valid()) + return false; + + Rect2 src=p_src_rect; + src.pos+=(rc.pos-margin.pos); + Rect2 src_c = rc.clip(src); + if (src_c.size==Size2()) + return false; + Vector2 ofs = (src_c.pos-src.pos); + + Vector2 scale = p_rect.size / p_src_rect.size; + if(scale.x < 0) + { + float mx = (margin.size.width - margin.pos.x); + mx -= margin.pos.x; + ofs.x = -(ofs.x + mx); + } + if(scale.y < 0) + { + float my = margin.size.height - margin.pos.y; + my -= margin.pos.y; + ofs.y = -(ofs.y + my); + } + Rect2 dr( p_rect.pos+ofs*scale,src_c.size*scale ); + + + + r_rect=dr; + r_src_rect=src_c; + return true; +} + AtlasTexture::AtlasTexture() { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index b780d70e1a84..86ff246498d1 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -70,6 +70,7 @@ public: virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const; virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const; virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const; + virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const; @@ -191,6 +192,7 @@ public: virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const; virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const; virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const; + virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const; AtlasTexture(); diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 5c54bd74e3cc..a8e4c80f8964 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -137,5 +137,7 @@ SceneStringNames::SceneStringNames() { drop_data = StaticCString::create("drop_data"); can_drop_data = StaticCString::create("can_drop_data"); + _im_update = StaticCString::create("_im_update"); + _queue_update = StaticCString::create("_queue_update"); } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 6a4e58ed5430..2286712250c5 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -145,6 +145,10 @@ public: StringName play_play; + StringName _im_update; + StringName _queue_update; + + }; diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp index 2de49d3d8104..e21848eac275 100644 --- a/servers/visual/rasterizer.cpp +++ b/servers/visual/rasterizer.cpp @@ -157,6 +157,9 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) { if (p_key.use_alpha) { code+="DIFFUSE_ALPHA=diffuse;\n"; + if (p_key.discard_alpha) { + code+="DISCARD=diffuse.a<0.5;\n"; + } } else { code+="DIFFUSE=diffuse.rgb;\n"; } @@ -262,6 +265,7 @@ void Rasterizer::_free_shader(const FixedMaterialShaderKey& p_key) { void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags p_flag, bool p_enabled) { + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); @@ -271,6 +275,7 @@ void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags case VS::FIXED_MATERIAL_FLAG_USE_ALPHA: fm.use_alpha=p_enabled; break; case VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY: fm.use_color_array=p_enabled; break; case VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE: fm.use_pointsize=p_enabled; break; + case VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA: fm.discard_alpha=p_enabled; break; } if (!fm.dirty_list.in_list()) @@ -288,6 +293,7 @@ bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags case VS::FIXED_MATERIAL_FLAG_USE_ALPHA: return fm.use_alpha;; break; case VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY: return fm.use_color_array;; break; case VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE: return fm.use_pointsize;; break; + case VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA: return fm.discard_alpha;; break; } diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 783231d2e504..a3cdff9859f7 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -55,6 +55,7 @@ protected: bool use_alpha:1; bool use_color_array:1; bool use_pointsize:1; + bool discard_alpha:1; bool valid:1; }; @@ -80,6 +81,7 @@ protected: RID self; bool use_alpha; bool use_color_array; + bool discard_alpha; bool use_pointsize; float point_size; Transform uv_xform; @@ -100,6 +102,7 @@ protected: k.use_alpha=use_alpha; k.use_color_array=use_color_array; k.use_pointsize=use_pointsize; + k.discard_alpha=discard_alpha; k.detail_blend=detail_blend; k.valid=true; for(int i=0;imaterial=p_material; + +} + +RID RasterizerDummy::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + +} /* PARTICLES API */ @@ -1627,6 +1695,12 @@ bool RasterizerDummy::is_mesh(const RID& p_rid) const { return mesh_owner.owns(p_rid); } + +bool RasterizerDummy::is_immediate(const RID& p_rid) const { + + return immediate_owner.owns(p_rid); +} + bool RasterizerDummy::is_multimesh(const RID& p_rid) const { return multimesh_owner.owns(p_rid); @@ -1703,6 +1777,12 @@ void RasterizerDummy::free(const RID& p_rid) { multimesh_owner.free(p_rid); memdelete(multimesh); + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + immediate_owner.free(p_rid); + memdelete(immediate); + } else if (particles_owner.owns(p_rid)) { Particles *particles = particles_owner.get(p_rid); diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h index 880e19c9b0aa..b683a25bdcac 100644 --- a/servers/visual/rasterizer_dummy.h +++ b/servers/visual/rasterizer_dummy.h @@ -231,8 +231,18 @@ class RasterizerDummy : public Rasterizer { }; + mutable RID_Owner multimesh_owner; + struct Immediate { + + + RID material; + int empty; + }; + + mutable RID_Owner immediate_owner; + struct Particles : public Geometry { ParticleSystemSW data; // software particle system @@ -490,6 +500,23 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible); virtual int multimesh_get_visible_instances(RID p_multimesh) const; + /* IMMEDIATE API */ + + virtual RID immediate_create(); + virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID()); + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_normal(RID p_immediate,const Vector3& p_normal); + virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent); + virtual void immediate_color(RID p_immediate,const Color& p_color); + virtual void immediate_uv(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_end(RID p_immediate); + virtual void immediate_clear(RID p_immediate); + virtual void immediate_set_material(RID p_immediate,RID p_material); + virtual RID immediate_get_material(RID p_immediate) const; + + virtual AABB immediate_get_aabb(RID p_mesh) const; + /* PARTICLES API */ virtual RID particles_create(); @@ -647,6 +674,7 @@ public: virtual void add_mesh( const RID& p_mesh, const InstanceData *p_data); virtual void add_multimesh( const RID& p_multimesh, const InstanceData *p_data); + virtual void add_immediate( const RID& p_immediate, const InstanceData *p_data) {} virtual void add_particles( const RID& p_particle_instance, const InstanceData *p_data); virtual void end_scene(); @@ -692,6 +720,7 @@ public: virtual bool is_texture(const RID& p_rid) const; virtual bool is_material(const RID& p_rid) const; virtual bool is_mesh(const RID& p_rid) const; + virtual bool is_immediate(const RID& p_rid) const; virtual bool is_multimesh(const RID& p_rid) const; virtual bool is_particles(const RID &p_beam) const; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 3061c2ddffa9..cdc1f678e728 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -1034,7 +1034,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::fragment_builtins_defs[]={ { "SPEC_EXP", TYPE_FLOAT}, { "GLOW", TYPE_FLOAT}, { "SHADE_PARAM", TYPE_FLOAT}, - { "DISCARD", TYPE_FLOAT}, + { "DISCARD", TYPE_BOOL}, { "SCREEN_UV", TYPE_VEC2}, { "POINT_COORD", TYPE_VEC2}, { "INV_CAMERA_MATRIX", TYPE_MAT4}, diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 6b74b34ba17c..bffc1c43fecb 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -519,6 +519,72 @@ int VisualServerRaster::multimesh_get_visible_instances(RID p_multimesh) const { } +/* IMMEDIATE API */ + + +RID VisualServerRaster::immediate_create() { + + return rasterizer->immediate_create(); +} + +void VisualServerRaster::immediate_begin(RID p_immediate,PrimitiveType p_primitive,RID p_texture){ + + rasterizer->immediate_begin(p_immediate,p_primitive,p_texture); +} +void VisualServerRaster::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + rasterizer->immediate_vertex(p_immediate,p_vertex); + +} +void VisualServerRaster::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + rasterizer->immediate_normal(p_immediate,p_normal); + +} +void VisualServerRaster::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + rasterizer->immediate_tangent(p_immediate,p_tangent); + +} +void VisualServerRaster::immediate_color(RID p_immediate,const Color& p_color){ + + rasterizer->immediate_color(p_immediate,p_color); + +} +void VisualServerRaster::immediate_uv(RID p_immediate,const Vector2& p_uv){ + + rasterizer->immediate_uv(p_immediate,p_uv); + +} +void VisualServerRaster::immediate_uv2(RID p_immediate,const Vector2& p_uv2){ + + rasterizer->immediate_uv2(p_immediate,p_uv2); + +} +void VisualServerRaster::immediate_end(RID p_immediate){ + + VS_CHANGED; + _dependency_queue_update(p_immediate,true); + rasterizer->immediate_end(p_immediate); + +} +void VisualServerRaster::immediate_clear(RID p_immediate){ + + VS_CHANGED; + _dependency_queue_update(p_immediate,true); + rasterizer->immediate_clear(p_immediate); + +} + +void VisualServerRaster::immediate_set_material(RID p_immediate,RID p_material) { + + rasterizer->immediate_set_material(p_immediate,p_material); +} + +RID VisualServerRaster::immediate_get_material(RID p_immediate) const { + + return rasterizer->immediate_get_material(p_immediate); +} /* PARTICLES API */ @@ -1705,6 +1771,8 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) { instance->data.morph_values.resize( rasterizer->mesh_get_morph_target_count(p_base)); } else if (rasterizer->is_multimesh(p_base)) { instance->base_type=INSTANCE_MULTIMESH; + } else if (rasterizer->is_immediate(p_base)) { + instance->base_type=INSTANCE_IMMEDIATE; } else if (rasterizer->is_particles(p_base)) { instance->base_type=INSTANCE_PARTICLES; instance->particles_info=memnew( Instance::ParticlesInfo ); @@ -2467,6 +2535,12 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) { new_aabb = rasterizer->multimesh_get_aabb(p_instance->base_rid); + } break; + case VisualServer::INSTANCE_IMMEDIATE: { + + new_aabb = rasterizer->immediate_get_aabb(p_instance->base_rid); + + } break; case VisualServer::INSTANCE_PARTICLES: { @@ -3498,6 +3572,9 @@ void VisualServerRaster::_instance_draw(Instance *p_instance) { case INSTANCE_MULTIMESH: { rasterizer->add_multimesh(p_instance->base_rid, &p_instance->data); } break; + case INSTANCE_IMMEDIATE: { + rasterizer->add_immediate(p_instance->base_rid, &p_instance->data); + } break; case INSTANCE_PARTICLES: { rasterizer->add_particles(p_instance->particles_info->instance, &p_instance->data); } break; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index c281e0b9e626..f6ef4ba6d53f 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -766,6 +766,21 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible); virtual int multimesh_get_visible_instances(RID p_multimesh) const; + /* IMMEDIATE API */ + + virtual RID immediate_create(); + virtual void immediate_begin(RID p_immediate,PrimitiveType p_rimitive,RID p_texture=RID()); + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_normal(RID p_immediate,const Vector3& p_normal); + virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent); + virtual void immediate_color(RID p_immediate,const Color& p_color); + virtual void immediate_uv(RID p_immediate, const Vector2& p_uv); + virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_end(RID p_immediate); + virtual void immediate_clear(RID p_immediate); + virtual void immediate_set_material(RID p_immediate,RID p_material); + virtual RID immediate_get_material(RID p_immediate) const; + /* PARTICLES API */ diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 87e13cb2024e..cfc4bd860541 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -741,6 +741,22 @@ public: FUNC2(multimesh_set_visible_instances,RID,int); FUNC1RC(int,multimesh_get_visible_instances,RID); + /* IMMEDIATE API */ + + + FUNC0R(RID,immediate_create); + FUNC3(immediate_begin,RID,PrimitiveType,RID); + FUNC2(immediate_vertex,RID,const Vector3&); + FUNC2(immediate_normal,RID,const Vector3&); + FUNC2(immediate_tangent,RID,const Plane&); + FUNC2(immediate_color,RID,const Color&); + FUNC2(immediate_uv,RID,const Vector2&); + FUNC2(immediate_uv2,RID,const Vector2&); + FUNC1(immediate_end,RID); + FUNC1(immediate_clear,RID); + FUNC2(immediate_set_material,RID,RID); + FUNC1RC(RID,immediate_get_material,RID); + /* PARTICLES API */ diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index a45e2c8eafff..08cc57e307b4 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -274,6 +274,55 @@ RID VisualServer::make_sphere_mesh(int p_lats,int p_lons,float p_radius) { return mesh; } + +RID VisualServer::material_2d_get(bool p_shaded, bool p_transparent, bool p_cut_alpha, bool p_opaque_prepass) { + + int version=0; + if (p_shaded) + version=1; + if (p_transparent) + version|=2; + if (p_cut_alpha) + version|=4; + if (p_opaque_prepass) + version|=8; + if (material_2d[version].is_valid()) + return material_2d[version]; + + //not valid, make + + material_2d[version]=fixed_material_create(); + fixed_material_set_flag(material_2d[version],FIXED_MATERIAL_FLAG_USE_ALPHA,p_transparent); + fixed_material_set_flag(material_2d[version],FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true); + fixed_material_set_flag(material_2d[version],FIXED_MATERIAL_FLAG_DISCARD_ALPHA,p_cut_alpha); + material_set_flag(material_2d[version],MATERIAL_FLAG_UNSHADED,!p_shaded); + material_set_flag(material_2d[version],MATERIAL_FLAG_DOUBLE_SIDED,true); + material_set_hint(material_2d[version],MATERIAL_HINT_OPAQUE_PRE_PASS,p_opaque_prepass); + fixed_material_set_texture(material_2d[version],FIXED_MATERIAL_PARAM_DIFFUSE,get_white_texture()); + //material cut alpha? + return material_2d[version]; +} + +RID VisualServer::get_white_texture() { + + if (white_texture.is_valid()) + return white_texture; + + DVector wt; + wt.resize(16*3); + { + DVector::Write w =wt.write(); + for(int i=0;i<16*3;i++) + w[i]=255; + } + Image white(4,4,0,Image::FORMAT_RGB,wt); + white_texture=texture_create(); + texture_allocate(white_texture,4,4,Image::FORMAT_RGB); + texture_set_data(white_texture,white); + return white_texture; + +} + void VisualServer::_bind_methods() { diff --git a/servers/visual_server.h b/servers/visual_server.h index e1793a230ef2..e5d1e7570204 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -56,6 +56,8 @@ class VisualServer : public Object { protected: RID _make_test_cube(); RID test_texture; + RID white_texture; + RID material_2d[16]; static VisualServer* (*create_func)(); static void _bind_methods(); @@ -189,6 +191,7 @@ public: MATERIAL_HINT_OPAQUE_PRE_PASS, MATERIAL_HINT_NO_SHADOW, MATERIAL_HINT_NO_DEPTH_DRAW, + MATERIAL_HINT_NO_DEPTH_DRAW_FOR_ALPHA, MATERIAL_HINT_MAX }; @@ -241,6 +244,7 @@ public: FIXED_MATERIAL_FLAG_USE_ALPHA, FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY, FIXED_MATERIAL_FLAG_USE_POINT_SIZE, + FIXED_MATERIAL_FLAG_DISCARD_ALPHA, FIXED_MATERIAL_FLAG_MAX, }; @@ -360,7 +364,22 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible)=0; virtual int multimesh_get_visible_instances(RID p_multimesh) const=0; - + /* IMMEDIATE API */ + + virtual RID immediate_create()=0; + virtual void immediate_begin(RID p_immediate,PrimitiveType p_rimitive,RID p_texture=RID())=0; + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex)=0; + virtual void immediate_normal(RID p_immediate,const Vector3& p_normal)=0; + virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent)=0; + virtual void immediate_color(RID p_immediate,const Color& p_color)=0; + virtual void immediate_uv(RID p_immediate,const Vector2& tex_uv)=0; + virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv)=0; + virtual void immediate_end(RID p_immediate)=0; + virtual void immediate_clear(RID p_immediate)=0; + virtual void immediate_set_material(RID p_immediate,RID p_material)=0; + virtual RID immediate_get_material(RID p_immediate) const=0; + + /* PARTICLES API */ virtual RID particles_create()=0; @@ -556,6 +575,8 @@ public: virtual void portal_set_connect_range(RID p_portal, float p_range) =0; virtual float portal_get_connect_range(RID p_portal) const =0; + + /* CAMERA API */ virtual RID camera_create()=0; @@ -675,6 +696,7 @@ public: ENV_BG_PARAM_CUBEMAP, ENV_BG_PARAM_ENERGY, ENV_BG_PARAM_SCALE, + ENV_BG_PARAM_GLOW, ENV_BG_PARAM_MAX }; @@ -698,8 +720,17 @@ public: virtual void environment_set_enable_fx(RID p_env,EnvironmentFx p_effect,bool p_enabled)=0; virtual bool environment_is_fx_enabled(RID p_env,EnvironmentFx p_mode) const=0; + enum EnvironmentFxBlurBlendMode { + ENV_FX_BLUR_BLEND_MODE_ADDITIVE, + ENV_FX_BLUR_BLEND_MODE_SCREEN, + ENV_FX_BLUR_BLEND_MODE_SOFTLIGHT, + }; + enum EnvironmentFxParam { ENV_FX_PARAM_GLOW_BLUR_PASSES, + ENV_FX_PARAM_GLOW_BLUR_SCALE, + ENV_FX_PARAM_GLOW_BLUR_STRENGTH, + ENV_FX_PARAM_GLOW_BLUR_BLEND_MODE, ENV_FX_PARAM_GLOW_BLOOM, ENV_FX_PARAM_GLOW_BLOOM_TRESHOLD, ENV_FX_PARAM_DOF_BLUR_PASSES, @@ -756,12 +787,13 @@ public: INSTANCE_NONE, INSTANCE_MESH, INSTANCE_MULTIMESH, + INSTANCE_IMMEDIATE, INSTANCE_PARTICLES, INSTANCE_LIGHT, INSTANCE_ROOM, INSTANCE_PORTAL, - INSTANCE_GEOMETRY_MASK=(1<get_popup()->is_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS)); - fileserver_menu->get_popup()->set_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),!ischecked); + bool ischecked = fileserver_menu->get_popup()->is_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS)); + fileserver_menu->get_popup()->set_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),!ischecked); + run_native->set_deploy_dumb(!ischecked); } break; case SETTINGS_UPDATE_ALWAYS: { @@ -3612,7 +3613,7 @@ EditorNode::EditorNode() { p->set_item_tooltip(p->get_item_index(RUN_FILE_SERVER),"Enable/Disable the File Server."); p->add_separator(); p->add_check_item("Deploy Dumb Clients",RUN_DEPLOY_DUMB_CLIENTS); - p->set_item_checked( p->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),true ); + //p->set_item_checked( p->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),true ); p->set_item_tooltip(p->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),"Deploy dumb clients when the File Server is active."); p->connect("item_pressed",this,"_menu_option"); diff --git a/tools/editor/editor_run_native.cpp b/tools/editor/editor_run_native.cpp index a0e04814a553..be1a124fc2dc 100644 --- a/tools/editor/editor_run_native.cpp +++ b/tools/editor/editor_run_native.cpp @@ -101,7 +101,7 @@ void EditorRunNative::_run_native(int p_idx,const String& p_platform) { Ref eep = EditorImportExport::get_singleton()->get_export_platform(p_platform); ERR_FAIL_COND(eep.is_null()); - eep->run(p_idx); + eep->run(p_idx,deploy_dumb); } void EditorRunNative::_bind_methods() { @@ -109,8 +109,20 @@ void EditorRunNative::_bind_methods() { ObjectTypeDB::bind_method("_run_native",&EditorRunNative::_run_native); } +void EditorRunNative::set_deploy_dumb(bool p_enabled) { + + deploy_dumb=p_enabled; +} + +bool EditorRunNative::is_deploy_dumb_enabled() const{ + + return deploy_dumb; +} + + EditorRunNative::EditorRunNative() { set_process(true); first=true; + deploy_dumb=false; } diff --git a/tools/editor/editor_run_native.h b/tools/editor/editor_run_native.h index ca3d41126fa6..f4bda2d07d77 100644 --- a/tools/editor/editor_run_native.h +++ b/tools/editor/editor_run_native.h @@ -38,6 +38,7 @@ class EditorRunNative : public HBoxContainer { Map menus; bool first; + bool deploy_dumb; void _run_native(int p_idx,const String& p_platform); @@ -46,6 +47,9 @@ protected: static void _bind_methods(); void _notification(int p_what); public: + + void set_deploy_dumb(bool p_enabled); + bool is_deploy_dumb_enabled() const; EditorRunNative(); }; diff --git a/tools/editor/fileserver/editor_file_server.cpp b/tools/editor/fileserver/editor_file_server.cpp index f72498f37fb0..f21d9b4ec103 100644 --- a/tools/editor/fileserver/editor_file_server.cpp +++ b/tools/editor/fileserver/editor_file_server.cpp @@ -317,12 +317,33 @@ EditorFileServer::EditorFileServer() { cmd=CMD_NONE; thread=Thread::create(_thread_start,this); + List local_ip; + IP::get_singleton()->get_local_addresses(&local_ip); EDITOR_DEF("file_server/port",6010); + String lip; + String hint; + for(List::Element *E=local_ip.front();E;E=E->next()) { + + String ip = E->get(); + if (ip=="127.0.0.1") + continue; + + if (lip!="") + lip=ip; + if (hint!="") + hint+=","; + hint+=ip; + + } + + EDITOR_DEF("file_server/host",lip); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"file_server/host",PROPERTY_HINT_ENUM,hint)); EDITOR_DEF("file_server/password",""); } EditorFileServer::~EditorFileServer() { + quit=true; Thread::wait_to_finish(thread); memdelete(wait_mutex); diff --git a/tools/editor/icons/icon_animated_sprite_3d.png b/tools/editor/icons/icon_animated_sprite_3d.png new file mode 100644 index 0000000000000000000000000000000000000000..19aa7ea2070e3ad1ec5f9178501205d739c42176 GIT binary patch literal 753 zcmVjA%*nbqw?>j^Iy|w^Epabjo&x&);01*qjWO(z^(oH&@OQ?E6 z&>^d8AOy$c;m^qjCqPRgeI;?cKotyOW%V06or?g3;HuCz-zERDO21eAc9w>ltd**~+W764`z6Ge-a6A`o6 zoXdvJ*4IBGiTtW%m7LVPO@xlu26&}jUmyex?e-N~2d@Hxsz=qEa~l@N znV65N7D5vJsXKSx00u5iO=b74>*D>0ct3(_k5+5e8jZ))>%YkO_+2@0;4Likb^)0z~ojm9^HU32>_@{QAH~G8>x6{w|f`>NW{bT_WA5%npjBJ z*I!{Y>SXeDR)4av01Vpg7BTm71yChNna5aISj|&Y&_?6(9@Xx|f<%!)>Cih^YjiNU zjz;q$0D>_oj7gQg5n-64?zi4>5g$I)z_)%p3SD3@QN zUccuoFIV+b?>+#Fa``m?a1iMJF@|A?;qV-Zc&Jofpjx{PLos%CE}-APnU4|elT~8# zorAzmH7Z$KdrNVAO4;2dNs0iV%wqsbA_Z!-PQ&xw=Zj>1CvcaR7SU*2q63BAWL-r( qs?{Eo@4I`!e>*1k4|)3Mm-`ch`^Y~IuPaml0000export_project(p_path,p_debug,p_password); + Error err = exporter->export_project(p_path,p_debug); if (err!=OK) { error->set_text("Error exporting project!"); error->popup_centered(Size2(300,70));;