godot/tools/editor/plugins/baked_light_editor_plugin.cpp
Juan Linietsky b324ff7ea5 A bit of everything:
-IMA-ADPCM support for samples, this means that sound effects can be compressed and use 4 timess less RAM.
-New 3D import workflow based on Wavefront OBJ. Import single objects as mesh resources instead of full scenes. Many people prefers to work this way. Just like the rest of the imported resources, these are updated in realtime if modified externally.
-Mesh resources now support naming surfaces. This helps reimporting to identify which user-created materials must be kept.
-Several fixes and improvements to SurfaceTool.
-Anti Aliasing added to WorldEnvironment effects (using FXAA)
-2D Physics bodies (RigidBody, KinematicBody, etc), Raycasts, Tilemap, etc support collision layers. This makes easy to group which objects collide against which.
-2D Trigger shapes can now also trigger collision reporting in other 2D bodies (it used to be in Area2D before)
-Viewport render target textures can now be filtered.
-Few fixes in GDscript make it easier to work with static functions and class members.
-Several and many bugfixes.
2014-05-14 01:22:15 -03:00

997 lines
20 KiB
C++

#include "baked_light_editor_plugin.h"
#include "scene/gui/box_container.h"
#include "scene/3d/mesh_instance.h"
#include "scene/3d/light.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 _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=8;
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 (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
for(int i=2;i<poly.size();i++) {
p_octant->surface_area+=Face3(poly[0],poly[i-1],poly[i]).get_area();
}
}
} 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::_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);
}
}
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::_node_removed(Node *p_node) {
if(p_node==node) {
node=NULL;
p_node->remove_child(preview);
preview->set_mesh(Ref<Mesh>());
hide();
}
}
void BakedLightEditor::_menu_option(int p_option) {
switch(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);
baker->throw_rays(100000);
float norm = baker->get_normalization();
float max_lum=0;
print_line("CELLS: "+itos(baker->cell_count));
DVector<Color> colors;
DVector<Vector3> vertices;
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;
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>max_lum)
max_lum=lum;
for (int i=0;i<6;i++) {
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);
}
}
for(int j=0;j<4;j++) {
face_points[j]*=baker->cell_size;
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);
#undef ADD_VTX
}
oct=oct->next_leaf;
}
}
print_line("max lum: "+rtos(max_lum));
Array a;
a.resize(Mesh::ARRAY_MAX);
a[Mesh::ARRAY_VERTEX]=vertices;
a[Mesh::ARRAY_COLOR]=colors;
Ref<FixedMaterial> matcol = memnew( FixedMaterial );
matcol->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
matcol->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
matcol->set_flag(FixedMaterial::FLAG_UNSHADED,true);
matcol->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true);
matcol->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
Ref<Mesh> m = memnew( Mesh );
m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
m->surface_set_material(0,matcol);
preview->set_mesh(m);
} break;
case MENU_OPTION_CLEAR: {
} break;
}
}
void BakedLightEditor::edit(BakedLight *p_baked_light) {
if (node==p_baked_light)
return;
if (node) {
node->remove_child(preview);
}
node=p_baked_light;
if (node)
node->add_child(preview);
}
void BakedLightEditor::_bind_methods() {
ObjectTypeDB::bind_method("_menu_option",&BakedLightEditor::_menu_option);
}
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");
err_dialog = memnew( AcceptDialog );
add_child(err_dialog);
node=NULL;
baker = memnew( BakedLightBaker );
preview = memnew( MeshInstance );
}
BakedLightEditor::~BakedLightEditor() {
memdelete(baker);
}
void BakedLightEditorPlugin::edit(Object *p_object) {
baked_light_editor->edit(p_object->cast_to<BakedLight>());
}
bool BakedLightEditorPlugin::handles(Object *p_object) const {
return p_object->is_type("BakedLight");
}
void BakedLightEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
baked_light_editor->show();
baked_light_editor->options->show();
} else {
baked_light_editor->hide();
baked_light_editor->options->show();
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;
}
}
}
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);
baked_light_editor->hide();
baked_light_editor->options->hide();
}
BakedLightEditorPlugin::~BakedLightEditorPlugin()
{
}