summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-06-11 10:41:03 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-06-11 10:41:03 -0300
commit9b8696d3dd92e2ed6f310ad0f0bf3c2182c9c6ae (patch)
treeb2ed0515196bb774504b54aab0bf242992ac3d9f /tools
parent6f0b4678e26c04abfc88c0226c803e78a108de98 (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.cpp63
-rw-r--r--tools/editor/editor_import_export.h14
-rw-r--r--tools/editor/icons/icon_bake.pngbin0 -> 419 bytes
-rw-r--r--tools/editor/icons/icon_reload.pngbin371 -> 567 bytes
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp1
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.cpp16
-rw-r--r--tools/editor/plugins/baked_light_baker.cpp1765
-rw-r--r--tools/editor/plugins/baked_light_baker.h316
-rw-r--r--tools/editor/plugins/baked_light_editor_plugin.cpp1080
-rw-r--r--tools/editor/plugins/baked_light_editor_plugin.h30
-rw-r--r--tools/editor/project_export.cpp70
-rw-r--r--tools/editor/project_export.h9
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
new file mode 100644
index 0000000000..b1b0f941da
--- /dev/null
+++ b/tools/editor/icons/icon_bake.png
Binary files differ
diff --git a/tools/editor/icons/icon_reload.png b/tools/editor/icons/icon_reload.png
index a79cd11546..07f53efb56 100644
--- a/tools/editor/icons/icon_reload.png
+++ b/tools/editor/icons/icon_reload.png
Binary files differ
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();