diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-06-11 10:41:03 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-06-11 10:41:03 -0300 |
commit | 9b8696d3dd92e2ed6f310ad0f0bf3c2182c9c6ae (patch) | |
tree | b2ed0515196bb774504b54aab0bf242992ac3d9f /tools | |
parent | 6f0b4678e26c04abfc88c0226c803e78a108de98 (diff) |
Light Baker!
-=-=-=-=-=-=
-Support for lightmap baker, have fun figuring out how it works before tutorial is published.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/editor/editor_import_export.cpp | 63 | ||||
-rw-r--r-- | tools/editor/editor_import_export.h | 14 | ||||
-rw-r--r-- | tools/editor/icons/icon_bake.png | bin | 0 -> 419 bytes | |||
-rw-r--r-- | tools/editor/icons/icon_reload.png | bin | 371 -> 567 bytes | |||
-rw-r--r-- | tools/editor/io_plugins/editor_import_collada.cpp | 1 | ||||
-rw-r--r-- | tools/editor/io_plugins/editor_texture_import_plugin.cpp | 16 | ||||
-rw-r--r-- | tools/editor/plugins/baked_light_baker.cpp | 1765 | ||||
-rw-r--r-- | tools/editor/plugins/baked_light_baker.h | 316 | ||||
-rw-r--r-- | tools/editor/plugins/baked_light_editor_plugin.cpp | 1080 | ||||
-rw-r--r-- | tools/editor/plugins/baked_light_editor_plugin.h | 30 | ||||
-rw-r--r-- | tools/editor/project_export.cpp | 70 | ||||
-rw-r--r-- | tools/editor/project_export.h | 9 |
12 files changed, 2381 insertions, 983 deletions
diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp index 9c921df5c6..649db5fc45 100644 --- a/tools/editor/editor_import_export.cpp +++ b/tools/editor/editor_import_export.cpp @@ -704,11 +704,11 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT; flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1533,6 +1533,26 @@ void EditorImportExport::load_config() { } + if (cf->has_section("script")) { + + if (cf->has_section_key("script","action")) { + + String action = cf->get_value("script","action"); + if (action=="compile") + script_action=SCRIPT_ACTION_COMPILE; + else if (action=="encrypt") + script_action=SCRIPT_ACTION_ENCRYPT; + else + script_action=SCRIPT_ACTION_NONE; + + } + + if (cf->has_section_key("script","encrypt_key")) { + + script_key = cf->get_value("script","encrypt_key"); + } + } + } @@ -1634,10 +1654,39 @@ void EditorImportExport::save_config() { cf->set_value("image_group_files","files",igfsave); } + switch(script_action) { + case SCRIPT_ACTION_NONE: cf->set_value("script","action","none"); break; + case SCRIPT_ACTION_COMPILE: cf->set_value("script","action","compile"); break; + case SCRIPT_ACTION_ENCRYPT: cf->set_value("script","action","encrypt"); break; + } + + cf->set_value("script","encrypt_key",script_key); + cf->save("res://export.cfg"); } + +void EditorImportExport::script_set_action(ScriptAction p_action) { + + script_action=p_action; +} + +EditorImportExport::ScriptAction EditorImportExport::script_get_action() const{ + + return script_action; +} + +void EditorImportExport::script_set_encryption_key(const String& p_key){ + + script_key=p_key; +} +String EditorImportExport::script_get_encryption_key() const{ + + return script_key; +} + + void EditorImportExport::_bind_methods() { ObjectTypeDB::bind_method(_MD("image_export_group_create"),&EditorImportExport::image_export_group_create); @@ -1649,6 +1698,11 @@ void EditorImportExport::_bind_methods() { ObjectTypeDB::bind_method(_MD("image_export_group_get_make_atlas"),&EditorImportExport::image_export_group_get_make_atlas); ObjectTypeDB::bind_method(_MD("image_export_group_get_shrink"),&EditorImportExport::image_export_group_get_shrink); ObjectTypeDB::bind_method(_MD("image_add_to_export_group"),&EditorImportExport::image_add_to_export_group); + ObjectTypeDB::bind_method(_MD("script_set_action"),&EditorImportExport::script_set_action); + ObjectTypeDB::bind_method(_MD("script_set_encryption_key"),&EditorImportExport::script_set_encryption_key); + ObjectTypeDB::bind_method(_MD("script_get_action"),&EditorImportExport::script_get_action); + ObjectTypeDB::bind_method(_MD("script_get_encryption_key"),&EditorImportExport::script_get_encryption_key); + } EditorImportExport::EditorImportExport() { @@ -1659,6 +1713,9 @@ EditorImportExport::EditorImportExport() { image_action_compress_quality=0.7; image_formats.insert("png"); image_shrink=1; + + script_action=SCRIPT_ACTION_COMPILE; + } diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h index 0f9068f8b3..8305e3c88c 100644 --- a/tools/editor/editor_import_export.h +++ b/tools/editor/editor_import_export.h @@ -227,6 +227,11 @@ public: IMAGE_ACTION_COMPRESS_RAM, }; + enum ScriptAction { + SCRIPT_ACTION_NONE, + SCRIPT_ACTION_COMPILE, + SCRIPT_ACTION_ENCRYPT + }; protected: @@ -254,6 +259,9 @@ protected: Map<StringName,StringName> image_group_files; Vector<String> diff_packs; + ScriptAction script_action; + String script_key; + static EditorImportExport* singleton; static void _bind_methods(); @@ -316,6 +324,11 @@ public: Set<String>& get_image_formats() { return image_formats; } + void script_set_action(ScriptAction p_action); + ScriptAction script_get_action() const; + + void script_set_encryption_key(const String& p_key); + String script_get_encryption_key() const; void load_config(); void save_config(); @@ -324,5 +337,6 @@ public: }; VARIANT_ENUM_CAST(EditorImportExport::ImageAction); +VARIANT_ENUM_CAST(EditorImportExport::ScriptAction); #endif // EDITOR_IMPORT_EXPORT_H diff --git a/tools/editor/icons/icon_bake.png b/tools/editor/icons/icon_bake.png Binary files differnew file mode 100644 index 0000000000..b1b0f941da --- /dev/null +++ b/tools/editor/icons/icon_bake.png diff --git a/tools/editor/icons/icon_reload.png b/tools/editor/icons/icon_reload.png Binary files differindex a79cd11546..07f53efb56 100644 --- a/tools/editor/icons/icon_reload.png +++ b/tools/editor/icons/icon_reload.png diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index 7e46a02c86..6cd6170bb6 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -290,6 +290,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) { } else { //mesh since nothing else node = memnew( MeshInstance ); + node->cast_to<MeshInstance>()->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT,true); } } break; case Collada::Node::TYPE_SKELETON: { diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 4da712c7b3..5d45594246 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -732,6 +732,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS)) tex_flags|=Texture::FLAG_MIPMAPS; + print_line("path: "+p_path+" flags: "+itos(tex_flags)); int shrink=1; if (from->has_option("shrink")) shrink=from->get_option("shrink"); @@ -1073,11 +1074,11 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=IMAGE_FLAG_REPEAT; flags|=IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1102,11 +1103,11 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=IMAGE_FLAG_REPEAT; flags|=IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -1147,10 +1148,13 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c MD5Update(&ctx,&shrink,1); MD5Final(&ctx); + + uint64_t sd=0; String smd5; String md5 = String::md5(ctx.digest); + print_line(p_path+" MD5: "+md5+" FLAGS: "+itos(flags)); String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/"); diff --git a/tools/editor/plugins/baked_light_baker.cpp b/tools/editor/plugins/baked_light_baker.cpp new file mode 100644 index 0000000000..ae5746321a --- /dev/null +++ b/tools/editor/plugins/baked_light_baker.cpp @@ -0,0 +1,1765 @@ + +#include "baked_light_baker.h" +#include <stdlib.h> +#include <cmath> +#include "io/marshalls.h" +#include "tools/editor/editor_node.h" + + +BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>& p_tex) { + + if (!tex_map.has(p_tex)) { + + Ref<ImageTexture> imgtex=p_tex; + if (imgtex.is_null()) + return NULL; + Image image=imgtex->get_data(); + if (image.empty()) + return NULL; + + if (image.get_format()!=Image::FORMAT_RGBA) { + if (image.get_format()>Image::FORMAT_INDEXED_ALPHA) { + Error err = image.decompress(); + if (err) + return NULL; + } + + if (image.get_format()!=Image::FORMAT_RGBA) + image.convert(Image::FORMAT_RGBA); + } + + DVector<uint8_t> dvt=image.get_data(); + DVector<uint8_t>::Read r=dvt.read(); + MeshTexture mt; + mt.tex_w=image.get_width(); + mt.tex_h=image.get_height(); + int len = image.get_width()*image.get_height()*4; + mt.tex.resize(len); + copymem(mt.tex.ptr(),r.ptr(),len); + + textures.push_back(mt); + tex_map[p_tex]=&textures.back()->get(); + } + + return tex_map[p_tex]; +} + + +void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform) { + + + for(int i=0;i<p_mesh->get_surface_count();i++) { + + if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) + continue; + Ref<Material> mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i); + + MeshMaterial *matptr=NULL; + + if (mat.is_valid()) { + + if (!mat_map.has(mat)) { + + MeshMaterial mm; + + Ref<FixedMaterial> fm = mat; + if (fm.is_valid()) { + //fixed route + mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE); + mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE)); + mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR); + mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR)); + } else { + + mm.diffuse.color=Color(1,1,1,1); + mm.diffuse.tex=NULL; + mm.specular.color=Color(0,0,0,1); + mm.specular.tex=NULL; + } + + materials.push_back(mm); + mat_map[mat]=&materials.back()->get(); + + } + + matptr=mat_map[mat]; + + } + + + int facecount=0; + + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { + + facecount=p_mesh->surface_get_array_index_len(i); + } else { + + facecount=p_mesh->surface_get_array_len(i); + } + + ERR_CONTINUE((facecount==0 || (facecount%3)!=0)); + + facecount/=3; + + int tbase=triangles.size(); + triangles.resize(facecount+tbase); + + + Array a = p_mesh->surface_get_arrays(i); + + DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; + DVector<Vector3>::Read vr=vertices.read(); + DVector<Vector2> uv; + DVector<Vector2>::Read uvr; + DVector<Vector3> normal; + DVector<Vector3>::Read normalr; + bool read_uv=false; + bool read_normal=false; + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV) { + + uv=a[Mesh::ARRAY_TEX_UV]; + uvr=uv.read(); + read_uv=true; + } + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) { + + normal=a[Mesh::ARRAY_NORMAL]; + normalr=normal.read(); + read_normal=true; + } + + Matrix3 normal_xform = p_xform.basis.inverse().transposed(); + + + if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { + + DVector<int> indices = a[Mesh::ARRAY_INDEX]; + DVector<int>::Read ir = indices.read(); + + for(int i=0;i<facecount;i++) { + Triangle &t=triangles[tbase+i]; + t.vertices[0]=p_xform.xform(vr[ ir[i*3+0] ]); + t.vertices[1]=p_xform.xform(vr[ ir[i*3+1] ]); + t.vertices[2]=p_xform.xform(vr[ ir[i*3+2] ]); + t.material=matptr; + if (read_uv) { + + t.uvs[0]=uvr[ ir[i*3+0] ]; + t.uvs[1]=uvr[ ir[i*3+1] ]; + t.uvs[2]=uvr[ ir[i*3+2] ]; + } + if (read_normal) { + + t.normals[0]=normal_xform.xform(normalr[ ir[i*3+0] ]).normalized(); + t.normals[1]=normal_xform.xform(normalr[ ir[i*3+1] ]).normalized(); + t.normals[2]=normal_xform.xform(normalr[ ir[i*3+2] ]).normalized(); + } + } + + } else { + + for(int i=0;i<facecount;i++) { + Triangle &t=triangles[tbase+i]; + t.vertices[0]=p_xform.xform(vr[ i*3+0 ]); + t.vertices[1]=p_xform.xform(vr[ i*3+1 ]); + t.vertices[2]=p_xform.xform(vr[ i*3+2 ]); + t.material=matptr; + if (read_uv) { + + t.uvs[0]=uvr[ i*3+0 ]; + t.uvs[1]=uvr[ i*3+1 ]; + t.uvs[2]=uvr[ i*3+2 ]; + } + if (read_normal) { + + t.normals[0]=normal_xform.xform(normalr[ i*3+0 ]).normalized(); + t.normals[1]=normal_xform.xform(normalr[ i*3+1 ]).normalized(); + t.normals[2]=normal_xform.xform(normalr[ i*3+2 ]).normalized(); + } + } + } + } + +} + + +void BakedLightBaker::_parse_geometry(Node* p_node) { + + if (p_node->cast_to<MeshInstance>()) { + + MeshInstance *meshi=p_node->cast_to<MeshInstance>(); + Ref<Mesh> mesh=meshi->get_mesh(); + if (mesh.is_valid()) { + _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform()); + } + } else if (p_node->cast_to<Light>()) { + + Light *dl=p_node->cast_to<Light>(); + + if (dl->get_bake_mode()!=Light::BAKE_MODE_DISABLED) { + + + LightData dirl; + dirl.type=VS::LightType(dl->get_light_type()); + dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE); + dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR); + dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY); + dirl.pos=dl->get_global_transform().origin; + dirl.up=dl->get_global_transform().basis.get_axis(1).normalized(); + dirl.left=dl->get_global_transform().basis.get_axis(0).normalized(); + dirl.dir=-dl->get_global_transform().basis.get_axis(2).normalized(); + dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE); + dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION); + dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION); + dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS); + dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL; + dirl.rays_thrown=0; + lights.push_back(dirl); + } + + } else if (p_node->cast_to<Spatial>()){ + + Spatial *sp = p_node->cast_to<Spatial>(); + + Array arr = p_node->call("_get_baked_light_meshes"); + for(int i=0;i<arr.size();i+=2) { + + Transform xform=arr[i]; + Ref<Mesh> mesh=arr[i+1]; + _add_mesh(mesh,Ref<Material>(),base_inv * (sp->get_global_transform() * xform)); + } + } + + for(int i=0;i<p_node->get_child_count();i++) { + + _parse_geometry(p_node->get_child(i)); + } +} + + +void BakedLightBaker::_fix_lights() { + + + total_light_area=0; + for(int i=0;i<lights.size();i++) { + + LightData &dl=lights[i]; + + switch(dl.type) { + case VS::LIGHT_DIRECTIONAL: { + + float up_max=-1e10; + float dir_max=-1e10; + float left_max=-1e10; + float up_min=1e10; + float dir_min=1e10; + float left_min=1e10; + + for(int j=0;j<triangles.size();j++) { + + for(int k=0;k<3;k++) { + + Vector3 v = triangles[j].vertices[k]; + + float up_d = dl.up.dot(v); + float dir_d = dl.dir.dot(v); + float left_d = dl.left.dot(v); + + if (up_d>up_max) + up_max=up_d; + if (up_d<up_min) + up_min=up_d; + + if (left_d>left_max) + left_max=left_d; + if (left_d<left_min) + left_min=left_d; + + if (dir_d>dir_max) + dir_max=dir_d; + if (dir_d<dir_min) + dir_min=dir_d; + + } + } + + //make a center point, then the upvector and leftvector + dl.pos = dl.left*( left_max+left_min )*0.5 + dl.up*( up_max+up_min )*0.5 + dl.dir*(dir_min-(dir_max-dir_min)); + dl.left*=(left_max-left_min)*0.5; + dl.up*=(up_max-up_min)*0.5; + dl.length = (dir_max - dir_min)*10; //arbitrary number to keep it in scale + dl.area=dl.left.length()*2*dl.up.length()*2; + dl.constant=1.0/dl.area; + } break; + case VS::LIGHT_OMNI: + case VS::LIGHT_SPOT: { + + dl.attenuation_table.resize(ATTENUATION_CURVE_LEN); + for(int j=0;j<ATTENUATION_CURVE_LEN;j++) { + dl.attenuation_table[j]=1.0-Math::pow(j/float(ATTENUATION_CURVE_LEN),dl.attenuation); + float falloff=j*dl.radius/float(ATTENUATION_CURVE_LEN); + if (falloff==0) + falloff=0.000001; + float intensity=4*Math_PI*(falloff*falloff); + //dl.attenuation_table[j]*=falloff*falloff; + dl.attenuation_table[j]*=1.0/(3.0/intensity); + + } + if (dl.type==VS::LIGHT_OMNI) { + + dl.area=4.0*Math_PI*pow(dl.radius,2.0); + dl.constant=1.0/3.5; + } else { + + + float r = Math::tan(Math::deg2rad(dl.spot_angle))*dl.radius; + float c = 1.0-(Math::deg2rad(dl.spot_angle)*0.5+0.5); + dl.constant=1.0/3.5; + dl.constant*=1.0/c; + + dl.area=Math_PI*r*r*c; + } + + } break; + + + } + + total_light_area+=dl.area; + } +} + +BakedLightBaker::BVH* BakedLightBaker::_parse_bvh(BVH** p_children, int p_size, int p_depth, int &max_depth) { + + if (p_depth>max_depth) { + max_depth=p_depth; + } + + if (p_size==1) { + + return p_children[0]; + } else if (p_size==0) { + + return NULL; + } + + + AABB aabb; + aabb=p_children[0]->aabb; + for(int i=1;i<p_size;i++) { + + aabb.merge_with(p_children[i]->aabb); + } + + int li=aabb.get_longest_axis_index(); + + switch(li) { + + case Vector3::AXIS_X: { + SortArray<BVH*,BVHCmpX> sort_x; + sort_x.nth_element(0,p_size,p_size/2,p_children); + //sort_x.sort(&p_bb[p_from],p_size); + } break; + case Vector3::AXIS_Y: { + SortArray<BVH*,BVHCmpY> sort_y; + sort_y.nth_element(0,p_size,p_size/2,p_children); + //sort_y.sort(&p_bb[p_from],p_size); + } break; + case Vector3::AXIS_Z: { + SortArray<BVH*,BVHCmpZ> sort_z; + sort_z.nth_element(0,p_size,p_size/2,p_children); + //sort_z.sort(&p_bb[p_from],p_size); + + } break; + } + + + BVH* left = _parse_bvh(p_children,p_size/2,p_depth+1,max_depth); + BVH* right = _parse_bvh(&p_children[p_size/2],p_size-p_size/2,p_depth+1,max_depth); + + BVH *_new = memnew(BVH); + _new->aabb=aabb; + _new->center=aabb.pos+aabb.size*0.5; + _new->children[0]=left; + _new->children[1]=right; + _new->leaf=NULL; + + return _new; +} + +void BakedLightBaker::_make_bvh() { + + Vector<BVH*> bases; + bases.resize(triangles.size()); + int max_depth=0; + for(int i=0;i<triangles.size();i++) { + bases[i]=memnew( BVH ); + bases[i]->leaf=&triangles[i]; + bases[i]->aabb.pos=triangles[i].vertices[0]; + bases[i]->aabb.expand_to(triangles[i].vertices[1]); + bases[i]->aabb.expand_to(triangles[i].vertices[2]); + triangles[i].aabb=bases[i]->aabb; + bases[i]->center=bases[i]->aabb.pos+bases[i]->aabb.size*0.5; + } + + bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth); + ray_stack = memnew_arr(uint32_t,max_depth); + bvh_stack = memnew_arr(BVH*,max_depth); +} + +void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_depth) { + + + + + uint32_t *stack=octant_stack; + uint32_t *ptr_stack=octantptr_stack; + Octant *octants=octant_pool.ptr(); + + stack[0]=0; + ptr_stack[0]=0; + + int stack_pos=0; + + + while(true) { + + Octant *octant=&octants[ptr_stack[stack_pos]]; + if (stack[stack_pos]<8) { + + int i = stack[stack_pos]; + stack[stack_pos]++; + + + + //fit_aabb=fit_aabb.grow(bvh->aabb.size.x*0.0001); + + int child_idx =octant->children[i]; + bool encloses; + if (!child_idx) { + + AABB aabb=octant->aabb; + aabb.size*=0.5; + if (i&1) + aabb.pos.x+=aabb.size.x; + if (i&2) + aabb.pos.y+=aabb.size.y; + if (i&4) + aabb.pos.z+=aabb.size.z; + + aabb.grow_by(cell_size*octree_extra_margin); + if (!aabb.intersects(p_triangle->aabb)) + continue; + encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb); + if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb)) + continue; + } else { + + Octant *child=&octants[child_idx]; + AABB aabb=child->aabb; + aabb.grow_by(cell_size*octree_extra_margin); + if (!aabb.intersects(p_triangle->aabb)) + continue; + encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb); + if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb)) + continue; + + } + + if (encloses) + stack[stack_pos]=8; // quick and dirty opt + + if (!child_idx) { + + + if (octant_pool_size==octant_pool.size()) { + octant_pool.resize(octant_pool_size+OCTANT_POOL_CHUNK); + octants=octant_pool.ptr(); + octant=&octants[ptr_stack[stack_pos]]; + } + child_idx=octant_pool_size++; + octant->children[i]=child_idx; + Octant *child=&octants[child_idx]; + + child->aabb=octant->aabb; + child->texture_x=0; + child->texture_y=0; + + child->aabb.size*=0.5; + if (i&1) + child->aabb.pos.x+=child->aabb.size.x; + if (i&2) + child->aabb.pos.y+=child->aabb.size.y; + if (i&4) + child->aabb.pos.z+=child->aabb.size.z; + + + + if (stack_pos==octree_depth-1) { + child->leaf=true; + child->offset[0]=child->aabb.pos.x+child->aabb.size.x*0.5; + child->offset[1]=child->aabb.pos.y+child->aabb.size.y*0.5; + child->offset[2]=child->aabb.pos.z+child->aabb.size.z*0.5; + child->next_leaf=leaf_list; + + for(int ci=0;ci<8;ci++) { + child->normal_accum[ci][0]=0; + child->normal_accum[ci][1]=0; + child->normal_accum[ci][2]=0; + } + + child->bake_neighbour=0; + child->first_neighbour=true; + leaf_list=child_idx; + cell_count++; + + int lz = lights.size(); + child->light = memnew_arr(OctantLight,lz); + + for(int li=0;li<lz;li++) { + for(int ci=0;ci<8;ci++) { + child->light[li].accum[ci][0]=0; + child->light[li].accum[ci][1]=0; + child->light[li].accum[ci][2]=0; + } + } + + child->parent=ptr_stack[stack_pos]; + + } else { + + child->leaf=false; + for(int j=0;j<8;j++) { + child->children[j]=0; + } + } + } + + if (!octants[child_idx].leaf) { + stack_pos++; + stack[stack_pos]=0; + ptr_stack[stack_pos]=child_idx; + } else { + + Octant *child=&octants[child_idx]; + + Vector3 n = Plane(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).normal; + + + for(int ci=0;ci<8;ci++) { + + Vector3 pos = child->aabb.pos; + + if (ci&1) + pos.x+=child->aabb.size.x; + if (ci&2) + pos.y+=child->aabb.size.y; + if (ci&4) + pos.z+=child->aabb.size.z; + + + pos.x=floor((pos.x+cell_size*0.5)/cell_size); + pos.y=floor((pos.y+cell_size*0.5)/cell_size); + pos.z=floor((pos.z+cell_size*0.5)/cell_size); + + Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos); + if (!E) { + endpoint_normal[pos]=n; + } else { + E->get()+=n; + } + + } + + } + + + } else { + stack_pos--; + if (stack_pos<0) + break; + } + } + + +} + + +void BakedLightBaker::_make_octree() { + + + AABB base = bvh->aabb; + float lal=base.get_longest_axis_size(); + //must be square because we want square blocks + base.size.x=lal; + base.size.y=lal; + base.size.z=lal; + base.grow_by(lal*0.001); //for precision + octree_aabb=base; + + cell_size=base.size.x; + for(int i=0;i<octree_depth;i++) + cell_size/=2.0; + octant_stack = memnew_arr(uint32_t,octree_depth*2 ); + octantptr_stack = memnew_arr(uint32_t,octree_depth*2 ); + + octant_pool.resize(OCTANT_POOL_CHUNK); + octant_pool_size=1; + Octant *root=octant_pool.ptr(); + root->leaf=false; + root->aabb=octree_aabb; + root->parent=-1; + for(int i=0;i<8;i++) + root->children[i]=0; + + EditorProgress ep("bake_octree","Parsing "+itos(triangles.size())+" Triangles:",triangles.size()); + + for(int i=0;i<triangles.size();i++) { + + _octree_insert(0,&triangles[i],octree_depth-1); + if ((i%1000)==0) { + + ep.step("Triangle# "+itos(i),i); + } + } + + { + uint32_t oct_idx=leaf_list; + Octant *octants=octant_pool.ptr(); + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + for(int ci=0;ci<8;ci++) { + + + Vector3 pos = oct->aabb.pos; + + if (ci&1) + pos.x+=oct->aabb.size.x; + if (ci&2) + pos.y+=oct->aabb.size.y; + if (ci&4) + pos.z+=oct->aabb.size.z; + + + pos.x=floor((pos.x+cell_size*0.5)/cell_size); + pos.y=floor((pos.y+cell_size*0.5)/cell_size); + pos.z=floor((pos.z+cell_size*0.5)/cell_size); + + Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos); + if (!E) { + //? + print_line("lolwut?"); + } else { + Vector3 n = E->get().normalized(); + oct->normal_accum[ci][0]=n.x; + oct->normal_accum[ci][1]=n.y; + oct->normal_accum[ci][2]=n.z; + + } + + } + + oct_idx=oct->next_leaf; + } + } + + +} + + + + + +void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light, const Plane& p_plane) { + + //stackless version + + uint32_t *stack=octant_stack; + uint32_t *ptr_stack=octantptr_stack; + Octant *octants=octant_pool.ptr(); + + stack[0]=0; + ptr_stack[0]=0; + + int stack_pos=0; + + + while(true) { + + Octant &octant=octants[ptr_stack[stack_pos]]; + + if (octant.leaf) { + + + + //if (p_plane.normal.dot(octant.aabb.get_support(p_plane.normal)) < p_plane.d-CMP_EPSILON) { //octants behind are no go + + + + float r=cell_size*plot_size; + for(int i=0;i<8;i++) { + Vector3 pos=octant.aabb.pos; + if (i&1) + pos.x+=octant.aabb.size.x; + if (i&2) + pos.y+=octant.aabb.size.y; + if (i&4) + pos.z+=octant.aabb.size.z; + + + + float d = p_plot_pos.distance_to(pos); + + if (d<=r) { + + + float intensity = 1.0 - (d/r)*(d/r); //not gauss but.. + float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]))); + intensity*=pow(damp,edge_damp); + //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); + octant.light[p_light_index].accum[i][0]+=p_light.r*intensity; + octant.light[p_light_index].accum[i][1]+=p_light.g*intensity; + octant.light[p_light_index].accum[i][2]+=p_light.b*intensity; + } + } + + stack_pos--; + } else if (stack[stack_pos]<8) { + + int i = stack[stack_pos]; + stack[stack_pos]++; + + if (!octant.children[i]) { + continue; + } + + Octant &child=octants[octant.children[i]]; + + if (!child.aabb.intersects(p_plot_aabb)) + continue; + + if (child.aabb.encloses(p_plot_aabb)) { + stack[stack_pos]=8; //don't test the rest + } + + stack_pos++; + stack[stack_pos]=0; + ptr_stack[stack_pos]=octant.children[i]; + } else { + stack_pos--; + if (stack_pos<0) + break; + } + } + + +} + + +float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce) { + + + uint32_t* stack = ray_stack; + BVH **bstack = bvh_stack; + + enum { + TEST_AABB_BIT=0, + VISIT_LEFT_BIT=1, + VISIT_RIGHT_BIT=2, + VISIT_DONE_BIT=3, + + + }; + + Vector3 n = (p_end-p_begin); + float len=n.length(); + if (len==0) + return 0; + n/=len; + + + real_t d=1e10; + bool inters=false; + Vector3 r_normal; + Vector3 r_point; + Vector3 end=p_end; + + Triangle *triangle=NULL; + + //for(int i=0;i<max_depth;i++) + // stack[i]=0; + + int level=0; + //AABB ray_aabb; + //ray_aabb.pos=p_begin; + //ray_aabb.expand_to(p_end); + + + const BVH *bvhptr = bvh; + + bstack[0]=bvh; + stack[0]=TEST_AABB_BIT; + + + while(true) { + + uint32_t mode = stack[level]; + const BVH &b = *bstack[level]; + bool done=false; + + switch(mode) { + case TEST_AABB_BIT: { + + if (b.leaf) { + + + Face3 f3(b.leaf->vertices[0],b.leaf->vertices[1],b.leaf->vertices[2]); + + + Vector3 res; + + if (f3.intersects_segment(p_begin,end,&res)) { + + + float nd = n.dot(res); + if (nd<d) { + + d=nd; + r_point=res; + end=res; + len=(p_begin-end).length(); + r_normal=f3.get_plane().get_normal(); + triangle=b.leaf; + inters=true; + } + + } + + stack[level]=VISIT_DONE_BIT; + } else { + + + bool valid = b.aabb.smits_intersect_ray(p_begin,n,0,len); + //bool valid = b.aabb.intersects_segment(p_begin,p_end); + // bool valid = b.aabb.intersects(ray_aabb); + + if (!valid) { + + stack[level]=VISIT_DONE_BIT; + + } else { + + stack[level]=VISIT_LEFT_BIT; + } + } + + } continue; + case VISIT_LEFT_BIT: { + + stack[level]=VISIT_RIGHT_BIT; + bstack[level+1]=b.children[0]; + stack[level+1]=TEST_AABB_BIT; + level++; + + } continue; + case VISIT_RIGHT_BIT: { + + stack[level]=VISIT_DONE_BIT; + bstack[level+1]=b.children[1]; + stack[level+1]=TEST_AABB_BIT; + level++; + } continue; + case VISIT_DONE_BIT: { + + if (level==0) { + done=true; + break; + } else + level--; + + } continue; + } + + + if (done) + break; + } + + + if (inters) { + + + + //should check if there is normals first + Vector2 uv; + if (true) { + + triangle->get_uv_and_normal(r_point,uv,r_normal); + + } else { + + } + + if (n.dot(r_normal)>0) + r_normal=-r_normal; + + + //ok... + Color diffuse_at_point(0.8,0.8,0.8); + Color specular_at_point(0.0,0.0,0.0); + + if (triangle->material) { + + //triangle->get_uv(r_point); + diffuse_at_point=triangle->material->diffuse.get_color(uv); + specular_at_point=triangle->material->specular.get_color(uv); + } + + float dist = p_begin.distance_to(r_point); + + AABB aabb; + aabb.pos=r_point; + aabb.pos-=Vector3(1,1,1)*cell_size*plot_size; + aabb.size=Vector3(2,2,2)*cell_size*plot_size; + + Color res_light=p_light; + float att=1.0; + float dp=(1.0-normal_damp)*n.dot(-r_normal)+normal_damp; + + if (p_att_curve) { + + p_att_pos+=dist; + int cpos = Math::fast_ftoi((p_att_pos/p_att_curve_len)*ATTENUATION_CURVE_LEN); + cpos=CLAMP(cpos,0,ATTENUATION_CURVE_LEN-1); + att=p_att_curve[cpos]; + } + + + res_light.r*=dp; + res_light.g*=dp; + res_light.b*=dp; + + //light is plotted before multiplication with diffuse, this way + //the multiplication can happen with more detail in the shader + + + float ret=1e6; + + if (p_bounces>0) { + + + p_rest-=dist; + if (p_rest<CMP_EPSILON) + return 0; + + if (r_normal==-n) + return 0; //todo change a little + + r_point+=r_normal*0.01; + + + + + diffuse_at_point.r=res_light.r*diffuse_at_point.r; + diffuse_at_point.g=res_light.g*diffuse_at_point.g; + diffuse_at_point.b=res_light.b*diffuse_at_point.b; + + specular_at_point.r=res_light.r*specular_at_point.r; + specular_at_point.g=res_light.g*specular_at_point.g; + specular_at_point.b=res_light.b*specular_at_point.b; + + + + if (use_diffuse && (diffuse_at_point.r>CMP_EPSILON || diffuse_at_point.g>CMP_EPSILON || diffuse_at_point.b>CMP_EPSILON)) { + //diffuse bounce + + Vector3 c1=r_normal.cross(n).normalized(); + Vector3 c2=r_normal.cross(c1).normalized(); + double r1 = double(rand())/RAND_MAX; + double r2 = double(rand())/RAND_MAX; + double r3 = double(rand())/RAND_MAX; +#if 0 + Vector3 next = - ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*(r3-0.5))).normalized()*0.5 + r_normal*0.5; + + if (next==Vector3()) + next=r_normal; + Vector3 rn=next.normalized(); + +#else + Vector3 rn = ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*r3*0.5)).normalized(); +#endif + + + ret=_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1); + } + + if (use_specular && (specular_at_point.r>CMP_EPSILON || specular_at_point.g>CMP_EPSILON || specular_at_point.b>CMP_EPSILON)) { + //specular bounce + + //Vector3 c1=r_normal.cross(n).normalized(); + //Vector3 c2=r_normal.cross(c1).normalized(); + + Vector3 rn = n - r_normal *r_normal.dot(n) * 2.0; + + _throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1); + } + } + + //specular later +// _plot_light_point(r_point,octree,octree_aabb,p_light); + + + Color plot_light=res_light; + plot_light.r*=att; + plot_light.g*=att; + plot_light.b*=att; + + if (!p_first_bounce) { + + + float r = plot_size * cell_size; + if (ret<r) { + //avoid accumulaiton of light on corners + //plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size); + plot_light=Color(0,0,0,0); + } + } + + + if (!p_first_bounce || lights[p_light_index].bake_direct) { + Plane plane(r_point,r_normal); + //print_line(String(plot_light)+String(" ")+rtos(att)); + _plot_light(p_light_index,r_point,aabb,plot_light,plane); + } + + + return dist; + } + + return 0; + +} + + + + +void BakedLightBaker::_make_octree_texture() { + + + BakedLightBaker::Octant *octants=octant_pool.ptr(); + + //find neighbours first, to have a better idea of what amount of space is needed + { + + Vector<OctantHash> octant_hashing; + octant_hashing.resize(octant_pool_size); + Vector<uint32_t> hash_table; + int hash_table_size=Math::larger_prime(16384); + hash_table.resize(hash_table_size); + uint32_t*hashptr = hash_table.ptr(); + OctantHash*octhashptr = octant_hashing.ptr(); + + for(int i=0;i<hash_table_size;i++) + hashptr[i]=0; + + + //step 1 add to hash table + + uint32_t oct_idx=leaf_list; + + + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + uint64_t base=0; + Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive + base=int((pos.x+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.y+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.z+cell_size*0.5)/cell_size); + + uint32_t hash = HashMapHahserDefault::hash(base); + uint32_t idx = hash % hash_table_size; + octhashptr[oct_idx].next=hashptr[idx]; + octhashptr[oct_idx].hash=hash; + octhashptr[oct_idx].value=base; + hashptr[idx]=oct_idx; + + oct_idx=oct->next_leaf; + + } + + //step 2 find neighbours + oct_idx=leaf_list; + int neighbours=0; + + + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive + pos.x+=cell_size; + uint64_t base=0; + base=int((pos.x+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.y+cell_size*0.5)/cell_size); + base<<=16; + base|=int((pos.z+cell_size*0.5)/cell_size); + + uint32_t hash = HashMapHahserDefault::hash(base); + uint32_t idx = hash % hash_table_size; + + uint32_t bucket = hashptr[idx]; + + while(bucket) { + + if (octhashptr[bucket].value==base) { + + oct->bake_neighbour=bucket; + octants[bucket].first_neighbour=false; + neighbours++; + break; + } + + bucket = octhashptr[bucket].next; + } + + oct_idx=oct->next_leaf; + + } + + print_line("octant with neighbour: "+itos(neighbours)); + + } + + + //ok let's try to just create a texture + + { + + int otex_w=(1<<lattice_size)*(1<<lattice_size)*2; //make sure lattice fits horizontally + Vector3 lattice_cell_size=octree_aabb.size; + for(int i=0;i<lattice_size;i++) { + + lattice_cell_size*=0.5; + } + + + + while(true) { + + //let's plot the leafs first, given the octree is not so obvious which size it will have + int row=4+4*(1<<lattice_size); + + + uint32_t oct_idx=leaf_list; + + //untag + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + //0,0 also means unprocessed + oct->texture_x=0; + oct->texture_y=0; + oct_idx=oct->next_leaf; + + } + + oct_idx=leaf_list; + + + print_line("begin at row "+itos(row)); + int longest_line_reused=0; + int col=0; + int processed=0; + + while(oct_idx) { + + BakedLightBaker::Octant *oct = &octants[oct_idx]; + if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) { + //was not processed + uint32_t current_idx=oct_idx; + int reused=0; + + while(current_idx) { + BakedLightBaker::Octant *o = &octants[current_idx]; + if (col+1 >= otex_w) { + col=0; + row+=4; + } + o->texture_x=col; + o->texture_y=row; + processed++; + + if (o->bake_neighbour) { + reused++; + } + col+=o->bake_neighbour ? 1 : 2; //reuse neighbour + current_idx=o->bake_neighbour; + } + + if (reused>longest_line_reused) { + longest_line_reused=reused; + } + } + oct_idx=oct->next_leaf; + } + + print_line("processed "+itos(processed)); + + print_line("longest reused: "+itos(longest_line_reused)); + + col=0; + row+=4; + print_line("end at row "+itos(row)); + + //put octree, no need for recursion, just loop backwards. + int regular_octants=0; + for(int i=octant_pool_size-1;i>=0;i--) { + + BakedLightBaker::Octant *oct = &octants[i]; + if (oct->leaf) //ignore leaf + continue; + if (oct->aabb.size.x>lattice_cell_size.x*1.1) { //bigger than latice, skip + oct->texture_x=0; + oct->texture_y=0; + } else if (oct->aabb.size.x>lattice_cell_size.x*0.8) { + //this is the initial lattice + Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive + int x = int((pos.x+lattice_cell_size.x*0.5)/lattice_cell_size.x); + int y = int((pos.y+lattice_cell_size.y*0.5)/lattice_cell_size.y); + int z = int((pos.z+lattice_cell_size.z*0.5)/lattice_cell_size.z); + //bug net + ERR_FAIL_INDEX(x,(1<<lattice_size)); + ERR_FAIL_INDEX(y,(1<<lattice_size)); + ERR_FAIL_INDEX(z,(1<<lattice_size)); + + /*int ofs = z*(1<<lattice_size)*(1<<lattice_size)+y*(1<<lattice_size)+x; + ofs*=4; + oct->texture_x=ofs%otex_w; + oct->texture_y=(ofs/otex_w)*4+4; + */ + + oct->texture_x=(x+(1<<lattice_size)*z)*2; + oct->texture_y=4+y*4; + //print_line("pos: "+itos(x)+","+itos(y)+","+itos(z)+" - ofs"+itos(oct->texture_x)+","+itos(oct->texture_y)); + + + } else { + //an everyday regular octant + + if (col+2 > otex_w) { + col=0; + row+=4; + } + + oct->texture_x=col; + oct->texture_y=row; + col+=2; + regular_octants++; + + + } + } + print_line("octants end at row "+itos(row)+" totalling"+itos(regular_octants)); + + //ok evaluation. + + if (otex_w<=2048 && row>2048) { //too big upwards, try bigger texture + otex_w*=2; + continue; + } else { + baked_octree_texture_w=otex_w; + baked_octree_texture_h=row+4; + break; + } + + } + + + } + + + baked_octree_texture_h=nearest_power_of_2(baked_octree_texture_h); + print_line("RESULT! "+itos(baked_octree_texture_w)+","+itos(baked_octree_texture_h)); + +} + + + + + + + + +double BakedLightBaker::get_normalization(int p_light_idx) const { + + double nrg=0; + + const LightData &dl=lights[p_light_idx]; + double cell_area = cell_size*cell_size;; + //nrg+= /*dl.energy */ (dl.rays_thrown * cell_area / dl.area); + nrg=dl.rays_thrown * cell_area; + nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel + nrg*=dl.constant; + //nrg*=5; + print_line("CS: "+rtos(cell_size)); + + return nrg; +} + +void BakedLightBaker::throw_rays(int p_amount) { + + + + for(int i=0;i<lights.size();i++) { + + LightData &dl=lights[i]; + + + int amount = p_amount * total_light_area / dl.area; + + switch(dl.type) { + + case VS::LIGHT_DIRECTIONAL: { + + + for(int j=0;j<amount;j++) { + Vector3 from = dl.pos; + double r1 = double(rand())/RAND_MAX; + double r2 = double(rand())/RAND_MAX; + from+=dl.up*(r1*2.0-1.0); + from+=dl.left*(r2*2.0-1.0); + Vector3 to = from+dl.dir*dl.length; + Color col=dl.diffuse; + col.r*=dl.energy; + col.g*=dl.energy; + col.b*=dl.energy; + dl.rays_thrown++; + total_rays++; + _throw_ray(i,from,to,dl.length,col,NULL,0,0,max_bounces,true); + } + } break; + case VS::LIGHT_OMNI: { + + + for(int j=0;j<amount;j++) { + Vector3 from = dl.pos; + + double r1 = double(rand())/RAND_MAX; + double r2 = double(rand())/RAND_MAX; + double r3 = double(rand())/RAND_MAX; + +#if 0 + //crap is not uniform.. + Vector3 dir = Vector3(r1*2.0-1.0,r2*2.0-1.0,r3*2.0-1.0).normalized(); + +#else + + double phi = r1*Math_PI*2.0; + double costheta = r2*2.0-1.0; + double u = r3; + + double theta = acos( costheta ); + double r = 1.0 * pow( u,1/3.0 ); + + Vector3 dir( + r * sin( theta) * cos( phi ), + r * sin( theta) * sin( phi ), + r * cos( theta ) + ); + dir.normalize(); + +#endif + Vector3 to = dl.pos+dir*dl.radius; + Color col=dl.diffuse; + col.r*=dl.energy; + col.g*=dl.energy; + col.b*=dl.energy; + + dl.rays_thrown++; + total_rays++; + _throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true); +// _throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true); + } + + } break; + case VS::LIGHT_SPOT: { + + for(int j=0;j<amount;j++) { + Vector3 from = dl.pos; + + double r1 = double(rand())/RAND_MAX; + double r2 = double(rand())/RAND_MAX; + double r3 = double(rand())/RAND_MAX; + + float d=Math::tan(Math::deg2rad(dl.spot_angle)); + + float x = sin(r1*Math_PI*2.0)*d; + float y = cos(r1*Math_PI*2.0)*d; + + Vector3 dir = r3*(dl.dir + dl.up*y + dl.left*x) + (1.0-r3)*dl.dir; + dir.normalize(); + + + Vector3 to = dl.pos+dir*dl.radius; + Color col=dl.diffuse; + col.r*=dl.energy; + col.g*=dl.energy; + col.b*=dl.energy; + + dl.rays_thrown++; + total_rays++; + _throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true); + // _throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true); + } + + } break; + + } + } +} + + + + + + + + + + + + + +void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) { + + if (baking) + return; + cell_count=0; + + base_inv=p_node->cast_to<Spatial>()->get_global_transform().affine_inverse(); + EditorProgress ep("bake","Light Baker Setup:",5); + baked_light=p_light; + lattice_size=baked_light->get_initial_lattice_subdiv(); + octree_depth=baked_light->get_cell_subdivision(); + plot_size=baked_light->get_plot_size(); + max_bounces=baked_light->get_bounces(); + use_diffuse=baked_light->get_bake_flag(BakedLight::BAKE_DIFFUSE); + use_specular=baked_light->get_bake_flag(BakedLight::BAKE_SPECULAR); + use_translucency=baked_light->get_bake_flag(BakedLight::BAKE_TRANSLUCENT); + + edge_damp=baked_light->get_edge_damp(); + normal_damp=baked_light->get_normal_damp(); + octree_extra_margin=baked_light->get_cell_extra_margin(); + + + + ep.step("Parsing Geometry",0); + _parse_geometry(p_node); + mat_map.clear(); + tex_map.clear(); + print_line("\ttotal triangles: "+itos(triangles.size())); + ep.step("Fixing Lights",1); + _fix_lights(); + ep.step("Making BVH",2); + _make_bvh(); + ep.step("Creating Light Octree",3); + _make_octree(); + ep.step("Creating Octree Texture",4); + _make_octree_texture(); + baking=true; + _start_thread(); + +} + + +void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) { + + + int len = baked_octree_texture_w*baked_octree_texture_h*4; + p_image.resize(len); + DVector<uint8_t>::Write w = p_image.write(); + zeromem(w.ptr(),len); + float gamma = baked_light->get_gamma_adjust(); + float mult = baked_light->get_energy_multiplier(); + + for(int i=0;i<len;i+=4) { + w[i+0]=0xFF; + w[i+1]=0; + w[i+2]=0xFF; + w[i+3]=0xFF; + } + + encode_uint32(baked_octree_texture_w,&w[0]); + encode_uint32(baked_octree_texture_h,&w[4]); + encode_uint32(0,&w[8]); + encode_float(1<<lattice_size,&w[12]); + encode_uint32(octree_depth-lattice_size,&w[16]); + + encode_float(octree_aabb.pos.x,&w[32]); + encode_float(octree_aabb.pos.y,&w[36]); + encode_float(octree_aabb.pos.z,&w[40]); + encode_float(octree_aabb.size.x,&w[44]); + encode_float(octree_aabb.size.y,&w[48]); + encode_float(octree_aabb.size.z,&w[52]); + + + BakedLightBaker::Octant *octants=octant_pool.ptr(); + int octant_count=octant_pool_size; + uint8_t *ptr = w.ptr(); + + + int child_offsets[8]={ + 0, + 4, + baked_octree_texture_w*4, + baked_octree_texture_w*4+4, + baked_octree_texture_w*8+0, + baked_octree_texture_w*8+4, + baked_octree_texture_w*8+baked_octree_texture_w*4, + baked_octree_texture_w*8+baked_octree_texture_w*4+4, + }; + + Vector<double> norm_arr; + norm_arr.resize(lights.size()); + + for(int i=0;i<lights.size();i++) { + norm_arr[i] = 1.0/get_normalization(i); + } + + const double *normptr=norm_arr.ptr(); + + int lz=lights.size(); + + for(int i=0;i<octant_count;i++) { + + Octant &oct=octants[i]; + if (oct.texture_x==0 && oct.texture_y==0) + continue; + int ofs = (oct.texture_y * baked_octree_texture_w + oct.texture_x)<<2; + + if (oct.leaf) { + + //write colors + for(int j=0;j<8;j++) { + + //if (!oct.children[j]) + // continue; + uint8_t *iptr=&ptr[ofs+child_offsets[j]]; + float r=0; + float g=0; + float b=0; + + for(int k=0;k<lz;k++) { + r+=oct.light[k].accum[j][0]*normptr[k]; + g+=oct.light[k].accum[j][1]*normptr[k]; + b+=oct.light[k].accum[j][2]*normptr[k]; + } + + r=pow(r*mult,gamma); + g=pow(g*mult,gamma); + b=pow(b*mult,gamma); + + float ic[3]={ + r, + g, + b, + }; + iptr[0]=CLAMP(ic[0]*255.0,0,255); + iptr[1]=CLAMP(ic[1]*255.0,0,255); + iptr[2]=CLAMP(ic[2]*255.0,0,255); + iptr[3]=255; + } + + } else { + + + //write indices + for(int j=0;j<8;j++) { + + if (!oct.children[j]) + continue; + Octant&choct=octants[oct.children[j]]; + uint8_t *iptr=&ptr[ofs+child_offsets[j]]; + + iptr[0]=choct.texture_x>>8; + iptr[1]=choct.texture_x&0xFF; + iptr[2]=choct.texture_y>>8; + iptr[3]=choct.texture_y&0xFF; + + } + } + + } + + +} + + +void BakedLightBaker::_free_bvh(BVH* p_bvh) { + + if (!p_bvh->leaf) { + if (p_bvh->children[0]) + _free_bvh(p_bvh->children[0]); + if (p_bvh->children[1]) + _free_bvh(p_bvh->children[1]); + } + + memdelete(p_bvh); + +} + + +bool BakedLightBaker::is_baking() { + + return baking; +} + +void BakedLightBaker::set_pause(bool p_pause){ + + if (paused==p_pause) + return; + + paused=p_pause; + + if (paused) { + _stop_thread(); + } else { + _start_thread(); + } +} +bool BakedLightBaker::is_paused() { + + return paused; + +} + +void BakedLightBaker::_bake_thread_func(void *arg) { + + BakedLightBaker *ble = (BakedLightBaker*)arg; + + ble->rays_at_snap_time=ble->total_rays; + ble->snap_time=OS::get_singleton()->get_ticks_usec(); + + while(!ble->bake_thread_exit) { + + ble->throw_rays(1000); + uint64_t t=OS::get_singleton()->get_ticks_usec(); + if (t-ble->snap_time>1000000) { + + double time = (t-ble->snap_time)/1000000.0; + + int rays=ble->total_rays-ble->rays_at_snap_time; + ble->rays_sec=int(rays/time); + ble->snap_time=OS::get_singleton()->get_ticks_usec(); + ble->rays_at_snap_time=ble->total_rays; + } + } + +} + +void BakedLightBaker::_start_thread() { + + if (thread!=NULL) + return; + bake_thread_exit=false; + thread=Thread::create(_bake_thread_func,this); + +} + +void BakedLightBaker::_stop_thread() { + + if (thread==NULL) + return; + bake_thread_exit=true; + Thread::wait_to_finish(thread); + thread=NULL; +} + +void BakedLightBaker::clear() { + + + + _stop_thread(); + + if (bvh) + _free_bvh(bvh); + + if (ray_stack) + memdelete_arr(ray_stack); + if (octant_stack) + memdelete_arr(octant_stack); + if (octantptr_stack) + memdelete_arr(octantptr_stack); + if (bvh_stack) + memdelete_arr(bvh_stack); + + for(int i=0;i<octant_pool.size();i++) { + if (octant_pool[i].leaf) { + memdelete_arr( octant_pool[i].light ); + } + } + octant_pool.clear(); + octant_pool_size=0; + bvh=NULL; + leaf_list=0; + cell_count=0; + ray_stack=NULL; + octant_stack=NULL; + octantptr_stack=NULL; + bvh_stack=NULL; + materials.clear(); + materials.clear(); + textures.clear(); + lights.clear(); + triangles.clear();; + endpoint_normal.clear(); + baked_octree_texture_w=0; + baked_octree_texture_h=0; + paused=false; + baking=false; + thread=NULL; + bake_thread_exit=false; + baked_light=Ref<BakedLight>(); + total_rays=0; + +} + +BakedLightBaker::BakedLightBaker() { + octree_depth=9; + lattice_size=4; + octant_pool.clear(); + octant_pool_size=0; + bvh=NULL; + leaf_list=0; + cell_count=0; + ray_stack=NULL; + bvh_stack=NULL; + octant_stack=NULL; + octantptr_stack=NULL; + plot_size=2.5; + max_bounces=2; + materials.clear(); + baked_octree_texture_w=0; + baked_octree_texture_h=0; + paused=false; + baking=false; + thread=NULL; + bake_thread_exit=false; + rays_at_snap_time=0; + snap_time=0; + rays_sec=0; + total_rays=0; + +} + +BakedLightBaker::~BakedLightBaker() { + + clear(); +} diff --git a/tools/editor/plugins/baked_light_baker.h b/tools/editor/plugins/baked_light_baker.h new file mode 100644 index 0000000000..99c8211eed --- /dev/null +++ b/tools/editor/plugins/baked_light_baker.h @@ -0,0 +1,316 @@ +#ifndef BAKED_LIGHT_BAKER_H +#define BAKED_LIGHT_BAKER_H + +#include "scene/3d/baked_light_instance.h" +#include "scene/3d/light.h" +#include "scene/3d/mesh_instance.h" +#include "os/thread.h" + +class BakedLightBaker { +public: + + enum { + + ATTENUATION_CURVE_LEN=256, + OCTANT_POOL_CHUNK=1000000 + }; + + struct OctantLight { + + double accum[8][3]; + }; + + struct Octant { + bool leaf; + AABB aabb; + uint16_t texture_x; + uint16_t texture_y; + float normal_accum[8][3]; + int parent; + union { + struct { + int next_leaf; + float offset[3]; + int bake_neighbour; + bool first_neighbour; + OctantLight *light; + }; + int children[8]; + }; + }; + + struct OctantHash { + + int next; + uint32_t hash; + uint64_t value; + + }; + + struct MeshTexture { + + Vector<uint8_t> tex; + int tex_w,tex_h; + + _FORCE_INLINE_ void get_color(const Vector2& p_uv,Color& ret) { + + if (tex_w && tex_h) { + + int x = Math::fast_ftoi(Math::fposmod(p_uv.x,1.0)*tex_w); + int y = Math::fast_ftoi(Math::fposmod(p_uv.y,1.0)*tex_w); + x=CLAMP(x,0,tex_w-1); + y=CLAMP(y,0,tex_h-1); + const uint8_t*ptr = &tex[(y*tex_w+x)*4]; + ret.r*=ptr[0]/255.0; + ret.g*=ptr[1]/255.0; + ret.b*=ptr[2]/255.0; + ret.a*=ptr[3]/255.0; + } + } + + }; + + struct Param { + + Color color; + MeshTexture*tex; + _FORCE_INLINE_ Color get_color(const Vector2& p_uv) { + + Color ret=color; + if (tex) + tex->get_color(p_uv,ret); + return ret; + + } + + }; + + struct MeshMaterial { + + Param diffuse; + Param specular; + Param emission; + }; + + struct Triangle { + + AABB aabb; + Vector3 vertices[3]; + Vector2 uvs[3]; + Vector3 normals[3]; + MeshMaterial *material; + + _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) { + + Vector3 v0 = vertices[1] - vertices[0]; + Vector3 v1 = vertices[2] - vertices[0]; + Vector3 v2 = p_pos - vertices[0]; + + float d00 = v0.dot( v0); + float d01 = v0.dot( v1); + float d11 = v1.dot( v1); + float d20 = v2.dot( v0); + float d21 = v2.dot( v1); + float denom = (d00 * d11 - d01 * d01); + if (denom==0) + return uvs[0]; + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + + return uvs[0]*u + uvs[1]*v + uvs[2]*w; + } + + _FORCE_INLINE_ void get_uv_and_normal(const Vector3& p_pos,Vector2& r_uv,Vector3& r_normal) { + + Vector3 v0 = vertices[1] - vertices[0]; + Vector3 v1 = vertices[2] - vertices[0]; + Vector3 v2 = p_pos - vertices[0]; + + float d00 = v0.dot( v0); + float d01 = v0.dot( v1); + float d11 = v1.dot( v1); + float d20 = v2.dot( v0); + float d21 = v2.dot( v1); + float denom = (d00 * d11 - d01 * d01); + if (denom==0) { + r_normal=normals[0]; + r_uv=uvs[0]; + return; + } + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + + r_uv=uvs[0]*u + uvs[1]*v + uvs[2]*w; + r_normal=(normals[0]*u+normals[1]*v+normals[2]*w).normalized(); + } + }; + + + struct BVH { + + AABB aabb; + Vector3 center; + Triangle *leaf; + BVH*children[2]; + }; + + + struct BVHCmpX { + + bool operator()(const BVH* p_left, const BVH* p_right) const { + + return p_left->center.x < p_right->center.x; + } + }; + + struct BVHCmpY { + + bool operator()(const BVH* p_left, const BVH* p_right) const { + + return p_left->center.y < p_right->center.y; + } + }; + struct BVHCmpZ { + + bool operator()(const BVH* p_left, const BVH* p_right) const { + + return p_left->center.z < p_right->center.z; + } + }; + + + struct LightData { + + VS::LightType type; + + Vector3 pos; + Vector3 up; + Vector3 left; + Vector3 dir; + Color diffuse; + Color specular; + float energy; + float length; + int rays_thrown; + + float radius; + float attenuation; + float spot_angle; + float spot_attenuation; + float area; + + float constant; + + bool bake_direct; + + Vector<float> attenuation_table; + + }; + + + Vector<LightData> lights; + + List<MeshMaterial> materials; + List<MeshTexture> textures; + + AABB octree_aabb; + Vector<Octant> octant_pool; + int octant_pool_size; + BVH*bvh; + Vector<Triangle> triangles; + Transform base_inv; + int leaf_list; + int octree_depth; + int cell_count; + uint32_t *ray_stack; + uint32_t *octant_stack; + uint32_t *octantptr_stack; + Map<Vector3,Vector3> endpoint_normal; + BVH **bvh_stack; + float cell_size; + float plot_size; //multiplied by cell size + float octree_extra_margin; + + int max_bounces; + uint64_t total_rays; + bool use_diffuse; + bool use_specular; + bool use_translucency; + + + int baked_octree_texture_w; + int baked_octree_texture_h; + int lattice_size; + float edge_damp; + float normal_damp; + + bool paused; + bool baking; + + Map<Ref<Material>,MeshMaterial*> mat_map; + Map<Ref<Texture>,MeshTexture*> tex_map; + + + + MeshTexture* _get_mat_tex(const Ref<Texture>& p_tex); + void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform); + void _parse_geometry(Node* p_node); + BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth); + void _make_bvh(); + void _make_octree(); + void _make_octree_texture(); + void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth); + + + void _free_bvh(BVH* p_bvh); + + void _fix_lights(); + + Ref<BakedLight> baked_light; + + + //void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,int p_octant=0); + void _plot_light(int p_light_index,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Plane& p_plane); + //void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light); + + float _throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false); + + + float total_light_area; + uint64_t rays_at_snap_time; + uint64_t snap_time; + int rays_sec; + + + Thread *thread; + bool bake_thread_exit; + static void _bake_thread_func(void *arg); + + void _start_thread(); + void _stop_thread(); +public: + + + void throw_rays(int p_amount); + double get_normalization(int p_light_idx) const; + + void bake(const Ref<BakedLight>& p_light,Node *p_base); + bool is_baking(); + void set_pause(bool p_pause); + bool is_paused(); + int get_rays_sec() { return rays_sec; } + + void update_octree_image(DVector<uint8_t> &p_image); + + Ref<BakedLight> get_baked_light() { return baked_light; } + + void clear(); + + BakedLightBaker(); + ~BakedLightBaker(); + +}; + +#endif // BAKED_LIGHT_BAKER_H diff --git a/tools/editor/plugins/baked_light_editor_plugin.cpp b/tools/editor/plugins/baked_light_editor_plugin.cpp index 77f9d1ed78..4d84b95900 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.cpp +++ b/tools/editor/plugins/baked_light_editor_plugin.cpp @@ -1,831 +1,19 @@ #include "baked_light_editor_plugin.h" #include "scene/gui/box_container.h" #include "scene/3d/mesh_instance.h" -#include "scene/3d/light.h" +#include "io/marshalls.h" +#include "io/resource_saver.h" -class BakedLightBaker { -public: - - enum { - - ATTENUATION_CURVE_LEN=256 - }; - - struct Octant { - bool leaf; - union { - struct { - float light_accum[3]; - float surface_area; - Octant *next_leaf; - float offset[3]; - }; - Octant* children[8]; - }; - }; - - struct Triangle { - - Vector3 vertices[3]; - Vector2 uv[3]; - }; - - - struct BVH { - - AABB aabb; - Vector3 center; - Triangle *leaf; - BVH*children[2]; - }; - - - struct BVHCmpX { - - bool operator()(const BVH* p_left, const BVH* p_right) const { - - return p_left->center.x < p_right->center.x; - } - }; - - struct BVHCmpY { - - bool operator()(const BVH* p_left, const BVH* p_right) const { - - return p_left->center.y < p_right->center.y; - } - }; - struct BVHCmpZ { - - bool operator()(const BVH* p_left, const BVH* p_right) const { - - return p_left->center.z < p_right->center.z; - } - }; - - - struct DirLight { - - - Vector3 pos; - Vector3 up; - Vector3 left; - Vector3 dir; - Color diffuse; - Color specular; - float energy; - float length; - int rays_thrown; - - }; - - AABB octree_aabb; - Octant *octree; - BVH*bvh; - Vector<Triangle> triangles; - Transform base_inv; - Octant *leaf_list; - int octree_depth; - int cell_count; - uint32_t *ray_stack; - BVH **bvh_stack; - float cell_size; - float plot_size; //multiplied by cell size - Vector<DirLight> directional_lights; - int max_bounces; - - - - void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform); - void _parse_geometry(Node* p_node); - BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth); - void _make_bvh(); - void _make_octree(); - void _octree_insert(const AABB& p_aabb,Octant *p_octant,Triangle* p_triangle, int p_depth); - - void _free_octree(Octant *p_octant) { - - if (!p_octant->leaf) { - - for(int i=0;i<8;i++) { - if (p_octant->children[i]) - _free_octree(p_octant->children[i]); - } - } - - memdelete(p_octant); - } - - void _free_bvh(BVH* p_bvh) { - - if (!p_bvh->leaf) { - if (p_bvh->children[0]) - _free_bvh(p_bvh->children[0]); - if (p_bvh->children[1]) - _free_bvh(p_bvh->children[1]); - } - - memdelete(p_bvh); - - } - - void _fix_lights(); - - - void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb, Octant *p_octant, const AABB& p_aabb,const Color& p_light); - void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light); - - void _throw_ray(const Vector3& p_from, const Vector3& p_to,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces); - - - void throw_rays(int p_amount); - float get_normalization() const; - - - void bake(Node *p_base); - - - void clear() { - - if (octree) - _free_octree(octree); - if (bvh) - _free_bvh(bvh); - - if (ray_stack) - memdelete_arr(ray_stack); - if (bvh_stack) - memdelete_arr(bvh_stack); - - octree=NULL; - bvh=NULL; - leaf_list=NULL; - cell_count=0; - ray_stack=NULL; - bvh_stack=NULL; - } - - BakedLightBaker() { - octree_depth=6; - octree=NULL; - bvh=NULL; - leaf_list=NULL; - cell_count=0; - ray_stack=NULL; - bvh_stack=NULL; - plot_size=2; - max_bounces=3; - } - - ~BakedLightBaker() { - - clear(); - } - -}; - - -void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform) { - - - for(int i=0;i<p_mesh->get_surface_count();i++) { - - if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) - continue; - Ref<Material> mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i); - - int facecount=0; - - - if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { - - facecount=p_mesh->surface_get_array_index_len(i); - } else { - - facecount=p_mesh->surface_get_array_len(i); - } - - ERR_CONTINUE((facecount==0 || (facecount%3)!=0)); - - facecount/=3; - - int tbase=triangles.size(); - triangles.resize(facecount+tbase); - - - Array a = p_mesh->surface_get_arrays(i); - - DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; - DVector<Vector3>::Read vr=vertices.read(); - - if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { - - DVector<int> indices = a[Mesh::ARRAY_INDEX]; - DVector<int>::Read ir = indices.read(); - - for(int i=0;i<facecount;i++) { - Triangle &t=triangles[tbase+i]; - t.vertices[0]=p_xform.xform(vr[ ir[i*3+0] ]); - t.vertices[1]=p_xform.xform(vr[ ir[i*3+1] ]); - t.vertices[2]=p_xform.xform(vr[ ir[i*3+2] ]); - } - - } else { - - for(int i=0;i<facecount;i++) { - Triangle &t=triangles[tbase+i]; - t.vertices[0]=p_xform.xform(vr[ i*3+0 ]); - t.vertices[1]=p_xform.xform(vr[ i*3+1 ]); - t.vertices[2]=p_xform.xform(vr[ i*3+2 ]); - } - } - } - -} - - -void BakedLightBaker::_parse_geometry(Node* p_node) { - - if (p_node->cast_to<MeshInstance>()) { - - MeshInstance *meshi=p_node->cast_to<MeshInstance>(); - Ref<Mesh> mesh=meshi->get_mesh(); - if (mesh.is_valid()) { - _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform()); - } - } - - if (p_node->cast_to<DirectionalLight>()) { - - DirectionalLight *dl=p_node->cast_to<DirectionalLight>(); - - DirLight dirl; - dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE); - dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR); - dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY); - dirl.pos=dl->get_global_transform().origin; - dirl.up=dl->get_global_transform().basis.get_axis(1).normalized(); - dirl.left=dl->get_global_transform().basis.get_axis(0).normalized(); - dirl.dir=-dl->get_global_transform().basis.get_axis(2).normalized(); - dirl.rays_thrown=0; - directional_lights.push_back(dirl); - - } - - for(int i=0;i<p_node->get_child_count();i++) { - - _parse_geometry(p_node->get_child(i)); - } -} - - -void BakedLightBaker::_fix_lights() { - - - for(int i=0;i<directional_lights.size();i++) { - - DirLight &dl=directional_lights[i]; - float up_max=-1e10; - float dir_max=-1e10; - float left_max=-1e10; - float up_min=1e10; - float dir_min=1e10; - float left_min=1e10; - - for(int j=0;j<triangles.size();j++) { - - for(int k=0;k<3;k++) { - - Vector3 v = triangles[j].vertices[j]; - - float up_d = dl.up.dot(v); - float dir_d = dl.dir.dot(v); - float left_d = dl.left.dot(v); - - if (up_d>up_max) - up_max=up_d; - if (up_d<up_min) - up_min=up_d; - - if (left_d>left_max) - left_max=left_d; - if (left_d<left_min) - left_min=left_d; - - if (dir_d>dir_max) - dir_max=dir_d; - if (dir_d<dir_min) - dir_min=dir_d; - - } - } - - //make a center point, then the upvector and leftvector - dl.pos = dl.left*( left_max+left_min )*0.5 + dl.up*( up_max+up_min )*0.5 + dl.dir*(dir_min-(dir_max-dir_min)); - dl.left*=(left_max-left_min)*0.5; - dl.up*=(up_max-up_min)*0.5; - dl.length = (dir_max - dir_min)*10; //arbitrary number to keep it in scale - - } -} - -BakedLightBaker::BVH* BakedLightBaker::_parse_bvh(BVH** p_children, int p_size, int p_depth, int &max_depth) { - - if (p_depth>max_depth) { - max_depth=p_depth; - } - - if (p_size==1) { - - return p_children[0]; - } else if (p_size==0) { - - return NULL; - } - - - AABB aabb; - aabb=p_children[0]->aabb; - for(int i=1;i<p_size;i++) { - - aabb.merge_with(p_children[i]->aabb); - } - - int li=aabb.get_longest_axis_index(); - - switch(li) { - - case Vector3::AXIS_X: { - SortArray<BVH*,BVHCmpX> sort_x; - sort_x.nth_element(0,p_size,p_size/2,p_children); - //sort_x.sort(&p_bb[p_from],p_size); - } break; - case Vector3::AXIS_Y: { - SortArray<BVH*,BVHCmpY> sort_y; - sort_y.nth_element(0,p_size,p_size/2,p_children); - //sort_y.sort(&p_bb[p_from],p_size); - } break; - case Vector3::AXIS_Z: { - SortArray<BVH*,BVHCmpZ> sort_z; - sort_z.nth_element(0,p_size,p_size/2,p_children); - //sort_z.sort(&p_bb[p_from],p_size); - - } break; - } - - - BVH* left = _parse_bvh(p_children,p_size/2,p_depth+1,max_depth); - BVH* right = _parse_bvh(&p_children[p_size/2],p_size-p_size/2,p_depth+1,max_depth); - - BVH *_new = memnew(BVH); - _new->aabb=aabb; - _new->center=aabb.pos+aabb.size*0.5; - _new->children[0]=left; - _new->children[1]=right; - _new->leaf=NULL; - - return _new; -} - -void BakedLightBaker::_make_bvh() { - - Vector<BVH*> bases; - bases.resize(triangles.size()); - int max_depth=0; - for(int i=0;i<triangles.size();i++) { - bases[i]=memnew( BVH ); - bases[i]->leaf=&triangles[i]; - bases[i]->aabb.pos=triangles[i].vertices[0]; - bases[i]->aabb.expand_to(triangles[i].vertices[1]); - bases[i]->aabb.expand_to(triangles[i].vertices[2]); - bases[i]->center=bases[i]->aabb.pos+bases[i]->aabb.size*0.5; - } - - bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth); - ray_stack = memnew_arr(uint32_t,max_depth); - bvh_stack = memnew_arr(BVH*,max_depth); -} - -void BakedLightBaker::_octree_insert(const AABB& p_aabb,Octant *p_octant,Triangle* p_triangle, int p_depth) { - - if (p_octant->leaf) { -#if 0 - if (p_aabb.has_point(p_triangle->vertices[0]) && p_aabb.has_point(p_triangle->vertices[1]) &&p_aabb.has_point(p_triangle->vertices[2])) { - //face is completely enclosed, add area - p_octant->surface_area+=Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area(); - } else { - //not completely enclosed, will need to be clipped.. - Vector<Vector3> poly; - poly.push_back(p_triangle->vertices[0]); - poly.push_back(p_triangle->vertices[1]); - poly.push_back(p_triangle->vertices[2]); - - //clip - for(int i=0;i<3;i++) { - - //top plane - Plane p(0,0,0,0); - p.normal[i]=1.0; - p.d=p_aabb.pos[i]+p_aabb.size[i]; - poly=Geometry::clip_polygon(poly,p); - - //bottom plane - p.normal[i]=-1.0; - p.d=-p_aabb.pos[i]; - poly=Geometry::clip_polygon(poly,p); - } - - - //calculate area - float clipped_area=0; - for(int i=2;i<poly.size();i++) { - clipped_area+=Face3(poly[0],poly[i-1],poly[i]).get_area(); - } - - print_line(itos(poly.size())+" Base: "+rtos(Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area())+" clipped: "+rtos(clipped_area)); - p_octant->surface_area+=clipped_area; - } -#endif - } else { - - - for(int i=0;i<8;i++) { - - AABB aabb=p_aabb; - aabb.size*=0.5; - if (i&1) - aabb.pos.x+=aabb.size.x; - if (i&2) - aabb.pos.y+=aabb.size.y; - if (i&4) - aabb.pos.z+=aabb.size.z; - - AABB fit_aabb=aabb; - //fit_aabb=fit_aabb.grow(bvh->aabb.size.x*0.0001); - - if (!Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb(fit_aabb)) - continue; - - if (!p_octant->children[i]) { - p_octant->children[i]=memnew(Octant); - if (p_depth==0) { - p_octant->children[i]->leaf=true; - p_octant->children[i]->light_accum[0]=0; - p_octant->children[i]->light_accum[1]=0; - p_octant->children[i]->light_accum[2]=0; - p_octant->children[i]->offset[0]=aabb.pos.x+aabb.size.x*0.5; - p_octant->children[i]->offset[1]=aabb.pos.y+aabb.size.y*0.5; - p_octant->children[i]->offset[2]=aabb.pos.z+aabb.size.z*0.5; - p_octant->children[i]->surface_area=0; - p_octant->children[i]->next_leaf=leaf_list; - leaf_list=p_octant->children[i]; - cell_count++; - } else { - - p_octant->children[i]->leaf=false; - for(int j=0;j<8;j++) { - p_octant->children[i]->children[j]=0; - } - } - } - - _octree_insert(aabb,p_octant->children[i],p_triangle,p_depth-1); - } - } -} - - -void BakedLightBaker::_make_octree() { - - AABB base = bvh->aabb; - float lal=base.get_longest_axis_size(); - //must be square because we want square blocks - base.size.x=lal; - base.size.y=lal; - base.size.z=lal; - base.grow_by(lal*0.001); //for precision - octree_aabb=base; - - cell_size=base.size.x; - for(int i=0;i<octree_depth;i++) - cell_size/=2.0; - - octree = memnew( Octant ); - octree->leaf=false; - for(int i=0;i<8;i++) - octree->children[i]=NULL; - - for(int i=0;i<triangles.size();i++) { - - _octree_insert(octree_aabb,octree,&triangles[i],octree_depth-1); - } - -} - - -void BakedLightBaker::_plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb, Octant *p_octant, const AABB& p_aabb,const Color& p_light) { - - - if (p_octant->leaf) { - - float r=cell_size*plot_size; - Vector3 center=p_aabb.pos+p_aabb.size*0.5; - float d = p_plot_pos.distance_to(center); - if (d>r) - return; //oh crap! outside radius - float intensity = 1.0;// - (d/r)*(d/r); //not gauss but.. - p_octant->light_accum[0]+=p_light.r*intensity; - p_octant->light_accum[1]+=p_light.g*intensity; - p_octant->light_accum[2]+=p_light.b*intensity; - - } else { - - for(int i=0;i<8;i++) { - - if (!p_octant->children[i]) - continue; - - AABB aabb=p_aabb; - aabb.size*=0.5; - if (i&1) - aabb.pos.x+=aabb.size.x; - if (i&2) - aabb.pos.y+=aabb.size.y; - if (i&4) - aabb.pos.z+=aabb.size.z; - - - if (!aabb.intersects(p_plot_aabb)) - continue; - - _plot_light(p_plot_pos,p_plot_aabb,p_octant->children[i],aabb,p_light); - - } - - } -} - -void BakedLightBaker::_plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light) { - - - if (p_octant->leaf) { - - p_octant->light_accum[0]+=p_light.r; - p_octant->light_accum[1]+=p_light.g; - p_octant->light_accum[2]+=p_light.b; - - } else { - - for(int i=0;i<8;i++) { - - if (!p_octant->children[i]) - continue; - - AABB aabb=p_aabb; - aabb.size*=0.5; - if (i&1) - aabb.pos.x+=aabb.size.x; - if (i&2) - aabb.pos.y+=aabb.size.y; - if (i&4) - aabb.pos.z+=aabb.size.z; - - - if (!aabb.has_point(p_plot_pos)) - continue; - - _plot_light_point(p_plot_pos,p_octant->children[i],aabb,p_light); - - } - - } -} - - -void BakedLightBaker::_throw_ray(const Vector3& p_begin, const Vector3& p_end,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces) { - - - uint32_t* stack = ray_stack; - BVH **bstack = bvh_stack; - - enum { - TEST_AABB_BIT=0, - VISIT_LEFT_BIT=1, - VISIT_RIGHT_BIT=2, - VISIT_DONE_BIT=3, - - - }; - - Vector3 n = (p_end-p_begin).normalized(); - real_t d=1e10; - bool inters=false; - Vector3 r_normal; - Vector3 r_point; - - //for(int i=0;i<max_depth;i++) - // stack[i]=0; - - int level=0; - //AABB ray_aabb; - //ray_aabb.pos=p_begin; - //ray_aabb.expand_to(p_end); - - - const BVH *bvhptr = bvh; - - bstack[0]=bvh; - stack[0]=TEST_AABB_BIT; - - - while(true) { - - uint32_t mode = stack[level]; - const BVH &b = *bstack[level]; - bool done=false; - - switch(mode) { - case TEST_AABB_BIT: { - - if (b.leaf) { - - - Face3 f3(b.leaf->vertices[0],b.leaf->vertices[1],b.leaf->vertices[2]); - - - Vector3 res; - - if (f3.intersects_segment(p_begin,p_end,&res)) { - - - float nd = n.dot(res); - if (nd<d) { - - d=nd; - r_point=res; - r_normal=f3.get_plane().get_normal(); - inters=true; - } - - } - - stack[level]=VISIT_DONE_BIT; - } else { - - - bool valid = b.aabb.intersects_segment(p_begin,p_end); - // bool valid = b.aabb.intersects(ray_aabb); - - if (!valid) { - - stack[level]=VISIT_DONE_BIT; - - } else { - - stack[level]=VISIT_LEFT_BIT; - } - } - - } continue; - case VISIT_LEFT_BIT: { - - stack[level]=VISIT_RIGHT_BIT; - bstack[level+1]=b.children[0]; - stack[level+1]=TEST_AABB_BIT; - level++; - - } continue; - case VISIT_RIGHT_BIT: { - - stack[level]=VISIT_DONE_BIT; - bstack[level+1]=b.children[1]; - stack[level+1]=TEST_AABB_BIT; - level++; - } continue; - case VISIT_DONE_BIT: { - - if (level==0) { - done=true; - break; - } else - level--; - - } continue; - } - - - if (done) - break; - } - - - if (inters) { - - //print_line("collision!"); - if (n.dot(r_normal)>0) - r_normal=-r_normal; - - //ok... - Color diffuse_at_point(0.8,0.8,0.8); - Color specular_at_point(0.8,0.8,0.8); - - AABB aabb; - aabb.pos=r_point; - aabb.pos-=Vector3(1,1,1)*cell_size*plot_size; - aabb.size=Vector3(2,2,2)*cell_size*plot_size; - - _plot_light(r_point,aabb,octree,octree_aabb,p_light); -// _plot_light_point(r_point,octree,octree_aabb,p_light); - - } - -} - - - - - - -float BakedLightBaker::get_normalization() const { - - float nrg=0; - for(int i=0;i<directional_lights.size();i++) { - - const DirLight &dl=directional_lights[i]; - float total_area = dl.left.length()*2*dl.up.length()*2; - float cell_area = cell_size*cell_size;; - nrg+= dl.energy * (dl.rays_thrown * cell_area / total_area); - nrg*=5; - } - - return nrg; -} - -void BakedLightBaker::throw_rays(int p_amount) { - - - - for(int i=0;i<directional_lights.size();i++) { - - DirLight &dl=directional_lights[i]; - - float sr = Math::sqrt(p_amount); - float aspect = dl.up.length()/dl.left.length(); - - - for(int j=0;j<p_amount;j++) { - Vector3 from = dl.pos; - from+=dl.up*(Math::randf()*2.0-1.0); - from+=dl.left*(Math::randf()*2.0-1.0); - Vector3 to = from+dl.dir*dl.length; - Color col=dl.diffuse; - col.r*=dl.energy; - col.g*=dl.energy; - col.b*=dl.energy; - dl.rays_thrown++; - _throw_ray(from,to,col,NULL,0,max_bounces); - } - - - } -} - - - - - - - - - - - - - -void BakedLightBaker::bake(Node* p_node) { - - cell_count=0; - - _parse_geometry(p_node); - _fix_lights(); - _make_bvh(); - _make_octree(); - -} - void BakedLightEditor::_end_baking() { - if (!bake_thread) - return; - - bake_thread_exit=true; - Thread::wait_to_finish(bake_thread); - bake_thread=NULL; - bake_thread_exit=false; + baker->clear(); + set_process(false); + button_bake->set_pressed(false); + bake_info->set_text(""); } void BakedLightEditor::_node_removed(Node *p_node) { @@ -833,71 +21,83 @@ void BakedLightEditor::_node_removed(Node *p_node) { if(p_node==node) { _end_baking(); node=NULL; - p_node->remove_child(preview); - preview->set_mesh(Ref<Mesh>()); + hide(); } } -void BakedLightEditor::_bake_thread_func(void *arg) { - BakedLightEditor *ble = (BakedLightEditor*)arg; - - while(!ble->bake_thread_exit) { - - ble->baker->throw_rays(1000); - } -} +void BakedLightEditor::_notification(int p_option) { -void BakedLightEditor::_notification(int p_option) { + if (p_option==NOTIFICATION_ENTER_SCENE) { + button_bake->set_icon(get_icon("Bake","EditorIcons")); + button_reset->set_icon(get_icon("Reload","EditorIcons")); + } if (p_option==NOTIFICATION_PROCESS) { - if (bake_thread) { + if (baker->is_baking() && !baker->is_paused()) { update_timeout-=get_process_delta_time(); if (update_timeout<0) { + if (baker->get_baked_light()!=node->get_baked_light()) { + _end_baking(); + return; + } + uint64_t t = OS::get_singleton()->get_ticks_msec(); - float norm = baker->get_normalization(); +#ifdef DEBUG_CUBES + double norm = baker->get_normalization(); float max_lum=0; + { DVector<Color>::Write cw=colors.write(); - BakedLightBaker::Octant *oct = baker->leaf_list; + BakedLightBaker::Octant *octants=baker->octant_pool.ptr(); + BakedLightBaker::Octant *oct = &octants[baker->leaf_list]; int vert_idx=0; while(oct) { - Color color; - color.r=oct->light_accum[0]/norm; - color.g=oct->light_accum[1]/norm; - color.b=oct->light_accum[2]/norm; - float lum = color.get_v(); - //if (lum<0.05) - // color.a=0; - if (lum>max_lum) - max_lum=lum; + Color colors[8]; + for(int i=0;i<8;i++) { + colors[i].r=oct->light_accum[i][0]/norm; + colors[i].g=oct->light_accum[i][1]/norm; + colors[i].b=oct->light_accum[i][2]/norm; + + float lum = colors[i].get_v(); + //if (lum<0.05) + // color.a=0; + if (lum>max_lum) + max_lum=lum; + + } + static const int vert2cub[36]={7,3,1,1,5,7,7,6,2,2,3,7,7,5,4,4,6,7,2,6,4,4,0,2,4,5,1,1,0,4,1,3,2,2,0,1}; for (int i=0;i<36;i++) { - cw[vert_idx++]=color; + cw[vert_idx++]=colors[vert2cub[i]]; } - oct=oct->next_leaf; + if (oct->next_leaf) + oct=&octants[oct->next_leaf]; + else + oct=NULL; } } - + print_line("MSCOL: "+itos(OS::get_singleton()->get_ticks_msec()-t)); + t = OS::get_singleton()->get_ticks_msec(); Array a; a.resize(Mesh::ARRAY_MAX); @@ -907,8 +107,28 @@ void BakedLightEditor::_notification(int p_option) { mesh->surface_remove(0); mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a); mesh->surface_set_material(0,material); +#endif + ERR_FAIL_COND(node->get_baked_light().is_null()); + + baker->update_octree_image(octree_texture); +#if 0 +//debug + Image img(baker->baked_octree_texture_w,baker->baked_octree_texture_h,0,Image::FORMAT_RGBA,octree_texture); + Ref<ImageTexture> it = memnew( ImageTexture ); + it->create_from_image(img); + ResourceSaver::save("baked_octree.png",it); + + +#endif + bake_info->set_text("rays/s: "+itos(baker->get_rays_sec())); + update_timeout=1; + print_line("MSUPDATE: "+itos(OS::get_singleton()->get_ticks_msec()-t)); + t=OS::get_singleton()->get_ticks_msec(); + node->get_baked_light()->set_octree(octree_texture); + print_line("MSSET: "+itos(OS::get_singleton()->get_ticks_msec()-t)); + + - update_timeout=1; } } } @@ -924,115 +144,73 @@ void BakedLightEditor::_menu_option(int p_option) { case MENU_OPTION_BAKE: { ERR_FAIL_COND(!node); - preview->set_mesh(Ref<Mesh>()); - baker->base_inv=node->get_global_transform().affine_inverse(); - baker->bake(node); - - print_line("CELLS: "+itos(baker->cell_count)); - print_line("cell size: "+rtos(baker->cell_size)); - colors.resize(baker->cell_count*36); - vertices.resize(baker->cell_count*36); - - - { - DVector<Color>::Write cw=colors.write(); - DVector<Vector3>::Write vw=vertices.write(); - BakedLightBaker::Octant *oct = baker->leaf_list; - int vert_idx=0; - - while(oct) { - - Color color; - - for (int i=0;i<6;i++) { + ERR_FAIL_COND(node->get_baked_light().is_null()); + baker->bake(node->get_baked_light(),node); + update_timeout=0; + set_process(true); - Vector3 face_points[4]; - for (int j=0;j<4;j++) { - - float v[3]; - v[0]=1.0; - v[1]=1-2*((j>>1)&1); - v[2]=v[1]*(1-2*(j&1)); - - for (int k=0;k<3;k++) { - if (i<3) - face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); - else - face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); - } - } + } break; + case MENU_OPTION_CLEAR: { - for(int j=0;j<4;j++) { - face_points[j]*=baker->cell_size*0.5; - face_points[j]+=Vector3(oct->offset[0],oct->offset[1],oct->offset[2]); - } -#define ADD_VTX(m_idx) \ - vw[vert_idx]=face_points[m_idx]; \ - cw[vert_idx]=color; \ - vert_idx++; - //tri 1 - ADD_VTX(0); - ADD_VTX(1); - ADD_VTX(2); - //tri 2 - ADD_VTX(2); - ADD_VTX(3); - ADD_VTX(0); + } break; -#undef ADD_VTX + } +} - } +void BakedLightEditor::_bake_pressed() { - oct=oct->next_leaf; - } + ERR_FAIL_COND(!node); + if (node->get_baked_light().is_null()) { + err_dialog->set_text("BakedLightInstance does not contain a BakedLight resource."); + err_dialog->popup_centered(Size2(350,70)); + button_bake->set_pressed(false); + return; + } + if (baker->is_baking()) { - } + baker->set_pause(!button_bake->is_pressed()); + if (baker->is_paused()) { - Array a; - a.resize(Mesh::ARRAY_MAX); - a[Mesh::ARRAY_VERTEX]=vertices; - a[Mesh::ARRAY_COLOR]=colors; - while(mesh->get_surface_count()) - mesh->surface_remove(0); - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a); - mesh->surface_set_material(0,material); + set_process(false); + bake_info->set_text(""); + } else { - bake_thread_exit=false; update_timeout=0; set_process(true); - bake_thread=Thread::create(_bake_thread_func,this); - preview->set_mesh(mesh); - + } - } break; - case MENU_OPTION_CLEAR: { + } else { + baker->bake(node->get_baked_light(),node); + update_timeout=0; + set_process(true); + } +} +void BakedLightEditor::_clear_pressed(){ - } break; + baker->clear(); + button_bake->set_pressed(false); + bake_info->set_text(""); - } } +void BakedLightEditor::edit(BakedLightInstance *p_baked_light) { -void BakedLightEditor::edit(BakedLight *p_baked_light) { - - if (node==p_baked_light) + if (p_baked_light==NULL || node==p_baked_light) { return; - if (node) { - node->remove_child(preview); } + if (node && node!=p_baked_light) + _end_baking(); - node=p_baked_light; - _end_baking(); - if (node) - node->add_child(preview); + node=p_baked_light; + //_end_baking(); } @@ -1041,35 +219,33 @@ void BakedLightEditor::edit(BakedLight *p_baked_light) { void BakedLightEditor::_bind_methods() { ObjectTypeDB::bind_method("_menu_option",&BakedLightEditor::_menu_option); + ObjectTypeDB::bind_method("_bake_pressed",&BakedLightEditor::_bake_pressed); + ObjectTypeDB::bind_method("_clear_pressed",&BakedLightEditor::_clear_pressed); } BakedLightEditor::BakedLightEditor() { - options = memnew( MenuButton ); - - options->set_text("BakedLight"); - options->get_popup()->add_item("Bake..",MENU_OPTION_BAKE); - options->get_popup()->add_item("Clear",MENU_OPTION_CLEAR); - options->get_popup()->connect("item_pressed", this,"_menu_option"); - + bake_hbox = memnew( HBoxContainer ); + button_bake = memnew( ToolButton ); + button_bake->set_text("Bake!"); + button_bake->set_toggle_mode(true); + button_reset = memnew( Button ); + bake_info = memnew( Label ); + bake_hbox->add_child( button_bake ); + bake_hbox->add_child( button_reset ); + bake_hbox->add_child( bake_info ); err_dialog = memnew( AcceptDialog ); add_child(err_dialog); node=NULL; baker = memnew( BakedLightBaker ); - preview = memnew( MeshInstance ); - bake_thread=NULL; - update_timeout=0; - material = Ref<FixedMaterial> ( memnew( FixedMaterial ) ); - material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); - material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); - material->set_flag(FixedMaterial::FLAG_UNSHADED,true); - material->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true); - material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1)); + button_bake->connect("pressed",this,"_bake_pressed"); + button_reset->connect("pressed",this,"_clear_pressed"); + + update_timeout=0; - mesh = Ref<Mesh>( memnew( Mesh )); } @@ -1081,28 +257,24 @@ BakedLightEditor::~BakedLightEditor() { void BakedLightEditorPlugin::edit(Object *p_object) { - baked_light_editor->edit(p_object->cast_to<BakedLight>()); + baked_light_editor->edit(p_object->cast_to<BakedLightInstance>()); } bool BakedLightEditorPlugin::handles(Object *p_object) const { - return p_object->is_type("BakedLight"); + return p_object->is_type("BakedLightInstance"); } void BakedLightEditorPlugin::make_visible(bool p_visible) { if (p_visible) { baked_light_editor->show(); - baked_light_editor->options->show(); + baked_light_editor->bake_hbox->show(); } else { baked_light_editor->hide(); - baked_light_editor->options->show(); + baked_light_editor->bake_hbox->hide(); baked_light_editor->edit(NULL); - if (baked_light_editor->node) { - baked_light_editor->node->remove_child(baked_light_editor->preview); - baked_light_editor->node=NULL; - } } } @@ -1112,9 +284,9 @@ BakedLightEditorPlugin::BakedLightEditorPlugin(EditorNode *p_node) { editor=p_node; baked_light_editor = memnew( BakedLightEditor ); editor->get_viewport()->add_child(baked_light_editor); - add_custom_control(CONTAINER_SPATIAL_EDITOR_MENU,baked_light_editor->options); + add_custom_control(CONTAINER_SPATIAL_EDITOR_MENU,baked_light_editor->bake_hbox); baked_light_editor->hide(); - baked_light_editor->options->hide(); + baked_light_editor->bake_hbox->hide(); } diff --git a/tools/editor/plugins/baked_light_editor_plugin.h b/tools/editor/plugins/baked_light_editor_plugin.h index 9424503a16..4ecc0b458f 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.h +++ b/tools/editor/plugins/baked_light_editor_plugin.h @@ -3,15 +3,17 @@ #include "tools/editor/editor_plugin.h" #include "tools/editor/editor_node.h" -#include "scene/3d/baked_light.h" +#include "tools/editor/plugins/baked_light_baker.h" #include "scene/gui/spin_box.h" + + /** @author Juan Linietsky <reduzio@gmail.com> */ -class BakedLightBaker; + class MeshInstance; class BakedLightEditor : public Control { @@ -20,20 +22,18 @@ class BakedLightEditor : public Control { float update_timeout; - DVector<Color> colors; - DVector<Vector3> vertices; - Ref<Mesh> mesh; - Ref<FixedMaterial> material; - - Thread *bake_thread; - bool bake_thread_exit; + DVector<uint8_t> octree_texture; - MeshInstance *preview; BakedLightBaker *baker; AcceptDialog *err_dialog; - MenuButton * options; - BakedLight *node; + HBoxContainer *bake_hbox; + Button *button_bake; + Button *button_reset; + Label *bake_info; + + + BakedLightInstance *node; enum Menu { @@ -41,7 +41,9 @@ class BakedLightEditor : public Control { MENU_OPTION_CLEAR }; - static void _bake_thread_func(void *arg); + void _bake_pressed(); + void _clear_pressed(); + void _end_baking(); void _menu_option(int); @@ -52,7 +54,7 @@ protected: void _notification(int p_what); public: - void edit(BakedLight *p_baked_light); + void edit(BakedLightInstance *p_baked_light); BakedLightEditor(); ~BakedLightEditor(); }; diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp index aac3837da9..d757a4c07d 100644 --- a/tools/editor/project_export.cpp +++ b/tools/editor/project_export.cpp @@ -232,6 +232,26 @@ void ProjectExportDialog::_format_toggled() { } +void ProjectExportDialog::_script_edited(Variant v) { + + if (updating_script) + return; + updating_script=true; + EditorNode::get_undo_redo()->create_action("Edit Script Options"); + EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"script_set_action",script_mode->get_selected()); + EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(),"script_set_action",EditorImportExport::get_singleton()->script_get_action()); + EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"script_set_encryption_key",script_key->get_text()); + EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(),"script_set_encryption_key",EditorImportExport::get_singleton()->script_get_encryption_key()); + EditorNode::get_undo_redo()->add_do_method(this,"_update_script"); + EditorNode::get_undo_redo()->add_undo_method(this,"_update_script"); + EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg"); + EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg"); + EditorNode::get_undo_redo()->commit_action(); + updating_script=false; + + +} + void ProjectExportDialog::_notification(int p_what) { switch(p_what) { @@ -277,10 +297,16 @@ void ProjectExportDialog::_notification(int p_what) { image_action->select(EditorImportExport::get_singleton()->get_export_image_action()); image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality()); image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_shrink()); + _update_script(); + + image_quality->connect("value_changed",this,"_quality_edited"); image_shrink->connect("value_changed",this,"_shrink_edited"); image_action->connect("item_selected",this,"_image_export_edited"); + script_mode->connect("item_selected",this,"_script_edited"); + script_key->connect("text_changed",this,"_script_edited"); + for(int i=0;i<formats.size();i++) { if (EditorImportExport::get_singleton()->get_image_formats().has(formats[i]->get_text(0))) formats[i]->set_checked(0,true); @@ -651,10 +677,15 @@ bool ProjectExportDialog::_update_group_treef(TreeItem *p_parent,EditorFileSyste } void ProjectExportDialog::_update_group_tree() { + if (updating) + return; + group_images->clear(); if (_get_selected_group()=="") return; + + updating=true; print_line("****UGT"); List<String> img_extensions; ImageLoader::get_recognized_extensions(&img_extensions); @@ -677,7 +708,7 @@ void ProjectExportDialog::_update_group_tree() { groupenum+=","+String(E->get()); } - + updating=false; _update_group_treef(NULL,EditorFileSystem::get_singleton()->get_filesystem(),extensions,groupenum,group_index); @@ -690,7 +721,7 @@ void ProjectExportDialog::_group_changed(Variant v) { return; if (_get_selected_group()=="") return; - + updating=true; StringName name = _get_selected_group(); EditorNode::get_undo_redo()->create_action("Change Image Group"); EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"image_export_group_set_image_action",name,group_image_action->get_selected()); @@ -706,6 +737,7 @@ void ProjectExportDialog::_group_changed(Variant v) { EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg"); EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg"); EditorNode::get_undo_redo()->commit_action(); + updating=false; } void ProjectExportDialog::_group_item_edited() { @@ -926,11 +958,11 @@ void ProjectExportDialog::_group_atlas_preview() { int flags=0; - if (Globals::get_singleton()->get("texture_import/filter")) + if (Globals::get_singleton()->get("image_loader/filter")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER; - if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) + if (!Globals::get_singleton()->get("image_loader/gen_mipmaps")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS; - if (!Globals::get_singleton()->get("texture_import/repeat")) + if (!Globals::get_singleton()->get("image_loader/repeat")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT; flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA; @@ -956,6 +988,17 @@ void ProjectExportDialog::_group_atlas_preview() { } +void ProjectExportDialog::_update_script() { + + if (updating_script) + return; + updating_script=true; + script_mode->select(EditorImportExport::get_singleton()->script_get_action()); + script_key->set_text(EditorImportExport::get_singleton()->script_get_encryption_key()); + updating_script=false; + +} + void ProjectExportDialog::_image_filter_changed(String) { _update_group_tree(); @@ -991,6 +1034,8 @@ void ProjectExportDialog::_bind_methods() { ObjectTypeDB::bind_method(_MD("_group_atlas_preview"),&ProjectExportDialog::_group_atlas_preview); ObjectTypeDB::bind_method(_MD("_group_select_all"),&ProjectExportDialog::_group_select_all); ObjectTypeDB::bind_method(_MD("_group_select_none"),&ProjectExportDialog::_group_select_none); + ObjectTypeDB::bind_method(_MD("_script_edited"),&ProjectExportDialog::_script_edited); + ObjectTypeDB::bind_method(_MD("_update_script"),&ProjectExportDialog::_update_script); ObjectTypeDB::bind_method(_MD("export_platform"),&ProjectExportDialog::export_platform); @@ -1171,7 +1216,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { group_lossy_quality->set_step(0.1); group_lossy_quality->set_val(0.7); group_options->add_margin_child("Lossy Quality:",group_lossy_quality); - group_lossy_quality->connect("value_changed",this,"_group_changed"); + group_lossy_quality->connect("value_changed",this,"_quality_edited"); group_atlas = memnew(CheckButton); group_atlas->set_pressed("Generate Atlas"); @@ -1261,6 +1306,18 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { hbc->add_child(button_reload); */ + script_vbox = memnew( VBoxContainer ); + script_vbox->set_name("Script"); + sections->add_child(script_vbox); + script_mode = memnew( OptionButton ); + script_vbox->add_margin_child("Script Export Mode:",script_mode); + script_mode->add_item("Text"); + script_mode->add_item("Compiled"); + script_mode->add_item("Encrypted (Provide Key Below)"); + script_key = memnew( LineEdit ); + script_vbox->add_margin_child("Script Encryption Key (256-bits as hex):",script_key); + + updating=false; @@ -1302,6 +1359,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { add_child(pck_export); button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck"); + updating_script=false; } diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h index 6ceffadc62..dfe7a2d900 100644 --- a/tools/editor/project_export.h +++ b/tools/editor/project_export.h @@ -132,6 +132,12 @@ private: TextureFrame *atlas_preview_frame; + VBoxContainer *script_vbox; + OptionButton *script_mode; + LineEdit *script_key; + + + void _export_mode_changed(int p_idx); void _prop_edited(String what); @@ -166,6 +172,9 @@ private: void _group_select_none(); void _group_del(Object *item,int p_column, int p_button); + bool updating_script; + void _update_script(); + void _script_edited(Variant v); void _export_action(const String& p_file); void _export_action_pck(const String& p_file); void ok_pressed(); |