summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/tests/test_render.cpp5
-rw-r--r--core/math/math_funcs.h102
-rw-r--r--core/rid.h8
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp1
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp9
-rw-r--r--drivers/gles3/rasterizer_gles3.h3
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp808
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h178
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp720
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h200
-rw-r--r--drivers/gles3/shader_gles3.cpp12
-rw-r--r--drivers/gles3/shaders/SCsub1
-rw-r--r--drivers/gles3/shaders/scene.glsl351
-rw-r--r--servers/visual/rasterizer.h99
-rw-r--r--servers/visual/shader_types.cpp13
-rw-r--r--servers/visual/visual_server_raster.cpp179
-rw-r--r--servers/visual/visual_server_raster.h103
-rw-r--r--servers/visual/visual_server_scene.cpp1517
-rw-r--r--servers/visual/visual_server_scene.h390
-rw-r--r--servers/visual/visual_server_viewport.cpp14
-rw-r--r--servers/visual_server.cpp746
-rw-r--r--servers/visual_server.h8
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.cpp1
23 files changed, 5196 insertions, 272 deletions
diff --git a/bin/tests/test_render.cpp b/bin/tests/test_render.cpp
index 7bf833c8a7..b971d412aa 100644
--- a/bin/tests/test_render.cpp
+++ b/bin/tests/test_render.cpp
@@ -173,7 +173,10 @@ public:
// vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
viewport = vs->viewport_create();
- vs->viewport_attach_to_screen(viewport,Rect2(Vector2(),OS::get_singleton()->get_window_size()));
+ Size2i screen_size = OS::get_singleton()->get_window_size();
+ vs->viewport_set_size(viewport,screen_size.x,screen_size.y);
+ vs->viewport_attach_to_screen(viewport,Rect2(Vector2(),screen_size));
+ vs->viewport_set_active(viewport,true);
vs->viewport_attach_camera( viewport, camera );
vs->viewport_set_scenario( viewport, scenario );
vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,3,30 ) ) );
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index fc76d96b2e..c8ced0b306 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -175,6 +175,108 @@ public:
static double log(double x);
static double exp(double x);
+
+ static _FORCE_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h)
+ {
+ uint16_t h_exp, h_sig;
+ uint32_t f_sgn, f_exp, f_sig;
+
+ h_exp = (h&0x7c00u);
+ f_sgn = ((uint32_t)h&0x8000u) << 16;
+ switch (h_exp) {
+ case 0x0000u: /* 0 or subnormal */
+ h_sig = (h&0x03ffu);
+ /* Signed zero */
+ if (h_sig == 0) {
+ return f_sgn;
+ }
+ /* Subnormal */
+ h_sig <<= 1;
+ while ((h_sig&0x0400u) == 0) {
+ h_sig <<= 1;
+ h_exp++;
+ }
+ f_exp = ((uint32_t)(127 - 15 - h_exp)) << 23;
+ f_sig = ((uint32_t)(h_sig&0x03ffu)) << 13;
+ return f_sgn + f_exp + f_sig;
+ case 0x7c00u: /* inf or NaN */
+ /* All-ones exponent and a copy of the significand */
+ return f_sgn + 0x7f800000u + (((uint32_t)(h&0x03ffu)) << 13);
+ default: /* normalized */
+ /* Just need to adjust the exponent and shift */
+ return f_sgn + (((uint32_t)(h&0x7fffu) + 0x1c000u) << 13);
+ }
+ }
+
+ static _FORCE_INLINE_ float halfptr_to_float(uint16_t *h) {
+
+ union {
+ uint32_t u32;
+ float f32;
+ } u;
+
+ u.u32=halfbits_to_floatbits(*h);
+ return u.f32;
+ }
+
+ static _FORCE_INLINE_ uint16_t make_half_float(float f) {
+
+ union {
+ float fv;
+ uint32_t ui;
+ } ci;
+ ci.fv=f;
+
+ uint32_t x = ci.ui;
+ uint32_t sign = (unsigned short)(x >> 31);
+ uint32_t mantissa;
+ uint32_t exp;
+ uint16_t hf;
+
+ // get mantissa
+ mantissa = x & ((1 << 23) - 1);
+ // get exponent bits
+ exp = x & (0xFF << 23);
+ if (exp >= 0x47800000)
+ {
+ // check if the original single precision float number is a NaN
+ if (mantissa && (exp == (0xFF << 23)))
+ {
+ // we have a single precision NaN
+ mantissa = (1 << 23) - 1;
+ }
+ else
+ {
+ // 16-bit half-float representation stores number as Inf
+ mantissa = 0;
+ }
+ hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) |
+ (uint16_t)(mantissa >> 13);
+ }
+ // check if exponent is <= -15
+ else if (exp <= 0x38000000)
+ {
+
+ /*// store a denorm half-float value or zero
+ exp = (0x38000000 - exp) >> 23;
+ mantissa >>= (14 + exp);
+
+ hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
+ */
+ hf=0; //denormals do not work for 3D, convert to zero
+ }
+ else
+ {
+ hf = (((uint16_t)sign) << 15) |
+ (uint16_t)((exp - 0x38000000) >> 13) |
+ (uint16_t)(mantissa >> 13);
+ }
+
+ return hf;
+ }
+
+
+
};
diff --git a/core/rid.h b/core/rid.h
index 85a69ac0ef..92b7e6ee69 100644
--- a/core/rid.h
+++ b/core/rid.h
@@ -181,6 +181,14 @@ public:
}
+
+ _FORCE_INLINE_ T * getptr(const RID& p_rid) {
+
+ return static_cast<T*>(p_rid.get_data());
+
+ }
+
+
_FORCE_INLINE_ bool owns(const RID& p_rid) const {
if (p_rid.get_data()==NULL)
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index b2228a6cfa..237b3ec3fc 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -117,6 +117,7 @@ void RasterizerCanvasGLES3::canvas_begin(){
glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a );
glClear(GL_COLOR_BUFFER_BIT);
storage->frame.clear_request=false;
+ print_line("canvas clear?");
}
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index eaa9825605..83c40edc1d 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -15,7 +15,7 @@ RasterizerCanvas *RasterizerGLES3::get_canvas() {
RasterizerScene *RasterizerGLES3::get_scene() {
- return NULL;
+ return scene;
}
@@ -111,6 +111,7 @@ void RasterizerGLES3::initialize() {
*/
storage->initialize();
canvas->initialize();
+ scene->initialize();
}
void RasterizerGLES3::begin_frame(){
@@ -124,6 +125,7 @@ void RasterizerGLES3::begin_frame(){
storage->update_dirty_shaders();
storage->update_dirty_materials();
+
}
void RasterizerGLES3::set_current_render_target(RID p_render_target){
@@ -131,6 +133,7 @@ void RasterizerGLES3::set_current_render_target(RID p_render_target){
if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) {
//handle pending clear request, if the framebuffer was not cleared
glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo);
+ print_line("unbind clear of: "+storage->frame.clear_request_color);
glClearColor(
storage->frame.clear_request_color.r,
storage->frame.clear_request_color.g,
@@ -265,8 +268,12 @@ RasterizerGLES3::RasterizerGLES3()
storage = memnew( RasterizerStorageGLES3 );
canvas = memnew( RasterizerCanvasGLES3 );
+ scene = memnew( RasterizerSceneGLES3 );
canvas->storage=storage;
storage->canvas=canvas;
+ scene->storage=storage;
+ storage->scene=scene;
+
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index d461664ea2..f70dac506d 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -4,6 +4,7 @@
#include "servers/visual/rasterizer.h"
#include "rasterizer_storage_gles3.h"
#include "rasterizer_canvas_gles3.h"
+#include "rasterizer_scene_gles3.h"
class RasterizerGLES3 : public Rasterizer {
@@ -12,6 +13,8 @@ class RasterizerGLES3 : public Rasterizer {
RasterizerStorageGLES3 *storage;
RasterizerCanvasGLES3 *canvas;
+ RasterizerSceneGLES3 *scene;
+
public:
virtual RasterizerStorage *get_storage();
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
new file mode 100644
index 0000000000..121620594d
--- /dev/null
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -0,0 +1,808 @@
+#include "rasterizer_scene_gles3.h"
+#include "globals.h"
+static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) {
+
+ p_array[ 0]=p_mtx.elements[0][0];
+ p_array[ 1]=p_mtx.elements[0][1];
+ p_array[ 2]=0;
+ p_array[ 3]=0;
+ p_array[ 4]=p_mtx.elements[1][0];
+ p_array[ 5]=p_mtx.elements[1][1];
+ p_array[ 6]=0;
+ p_array[ 7]=0;
+ p_array[ 8]=0;
+ p_array[ 9]=0;
+ p_array[10]=1;
+ p_array[11]=0;
+ p_array[12]=p_mtx.elements[2][0];
+ p_array[13]=p_mtx.elements[2][1];
+ p_array[14]=0;
+ p_array[15]=1;
+}
+
+
+static _FORCE_INLINE_ void store_transform(const Transform& p_mtx, float* p_array) {
+ p_array[ 0]=p_mtx.basis.elements[0][0];
+ p_array[ 1]=p_mtx.basis.elements[1][0];
+ p_array[ 2]=p_mtx.basis.elements[2][0];
+ p_array[ 3]=0;
+ p_array[ 4]=p_mtx.basis.elements[0][1];
+ p_array[ 5]=p_mtx.basis.elements[1][1];
+ p_array[ 6]=p_mtx.basis.elements[2][1];
+ p_array[ 7]=0;
+ p_array[ 8]=p_mtx.basis.elements[0][2];
+ p_array[ 9]=p_mtx.basis.elements[1][2];
+ p_array[10]=p_mtx.basis.elements[2][2];
+ p_array[11]=0;
+ p_array[12]=p_mtx.origin.x;
+ p_array[13]=p_mtx.origin.y;
+ p_array[14]=p_mtx.origin.z;
+ p_array[15]=1;
+}
+
+static _FORCE_INLINE_ void store_camera(const CameraMatrix& p_mtx, float* p_array) {
+
+ for (int i=0;i<4;i++) {
+ for (int j=0;j<4;j++) {
+
+ p_array[i*4+j]=p_mtx.matrix[i][j];
+ }
+ }
+}
+
+
+
+RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
+
+
+ return RID();
+}
+
+void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,const Transform& p_transform){
+
+
+}
+
+
+bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass) {
+
+ if (p_material->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ glEnable(GL_CULL_FACE);
+ }
+
+ //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+
+ /*
+ if (p_material->flags[VS::MATERIAL_FLAG_WIREFRAME])
+ glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+ else
+ glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+ */
+
+ //if (p_material->line_width)
+ // glLineWidth(p_material->line_width);
+
+
+ //blend mode
+ if (state.current_blend_mode!=p_material->shader->spatial.blend_mode) {
+
+ switch(p_material->shader->spatial.blend_mode) {
+
+ case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ } break;
+ case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD: {
+
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE);
+
+ } break;
+ case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_SUB: {
+
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+ } break;
+ case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ } break;
+ }
+
+ state.current_blend_mode=p_material->shader->spatial.blend_mode;
+
+ }
+
+ //material parameters
+
+ state.scene_shader.set_custom_shader(p_material->shader->custom_code_id);
+ bool rebind = state.scene_shader.bind();
+
+
+ if (p_material->ubo_id) {
+ glBindBufferBase(GL_UNIFORM_BUFFER,1,p_material->ubo_id);
+ }
+
+
+
+ int tc = p_material->textures.size();
+ RID* textures = p_material->textures.ptr();
+
+ for(int i=0;i<tc;i++) {
+
+ glActiveTexture(GL_TEXTURE0+i);
+
+ RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull( textures[i] );
+ if (!t) {
+ //check hints
+ glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex);
+ continue;
+ }
+
+ glBindTexture(t->target,t->tex_id);
+ }
+
+
+ return rebind;
+
+}
+
+
+void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) {
+
+ switch(e->instance->base_type) {
+
+ case VS::INSTANCE_MESH: {
+
+ RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+ glBindVertexArray(s->array_id); // everything is so easy nowadays
+ } break;
+ }
+
+}
+
+static const GLenum gl_primitive[]={
+ GL_POINTS,
+ GL_LINES,
+ GL_LINE_STRIP,
+ GL_LINE_LOOP,
+ GL_TRIANGLES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN
+};
+
+
+
+void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
+
+ switch(e->instance->base_type) {
+
+ case VS::INSTANCE_MESH: {
+
+ RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+
+ if (s->index_array_len>0) {
+
+ glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0);
+
+ } else {
+
+ glDrawArrays(gl_primitive[s->primitive],0,s->array_len);
+
+ }
+
+ } break;
+ }
+
+}
+
+void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,bool p_reverse_cull,bool p_alpha_pass) {
+
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
+ //p_reverse_cull=!p_reverse_cull;
+ glFrontFace(GL_CCW);
+ } else {
+ glFrontFace(GL_CW);
+ }
+
+ glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo
+
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false);
+
+ state.current_blend_mode=-1;
+
+ glDisable(GL_BLEND);
+
+ RasterizerStorageGLES3::Material* prev_material=NULL;
+ RasterizerStorageGLES3::Geometry* prev_geometry=NULL;
+ VS::InstanceType prev_base_type = VS::INSTANCE_MAX;
+
+ for (int i=0;i<p_element_count;i++) {
+
+ RenderList::Element *e = p_elements[i];
+ RasterizerStorageGLES3::Material* material= e->material;
+
+ bool rebind=i==0;
+
+ if (material!=prev_material || rebind) {
+
+ rebind = _setup_material(material,p_alpha_pass);
+// _rinfo.mat_change_count++;
+ }
+
+
+ if (prev_base_type != e->instance->base_type || prev_geometry!=e->geometry) {
+
+ _setup_geometry(e);
+ }
+
+// _set_cull(e->mirror,p_reverse_cull);
+
+ state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform);
+
+
+// _render(e->geometry, material, skeleton,e->owner,e->instance->transform);
+
+ _render_geometry(e);
+
+ prev_material=material;
+ prev_base_type=e->instance->base_type;
+ prev_geometry=e->geometry;
+ }
+
+ //print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count));
+
+
+ glFrontFace(GL_CW);
+ glBindVertexArray(0);
+
+}
+
+void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material) {
+
+ RasterizerStorageGLES3::Material *m=NULL;
+ RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override :(p_material>=0?p_instance->materials[p_material]:p_geometry->material);
+
+/*
+#ifdef DEBUG_ENABLED
+ if (current_debug==VS::SCENARIO_DEBUG_OVERDRAW) {
+ m_src=overdraw_material;
+ }
+
+#endif
+*/
+ if (m_src.is_valid()) {
+ m=storage->material_owner.getornull( m_src );
+ if (!m->shader) {
+ m=NULL;
+ }
+ }
+
+ if (!m) {
+ m=storage->material_owner.getptr( default_material );
+ }
+
+ ERR_FAIL_COND(!m);
+
+
+
+ //bool has_base_alpha=(m->shader_cache && m->shader_cache->has_alpha);
+ //bool has_blend_alpha=m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX || m->flags[VS::MATERIAL_FLAG_ONTOP];
+ bool has_alpha = false; //has_base_alpha || has_blend_alpha;
+
+#if 0
+ if (shadow) {
+
+ if (has_blend_alpha || (has_base_alpha && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA))
+ return; //bye
+
+ if (!m->shader_cache || (!m->shader_cache->writes_vertex && !m->shader_cache->uses_discard && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) {
+ //shader does not use discard and does not write a vertex position, use generic material
+ if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)
+ m = shadow_mat_double_sided_ptr;
+ else
+ m = shadow_mat_ptr;
+ if (m->last_pass!=frame) {
+
+ if (m->shader.is_valid()) {
+
+ m->shader_cache=shader_owner.get(m->shader);
+ if (m->shader_cache) {
+
+
+ if (!m->shader_cache->valid)
+ m->shader_cache=NULL;
+ } else {
+ m->shader=RID();
+ }
+
+ } else {
+ m->shader_cache=NULL;
+ }
+
+ m->last_pass=frame;
+ }
+ }
+
+ render_list = &opaque_render_list;
+ /* notyet
+ if (!m->shader_cache || m->shader_cache->can_zpass)
+ render_list = &alpha_render_list;
+ } else {
+ render_list = &opaque_render_list;
+ }*/
+
+ } else {
+ if (has_alpha) {
+ render_list = &alpha_render_list;
+ } else {
+ render_list = &opaque_render_list;
+
+ }
+ }
+#endif
+
+ RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element();
+
+ if (!e)
+ return;
+
+ e->geometry=p_geometry;
+ e->material=m;
+ e->instance=p_instance;
+ e->owner=p_owner;
+ e->additive=false;
+ e->additive_ptr=&e->additive;
+ e->sort_key=0;
+
+ if (e->geometry->last_pass!=render_pass) {
+ e->geometry->last_pass=render_pass;
+ e->geometry->index=current_geometry_index++;
+ }
+
+ e->sort_key|=uint64_t(e->instance->base_type)<<RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT;
+ e->sort_key|=uint64_t(e->instance->base_type)<<RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT;
+
+ if (e->material->last_pass!=render_pass) {
+ e->material->last_pass=render_pass;
+ e->material->index=current_material_index++;
+ }
+
+ e->sort_key|=uint64_t(e->material->index)<<RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT;
+
+ e->sort_key|=uint64_t(e->instance->depth_layer)<<RenderList::SORT_KEY_DEPTH_LAYER_SHIFT;
+
+ //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE)
+ // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING;
+
+ bool mirror = e->instance->mirror;
+
+// if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES])
+// e->mirror=!e->mirror;
+
+ if (mirror) {
+ e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG;
+ }
+
+ //e->light_type=0xFF; // no lights!
+ e->sort_key|=uint64_t(0xF)<<RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; //light type 0xF is no light?
+ e->sort_key|=uint64_t(0xFFFF)<<RenderList::SORT_KEY_LIGHT_INDEX_SHIFT;
+/* prepass
+ if (!shadow && !has_blend_alpha && has_alpha && m->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA) {
+
+ //if nothing exists, add this element as opaque too
+ RenderList::Element *oe = opaque_render_list.add_element();
+
+ if (!oe)
+ return;
+
+ memcpy(oe,e,sizeof(RenderList::Element));
+ oe->additive_ptr=&oe->additive;
+ }
+*/
+
+#if 0
+ if (shadow || m->flags[VS::MATERIAL_FLAG_UNSHADED] || current_debug==VS::SCENARIO_DEBUG_SHADELESS) {
+
+ e->light_type=0x7F; //unshaded is zero
+ } else {
+
+ bool duplicate=false;
+
+
+ for(int i=0;i<directional_light_count;i++) {
+ uint16_t sort_key = directional_lights[i]->sort_key;
+ uint8_t light_type = VS::LIGHT_DIRECTIONAL;
+ if (directional_lights[i]->base->shadow_enabled) {
+ light_type|=0x8;
+ if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS)
+ light_type|=0x10;
+ else if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS)
+ light_type|=0x30;
+
+ }
+
+ RenderList::Element *ec;
+ if (duplicate) {
+
+ ec = render_list->add_element();
+ memcpy(ec,e,sizeof(RenderList::Element));
+ } else {
+
+ ec=e;
+ duplicate=true;
+ }
+
+ ec->light_type=light_type;
+ ec->light=sort_key;
+ ec->additive_ptr=&e->additive;
+
+ }
+
+
+ const RID *liptr = p_instance->light_instances.ptr();
+ int ilc=p_instance->light_instances.size();
+
+
+
+ for(int i=0;i<ilc;i++) {
+
+ LightInstance *li=light_instance_owner.get( liptr[i] );
+ if (!li || li->last_pass!=scene_pass) //lit by light not in visible scene
+ continue;
+ uint8_t light_type=li->base->type|0x40; //penalty to ensure directionals always go first
+ if (li->base->shadow_enabled) {
+ light_type|=0x8;
+ }
+ uint16_t sort_key =li->sort_key;
+
+ RenderList::Element *ec;
+ if (duplicate) {
+
+ ec = render_list->add_element();
+ memcpy(ec,e,sizeof(RenderList::Element));
+ } else {
+
+ duplicate=true;
+ ec=e;
+ }
+
+ ec->light_type=light_type;
+ ec->light=sort_key;
+ ec->additive_ptr=&e->additive;
+
+ }
+
+
+
+ }
+
+#endif
+}
+
+void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){
+
+
+ //fill up ubo
+
+ store_camera(p_cam_projection,state.ubo_data.projection_matrix);
+ store_transform(p_cam_transform,state.ubo_data.camera_matrix);
+ store_transform(p_cam_transform.affine_inverse(),state.ubo_data.camera_inverse_matrix);
+ for(int i=0;i<4;i++) {
+ state.ubo_data.time[i]=storage->frame.time[i];
+ }
+
+
+ glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::SceneDataUBO), &state.ubo_data);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+
+ render_list.clear();
+
+ render_pass++;
+ current_material_index=0;
+
+ //fill list
+
+ for(int i=0;i<p_cull_count;i++) {
+
+ InstanceBase *inst = p_cull_result[i];
+ switch(inst->base_type) {
+
+ case VS::INSTANCE_MESH: {
+
+ RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(inst->base);
+ ERR_CONTINUE(!mesh);
+
+ int ssize = mesh->surfaces.size();
+
+ for (int i=0;i<ssize;i++) {
+
+ int mat_idx = inst->materials[i].is_valid() ? i : -1;
+ RasterizerStorageGLES3::Surface *s = mesh->surfaces[i];
+ _add_geometry(s,inst,NULL,mat_idx);
+ }
+
+ //mesh->last_pass=frame;
+
+ } break;
+ case VS::INSTANCE_MULTIMESH: {
+
+ } break;
+ case VS::INSTANCE_IMMEDIATE: {
+
+ } break;
+
+ }
+ }
+
+ //
+
+
+ glEnable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glClearDepth(1.0);
+ glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo);
+
+
+ if (true) {
+
+ if (storage->frame.clear_request) {
+
+ glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a );
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ storage->frame.clear_request=false;
+
+ }
+ }
+
+ state.current_depth_test=true;
+ state.current_depth_mask=true;
+ state.texscreen_copied=false;
+
+ glBlendEquation(GL_FUNC_ADD);
+
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ glDisable(GL_BLEND);
+ //current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
+
+
+ render_list.sort_by_key(false);
+
+ //_render_list_forward(&opaque_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting);
+/*
+ if (draw_tex_background) {
+
+ //most 3D vendors recommend drawing a texture bg or skybox here,
+ //after opaque geometry has been drawn
+ //so the zbuffer can get rid of most pixels
+ _draw_tex_bg();
+ }
+*/
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+// glDisable(GL_BLEND);
+// current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
+// state.scene_shader.set_conditional(SceneShaderGLES3::USE_GLOW,false);
+// if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) {
+// glColorMask(1,1,1,0); //don't touch alpha
+// }
+
+
+ _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,false,false);
+
+ //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true);
+ //glColorMask(1,1,1,1);
+
+// state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false);
+
+ glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+#if 0
+ if (use_fb) {
+
+
+
+ for(int i=0;i<VS::ARRAY_MAX;i++) {
+ glDisableVertexAttribArray(i);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_SCISSOR_TEST);
+ glDepthMask(false);
+
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR]) {
+
+ int hdr_tm = current_env->fx_param[VS::ENV_FX_PARAM_HDR_TONEMAPPER];
+ switch(hdr_tm) {
+ case VS::ENV_FX_HDR_TONE_MAPPER_LINEAR: {
+
+
+ } break;
+ case VS::ENV_FX_HDR_TONE_MAPPER_LOG: {
+ copy_shader.set_conditional(CopyShaderGLES2::USE_LOG_TONEMAPPER,true);
+
+ } break;
+ case VS::ENV_FX_HDR_TONE_MAPPER_REINHARDT: {
+ copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,true);
+ } break;
+ case VS::ENV_FX_HDR_TONE_MAPPER_REINHARDT_AUTOWHITE: {
+
+ copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,true);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_AUTOWHITE,true);
+ } break;
+ }
+
+
+ _process_hdr();
+ }
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) {
+ _process_glow_bloom();
+ int glow_transfer_mode=current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_BLEND_MODE];
+ if (glow_transfer_mode==1)
+ copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,true);
+ if (glow_transfer_mode==2)
+ copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,true);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer);
+
+ Size2 size;
+ if (current_rt) {
+ glBindFramebuffer(GL_FRAMEBUFFER, current_rt->fbo);
+ glViewport( 0,0,viewport.width,viewport.height);
+ size=Size2(viewport.width,viewport.height);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
+ glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height );
+ size=Size2(viewport.width,viewport.height);
+ }
+
+ //time to copy!!!
+ copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,current_env && current_env->fx_enabled[VS::ENV_FX_BCS]);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,current_env && current_env->fx_enabled[VS::ENV_FX_HDR]);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,true);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,current_env && current_env->fx_enabled[VS::ENV_FX_FXAA]);
+
+ copy_shader.bind();
+ //copy_shader.set_uniform(CopyShaderGLES2::SOURCE,0);
+
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) {
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, framebuffer.blur[0].color );
+ glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::GLOW_SOURCE),1);
+
+ }
+
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR]) {
+
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, current_vd->lum_color );
+ glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::HDR_SOURCE),2);
+ copy_shader.set_uniform(CopyShaderGLES2::TONEMAP_EXPOSURE,float(current_env->fx_param[VS::ENV_FX_PARAM_HDR_EXPOSURE]));
+ copy_shader.set_uniform(CopyShaderGLES2::TONEMAP_WHITE,float(current_env->fx_param[VS::ENV_FX_PARAM_HDR_WHITE]));
+
+ }
+
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_FXAA])
+ copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Size2(1.0/size.x,1.0/size.y));
+
+
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_BCS]) {
+
+ Vector3 bcs;
+ bcs.x=current_env->fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS];
+ bcs.y=current_env->fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST];
+ bcs.z=current_env->fx_param[VS::ENV_FX_PARAM_BCS_SATURATION];
+ copy_shader.set_uniform(CopyShaderGLES2::BCS,bcs);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, framebuffer.color );
+ glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
+
+ _copy_screen_quad();
+
+ copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_AUTOWHITE,false);
+ copy_shader.set_conditional(CopyShaderGLES2::USE_LOG_TONEMAPPER,false);
+
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_8BIT_HDR,false);
+
+
+ if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR] && GLOBAL_DEF("rasterizer/debug_hdr",false)) {
+ _debug_luminances();
+ }
+ }
+
+ current_env=NULL;
+ current_debug=VS::SCENARIO_DEBUG_DISABLED;
+ if (GLOBAL_DEF("rasterizer/debug_shadow_maps",false)) {
+ _debug_shadows();
+ }
+// _debug_luminances();
+// _debug_samplers();
+
+ if (using_canvas_bg) {
+ using_canvas_bg=false;
+ glColorMask(1,1,1,1); //don't touch alpha
+ }
+#endif
+}
+
+bool RasterizerSceneGLES3::free(RID p_rid) {
+
+ return false;
+
+}
+
+void RasterizerSceneGLES3::initialize() {
+
+ state.scene_shader.init();
+
+ default_shader = storage->shader_create(VS::SHADER_SPATIAL);
+ default_material = storage->material_create();
+ storage->material_set_shader(default_material,default_shader);
+
+ glGenBuffers(1, &state.scene_ubo);
+ glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ render_list.max_elements=GLOBAL_DEF("rendering/gles3/max_renderable_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS);
+ if (render_list.max_elements>1000000)
+ render_list.max_elements=1000000;
+ if (render_list.max_elements<1024)
+ render_list.max_elements=1024;
+
+ render_list.init();
+}
+
+void RasterizerSceneGLES3::finalize(){
+
+
+}
+
+
+RasterizerSceneGLES3::RasterizerSceneGLES3()
+{
+
+}
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
new file mode 100644
index 0000000000..6fba777fc8
--- /dev/null
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -0,0 +1,178 @@
+#ifndef RASTERIZERSCENEGLES3_H
+#define RASTERIZERSCENEGLES3_H
+
+#include "rasterizer_storage_gles3.h"
+#include "drivers/gles3/shaders/scene.glsl.h"
+
+class RasterizerSceneGLES3 : public RasterizerScene {
+public:
+
+ uint64_t render_pass;
+ uint32_t current_material_index;
+ uint32_t current_geometry_index;
+
+ RID default_material;
+ RID default_shader;
+
+ RasterizerStorageGLES3 *storage;
+
+
+
+ struct State {
+
+ bool current_depth_test;
+ bool current_depth_mask;
+ bool texscreen_copied;
+ int current_blend_mode;
+
+ SceneShaderGLES3 scene_shader;
+
+
+ struct SceneDataUBO {
+
+ float projection_matrix[16];
+ float camera_inverse_matrix[16];
+ float camera_matrix[16];
+ float time[4];
+ float ambient_light[4];
+
+ } ubo_data;
+
+ GLuint scene_ubo;
+
+
+
+ } state;
+
+ struct RenderList {
+
+ enum {
+ DEFAULT_MAX_ELEMENTS=65536,
+ MAX_LIGHTS=4,
+ SORT_FLAG_SKELETON=1,
+ SORT_FLAG_INSTANCING=2,
+
+ SORT_KEY_DEPTH_LAYER_SHIFT=58,
+ SORT_KEY_LIGHT_TYPE_SHIFT=54, //type is most important
+ SORT_KEY_LIGHT_INDEX_SHIFT=38, //type is most important
+ SORT_KEY_MATERIAL_INDEX_SHIFT=22,
+ SORT_KEY_GEOMETRY_INDEX_SHIFT=6,
+ SORT_KEY_GEOMETRY_TYPE_SHIFT=2,
+ SORT_KEY_SKELETON_FLAG=2,
+ SORT_KEY_MIRROR_FLAG=1
+
+ };
+
+ int max_elements;
+
+ struct Element {
+
+ RasterizerScene::InstanceBase *instance;
+ RasterizerStorageGLES3::Geometry *geometry;
+ RasterizerStorageGLES3::Material *material;
+ RasterizerStorageGLES3::GeometryOwner *owner;
+ uint64_t sort_key;
+ bool *additive_ptr;
+ bool additive;
+
+ };
+
+
+ Element *_elements;
+ Element **elements;
+
+ int element_count;
+ int alpha_element_count;
+
+ void clear() {
+
+ element_count=0;
+ alpha_element_count=0;
+ }
+
+ //should eventually be replaced by radix
+
+ struct SortByKey {
+
+ _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const {
+ return A->sort_key < B->sort_key;
+ }
+ };
+
+ void sort_by_key(bool p_alpha) {
+
+ SortArray<Element*,SortByKey> sorter;
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements-alpha_element_count-1],alpha_element_count);
+ } else {
+ sorter.sort(elements,element_count);
+ }
+ }
+
+
+ _FORCE_INLINE_ Element* add_element() {
+
+ if (element_count+alpha_element_count>=max_elements)
+ return NULL;
+ elements[element_count]=&_elements[element_count];
+ return elements[element_count++];
+ }
+
+ _FORCE_INLINE_ Element* add_alpha_element() {
+
+ if (element_count+alpha_element_count>=max_elements)
+ return NULL;
+ int idx = max_elements-alpha_element_count-1;
+ elements[idx]=&_elements[idx];
+ alpha_element_count++;
+ return elements[idx];
+ }
+
+ void init() {
+
+ element_count = 0;
+ alpha_element_count =0;
+ elements=memnew_arr(Element*,max_elements);
+ _elements=memnew_arr(Element,max_elements);
+ for (int i=0;i<max_elements;i++)
+ elements[i]=&_elements[i]; // assign elements
+
+ }
+
+ RenderList() {
+
+ max_elements=DEFAULT_MAX_ELEMENTS;
+ }
+
+ ~RenderList() {
+ memdelete_arr(elements);
+ memdelete_arr(_elements);
+ }
+ };
+
+
+
+ RenderList render_list;
+
+ _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass);
+ _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
+ _FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
+
+
+ void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, bool p_reverse_cull, bool p_alpha_pass);
+
+ virtual RID light_instance_create(RID p_light);
+ virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform);
+
+ _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material);
+
+ virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment);
+
+ virtual bool free(RID p_rid);
+
+ void initialize();
+ void finalize();
+ RasterizerSceneGLES3();
+};
+
+#endif // RASTERIZERSCENEGLES3_H
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 74b7d72652..f633ef21cc 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1,5 +1,6 @@
#include "rasterizer_storage_gles3.h"
#include "rasterizer_canvas_gles3.h"
+#include "rasterizer_scene_gles3.h"
#include "globals.h"
/* TEXTURE API */
@@ -1039,7 +1040,7 @@ void RasterizerStorageGLES3::shader_set_mode(RID p_shader,VS::ShaderMode p_mode)
ShaderGLES3* shaders[VS::SHADER_MAX]={
&canvas->state.canvas_shader,
- &canvas->state.canvas_shader,
+ &scene->state.scene_shader,
&canvas->state.canvas_shader,
};
@@ -1108,6 +1109,37 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
actions->uniforms=&p_shader->uniforms;
} break;
+
+ case VS::SHADER_SPATIAL: {
+
+ p_shader->spatial.blend_mode=Shader::Spatial::BLEND_MODE_MIX;
+ p_shader->spatial.depth_draw_mode=Shader::Spatial::DEPTH_DRAW_OPAQUE;
+ p_shader->spatial.cull_mode=Shader::Spatial::CULL_MODE_BACK;
+ p_shader->spatial.uses_alpha=false;
+ p_shader->spatial.unshaded=false;
+ p_shader->spatial.ontop=false;
+
+ shaders.actions_scene.render_mode_values["blend_add"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_ADD);
+ shaders.actions_scene.render_mode_values["blend_mix"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MIX);
+ shaders.actions_scene.render_mode_values["blend_sub"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_SUB);
+ shaders.actions_scene.render_mode_values["blend_mul"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MUL);
+
+ shaders.actions_scene.render_mode_values["depth_draw_opaque"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_OPAQUE);
+ shaders.actions_scene.render_mode_values["depth_draw_always"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_ALWAYS);
+ shaders.actions_scene.render_mode_values["depth_draw_never"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_NEVER);
+ shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS);
+
+ shaders.actions_scene.render_mode_values["cull_front"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_FRONT);
+ shaders.actions_scene.render_mode_values["cull_back"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK);
+ shaders.actions_scene.render_mode_values["cull_disable"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED);
+
+ shaders.actions_canvas.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded;
+ shaders.actions_canvas.render_mode_flags["ontop"]=&p_shader->spatial.ontop;
+
+ shaders.actions_canvas.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha;
+
+ }
+
}
@@ -1905,97 +1937,685 @@ void RasterizerStorageGLES3::update_dirty_materials() {
RID RasterizerStorageGLES3::mesh_create(){
- return RID();
+ Mesh * mesh = memnew( Mesh );
+
+ return mesh_owner.make_rid(mesh);
}
-void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const Vector<DVector<uint8_t> >& p_blend_shapes){
+void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes,const Vector<AABB>& p_bone_aabbs){
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND(!(p_format&VS::ARRAY_FORMAT_VERTEX));
+
+ //must have index and bones, both.
+ {
+ uint32_t bones_weight = VS::ARRAY_FORMAT_BONES|VS::ARRAY_FORMAT_WEIGHTS;
+ ERR_EXPLAIN("Array must have both bones and weights in format or none.");
+ ERR_FAIL_COND( (p_format&bones_weight) && (p_format&bones_weight)!=bones_weight );
+ }
+
+
+ bool has_morph = p_blend_shapes.size();
+
+ Surface::Attrib attribs[VS::ARRAY_MAX],morph_attribs[VS::ARRAY_MAX];
+
+ int stride=0;
+ int morph_stride=0;
+
+ for(int i=0;i<VS::ARRAY_MAX;i++) {
+
+ if (! (p_format&(1<<i) ) ) {
+ attribs[i].enabled=false;
+ morph_attribs[i].enabled=false;
+ continue;
+ }
+
+ attribs[i].enabled=true;
+ attribs[i].offset=stride;
+ attribs[i].index=i;
+
+ if (has_morph) {
+ morph_attribs[i].enabled=true;
+ morph_attribs[i].offset=morph_stride;
+ morph_attribs[i].index=i+8;
+ } else {
+ morph_attribs[i].enabled=false;
+ }
+
+ switch(i) {
+
+ case VS::ARRAY_VERTEX: {
+
+ if (p_format&VS::ARRAY_FLAG_USE_2D_VERTICES) {
+ attribs[i].size=2;
+ } else {
+ attribs[i].size=3;
+ }
+
+ if (p_format&VS::ARRAY_COMPRESS_VERTEX) {
+ attribs[i].type=GL_HALF_FLOAT;
+ stride+=attribs[i].size*2;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=attribs[i].size*4;
+ }
+
+ attribs[i].normalized=GL_FALSE;
+
+ if (has_morph) {
+ //morph
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=attribs[i].size*4;
+ }
+ } break;
+ case VS::ARRAY_NORMAL: {
+
+ attribs[i].size=3;
+
+ if (p_format&VS::ARRAY_COMPRESS_NORMAL) {
+ attribs[i].type=GL_BYTE;
+ stride+=4; //pad extra byte
+ attribs[i].normalized=GL_TRUE;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=12;
+ attribs[i].normalized=GL_FALSE;
+ }
+
+ if (has_morph) {
+ //morph
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=12;
+ }
+
+ } break;
+ case VS::ARRAY_TANGENT: {
+
+ attribs[i].size=4;
+
+ if (p_format&VS::ARRAY_COMPRESS_TANGENT) {
+ attribs[i].type=GL_BYTE;
+ stride+=4;
+ attribs[i].normalized=GL_TRUE;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=16;
+ attribs[i].normalized=GL_FALSE;
+ }
+
+ if (has_morph) {
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=16;
+ }
+
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ attribs[i].size=4;
+
+ if (p_format&VS::ARRAY_COMPRESS_COLOR) {
+ attribs[i].type=GL_UNSIGNED_BYTE;
+ stride+=4;
+ attribs[i].normalized=GL_TRUE;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=16;
+ attribs[i].normalized=GL_FALSE;
+ }
+
+ if (has_morph) {
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=16;
+ }
+
+ } break;
+ case VS::ARRAY_TEX_UV: {
+
+ attribs[i].size=2;
+
+ if (p_format&VS::ARRAY_COMPRESS_TEX_UV) {
+ attribs[i].type=GL_HALF_FLOAT;
+ stride+=4;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=8;
+ }
+
+ attribs[i].normalized=GL_FALSE;
+
+ if (has_morph) {
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=8;
+ }
+
+ } break;
+ case VS::ARRAY_TEX_UV2: {
+
+ attribs[i].size=2;
+
+ if (p_format&VS::ARRAY_COMPRESS_TEX_UV2) {
+ attribs[i].type=GL_HALF_FLOAT;
+ stride+=4;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=8;
+ }
+ attribs[i].normalized=GL_FALSE;
+
+ if (has_morph) {
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=8;
+ }
+
+ } break;
+ case VS::ARRAY_BONES: {
+
+ attribs[i].size=4;
+
+ if (p_format&VS::ARRAY_COMPRESS_BONES) {
+
+ if (p_format&VS::ARRAY_FLAG_USE_16_BIT_BONES) {
+ attribs[i].type=GL_UNSIGNED_SHORT;
+ stride+=8;
+ } else {
+ attribs[i].type=GL_UNSIGNED_BYTE;
+ stride+=4;
+ }
+ } else {
+ attribs[i].type=GL_UNSIGNED_SHORT;
+ stride+=8;
+ }
+
+ attribs[i].normalized=GL_FALSE;
+
+ if (has_morph) {
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_UNSIGNED_SHORT;
+ morph_stride+=8;
+ }
+
+ } break;
+ case VS::ARRAY_WEIGHTS: {
+
+ attribs[i].size=4;
+
+ if (p_format&VS::ARRAY_COMPRESS_WEIGHTS) {
+
+ attribs[i].type=GL_UNSIGNED_SHORT;
+ stride+=8;
+ attribs[i].normalized=GL_TRUE;
+ } else {
+ attribs[i].type=GL_FLOAT;
+ stride+=16;
+ attribs[i].normalized=GL_FALSE;
+ }
+
+ if (has_morph) {
+ morph_attribs[i].normalized=GL_FALSE;
+ morph_attribs[i].size=attribs[i].size;
+ morph_attribs[i].type=GL_FLOAT;
+ morph_stride+=8;
+ }
+ } break;
+ case VS::ARRAY_INDEX: {
+
+ attribs[i].size=1;
+
+ if (p_vertex_count>=(1<<16)) {
+ attribs[i].type=GL_UNSIGNED_INT;
+ attribs[i].stride=4;
+ } else {
+ attribs[i].type=GL_UNSIGNED_SHORT;
+ attribs[i].stride=2;
+ }
+
+ attribs[i].normalized=GL_FALSE;
+
+ } break;
+
+ }
+ }
+
+ for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+ attribs[i].stride=stride;
+ if (has_morph) {
+ morph_attribs[i].stride=morph_stride;
+ }
+ }
+
+ //validate sizes
+
+ int array_size = stride * p_vertex_count;
+ int index_array_size=0;
+
+ ERR_FAIL_COND(p_array.size()!=array_size);
+
+ if (p_format&VS::ARRAY_FORMAT_INDEX) {
+
+ index_array_size=attribs[VS::ARRAY_INDEX].stride*p_index_count;
+
+ print_line("index count: "+itos(p_index_count)+" stride: "+itos(attribs[VS::ARRAY_INDEX].stride) );
+ }
+
+
+ ERR_FAIL_COND(p_index_array.size()!=index_array_size);
+
+ ERR_FAIL_COND(p_blend_shapes.size()!=mesh->morph_target_count);
+
+ for(int i=0;i<p_blend_shapes.size();i++) {
+ ERR_FAIL_COND(p_blend_shapes[i].size()!=array_size);
+ }
+
+ //ok all valid, create stuff
+
+ Surface * surface = memnew( Surface );
+
+ surface->active=true;
+ surface->array_len=p_vertex_count;
+ surface->index_array_len=p_index_count;
+ surface->primitive=p_primitive;
+ surface->mesh=mesh;
+ surface->format=p_format;
+ surface->skeleton_bone_aabb=p_bone_aabbs;
+ surface->skeleton_bone_used.resize(surface->skeleton_bone_aabb.size());
+ surface->aabb=p_aabb;
+ surface->max_bone=p_bone_aabbs.size();
+
+ for(int i=0;i<surface->skeleton_bone_used.size();i++) {
+ if (surface->skeleton_bone_aabb[i].size.x<0 || surface->skeleton_bone_aabb[i].size.y<0 || surface->skeleton_bone_aabb[i].size.z<0) {
+ surface->skeleton_bone_used[i]=false;
+ } else {
+ surface->skeleton_bone_used[i]=true;
+ }
+ }
+
+ for(int i=0;i<VS::ARRAY_MAX;i++) {
+ surface->attribs[i]=attribs[i];
+ surface->morph_attribs[i]=morph_attribs[i];
+ }
+
+ {
+
+ DVector<uint8_t>::Read vr = p_array.read();
+
+ glGenBuffers(1,&surface->vertex_id);
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ glBufferData(GL_ARRAY_BUFFER,array_size,vr.ptr(),GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+
+ if (p_format&VS::ARRAY_FORMAT_INDEX) {
+
+ DVector<uint8_t>::Read ir = p_index_array.read();
+
+ glGenBuffers(1,&surface->index_id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_array_size,ir.ptr(),GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
+ }
+ //generate arrays for faster state switching
+
+ glGenVertexArrays(1,&surface->array_id);
+ glBindVertexArray(surface->array_id);
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+
+ for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+ if (!attribs[i].enabled)
+ continue;
+
+ glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+ glEnableVertexAttribArray(attribs[i].index);
+
+ }
+
+ if (surface->index_id) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ }
+
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+ }
+
+ {
+
+ //blend shapes
+
+ for(int i=0;i<p_blend_shapes.size();i++) {
+
+ Surface::MorphTarget mt;
+
+ DVector<uint8_t>::Read vr = p_blend_shapes[i].read();
+
+ glGenBuffers(1,&mt.vertex_id);
+ glBindBuffer(GL_ARRAY_BUFFER,mt.vertex_id);
+ glBufferData(GL_ARRAY_BUFFER,array_size,vr.ptr(),GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+ glGenVertexArrays(1,&mt.array_id);
+ glBindVertexArray(mt.array_id);
+ glBindBuffer(GL_ARRAY_BUFFER,mt.vertex_id);
+
+ for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+ if (!attribs[i].enabled)
+ continue;
+
+ glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+ glEnableVertexAttribArray(attribs[i].index);
+
+ }
+
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+ surface->morph_targets.push_back(mt);
+
+ }
+ }
+
+ mesh->surfaces.push_back(surface);
+ mesh->instance_change_notify();
}
void RasterizerStorageGLES3::mesh_set_morph_target_count(RID p_mesh,int p_amount){
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+
+ ERR_FAIL_COND(mesh->surfaces.size()!=0);
+ ERR_FAIL_COND(p_amount<0);
+
+ mesh->morph_target_count=p_amount;
}
int RasterizerStorageGLES3::mesh_get_morph_target_count(RID p_mesh) const{
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,0);
+
+ return mesh->morph_target_count;
}
void RasterizerStorageGLES3::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode){
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ mesh->morph_target_mode=p_mode;
}
VS::MorphTargetMode RasterizerStorageGLES3::mesh_get_morph_target_mode(RID p_mesh) const{
- return VS::MORPH_MODE_NORMALIZED;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,VS::MORPH_MODE_NORMALIZED);
+
+ return mesh->morph_target_mode;
}
void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material){
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_surface,mesh->surfaces.size());
+
+ mesh->surfaces[p_surface]->material=p_material;
}
RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{
- return RID();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,RID());
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),RID());
+
+ return mesh->surfaces[p_surface]->material;
}
int RasterizerStorageGLES3::mesh_surface_get_array_len(RID p_mesh, int p_surface) const{
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,0);
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),0);
+
+ return mesh->surfaces[p_surface]->array_len;
+
}
int RasterizerStorageGLES3::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const{
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,0);
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),0);
- return 0;
+ return mesh->surfaces[p_surface]->index_array_len;
}
DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int p_surface) const{
- return DVector<uint8_t>();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,DVector<uint8_t>());
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),DVector<uint8_t>());
+
+ Surface *surface = mesh->surfaces[p_surface];
+
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_len,GL_MAP_READ_BIT);
+
+ ERR_FAIL_COND_V(!data,DVector<uint8_t>());
+
+ DVector<uint8_t> ret;
+ ret.resize(surface->array_len);
+
+ {
+
+ DVector<uint8_t>::Write w = ret.write();
+ copymem(w.ptr(),data,surface->array_len);
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+
+ return ret;
}
-DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const{
+DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const {
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,DVector<uint8_t>());
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),DVector<uint8_t>());
+
+ Surface *surface = mesh->surfaces[p_surface];
+
+ ERR_FAIL_COND_V(surface->index_array_len==0,DVector<uint8_t>());
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->vertex_id);
+ void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_len,GL_MAP_READ_BIT);
+
+ ERR_FAIL_COND_V(!data,DVector<uint8_t>());
+
+ DVector<uint8_t> ret;
+ ret.resize(surface->index_array_len);
+
+ {
+
+ DVector<uint8_t>::Write w = ret.write();
+ copymem(w.ptr(),data,surface->index_array_len);
+ }
+
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
- return DVector<uint8_t>();
+ return ret;
}
uint32_t RasterizerStorageGLES3::mesh_surface_get_format(RID p_mesh, int p_surface) const{
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+
+ ERR_FAIL_COND_V(!mesh,0);
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),0);
+
+ return mesh->surfaces[p_surface]->format;
+
}
+
VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const{
- return VS::PRIMITIVE_MAX;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_MAX);
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),VS::PRIMITIVE_MAX);
+
+ return mesh->surfaces[p_surface]->primitive;
}
-void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh,int p_index){
+void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_surface,mesh->surfaces.size());
+ Surface *surface = mesh->surfaces[p_surface];
+ ERR_FAIL_COND(surface->index_array_len==0);
+
+ glDeleteBuffers(1,&surface->array_id);
+ if (surface->index_id) {
+ glDeleteBuffers(1,&surface->index_id);
+ }
+
+ glDeleteVertexArrays(1,&surface->array_id);
+
+ for(int i=0;i<surface->morph_targets.size();i++) {
+
+ glDeleteBuffers(1,&surface->morph_targets[i].vertex_id);
+ glDeleteVertexArrays(1,&surface->morph_targets[i].array_id);
+ }
+
+ memdelete(surface);
+
+ mesh->surfaces.remove(p_surface);
+
+ mesh->instance_change_notify();
}
int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const{
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,0);
+ return mesh->surfaces.size();
+
}
void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb){
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ mesh->custom_aabb=p_aabb;
}
AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const{
- return AABB();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,AABB());
+
+ return mesh->custom_aabb;
+
}
-AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh) const{
+AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
+
+ Mesh *mesh = mesh_owner.get( p_mesh );
+ ERR_FAIL_COND_V(!mesh,AABB());
+
+ if (mesh->custom_aabb!=AABB())
+ return mesh->custom_aabb;
+/*
+ Skeleton *sk=NULL;
+ if (p_skeleton.is_valid())
+ sk=skeleton_owner.get(p_skeleton);
+*/
+ AABB aabb;
+ /*
+ if (sk && sk->bones.size()!=0) {
+
+
+ for (int i=0;i<mesh->surfaces.size();i++) {
+
+ AABB laabb;
+ if (mesh->surfaces[i]->format&VS::ARRAY_FORMAT_BONES && mesh->surfaces[i]->skeleton_bone_aabb.size()) {
+
+
+ int bs = mesh->surfaces[i]->skeleton_bone_aabb.size();
+ const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr();
+ const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr();
+
+ int sbs = sk->bones.size();
+ ERR_CONTINUE(bs>sbs);
+ Skeleton::Bone *skb = sk->bones.ptr();
+
+ bool first=true;
+ for(int j=0;j<bs;j++) {
+
+ if (!skused[j])
+ continue;
+ AABB baabb = skb[ j ].transform_aabb ( skbones[j] );
+ if (first) {
+ laabb=baabb;
+ first=false;
+ } else {
+ laabb.merge_with(baabb);
+ }
+ }
+
+ } else {
+
+ laabb=mesh->surfaces[i]->aabb;
+ }
+
+ if (i==0)
+ aabb=laabb;
+ else
+ aabb.merge_with(laabb);
+ }
+ } else {
+*/
+ for (int i=0;i<mesh->surfaces.size();i++) {
+
+ if (i==0)
+ aabb=mesh->surfaces[i]->aabb;
+ else
+ aabb.merge_with(mesh->surfaces[i]->aabb);
+ }
+/*
+ }
+*/
+ return aabb;
- return AABB();
}
void RasterizerStorageGLES3::mesh_clear(RID p_mesh){
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ while(mesh->surfaces.size()) {
+ mesh_remove_surface(p_mesh,0);
+ }
}
/* MULTIMESH API */
@@ -2206,6 +2826,16 @@ void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::L
}
+VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
+
+ return VS::LIGHT_DIRECTIONAL;
+}
+
+AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const {
+
+ return AABB();
+}
+
/* PROBE API */
RID RasterizerStorageGLES3::reflection_probe_create(){
@@ -2292,6 +2922,42 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color
}
+void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance) {
+
+ Instantiable *inst=NULL;
+ switch(p_instance->base_type) {
+ case VS::INSTANCE_MESH: {
+ inst = mesh_owner.getornull(p_base);
+ ERR_FAIL_COND(!inst);
+ } break;
+ default: {
+ ERR_FAIL();
+ }
+ }
+
+ inst->instance_list.add( &p_instance->dependency_item );
+}
+
+void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance){
+
+ Instantiable *inst=NULL;
+
+ switch(p_instance->base_type) {
+ case VS::INSTANCE_MESH: {
+ inst = mesh_owner.getornull(p_base);
+ ERR_FAIL_COND(!inst);
+
+ } break;
+ default: {
+ ERR_FAIL();
+ }
+ }
+
+ ERR_FAIL_COND(!inst);
+
+ inst->instance_list.remove( &p_instance->dependency_item );
+}
+
/* RENDER TARGET */
@@ -2773,6 +3439,15 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder,
}
+VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
+
+ if (mesh_owner.owns(p_rid)) {
+ return VS::INSTANCE_MESH;
+ }
+
+ return VS::INSTANCE_NONE;
+}
+
bool RasterizerStorageGLES3::free(RID p_rid){
if (render_target_owner.owns(p_rid)) {
@@ -2834,6 +3509,15 @@ bool RasterizerStorageGLES3::free(RID p_rid){
material_owner.free(p_rid);
memdelete(material);
+ } else if (mesh_owner.owns(p_rid)) {
+
+ // delete the texture
+ Mesh *mesh = mesh_owner.get(p_rid);
+
+ mesh_clear(p_rid);
+
+ mesh_owner.free(p_rid);
+ memdelete(mesh);
} else if (canvas_occluder_owner.owns(p_rid)) {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index b7b3e607c6..950d65b9d0 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -10,12 +10,14 @@
#include "shader_compiler_gles3.h"
class RasterizerCanvasGLES3;
+class RasterizerSceneGLES3;
class RasterizerStorageGLES3 : public RasterizerStorage {
public:
RasterizerCanvasGLES3 *canvas;
+ RasterizerSceneGLES3 *scene;
enum FBOFormat {
FBO_FORMAT_16_BITS,
@@ -59,6 +61,7 @@ public:
ShaderCompilerGLES3 compiler;
ShaderCompilerGLES3::IdentifierActions actions_canvas;
+ ShaderCompilerGLES3::IdentifierActions actions_scene;
} shaders;
struct Resources {
@@ -230,6 +233,40 @@ public:
} canvas_item;
+ struct Spatial {
+
+ enum BlendMode {
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ };
+
+ int blend_mode;
+
+ enum DepthDrawMode {
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS,
+ DEPTH_DRAW_NEVER,
+ DEPTH_DRAW_ALPHA_PREPASS,
+ };
+
+ int depth_draw_mode;
+
+ enum CullMode {
+ CULL_MODE_FRONT,
+ CULL_MODE_BACK,
+ CULL_MODE_DISABLED,
+ };
+
+ int cull_mode;
+
+ bool uses_alpha;
+ bool unshaded;
+ bool ontop;
+
+ } spatial;
+
Shader() : dirty_list(this) {
shader=NULL;
@@ -272,10 +309,14 @@ public:
SelfList<Material> dirty_list;
Vector<RID> textures;
+ uint32_t index;
+ uint64_t last_pass;
+
Material() : list(this), dirty_list(this) {
shader=NULL;
ubo_id=0;
ubo_size=0;
+ last_pass=0;
}
};
@@ -300,9 +341,155 @@ public:
/* MESH API */
+ struct Instantiable : public RID_Data {
+
+ enum Type {
+ GEOMETRY_INVALID,
+ GEOMETRY_SURFACE,
+ GEOMETRY_IMMEDIATE,
+ GEOMETRY_MULTISURFACE,
+ };
+
+ SelfList<RasterizerScene::InstanceBase>::List instance_list;
+
+ _FORCE_INLINE_ void instance_change_notify() {
+
+ SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
+ while(instances) {
+
+ instances->self()->base_changed();
+ instances=instances->next();
+ }
+ }
+
+ Instantiable() { }
+ virtual ~Instantiable() {
+
+ while(instance_list.first()) {
+ instance_list.first()->self()->base_removed();
+ }
+ }
+ };
+
+ struct Geometry : Instantiable {
+
+ enum Type {
+ GEOMETRY_INVALID,
+ GEOMETRY_SURFACE,
+ GEOMETRY_IMMEDIATE,
+ GEOMETRY_MULTISURFACE,
+ };
+
+ Type type;
+ RID material;
+ uint64_t last_pass;
+ uint32_t index;
+
+ Geometry() {
+ last_pass=0;
+ index=0;
+ }
+
+ };
+
+ struct GeometryOwner : public Instantiable {
+
+ virtual ~GeometryOwner() {}
+ };
+
+ struct Mesh;
+ struct Surface : public Geometry {
+
+ struct Attrib {
+
+ bool enabled;
+ GLuint index;
+ GLint size;
+ GLenum type;
+ GLboolean normalized;
+ GLsizei stride;
+ uint32_t offset;
+ };
+
+ Attrib attribs[VS::ARRAY_MAX];
+ Attrib morph_attribs[VS::ARRAY_MAX];
+
+
+ Mesh *mesh;
+ uint32_t format;
+
+ GLuint array_id;
+ GLuint vertex_id;
+ GLuint index_id;
+
+ Vector<AABB> skeleton_bone_aabb;
+ Vector<bool> skeleton_bone_used;
+
+ //bool packed;
+
+ struct MorphTarget {
+ GLuint vertex_id;
+ GLuint array_id;
+ };
+
+ Vector<MorphTarget> morph_targets;
+
+ AABB aabb;
+
+ int array_len;
+ int index_array_len;
+ int max_bone;
+
+ int array_bytes;
+
+
+ VS::PrimitiveType primitive;
+
+ bool active;
+
+ Surface() {
+
+ array_bytes=0;
+ mesh=NULL;
+ format=0;
+ array_id=0;
+ vertex_id=0;
+ index_id=0;
+ array_len=0;
+ type=GEOMETRY_SURFACE;
+ primitive=VS::PRIMITIVE_POINTS;
+ index_array_len=0;
+ active=false;
+
+ }
+
+ ~Surface() {
+
+ }
+ };
+
+
+ struct Mesh : public GeometryOwner {
+
+ bool active;
+ Vector<Surface*> surfaces;
+ int morph_target_count;
+ VS::MorphTargetMode morph_target_mode;
+ AABB custom_aabb;
+ mutable uint64_t last_pass;
+ Mesh() {
+ morph_target_mode=VS::MORPH_MODE_NORMALIZED;
+ morph_target_count=0;
+ last_pass=0;
+ active=false;
+ }
+ };
+
+ mutable RID_Owner<Mesh> mesh_owner;
+
virtual RID mesh_create();
- virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >());
+ virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >(),const Vector<AABB>& p_bone_aabbs=Vector<AABB>());
virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount);
virtual int mesh_get_morph_target_count(RID p_mesh) const;
@@ -324,13 +511,13 @@ public:
virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
- virtual void mesh_remove_surface(RID p_mesh,int p_index);
+ virtual void mesh_remove_surface(RID p_mesh, int p_surface);
virtual int mesh_get_surface_count(RID p_mesh) const;
virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb);
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
- virtual AABB mesh_get_aabb(RID p_mesh) const;
+ virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const;
virtual void mesh_clear(RID p_mesh);
/* MULTIMESH API */
@@ -401,6 +588,8 @@ public:
virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode);
+ virtual VS::LightType light_get_type(RID p_light) const;
+ virtual AABB light_get_aabb(RID p_light) const;
/* PROBE API */
virtual RID reflection_probe_create();
@@ -434,6 +623,9 @@ public:
virtual void portal_set_disabled_color(RID p_portal, const Color& p_color);
+ virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance);
+ virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance);
+
/* RENDER TARGET */
struct RenderTarget : public RID_Data {
@@ -522,6 +714,8 @@ public:
virtual RID canvas_light_occluder_create();
virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines);
+ virtual VS::InstanceType get_base_type(RID p_rid) const;
+
virtual bool free(RID p_rid);
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 35191fecf7..ebdf60cf42 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -662,8 +662,8 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
fragment_code0=code.ascii();
} else {
fragment_code0=code.substr(0,cpos).ascii();
- code = code.substr(cpos+globals_tag.length(),code.length());
-
+ //print_line("CODE0:\n"+String(fragment_code0.get_data()));
+ code = code.substr(cpos+globals_tag.length(),code.length());
cpos = code.find(material_tag);
if (cpos==-1) {
@@ -671,14 +671,18 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
} else {
fragment_code1=code.substr(0,cpos).ascii();
- String code2 = code.substr(cpos+material_tag.length(),code.length());
+ //print_line("CODE1:\n"+String(fragment_code1.get_data()));
+ String code2 = code.substr(cpos+material_tag.length(),code.length());
cpos = code2.find(code_tag);
+
if (cpos==-1) {
fragment_code2=code2.ascii();
} else {
fragment_code2=code2.substr(0,cpos).ascii();
+ //print_line("CODE2:\n"+String(fragment_code2.get_data()));
+
String code3 = code2.substr(cpos+code_tag.length(),code2.length());
cpos = code3.find(light_code_tag);
@@ -687,7 +691,9 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
} else {
fragment_code3=code3.substr(0,cpos).ascii();
+ // print_line("CODE3:\n"+String(fragment_code3.get_data()));
fragment_code4 = code3.substr(cpos+light_code_tag.length(),code3.length()).ascii();
+ //print_line("CODE4:\n"+String(fragment_code4.get_data()));
}
}
}
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 628fa14e4e..0fa0e3b73a 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -4,4 +4,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
env.GLES3_GLSL('copy.glsl');
env.GLES3_GLSL('canvas.glsl');
env.GLES3_GLSL('canvas_shadow.glsl');
+ env.GLES3_GLSL('scene.glsl');
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
new file mode 100644
index 0000000000..4183e828f5
--- /dev/null
+++ b/drivers/gles3/shaders/scene.glsl
@@ -0,0 +1,351 @@
+[vertex]
+
+
+
+/*
+from VisualServer:
+
+ARRAY_VERTEX=0,
+ARRAY_NORMAL=1,
+ARRAY_TANGENT=2,
+ARRAY_COLOR=3,
+ARRAY_TEX_UV=4,
+ARRAY_TEX_UV2=5,
+ARRAY_BONES=6,
+ARRAY_WEIGHTS=7,
+ARRAY_INDEX=8,
+*/
+
+//hack to use uv if no uv present so it works with lightmap
+
+
+/* INPUT ATTRIBS */
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=1) in vec3 normal_attrib;
+layout(location=2) in vec4 tangent_attrib;
+layout(location=3) in vec4 color_attrib;
+layout(location=4) in vec2 uv_attrib;
+layout(location=5) in vec2 uv2_attrib;
+
+uniform float normal_mult;
+
+#ifdef USE_SKELETON
+layout(location=6) mediump ivec4 bone_indices; // attrib:6
+layout(location=7) mediump vec4 bone_weights; // attrib:7
+uniform highp sampler2D skeleton_matrices;
+#endif
+
+#ifdef USE_ATTRIBUTE_INSTANCING
+
+layout(location=8) in highp vec4 instance_xform0;
+layout(location=9) in highp vec4 instance_xform1;
+layout(location=10) in highp vec4 instance_xform2;
+layout(location=11) in lowp vec4 instance_color;
+
+#endif
+
+layout(std140) uniform SceneData { //ubo:0
+
+ highp mat4 projection_matrix;
+ highp mat4 camera_inverse_matrix;
+ highp mat4 camera_matrix;
+ highp vec4 time;
+
+ highp vec4 ambient_light;
+};
+
+uniform highp mat4 world_transform;
+
+/* Varyings */
+
+out vec3 vertex_interp;
+out vec3 normal_interp;
+
+#if defined(ENABLE_COLOR_INTERP)
+out vec4 color_interp;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+out vec2 uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+out vec2 uv2_interp;
+#endif
+
+#if defined(ENABLE_VAR1_INTERP)
+out vec4 var1_interp;
+#endif
+
+#if defined(ENABLE_VAR2_INTERP)
+out vec4 var2_interp;
+#endif
+
+#if defined(ENABLE_TANGENT_INTERP)
+out vec3 tangent_interp;
+out vec3 binormal_interp;
+#endif
+
+
+#if !defined(USE_DEPTH_SHADOWS) && defined(USE_SHADOW_PASS)
+
+varying vec4 position_interp;
+
+#endif
+
+#ifdef USE_SHADOW_PASS
+
+uniform highp float shadow_z_offset;
+uniform highp float shadow_z_slope_scale;
+
+#endif
+
+
+VERTEX_SHADER_GLOBALS
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData { //ubo:1
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+
+void main() {
+
+ highp vec4 vertex_in = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0);
+ highp mat4 modelview = camera_inverse_matrix * world_transform;
+ vec3 normal_in = normal_attrib;
+ normal_in*=normal_mult;
+#if defined(ENABLE_TANGENT_INTERP)
+ vec3 tangent_in = tangent_attrib.xyz;
+ tangent_in*=normal_mult;
+ float binormalf = tangent_attrib.a;
+#endif
+
+#ifdef USE_SKELETON
+
+ {
+ //skeleton transform
+ highp mat4 m=mat4(texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.x;
+ m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.y;
+ m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.z;
+ m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.w;
+
+ vertex_in = vertex_in * m;
+ normal_in = (vec4(normal_in,0.0) * m).xyz;
+#if defined(ENABLE_TANGENT_INTERP)
+ tangent_in = (vec4(tangent_in,0.0) * m).xyz;
+#endif
+ }
+
+#endif
+
+ vertex_interp = (modelview * vertex_in).xyz;
+ normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz);
+
+#if defined(ENABLE_TANGENT_INTERP)
+ tangent_interp=normalize((modelview * vec4(tangent_in,0.0)).xyz);
+ binormal_interp = normalize( cross(normal_interp,tangent_interp) * binormalf );
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+ color_interp = color_attrib;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+ uv_interp = uv_attrib;
+#endif
+#if defined(ENABLE_UV2_INTERP)
+ uv2_interp = uv2_attrib;
+#endif
+
+
+VERTEX_SHADER_CODE
+
+
+#ifdef USE_SHADOW_PASS
+
+ float z_ofs = shadow_z_offset;
+ z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale;
+ vertex_interp.z-=z_ofs;
+#endif
+
+
+#ifdef USE_FOG
+
+ fog_interp.a = pow( clamp( (length(vertex_interp)-fog_params.x)/(fog_params.y-fog_params.x), 0.0, 1.0 ), fog_params.z );
+ fog_interp.rgb = mix( fog_color_begin, fog_color_end, fog_interp.a );
+#endif
+
+#ifndef VERTEX_SHADER_WRITE_POSITION
+//vertex shader might write a position
+ gl_Position = projection_matrix * vec4(vertex_interp,1.0);
+#endif
+
+
+
+
+}
+
+
+[fragment]
+
+
+//hack to use uv if no uv present so it works with lightmap
+
+
+/* Varyings */
+
+#if defined(ENABLE_COLOR_INTERP)
+in vec4 color_interp;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+in vec2 uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+in vec2 uv2_interp;
+#endif
+
+#if defined(ENABLE_TANGENT_INTERP)
+in vec3 tangent_interp;
+in vec3 binormal_interp;
+#endif
+
+#if defined(ENABLE_VAR1_INTERP)
+in vec4 var1_interp;
+#endif
+
+#if defined(ENABLE_VAR2_INTERP)
+in vec4 var2_interp;
+#endif
+
+in vec3 vertex_interp;
+in vec3 normal_interp;
+
+
+/* Material Uniforms */
+
+
+FRAGMENT_SHADER_GLOBALS
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData {
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+
+layout(std140) uniform SceneData {
+
+ highp mat4 projection_matrix;
+ highp mat4 camera_inverse_matrix;
+ highp mat4 camera_matrix;
+ highp vec4 time;
+
+ highp vec4 ambient_light;
+};
+
+layout(location=0) out vec4 frag_color;
+
+void main() {
+
+ //lay out everything, whathever is unused is optimized away anyway
+ vec3 vertex = vertex_interp;
+ vec3 albedo = vec3(0.9,0.9,0.9);
+ vec3 metal = vec3(0.0,0.0,0.0);
+ float rough = 0.0;
+ float alpha = 1.0;
+
+#ifdef METERIAL_DOUBLESIDED
+ float side=float(gl_FrontFacing)*2.0-1.0;
+#else
+ float side=1.0;
+#endif
+
+
+#if defined(ENABLE_TANGENT_INTERP)
+ vec3 binormal = normalize(binormal_interp)*side;
+ vec3 tangent = normalize(tangent_interp)*side;
+#endif
+ vec3 normal = normalize(normal_interp)*side;
+
+#if defined(ENABLE_UV_INTERP)
+ vec2 uv = uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+ vec2 uv2 = uv2_interp;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+ vec4 color = color_interp;
+#endif
+
+#if defined(ENABLE_NORMALMAP)
+
+ vec3 normalmap = vec3(0.0);
+#endif
+
+ float normaldepth=1.0;
+
+
+
+#if defined(ENABLE_DISCARD)
+ bool discard_=false;
+#endif
+
+{
+
+
+FRAGMENT_SHADER_CODE
+
+}
+
+#if defined(ENABLE_NORMALMAP)
+
+ normal = normalize( mix(normal_interp,tangent_interp * normalmap.x + binormal_interp * normalmap.y + normal_interp * normalmap.z,normaldepth) ) * side;
+
+#endif
+
+#if defined(ENABLE_DISCARD)
+ if (discard_) {
+ //easy to eliminate dead code
+ discard;
+ }
+#endif
+
+#ifdef ENABLE_CLIP_ALPHA
+ if (diffuse.a<0.99) {
+ //used for doublepass and shadowmapping
+ discard;
+ }
+#endif
+
+
+
+#if defined(USE_LIGHT_SHADER_CODE)
+//light is written by the light shader
+{
+
+LIGHT_SHADER_CODE
+
+}
+#endif
+
+ frag_color=vec4(albedo,alpha);
+}
+
+
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 865298f64e..d3f27687ca 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -33,6 +33,75 @@
#include "servers/visual_server.h"
#include "camera_matrix.h"
+#include "self_list.h"
+
+
+class RasterizerScene {
+public:
+
+
+ struct InstanceBase : RID_Data {
+
+ VS::InstanceType base_type;
+ RID base;
+
+ RID skeleton;
+ RID material_override;
+
+ Transform transform;
+
+ int depth_layer;
+
+ //RID sampled_light;
+
+ Vector<RID> materials;
+ Vector<RID> light_instances;
+
+ Vector<float> morph_values;
+
+ //BakedLightData *baked_light;
+ VS::ShadowCastingSetting cast_shadows;
+ //Transform *baked_light_octree_xform;
+ //int baked_lightmap_id;
+
+ bool mirror :8;
+ bool depth_scale :8;
+ bool billboard :8;
+ bool billboard_y :8;
+ bool receive_shadows : 8;
+
+ SelfList<InstanceBase> dependency_item;
+
+ virtual void base_removed()=0;
+ virtual void base_changed()=0;
+
+ InstanceBase() : dependency_item(this) {
+
+ base_type=VS::INSTANCE_NONE;
+ cast_shadows=VS::SHADOW_CASTING_SETTING_ON;
+ receive_shadows=true;
+ depth_scale=false;
+ billboard=false;
+ billboard_y=false;
+ depth_layer=0;
+
+ }
+ };
+
+ virtual RID light_instance_create(RID p_light)=0;
+ virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform)=0;
+
+ virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment)=0;
+
+ virtual bool free(RID p_rid)=0;
+
+ virtual ~RasterizerScene() {}
+};
+
+
+
+
+
class RasterizerStorage {
@@ -88,7 +157,7 @@ public:
virtual RID mesh_create()=0;
- virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >())=0;
+ virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >(),const Vector<AABB>& p_bone_aabbs=Vector<AABB>())=0;
virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount)=0;
virtual int mesh_get_morph_target_count(RID p_mesh) const=0;
@@ -116,7 +185,7 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb)=0;
virtual AABB mesh_get_custom_aabb(RID p_mesh) const=0;
- virtual AABB mesh_get_aabb(RID p_mesh) const=0;
+ virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const=0;
virtual void mesh_clear(RID p_mesh)=0;
/* MULTIMESH API */
@@ -184,9 +253,11 @@ public:
virtual void light_set_cull_mask(RID p_light,uint32_t p_mask)=0;
virtual void light_set_shader(RID p_light,RID p_shader)=0;
-
virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode)=0;
+ virtual VS::LightType light_get_type(RID p_light) const=0;
+ virtual AABB light_get_aabb(RID p_light) const=0;
+
/* PROBE API */
virtual RID reflection_probe_create()=0;
@@ -220,6 +291,10 @@ public:
virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=0;
+
+ virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
+ virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
+
/* RENDER TARGET */
enum RenderTargetFlags {
@@ -246,6 +321,8 @@ public:
virtual RID canvas_light_occluder_create()=0;
virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines)=0;
+
+ virtual VS::InstanceType get_base_type(RID p_rid) const=0;
virtual bool free(RID p_rid)=0;
@@ -257,6 +334,7 @@ public:
+
class RasterizerCanvas {
public:
@@ -563,7 +641,7 @@ public:
case Item::Command::TYPE_MESH: {
const Item::CommandMesh* mesh = static_cast< const Item::CommandMesh*>(c);
- AABB aabb = RasterizerStorage::base_signleton->mesh_get_aabb(mesh->mesh);
+ AABB aabb = RasterizerStorage::base_signleton->mesh_get_aabb(mesh->mesh,mesh->skeleton);
r=Rect2(aabb.pos.x,aabb.pos.y,aabb.size.x,aabb.size.y);
@@ -654,17 +732,6 @@ public:
};
-
-class RasterizerScene {
-public:
-
-
-
- virtual ~RasterizerScene() {}
-};
-
-
-
class Rasterizer {
protected:
static Rasterizer* (*_create_func)();
@@ -689,8 +756,6 @@ public:
};
-
-
#if 0
/**
@author Juan Linietsky <reduzio@gmail.com>
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
index 1a01a19021..767d11bc84 100644
--- a/servers/visual/shader_types.cpp
+++ b/servers/visual/shader_types.cpp
@@ -58,8 +58,8 @@ ShaderTypes::ShaderTypes()
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ALBEDO"]=ShaderLanguage::TYPE_VEC3;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ALPHA"]=ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["METAL"]=ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ROUGH"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECULAR"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ROUGHNESS"]=ShaderLanguage::TYPE_FLOAT;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"]=ShaderLanguage::TYPE_VEC3;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT;
shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["DISCARD"]=ShaderLanguage::TYPE_BOOL;
@@ -77,10 +77,6 @@ ShaderTypes::ShaderTypes()
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_sub");
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mul");
- shader_modes[VS::SHADER_SPATIAL].modes.insert("special_glow");
- shader_modes[VS::SHADER_SPATIAL].modes.insert("special_subsurf");
- shader_modes[VS::SHADER_SPATIAL].modes.insert("special_specular");
-
shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_opaque");
shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_always");
shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_never");
@@ -90,12 +86,10 @@ ShaderTypes::ShaderTypes()
shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_back");
shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_disable");
- shader_modes[VS::SHADER_SPATIAL].modes.insert("lightmap_on_uv2");
shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded");
shader_modes[VS::SHADER_SPATIAL].modes.insert("ontop");
- shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_model_space");
- shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_camera_space");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_transform");
/************ CANVAS ITEM **************************/
@@ -158,4 +152,5 @@ ShaderTypes::ShaderTypes()
+
}
diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp
index d6e057bb52..70abfe2361 100644
--- a/servers/visual/visual_server_raster.cpp
+++ b/servers/visual/visual_server_raster.cpp
@@ -34,183 +34,12 @@
#include "io/marshalls.h"
#include "visual_server_canvas.h"
#include "visual_server_global.h"
+#include "visual_server_scene.h"
// careful, these may run in different threads than the visual server
-/* CAMERA API */
-
-RID VisualServerRaster::camera_create() {
-
- return RID();
-}
-void VisualServerRaster::camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far) {
-
-}
-void VisualServerRaster::camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far){
-
-}
-void VisualServerRaster::camera_set_transform(RID p_camera,const Transform& p_transform) {
-
-}
-void VisualServerRaster::camera_set_cull_mask(RID p_camera,uint32_t p_layers){
-
-}
-void VisualServerRaster::camera_set_environment(RID p_camera,RID p_env){
-
-}
-void VisualServerRaster::camera_set_use_vertical_aspect(RID p_camera,bool p_enable){
-
-}
-
-
-/* ENVIRONMENT API */
-
-RID VisualServerRaster::environment_create(){
-
- return RID();
-}
-
-void VisualServerRaster::environment_set_background(RID p_env,EnvironmentBG p_bg){
-
-}
-void VisualServerRaster::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){
-
-}
-void VisualServerRaster::environment_set_bg_color(RID p_env,const Color& p_color){
-
-}
-void VisualServerRaster::environment_set_canvas_max_layer(RID p_env,int p_max_layer){
-
-}
-void VisualServerRaster::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){
-
-}
-
-void VisualServerRaster::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,EnvironmentGlowBlendMode p_blend_mode){
-
-}
-void VisualServerRaster::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){
-
-}
-
-void VisualServerRaster::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,EnvironmentToneMapper p_tone_mapper){
-
-}
-void VisualServerRaster::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){
-
-}
-void VisualServerRaster::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){
-
-}
-void VisualServerRaster::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){
-
-}
-void VisualServerRaster::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){
-
-}
-
-
-/* SCENARIO API */
-
-
-RID VisualServerRaster::scenario_create() {
-
- return RID();
-}
-
-void VisualServerRaster::scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode){
-
-}
-void VisualServerRaster::scenario_set_environment(RID p_scenario, RID p_environment){
-
-}
-RID VisualServerRaster::scenario_get_environment(RID p_scenario, RID p_environment) const{
-
- return RID();
-}
-void VisualServerRaster::scenario_set_fallback_environment(RID p_scenario, RID p_environment){
-
-}
-
-
-/* INSTANCING API */
-// from can be mesh, light, area and portal so far.
-RID VisualServerRaster::instance_create(){
-
- return RID();
-}
-
-void VisualServerRaster::instance_set_base(RID p_instance, RID p_base){
-
-}
-void VisualServerRaster::instance_set_scenario(RID p_instance, RID p_scenario){
-
-}
-void VisualServerRaster::instance_set_layer_mask(RID p_instance, uint32_t p_mask){
-
-}
-void VisualServerRaster::instance_set_transform(RID p_instance, const Transform& p_transform){
-
-}
-void VisualServerRaster::instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID){
-
-}
-void VisualServerRaster::instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight){
-
-}
-void VisualServerRaster::instance_set_surface_material(RID p_instance,int p_surface, RID p_material){
-
-}
-
-void VisualServerRaster::instance_attach_skeleton(RID p_instance,RID p_skeleton){
-
-}
-void VisualServerRaster::instance_set_exterior( RID p_instance, bool p_enabled ){
-
-}
-void VisualServerRaster::instance_set_room( RID p_instance, RID p_room ){
-
-}
-
-void VisualServerRaster::instance_set_extra_visibility_margin( RID p_instance, real_t p_margin ){
-
-}
-
-// don't use these in a game!
-Vector<ObjectID> VisualServerRaster::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{
-
- return Vector<ObjectID>();
-}
-
-Vector<ObjectID> VisualServerRaster::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{
-
- return Vector<ObjectID>();
-}
-Vector<ObjectID> VisualServerRaster::instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario) const {
-
- return Vector<ObjectID>();
-}
-
-
-void VisualServerRaster::instance_geometry_set_flag(RID p_instance,InstanceFlags p_flags,bool p_enabled){
-
-}
-void VisualServerRaster::instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) {
-
-}
-void VisualServerRaster::instance_geometry_set_material_override(RID p_instance, RID p_material){
-
-}
-
-
-void VisualServerRaster::instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin){
-
-}
-void VisualServerRaster::instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance){
-
-}
/* CURSOR */
void VisualServerRaster::cursor_set_rotation(float p_rotation, int p_cursor ){
@@ -247,6 +76,8 @@ void VisualServerRaster::free( RID p_rid ){
return;
if (VSG::viewport->free(p_rid))
return;
+ if (VSG::scene->free(p_rid))
+ return;
}
@@ -258,6 +89,9 @@ void VisualServerRaster::draw(){
// print_line("changes: "+itos(changes));
changes=0;
+
+ VSG::scene->update_dirty_instances(); //update scene stuff
+
VSG::rasterizer->begin_frame();
VSG::viewport->draw_viewports();
//_draw_cursors_and_margins();
@@ -322,6 +156,7 @@ VisualServerRaster::VisualServerRaster() {
VSG::canvas = memnew( VisualServerCanvas);
VSG::viewport = memnew( VisualServerViewport);
+ VSG::scene = memnew( VisualServerScene );
VSG::rasterizer = Rasterizer::create();
VSG::storage=VSG::rasterizer->get_storage();
VSG::canvas_render=VSG::rasterizer->get_canvas();
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 2171998f3f..62d45f8206 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -37,6 +37,7 @@
#include "visual_server_global.h"
#include "visual_server_viewport.h"
#include "visual_server_canvas.h"
+#include "visual_server_scene.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -600,6 +601,7 @@ public:
#define BIND6(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6); }
#define BIND7(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7); }
#define BIND8(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7,m_type8) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7,m_type8 arg8) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); }
+#define BIND9(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7,m_type8,m_type9) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7,m_type8 arg8,m_type9 arg9) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); }
#define BIND10(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7,m_type8,m_type9,m_type10) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7,m_type8 arg8,m_type9 arg9,m_type10 arg10) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10); }
//from now on, calls forwarded to this singleton
@@ -659,7 +661,7 @@ public:
BIND0R(RID,mesh_create)
- BIND8(mesh_add_surface,RID,uint32_t,PrimitiveType,const DVector<uint8_t>&,int ,const DVector<uint8_t>& ,int ,const Vector<DVector<uint8_t> >& )
+ BIND10(mesh_add_surface,RID,uint32_t,PrimitiveType,const DVector<uint8_t>&,int ,const DVector<uint8_t>& ,int ,const AABB&,const Vector<DVector<uint8_t> >&,const Vector<AABB>& )
BIND2(mesh_set_morph_target_count,RID,int)
BIND1RC(int,mesh_get_morph_target_count,RID)
@@ -788,13 +790,18 @@ public:
/* CAMERA API */
- virtual RID camera_create();
- virtual void camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far);
- virtual void camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far);
- virtual void camera_set_transform(RID p_camera,const Transform& p_transform);
- virtual void camera_set_cull_mask(RID p_camera,uint32_t p_layers);
- virtual void camera_set_environment(RID p_camera,RID p_env);
- virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable);
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE VSG::scene
+
+
+ BIND0R(RID, camera_create)
+ BIND4(camera_set_perspective,RID,float, float , float )
+ BIND4(camera_set_orthogonal,RID,float , float , float )
+ BIND2(camera_set_transform,RID,const Transform&)
+ BIND2(camera_set_cull_mask,RID,uint32_t )
+ BIND2(camera_set_environment,RID ,RID )
+ BIND2(camera_set_use_vertical_aspect,RID,bool)
#undef BINDBASE
//from now on, calls forwarded to this singleton
@@ -839,66 +846,69 @@ public:
/* ENVIRONMENT API */
- virtual RID environment_create();
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE VSG::scene
+
+ BIND0R(RID,environment_create)
- virtual void environment_set_background(RID p_env,EnvironmentBG p_bg);
- virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0);
- virtual void environment_set_bg_color(RID p_env,const Color& p_color);
- virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer);
- virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0);
+ BIND2(environment_set_background,RID ,EnvironmentBG )
+ BIND3(environment_set_skybox,RID,RID ,float )
+ BIND2(environment_set_bg_color,RID,const Color& )
+ BIND2(environment_set_canvas_max_layer,RID,int )
+ BIND3(environment_set_ambient_light,RID,const Color& ,float )
- virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,EnvironmentGlowBlendMode p_blend_mode);
- virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture);
+ BIND7(environment_set_glow,RID,bool ,int ,float ,float ,float ,EnvironmentGlowBlendMode )
+ BIND5(environment_set_fog,RID,bool ,float ,float ,RID )
- virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,EnvironmentToneMapper p_tone_mapper);
- virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness);
- virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast);
- virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation);
- virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp);
+ BIND8(environment_set_tonemap,RID,bool ,float ,float ,float ,float ,float ,EnvironmentToneMapper )
+ BIND3(environment_set_brightness,RID,bool ,float )
+ BIND3(environment_set_contrast,RID,bool ,float )
+ BIND3(environment_set_saturation,RID,bool ,float )
+ BIND3(environment_set_color_correction,RID,bool ,RID )
/* SCENARIO API */
- virtual RID scenario_create();
+ BIND0R(RID,scenario_create)
- virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode);
- virtual void scenario_set_environment(RID p_scenario, RID p_environment);
- virtual RID scenario_get_environment(RID p_scenario, RID p_environment) const;
- virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+ BIND2(scenario_set_debug,RID,ScenarioDebugMode )
+ BIND2(scenario_set_environment,RID, RID )
+ BIND2(scenario_set_fallback_environment,RID, RID )
/* INSTANCING API */
// from can be mesh, light, area and portal so far.
- virtual RID instance_create(); // from can be mesh, light, poly, area and portal so far.
+ BIND0R(RID,instance_create)
- virtual void instance_set_base(RID p_instance, RID p_base); // from can be mesh, light, poly, area and portal so far.
- virtual void instance_set_scenario(RID p_instance, RID p_scenario); // from can be mesh, light, poly, area and portal so far.
- virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
- virtual void instance_set_transform(RID p_instance, const Transform& p_transform);
- virtual void instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID);
- virtual void instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight);
- virtual void instance_set_surface_material(RID p_instance,int p_surface, RID p_material);
+ BIND2(instance_set_base,RID, RID ) // from can be mesh, light, poly, area and portal so far.
+ BIND2(instance_set_scenario,RID, RID ) // from can be mesh, light, poly, area and portal so far.
+ BIND2(instance_set_layer_mask,RID, uint32_t )
+ BIND2(instance_set_transform,RID, const Transform& )
+ BIND2(instance_attach_object_instance_ID,RID,ObjectID )
+ BIND3(instance_set_morph_target_weight,RID,int , float )
+ BIND3(instance_set_surface_material,RID,int , RID )
- virtual void instance_attach_skeleton(RID p_instance,RID p_skeleton);
- virtual void instance_set_exterior( RID p_instance, bool p_enabled );
- virtual void instance_set_room( RID p_instance, RID p_room );
+ BIND2(instance_attach_skeleton,RID,RID )
+ BIND2(instance_set_exterior, RID, bool )
+ BIND2(instance_set_room, RID, RID )
- virtual void instance_set_extra_visibility_margin( RID p_instance, real_t p_margin );
+ BIND2(instance_set_extra_visibility_margin, RID, real_t )
// don't use these in a game!
- virtual Vector<ObjectID> instances_cull_aabb(const AABB& p_aabb, RID p_scenario=RID()) const;
- virtual Vector<ObjectID> instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario=RID()) const;
- virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario=RID()) const;
+ BIND2RC(Vector<ObjectID>,instances_cull_aabb,const AABB& , RID)
+ BIND3RC(Vector<ObjectID>,instances_cull_ray,const Vector3& , const Vector3& , RID )
+ BIND2RC(Vector<ObjectID>,instances_cull_convex,const Vector<Plane>& , RID)
- virtual void instance_geometry_set_flag(RID p_instance,InstanceFlags p_flags,bool p_enabled);
- virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting);
- virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
+ BIND3(instance_geometry_set_flag,RID,InstanceFlags ,bool )
+ BIND2(instance_geometry_set_cast_shadows_setting,RID, ShadowCastingSetting )
+ BIND2(instance_geometry_set_material_override,RID, RID )
- virtual void instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin);
- virtual void instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance);
+ BIND5(instance_geometry_set_draw_range,RID,float ,float ,float ,float )
+ BIND2(instance_geometry_set_as_instance_lod,RID,RID )
#undef BINDBASE
@@ -1055,6 +1065,7 @@ public:
#undef BIND6
#undef BIND7
#undef BIND8
+#undef BIND9
#undef BIND10
};
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
new file mode 100644
index 0000000000..a3b1d76fb8
--- /dev/null
+++ b/servers/visual/visual_server_scene.cpp
@@ -0,0 +1,1517 @@
+#include "visual_server_scene.h"
+#include "visual_server_global.h"
+
+/* CAMERA API */
+
+
+RID VisualServerScene::camera_create() {
+
+ Camera * camera = memnew( Camera );
+ return camera_owner.make_rid( camera );
+
+}
+
+void VisualServerScene::camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far) {
+
+ Camera *camera = camera_owner.get( p_camera );
+ ERR_FAIL_COND(!camera);
+ camera->type=Camera::PERSPECTIVE;
+ camera->fov=p_fovy_degrees;
+ camera->znear=p_z_near;
+ camera->zfar=p_z_far;
+
+}
+
+void VisualServerScene::camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far) {
+
+ Camera *camera = camera_owner.get( p_camera );
+ ERR_FAIL_COND(!camera);
+ camera->type=Camera::ORTHOGONAL;
+ camera->size=p_size;
+ camera->znear=p_z_near;
+ camera->zfar=p_z_far;
+}
+
+void VisualServerScene::camera_set_transform(RID p_camera,const Transform& p_transform) {
+
+ Camera *camera = camera_owner.get( p_camera );
+ ERR_FAIL_COND(!camera);
+ camera->transform=p_transform.orthonormalized();
+
+
+}
+
+void VisualServerScene::camera_set_cull_mask(RID p_camera,uint32_t p_layers) {
+
+
+ Camera *camera = camera_owner.get( p_camera );
+ ERR_FAIL_COND(!camera);
+
+ camera->visible_layers=p_layers;
+
+}
+
+void VisualServerScene::camera_set_environment(RID p_camera,RID p_env) {
+
+ Camera *camera = camera_owner.get( p_camera );
+ ERR_FAIL_COND(!camera);
+ camera->env=p_env;
+
+}
+
+
+void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera,bool p_enable) {
+
+ Camera *camera = camera_owner.get( p_camera );
+ ERR_FAIL_COND(!camera);
+ camera->vaspect=p_enable;
+
+}
+
+
+
+/* ENVIRONMENT API */
+
+RID VisualServerScene::environment_create(){
+
+ return RID();
+}
+
+void VisualServerScene::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){
+
+}
+void VisualServerScene::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){
+
+}
+void VisualServerScene::environment_set_bg_color(RID p_env,const Color& p_color){
+
+}
+void VisualServerScene::environment_set_canvas_max_layer(RID p_env,int p_max_layer){
+
+}
+void VisualServerScene::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){
+
+}
+
+void VisualServerScene::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){
+
+}
+void VisualServerScene::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){
+
+}
+
+void VisualServerScene::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){
+
+}
+void VisualServerScene::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){
+
+}
+void VisualServerScene::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){
+
+}
+void VisualServerScene::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){
+
+}
+void VisualServerScene::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){
+
+}
+
+
+/* SCENARIO API */
+
+
+
+void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int) {
+
+// VisualServerScene *self = (VisualServerScene*)p_self;
+ Instance *A = p_A;
+ Instance *B = p_B;
+
+ //instance indices are designed so greater always contains lesser
+ if (A->base_type > B->base_type) {
+ SWAP(A,B); //lesser always first
+ }
+
+ if (B->base_type==VS::INSTANCE_LIGHT && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceLightData * light = static_cast<InstanceLightData*>(B->base_data);
+ InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data);
+
+
+ InstanceLightData::PairInfo pinfo;
+ pinfo.geometry=A;
+ pinfo.L = geom->lighting.push_back(B);
+
+ List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo);
+
+ light->shadow_sirty=true;
+ geom->lighting_dirty=true;
+
+ return E; //this element should make freeing faster
+ }
+
+#if 0
+ if (A->base_type==INSTANCE_PORTAL) {
+
+ ERR_FAIL_COND_V( B->base_type!=INSTANCE_PORTAL,NULL );
+
+ A->portal_info->candidate_set.insert(B);
+ B->portal_info->candidate_set.insert(A);
+
+ self->_portal_attempt_connect(A);
+ //attempt to conncet portal A (will go through B anyway)
+ //this is a little hackish, but works fine in practice
+
+ } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+ if (B->base_type==INSTANCE_BAKED_LIGHT) {
+ SWAP(A,B);
+ }
+
+ ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL);
+ B->baked_light_sampler_info->baked_lights.insert(A);
+
+ } else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
+
+ if (B->base_type==INSTANCE_ROOM)
+ SWAP(A,B);
+
+ ERR_FAIL_COND_V(! ((1<<B->base_type)&INSTANCE_GEOMETRY_MASK ),NULL);
+
+ B->auto_rooms.insert(A);
+ A->room_info->owned_autoroom_geometry.insert(B);
+
+ self->_instance_validate_autorooms(B);
+
+
+ } else {
+
+ if (B->base_type==INSTANCE_LIGHT) {
+
+ SWAP(A,B);
+ } else if (A->base_type!=INSTANCE_LIGHT) {
+ return NULL;
+ }
+
+
+ A->light_info->affected.insert(B);
+ B->lights.insert(A);
+ B->light_cache_dirty=true;
+
+
+ }
+#endif
+
+ return NULL;
+
+}
+void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int,void* udata) {
+
+// VisualServerScene *self = (VisualServerScene*)p_self;
+ Instance *A = p_A;
+ Instance *B = p_B;
+
+ //instance indices are designed so greater always contains lesser
+ if (A->base_type > B->base_type) {
+ SWAP(A,B); //lesser always first
+ }
+
+
+
+ if (B->base_type==VS::INSTANCE_LIGHT && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceLightData * light = static_cast<InstanceLightData*>(B->base_data);
+ InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data);
+
+ List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element*>(udata);
+
+ geom->lighting.erase(E->get().L);
+ light->geometries.erase(E);
+
+ light->shadow_sirty=true;
+ geom->lighting_dirty=true;
+
+
+ }
+#if 0
+ if (A->base_type==INSTANCE_PORTAL) {
+
+ ERR_FAIL_COND( B->base_type!=INSTANCE_PORTAL );
+
+
+ A->portal_info->candidate_set.erase(B);
+ B->portal_info->candidate_set.erase(A);
+
+ //after disconnecting them, see if they can connect again
+ self->_portal_attempt_connect(A);
+ self->_portal_attempt_connect(B);
+
+ } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+ if (B->base_type==INSTANCE_BAKED_LIGHT) {
+ SWAP(A,B);
+ }
+
+ ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER);
+ B->baked_light_sampler_info->baked_lights.erase(A);
+
+ } else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
+
+ if (B->base_type==INSTANCE_ROOM)
+ SWAP(A,B);
+
+ ERR_FAIL_COND(! ((1<<B->base_type)&INSTANCE_GEOMETRY_MASK ));
+
+ B->auto_rooms.erase(A);
+ B->valid_auto_rooms.erase(A);
+ A->room_info->owned_autoroom_geometry.erase(B);
+
+ }else {
+
+
+
+ if (B->base_type==INSTANCE_LIGHT) {
+
+ SWAP(A,B);
+ } else if (A->base_type!=INSTANCE_LIGHT) {
+ return;
+ }
+
+
+ A->light_info->affected.erase(B);
+ B->lights.erase(A);
+ B->light_cache_dirty=true;
+
+ }
+#endif
+}
+
+RID VisualServerScene::scenario_create() {
+
+ Scenario *scenario = memnew( Scenario );
+ ERR_FAIL_COND_V(!scenario,RID());
+ RID scenario_rid = scenario_owner.make_rid( scenario );
+ scenario->self=scenario_rid;
+
+ scenario->octree.set_pair_callback(_instance_pair,this);
+ scenario->octree.set_unpair_callback(_instance_unpair,this);
+
+ return scenario_rid;
+}
+
+void VisualServerScene::scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode) {
+
+ Scenario *scenario = scenario_owner.get(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->debug=p_debug_mode;
+}
+
+void VisualServerScene::scenario_set_environment(RID p_scenario, RID p_environment) {
+
+ Scenario *scenario = scenario_owner.get(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->environment=p_environment;
+
+}
+
+void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
+
+
+ Scenario *scenario = scenario_owner.get(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->fallback_environment=p_environment;
+
+
+}
+
+
+
+/* INSTANCING API */
+
+void VisualServerScene::_instance_queue_update(Instance *p_instance,bool p_update_aabb,bool p_update_materials) {
+
+ if (p_update_aabb)
+ p_instance->update_aabb=true;
+ if (p_update_materials)
+ p_instance->update_materials=true;
+
+ if (p_instance->update_item.in_list())
+ return;
+
+ _instance_update_list.add(&p_instance->update_item);
+
+
+}
+
+// from can be mesh, light, area and portal so far.
+RID VisualServerScene::instance_create(){
+
+ Instance *instance = memnew( Instance );
+ ERR_FAIL_COND_V(!instance,RID());
+
+ RID instance_rid = instance_owner.make_rid(instance);
+ instance->self=instance_rid;
+
+
+ return instance_rid;
+
+
+}
+
+void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ Scenario *scenario = instance->scenario;
+
+ if (instance->base_type!=VS::INSTANCE_NONE) {
+ //free anything related to that base
+
+ VSG::storage->instance_remove_dependency(instance->base,instance);
+
+ if (scenario && instance->octree_id) {
+ scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
+ instance->octree_id=0;
+ }
+
+ switch(instance->base_type) {
+ case VS::INSTANCE_LIGHT: {
+
+ InstanceLightData *light = static_cast<InstanceLightData*>(instance->base_data);
+
+ if (instance->scenario && light->D) {
+ instance->scenario->directional_lights.erase( light->D );
+ light->D=NULL;
+ }
+ VSG::scene_render->free(light->instance);
+
+ }
+ }
+
+ if (instance->base_data) {
+ memdelete( instance->base_data );
+ instance->base_data=NULL;
+ }
+
+ instance->morph_values.clear();
+ instance->materials.clear();
+
+#if 0
+ if (instance->light_info) {
+
+ if (instance->scenario && instance->light_info->D)
+ instance->scenario->directional_lights.erase( instance->light_info->D );
+ rasterizer->free(instance->light_info->instance);
+ memdelete(instance->light_info);
+ instance->light_info=NULL;
+ }
+
+
+
+ if ( instance->room ) {
+
+ instance_set_room(p_instance,RID());
+ /*
+ if((1<<instance->base_type)&INSTANCE_GEOMETRY_MASK)
+ instance->room->room_info->owned_geometry_instances.erase(instance->RE);
+ else if (instance->base_type==INSTANCE_PORTAL) {
+ print_line("freeing portal, is it there? "+itos(instance->room->room_info->owned_portal_instances.(instance->RE)));
+ instance->room->room_info->owned_portal_instances.erase(instance->RE);
+ } else if (instance->base_type==INSTANCE_ROOM)
+ instance->room->room_info->owned_room_instances.erase(instance->RE);
+ else if (instance->base_type==INSTANCE_LIGHT)
+ instance->room->room_info->owned_light_instances.erase(instance->RE);
+
+ instance->RE=NULL;*/
+ }
+
+
+
+
+
+
+ if (instance->portal_info) {
+
+ _portal_disconnect(instance,true);
+ memdelete(instance->portal_info);
+ instance->portal_info=NULL;
+
+ }
+
+ if (instance->baked_light_info) {
+
+ while(instance->baked_light_info->owned_instances.size()) {
+
+ Instance *owned=instance->baked_light_info->owned_instances.front()->get();
+ owned->baked_light=NULL;
+ owned->data.baked_light=NULL;
+ owned->data.baked_light_octree_xform=NULL;
+ owned->BLE=NULL;
+ instance->baked_light_info->owned_instances.pop_front();
+ }
+
+ memdelete(instance->baked_light_info);
+ instance->baked_light_info=NULL;
+
+ }
+
+ if (instance->scenario && instance->octree_id) {
+ instance->scenario->octree.erase( instance->octree_id );
+ instance->octree_id=0;
+ }
+
+
+ if (instance->room_info) {
+
+ for(List<Instance*>::Element *E=instance->room_info->owned_geometry_instances.front();E;E=E->next()) {
+
+ Instance *owned = E->get();
+ owned->room=NULL;
+ owned->RE=NULL;
+ }
+ for(List<Instance*>::Element *E=instance->room_info->owned_portal_instances.front();E;E=E->next()) {
+
+ _portal_disconnect(E->get(),true);
+ Instance *owned = E->get();
+ owned->room=NULL;
+ owned->RE=NULL;
+ }
+
+ for(List<Instance*>::Element *E=instance->room_info->owned_room_instances.front();E;E=E->next()) {
+
+ Instance *owned = E->get();
+ owned->room=NULL;
+ owned->RE=NULL;
+ }
+
+ if (instance->room_info->disconnected_child_portals.size()) {
+ ERR_PRINT("BUG: Disconnected portals remain!");
+ }
+ memdelete(instance->room_info);
+ instance->room_info=NULL;
+
+ }
+
+ if (instance->particles_info) {
+
+ rasterizer->free( instance->particles_info->instance );
+ memdelete(instance->particles_info);
+ instance->particles_info=NULL;
+
+ }
+
+ if (instance->baked_light_sampler_info) {
+
+ while (instance->baked_light_sampler_info->owned_instances.size()) {
+
+ instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID());
+ }
+
+ if (instance->baked_light_sampler_info->sampled_light.is_valid()) {
+ rasterizer->free(instance->baked_light_sampler_info->sampled_light);
+ }
+ memdelete( instance->baked_light_sampler_info );
+ instance->baked_light_sampler_info=NULL;
+ }
+#endif
+
+ }
+
+
+ instance->base_type=VS::INSTANCE_NONE;
+ instance->base=RID();
+
+
+ if (p_base.is_valid()) {
+
+ instance->base_type=VSG::storage->get_base_type(p_base);
+ ERR_FAIL_COND(instance->base_type==VS::INSTANCE_NONE);
+
+ switch(instance->base_type) {
+ case VS::INSTANCE_LIGHT: {
+
+ InstanceLightData *light = memnew( InstanceLightData );
+
+ if (scenario && VSG::storage->light_get_type(p_base)==VS::LIGHT_DIRECTIONAL) {
+ light->D = scenario->directional_lights.push_back(instance);
+ }
+
+ light->instance = VSG::scene_render->light_instance_create(p_base);
+
+ instance->base_data=light;
+ }
+ case VS::INSTANCE_MESH: {
+
+ InstanceGeometryData *geom = memnew( InstanceGeometryData );
+ instance->base_data=geom;
+ }
+
+ }
+
+ VSG::storage->instance_add_dependency(p_base,instance);
+
+ instance->base=p_base;
+
+ if (scenario)
+ _instance_queue_update(instance,true,true);
+
+
+#if 0
+ if (rasterizer->is_mesh(p_base)) {
+ instance->base_type=INSTANCE_MESH;
+ instance->data.morph_values.resize( rasterizer->mesh_get_morph_target_count(p_base));
+ instance->data.materials.resize( rasterizer->mesh_get_surface_count(p_base));
+ } else if (rasterizer->is_multimesh(p_base)) {
+ instance->base_type=INSTANCE_MULTIMESH;
+ } else if (rasterizer->is_immediate(p_base)) {
+ instance->base_type=INSTANCE_IMMEDIATE;
+ } else if (rasterizer->is_particles(p_base)) {
+ instance->base_type=INSTANCE_PARTICLES;
+ instance->particles_info=memnew( Instance::ParticlesInfo );
+ instance->particles_info->instance = rasterizer->particles_instance_create( p_base );
+ } else if (rasterizer->is_light(p_base)) {
+
+ instance->base_type=INSTANCE_LIGHT;
+ instance->light_info = memnew( Instance::LightInfo );
+ instance->light_info->instance = rasterizer->light_instance_create(p_base);
+ if (instance->scenario && rasterizer->light_get_type(p_base)==LIGHT_DIRECTIONAL) {
+
+ instance->light_info->D = instance->scenario->directional_lights.push_back(instance->self);
+ }
+
+ } else if (room_owner.owns(p_base)) {
+ instance->base_type=INSTANCE_ROOM;
+ instance->room_info = memnew( Instance::RoomInfo );
+ instance->room_info->room=room_owner.get(p_base);
+ } else if (portal_owner.owns(p_base)) {
+
+ instance->base_type=INSTANCE_PORTAL;
+ instance->portal_info = memnew(Instance::PortalInfo);
+ instance->portal_info->portal=portal_owner.get(p_base);
+ } else if (baked_light_owner.owns(p_base)) {
+
+ instance->base_type=INSTANCE_BAKED_LIGHT;
+ instance->baked_light_info=memnew(Instance::BakedLightInfo);
+ instance->baked_light_info->baked_light=baked_light_owner.get(p_base);
+
+ //instance->portal_info = memnew(Instance::PortalInfo);
+ //instance->portal_info->portal=portal_owner.get(p_base);
+ } else if (baked_light_sampler_owner.owns(p_base)) {
+
+
+ instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER;
+ instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo);
+ instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base);
+
+ //instance->portal_info = memnew(Instance::PortalInfo);
+ //instance->portal_info->portal=portal_owner.get(p_base);
+
+ } else {
+ ERR_EXPLAIN("Invalid base RID for instance!")
+ ERR_FAIL();
+ }
+
+ instance_dependency_map[ p_base ].insert( instance->self );
+#endif
+
+
+ }
+}
+void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ if (instance->scenario) {
+
+ instance->scenario->instances.remove( &instance->scenario_item );
+
+ if (instance->octree_id) {
+ instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
+ instance->octree_id=0;
+ }
+
+
+ switch(instance->base_type) {
+
+ case VS::INSTANCE_LIGHT: {
+
+
+ InstanceLightData *light = static_cast<InstanceLightData*>(instance->base_data);
+
+ if (light->D) {
+ instance->scenario->directional_lights.erase( light->D );
+ light->D=NULL;
+ }
+ }
+ }
+
+ instance->scenario=NULL;
+ }
+
+
+ if (p_scenario.is_valid()) {
+
+ Scenario *scenario = scenario_owner.get( p_scenario );
+ ERR_FAIL_COND(!scenario);
+
+ instance->scenario=scenario;
+
+ scenario->instances.add( &instance->scenario_item );
+
+
+ switch(instance->base_type) {
+
+ case VS::INSTANCE_LIGHT: {
+
+
+ InstanceLightData *light = static_cast<InstanceLightData*>(instance->base_data);
+
+ if (VSG::storage->light_get_type(instance->base)==VS::LIGHT_DIRECTIONAL) {
+ light->D = scenario->directional_lights.push_back(instance);
+ }
+ }
+ }
+
+ _instance_queue_update(instance,true,true);
+ }
+}
+void VisualServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask){
+
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ instance->layer_mask=p_mask;
+}
+void VisualServerScene::instance_set_transform(RID p_instance, const Transform& p_transform){
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ if (instance->transform==p_transform)
+ return; //must be checked to avoid worst evil
+
+ instance->transform=p_transform;
+ _instance_queue_update(instance,true);
+}
+void VisualServerScene::instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID){
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ instance->object_ID=p_ID;
+
+}
+void VisualServerScene::instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight){
+
+}
+void VisualServerScene::instance_set_surface_material(RID p_instance,int p_surface, RID p_material){
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ _update_dirty_instance(instance);
+
+ ERR_FAIL_INDEX(p_surface,instance->materials.size());
+
+ instance->materials[p_surface]=p_material;
+
+}
+
+void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){
+
+ Instance *instance = instance_owner.get( p_instance );
+ ERR_FAIL_COND( !instance );
+
+ instance->skeleton=p_skeleton;
+
+ _instance_queue_update(instance,true);
+}
+
+void VisualServerScene::instance_set_exterior( RID p_instance, bool p_enabled ){
+
+}
+void VisualServerScene::instance_set_room( RID p_instance, RID p_room ){
+
+}
+
+void VisualServerScene::instance_set_extra_visibility_margin( RID p_instance, real_t p_margin ){
+
+}
+
+// don't use these in a game!
+Vector<ObjectID> VisualServerScene::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{
+
+ return Vector<ObjectID>();
+}
+
+Vector<ObjectID> VisualServerScene::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{
+
+ return Vector<ObjectID>();
+}
+Vector<ObjectID> VisualServerScene::instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario) const {
+
+ return Vector<ObjectID>();
+}
+
+
+void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled){
+
+}
+void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) {
+
+}
+void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material){
+
+}
+
+
+void VisualServerScene::instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin){
+
+}
+void VisualServerScene::instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance){
+
+}
+
+
+void VisualServerScene::_update_instance(Instance *p_instance) {
+
+ p_instance->version++;
+
+ if (p_instance->base_type == VS::INSTANCE_LIGHT) {
+
+ InstanceLightData *light = static_cast<InstanceLightData*>(p_instance->base_data);
+
+ VSG::scene_render->light_instance_set_transform( light->instance, p_instance->transform );
+
+ }
+
+
+ if (p_instance->aabb.has_no_surface())
+ return;
+
+#if 0
+ if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
+
+ rasterizer->particles_instance_set_transform( p_instance->particles_info->instance, p_instance->data.transform );
+ }
+
+#endif
+ if ((1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData*>(p_instance->base_data);
+ //make sure lights are updated
+
+ for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) {
+ InstanceLightData *light = static_cast<InstanceLightData*>(E->get()->base_data);
+ light->shadow_sirty=true;
+ }
+
+ }
+#if 0
+ else if (p_instance->base_type == INSTANCE_ROOM) {
+
+ p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse();
+ } else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) {
+
+ Transform scale;
+ scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size);
+ scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos;
+ //print_line("scale: "+scale);
+ p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse();
+ }
+
+
+#endif
+
+ p_instance->mirror = p_instance->transform.basis.determinant() < 0.0;
+
+ AABB new_aabb;
+#if 0
+ if (p_instance->base_type==INSTANCE_PORTAL) {
+
+ //portals need to be transformed in a special way, so they don't become too wide if they have scale..
+ Transform portal_xform = p_instance->data.transform;
+ portal_xform.basis.set_axis(2,portal_xform.basis.get_axis(2).normalized());
+
+ p_instance->portal_info->plane_cache=Plane( p_instance->data.transform.origin, portal_xform.basis.get_axis(2));
+ int point_count=p_instance->portal_info->portal->shape.size();
+ p_instance->portal_info->transformed_point_cache.resize(point_count);
+
+ AABB portal_aabb;
+
+ for(int i=0;i<point_count;i++) {
+
+ Point2 src = p_instance->portal_info->portal->shape[i];
+ Vector3 point = portal_xform.xform(Vector3(src.x,src.y,0));
+ p_instance->portal_info->transformed_point_cache[i]=point;
+ if (i==0)
+ portal_aabb.pos=point;
+ else
+ portal_aabb.expand_to(point);
+ }
+
+ portal_aabb.grow_by(p_instance->portal_info->portal->connect_range);
+
+ new_aabb = portal_aabb;
+
+ } else {
+#endif
+ new_aabb = p_instance->transform.xform(p_instance->aabb);
+#if 0
+ }
+#endif
+
+
+ p_instance->transformed_aabb=new_aabb;
+
+ if (!p_instance->scenario) {
+
+ return;
+ }
+
+
+
+ if (p_instance->octree_id==0) {
+
+ uint32_t base_type = 1<<p_instance->base_type;
+ uint32_t pairable_mask=0;
+ bool pairable=false;
+
+ if (p_instance->base_type == VS::INSTANCE_LIGHT) {
+
+ pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0;
+ pairable=true;
+ }
+#if 0
+
+ if (p_instance->base_type == VS::INSTANCE_PORTAL) {
+
+ pairable_mask=(1<<INSTANCE_PORTAL);
+ pairable=true;
+ }
+
+ if (p_instance->base_type == VS::INSTANCE_BAKED_LIGHT_SAMPLER) {
+
+ pairable_mask=(1<<INSTANCE_BAKED_LIGHT);
+ pairable=true;
+ }
+
+
+ if (!p_instance->room && (1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+ base_type|=VS::INSTANCE_ROOMLESS_MASK;
+ }
+
+ if (p_instance->base_type == VS::INSTANCE_ROOM) {
+
+ pairable_mask=INSTANCE_ROOMLESS_MASK;
+ pairable=true;
+ }
+#endif
+
+ // not inside octree
+ p_instance->octree_id = p_instance->scenario->octree.create(p_instance,new_aabb,0,pairable,base_type,pairable_mask);
+
+ } else {
+
+ // if (new_aabb==p_instance->data.transformed_aabb)
+ // return;
+
+ p_instance->scenario->octree.move(p_instance->octree_id,new_aabb);
+ }
+#if 0
+ if (p_instance->base_type==INSTANCE_PORTAL) {
+
+ _portal_attempt_connect(p_instance);
+ }
+
+ if (!p_instance->room && (1<<p_instance->base_type)&INSTANCE_GEOMETRY_MASK) {
+
+ _instance_validate_autorooms(p_instance);
+ }
+
+ if (p_instance->base_type == INSTANCE_ROOM) {
+
+ for(Set<Instance*>::Element *E=p_instance->room_info->owned_autoroom_geometry.front();E;E=E->next())
+ _instance_validate_autorooms(E->get());
+ }
+#endif
+
+}
+
+void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
+
+ AABB new_aabb;
+
+ ERR_FAIL_COND(p_instance->base_type!=VS::INSTANCE_NONE && !p_instance->base.is_valid());
+
+ switch(p_instance->base_type) {
+ case VisualServer::INSTANCE_NONE: {
+
+ // do nothing
+ } break;
+ case VisualServer::INSTANCE_MESH: {
+
+ new_aabb = VSG::storage->mesh_get_aabb(p_instance->base,p_instance->skeleton);
+
+ } break;
+#if 0
+ case VisualServer::INSTANCE_MULTIMESH: {
+
+ new_aabb = rasterizer->multimesh_get_aabb(p_instance->base);
+
+ } break;
+ case VisualServer::INSTANCE_IMMEDIATE: {
+
+ new_aabb = rasterizer->immediate_get_aabb(p_instance->base);
+
+
+ } break;
+ case VisualServer::INSTANCE_PARTICLES: {
+
+ new_aabb = rasterizer->particles_get_aabb(p_instance->base);
+
+
+ } break;
+#endif
+ case VisualServer::INSTANCE_LIGHT: {
+
+ new_aabb = VSG::storage->light_get_aabb(p_instance->base);
+
+ } break;
+#if 0
+ case VisualServer::INSTANCE_ROOM: {
+
+ Room *room = room_owner.get( p_instance->base );
+ ERR_FAIL_COND(!room);
+ new_aabb=room->bounds.get_aabb();
+
+ } break;
+ case VisualServer::INSTANCE_PORTAL: {
+
+ Portal *portal = portal_owner.get( p_instance->base );
+ ERR_FAIL_COND(!portal);
+ for (int i=0;i<portal->shape.size();i++) {
+
+ Vector3 point( portal->shape[i].x, portal->shape[i].y, 0 );
+ if (i==0) {
+
+ new_aabb.pos=point;
+ new_aabb.size.z=0.01; // make it not flat for octree
+ } else {
+
+ new_aabb.expand_to(point);
+ }
+ }
+
+ } break;
+ case VisualServer::INSTANCE_BAKED_LIGHT: {
+
+ BakedLight *baked_light = baked_light_owner.get( p_instance->base );
+ ERR_FAIL_COND(!baked_light);
+ new_aabb=baked_light->octree_aabb;
+
+ } break;
+ case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: {
+
+ BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base );
+ ERR_FAIL_COND(!baked_light_sampler);
+ float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+
+ new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2));
+
+ } break;
+#endif
+ default: {}
+ }
+
+ if (p_instance->extra_margin)
+ new_aabb.grow_by(p_instance->extra_margin);
+
+ p_instance->aabb=new_aabb;
+
+}
+
+
+
+void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size) {
+
+
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+
+ render_pass++;
+ uint32_t camera_layer_mask=camera->visible_layers;
+
+
+ /* STEP 1 - SETUP CAMERA */
+ CameraMatrix camera_matrix;
+ bool ortho=false;
+
+ switch(camera->type) {
+ case Camera::ORTHOGONAL: {
+
+ camera_matrix.set_orthogonal(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect
+
+ );
+ ortho=true;
+ } break;
+ case Camera::PERSPECTIVE: {
+
+ camera_matrix.set_perspective(
+ camera->fov,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect
+
+ );
+ ortho=false;
+
+ } break;
+ }
+
+
+// rasterizer->set_camera(camera->transform, camera_matrix,ortho);
+
+ Vector<Plane> planes = camera_matrix.get_projection_planes(camera->transform);
+
+ Plane near_plane(camera->transform.origin,-camera->transform.basis.get_axis(2).normalized());
+
+ /* STEP 2 - CULL */
+ int cull_count = scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL);
+ light_cull_count=0;
+// light_samplers_culled=0;
+
+/* print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0));
+ print_line("OTO: "+itos(p_scenario->octree.get_octant_count()));
+// print_line("OTE: "+itos(p_scenario->octree.get_elem_count()));
+ print_line("OTP: "+itos(p_scenario->octree.get_pair_count()));
+*/
+
+ /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */
+
+
+ // compute portals
+#if 0
+ exterior_visited=false;
+ exterior_portal_cull_count=0;
+
+ if (room_cull_enabled) {
+ for(int i=0;i<cull_count;i++) {
+
+ Instance *ins = instance_cull_result[i];
+ ins->last_render_pass=render_pass;
+
+ if (ins->base_type!=INSTANCE_PORTAL)
+ continue;
+
+ if (ins->room)
+ continue;
+
+ ERR_CONTINUE(exterior_portal_cull_count>=MAX_EXTERIOR_PORTALS);
+ exterior_portal_cull_result[exterior_portal_cull_count++]=ins;
+
+ }
+
+ room_cull_count = p_scenario->octree.cull_point(camera->transform.origin,room_cull_result,MAX_ROOM_CULL,NULL,(1<<INSTANCE_ROOM)|(1<<INSTANCE_PORTAL));
+
+
+ Set<Instance*> current_rooms;
+ Set<Instance*> portal_rooms;
+ //add to set
+ for(int i=0;i<room_cull_count;i++) {
+
+ if (room_cull_result[i]->base_type==INSTANCE_ROOM) {
+ current_rooms.insert(room_cull_result[i]);
+ }
+ if (room_cull_result[i]->base_type==INSTANCE_PORTAL) {
+ //assume inside that room if also inside the portal..
+ if (room_cull_result[i]->room) {
+ portal_rooms.insert(room_cull_result[i]->room);
+ }
+
+ SWAP(room_cull_result[i],room_cull_result[room_cull_count-1]);
+ room_cull_count--;
+ i--;
+ }
+ }
+
+ //remove from set if it has a parent room or BSP doesn't contain
+ for(int i=0;i<room_cull_count;i++) {
+ Instance *r = room_cull_result[i];
+
+ //check inside BSP
+ Vector3 room_local_point = r->room_info->affine_inverse.xform( camera->transform.origin );
+
+ if (!portal_rooms.has(r) && !r->room_info->room->bounds.point_is_inside(room_local_point)) {
+
+ current_rooms.erase(r);
+ continue;
+ }
+
+ //check parent
+ while (r->room) {// has parent room
+
+ current_rooms.erase(r);
+ r=r->room;
+ }
+
+ }
+
+ if (current_rooms.size()) {
+ //camera is inside a room
+ // go through rooms
+ for(Set<Instance*>::Element *E=current_rooms.front();E;E=E->next()) {
+ _cull_room(camera,E->get());
+ }
+
+ } else {
+ //start from exterior
+ _cull_room(camera,NULL);
+
+ }
+ }
+
+#endif
+ /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */
+
+ for(int i=0;i<cull_count;i++) {
+
+ Instance *ins = instance_cull_result[i];
+
+ bool keep=false;
+
+
+ if ((camera_layer_mask&ins->layer_mask)==0) {
+
+ //failure
+ } else if (ins->base_type==VS::INSTANCE_LIGHT && ins->visible) {
+
+ if (light_cull_count<MAX_LIGHTS_CULLED) {
+
+ InstanceLightData * light = static_cast<InstanceLightData*>(ins->base_data);
+
+ if (!light->geometries.empty()) {
+ //do not add this light if no geometry is affected by it..
+ light_cull_result[light_cull_count]=ins;
+ light_instance_cull_result[light_cull_count]=light->instance;
+
+ light_cull_count++;
+ }
+
+// rasterizer->light_instance_set_active_hint(ins->light_info->instance);
+ }
+
+ } else if ((1<<ins->base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
+
+ keep=true;
+#if 0
+ bool discarded=false;
+
+ if (ins->draw_range_end>0) {
+
+ float d = cull_range.nearp.distance_to(ins->data.transform.origin);
+ if (d<0)
+ d=0;
+ discarded=(d<ins->draw_range_begin || d>=ins->draw_range_end);
+
+
+ }
+
+ if (!discarded) {
+
+ // test if this geometry should be visible
+
+ if (room_cull_enabled) {
+
+
+ if (ins->visible_in_all_rooms) {
+ keep=true;
+ } else if (ins->room) {
+
+ if (ins->room->room_info->last_visited_pass==render_pass)
+ keep=true;
+ } else if (ins->auto_rooms.size()) {
+
+
+ for(Set<Instance*>::Element *E=ins->auto_rooms.front();E;E=E->next()) {
+
+ if (E->get()->room_info->last_visited_pass==render_pass) {
+ keep=true;
+ break;
+ }
+ }
+ } else if(exterior_visited)
+ keep=true;
+ } else {
+
+ keep=true;
+ }
+
+
+ }
+
+
+ if (keep) {
+ // update cull range
+ float min,max;
+ ins->transformed_aabb.project_range_in_plane(cull_range.nearp,min,max);
+
+ if (min<cull_range.min)
+ cull_range.min=min;
+ if (max>cull_range.max)
+ cull_range.max=max;
+
+ if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) {
+ if (light_samplers_culled<MAX_LIGHT_SAMPLERS) {
+ light_sampler_cull_result[light_samplers_culled++]=ins->sampled_light;
+ ins->sampled_light->baked_light_sampler_info->last_pass=render_pass;
+ }
+ }
+ }
+#endif
+
+
+ InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(ins->base_data);
+
+ if (geom->lighting_dirty) {
+ int l=0;
+ //only called when lights AABB enter/exit this geometry
+ ins->light_instances.resize(geom->lighting.size());
+
+ for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) {
+
+ InstanceLightData * light = static_cast<InstanceLightData*>(E->get()->base_data);
+
+ ins->light_instances[l++]=light->instance;
+ }
+
+ geom->lighting_dirty=false;
+ }
+
+ }
+
+ if (!keep) {
+ // remove, no reason to keep
+ cull_count--;
+ SWAP( instance_cull_result[i], instance_cull_result[ cull_count ] );
+ i--;
+ ins->last_render_pass=0; // make invalid
+ } else {
+
+ ins->last_render_pass=render_pass;
+ }
+ }
+
+ /* STEP 5 - PROCESS LIGHTS */
+
+ RID *directional_light_ptr=&light_instance_cull_result[light_cull_count];
+ int directional_light_count=0;
+
+ // directional lights
+ {
+ for (List<Instance*>::Element *E=scenario->directional_lights.front();E;E=E->next()) {
+
+ if (light_cull_count+directional_light_count>=MAX_LIGHTS_CULLED) {
+ break;
+ }
+
+ if (!E->get()->visible)
+ continue;
+
+ InstanceLightData * light = static_cast<InstanceLightData*>(E->get()->base_data);
+
+
+ //check shadow..
+
+
+/* if (light && light->light_info->enabled && rasterizer->light_has_shadow(light->base_rid)) {
+ //rasterizer->light_instance_set_active_hint(light->light_info->instance);
+ _light_instance_update_shadow(light,p_scenario,camera,cull_range);
+ }
+*/
+
+ //add to list
+
+
+ directional_light_ptr[directional_light_count++]=light->instance;
+
+ }
+ }
+
+#if 0
+ { //this should eventually change to
+ //assign shadows by distance to camera
+ SortArray<Instance*,_InstanceLightsort> sorter;
+ sorter.sort(light_cull_result,light_cull_count);
+ for (int i=0;i<light_cull_count;i++) {
+
+ Instance *ins = light_cull_result[i];
+
+ if (!rasterizer->light_has_shadow(ins->base_rid) || !shadows_enabled)
+ continue;
+
+ /* for far shadows?
+ if (ins->version == ins->light_info->last_version && rasterizer->light_instance_has_far_shadow(ins->light_info->instance))
+ continue; // didn't change
+ */
+
+ _light_instance_update_shadow(ins,p_scenario,camera,cull_range);
+ ins->light_info->last_version=ins->version;
+ }
+ }
+#endif
+ /* ENVIRONMENT */
+
+ RID environment;
+ if (camera->env.is_valid()) //camera has more environment priority
+ environment=camera->env;
+ else if (scenario->environment.is_valid())
+ environment=scenario->environment;
+ else
+ environment=scenario->fallback_environment;
+
+#if 0
+ /* STEP 6 - SAMPLE BAKED LIGHT */
+
+ bool islinear =false;
+ if (environment.is_valid()) {
+ islinear = rasterizer->environment_is_fx_enabled(environment,VS::ENV_FX_SRGB);
+ }
+
+ for(int i=0;i<light_samplers_culled;i++) {
+
+ _process_sampled_light(camera->transform,light_sampler_cull_result[i],islinear);
+ }
+#endif
+ /* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/
+
+#if 0
+ // add lights
+
+ {
+ List<RID>::Element *E=p_scenario->directional_lights.front();
+
+
+ for(;E;E=E->next()) {
+ Instance *light = E->get().is_valid()?instance_owner.get(E->get()):NULL;
+
+ ERR_CONTINUE(!light);
+ if (!light->light_info->enabled)
+ continue;
+
+ rasterizer->add_light(light->light_info->instance);
+ light->light_info->last_add_pass=render_pass;
+ }
+
+ for (int i=0;i<light_cull_count;i++) {
+
+ Instance *ins = light_cull_result[i];
+ rasterizer->add_light(ins->light_info->instance);
+ ins->light_info->last_add_pass=render_pass;
+ }
+ }
+ // add geometry
+#endif
+
+
+ VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count,directional_light_ptr,directional_light_count,environment);
+
+}
+
+
+
+void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
+
+
+ if (p_instance->update_aabb)
+ _update_instance_aabb(p_instance);
+
+ if (p_instance->update_materials) {
+ if (p_instance->base_type==VS::INSTANCE_MESH) {
+ p_instance->materials.resize(VSG::storage->mesh_get_surface_count(p_instance->base));
+ }
+ }
+
+ _update_instance(p_instance);
+
+ p_instance->update_aabb=false;
+ p_instance->update_materials=false;
+
+ _instance_update_list.remove( &p_instance->update_item );
+}
+
+
+void VisualServerScene::update_dirty_instances() {
+
+ while(_instance_update_list.first()) {
+
+ _update_dirty_instance( _instance_update_list.first()->self() );
+ }
+}
+
+bool VisualServerScene::free(RID p_rid) {
+
+ if (camera_owner.owns(p_rid)) {
+
+ Camera *camera = camera_owner.get( p_rid );
+
+ camera_owner.free(p_rid);
+ memdelete(camera);
+
+ } else if (scenario_owner.owns(p_rid)) {
+
+ Scenario *scenario = scenario_owner.get( p_rid );
+
+ while(scenario->instances.first()) {
+ instance_set_scenario(scenario->instances.first()->self()->self,RID());
+ }
+
+ scenario_owner.free(p_rid);
+ memdelete(scenario);
+
+ } else if (instance_owner.owns(p_rid)) {
+ // delete the instance
+
+ update_dirty_instances();
+
+ Instance *instance = instance_owner.get(p_rid);
+
+ instance_set_room(p_rid,RID());
+ instance_set_scenario(p_rid,RID());
+ instance_set_base(p_rid,RID());
+
+ if (instance->skeleton.is_valid())
+ instance_attach_skeleton(p_rid,RID());
+
+ instance_owner.free(p_rid);
+ memdelete(instance);
+ } else {
+ return false;
+ }
+
+
+ return true;
+}
+
+VisualServerScene *VisualServerScene::singleton=NULL;
+
+VisualServerScene::VisualServerScene() {
+
+
+ render_pass=1;
+ singleton=this;
+
+}
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
new file mode 100644
index 0000000000..ceec4af598
--- /dev/null
+++ b/servers/visual/visual_server_scene.h
@@ -0,0 +1,390 @@
+#ifndef VISUALSERVERSCENE_H
+#define VISUALSERVERSCENE_H
+
+#include "servers/visual/rasterizer.h"
+
+#include "geometry.h"
+#include "allocators.h"
+#include "octree.h"
+#include "self_list.h"
+
+class VisualServerScene {
+public:
+
+
+ enum {
+
+ MAX_INSTANCE_CULL=65536,
+ MAX_LIGHTS_CULLED=4096,
+ MAX_ROOM_CULL=32,
+ MAX_EXTERIOR_PORTALS=128,
+ };
+
+ uint64_t render_pass;
+
+
+ static VisualServerScene *singleton;
+#if 0
+ struct Portal {
+
+ bool enabled;
+ float disable_distance;
+ Color disable_color;
+ float connect_range;
+ Vector<Point2> shape;
+ Rect2 bounds;
+
+
+ Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; }
+ };
+
+ struct BakedLight {
+
+ Rasterizer::BakedLightData data;
+ DVector<int> sampler;
+ AABB octree_aabb;
+ Size2i octree_tex_size;
+ Size2i light_tex_size;
+
+ };
+
+ struct BakedLightSampler {
+
+ float params[BAKED_LIGHT_SAMPLER_MAX];
+ int resolution;
+ Vector<Vector3> dp_cache;
+
+ BakedLightSampler() {
+ params[BAKED_LIGHT_SAMPLER_STRENGTH]=1.0;
+ params[BAKED_LIGHT_SAMPLER_ATTENUATION]=1.0;
+ params[BAKED_LIGHT_SAMPLER_RADIUS]=1.0;
+ params[BAKED_LIGHT_SAMPLER_DETAIL_RATIO]=0.1;
+ resolution=16;
+ }
+ };
+
+ void _update_baked_light_sampler_dp_cache(BakedLightSampler * blsamp);
+
+#endif
+
+
+ struct Camera : public RID_Data {
+
+ enum Type {
+ PERSPECTIVE,
+ ORTHOGONAL
+ };
+ Type type;
+ float fov;
+ float znear,zfar;
+ float size;
+ uint32_t visible_layers;
+ bool vaspect;
+ RID env;
+
+ Transform transform;
+
+ Camera() {
+
+ visible_layers=0xFFFFFFFF;
+ fov=60;
+ type=PERSPECTIVE;
+ znear=0.1; zfar=100;
+ size=1.0;
+ vaspect=false;
+
+ }
+ };
+
+ mutable RID_Owner<Camera> camera_owner;
+
+ virtual RID camera_create();
+ virtual void camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far);
+ virtual void camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far);
+ virtual void camera_set_transform(RID p_camera,const Transform& p_transform);
+ virtual void camera_set_cull_mask(RID p_camera,uint32_t p_layers);
+ virtual void camera_set_environment(RID p_camera,RID p_env);
+ virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable);
+
+
+ /*
+
+ struct RoomInfo {
+
+ Transform affine_inverse;
+ Room *room;
+ List<Instance*> owned_geometry_instances;
+ List<Instance*> owned_portal_instances;
+ List<Instance*> owned_room_instances;
+ List<Instance*> owned_light_instances; //not used, but just for the sake of it
+ Set<Instance*> disconnected_child_portals;
+ Set<Instance*> owned_autoroom_geometry;
+ uint64_t last_visited_pass;
+ RoomInfo() { last_visited_pass=0; }
+
+ };
+
+ struct InstancePortal {
+
+ Portal *portal;
+ Set<Instance*> candidate_set;
+ Instance *connected;
+ uint64_t last_visited_pass;
+
+ Plane plane_cache;
+ Vector<Vector3> transformed_point_cache;
+
+
+ PortalInfo() { connected=NULL; last_visited_pass=0;}
+ };
+*/
+
+ /* ENVIRONMENT API */
+
+ virtual RID environment_create();
+
+ virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg);
+ virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0);
+ virtual void environment_set_bg_color(RID p_env,const Color& p_color);
+ virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer);
+ virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0);
+
+ virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode);
+ virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture);
+
+ virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper);
+ virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness);
+ virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast);
+ virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation);
+ virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp);
+
+
+ /* SCENARIO API */
+
+ struct Instance;
+
+ struct Scenario : RID_Data {
+
+
+ VS::ScenarioDebugMode debug;
+ RID self;
+ // well wtf, balloon allocator is slower?
+
+ Octree<Instance,true> octree;
+
+ List<Instance*> directional_lights;
+ RID environment;
+ RID fallback_environment;
+
+ SelfList<Instance>::List instances;
+
+ Scenario() { debug=VS::SCENARIO_DEBUG_DISABLED; }
+ };
+
+ RID_Owner<Scenario> scenario_owner;
+
+ static void* _instance_pair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int);
+ static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int,void*);
+
+ virtual RID scenario_create();
+
+ virtual void scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode);
+ virtual void scenario_set_environment(RID p_scenario, RID p_environment);
+ virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+
+
+ /* INSTANCING API */
+
+ struct InstanceBaseData {
+
+
+ virtual ~InstanceBaseData() {}
+ };
+
+
+
+ struct Instance : RasterizerScene::InstanceBase {
+
+ RID self;
+ //scenario stuff
+ OctreeElementID octree_id;
+ Scenario *scenario;
+ SelfList<Instance> scenario_item;
+
+ //aabb stuff
+ bool update_aabb;
+ bool update_materials;
+ SelfList<Instance> update_item;
+
+
+ AABB aabb;
+ AABB transformed_aabb;
+ float extra_margin;
+ uint32_t object_ID;
+ bool visible;
+ uint32_t layer_mask;
+
+ float lod_begin;
+ float lod_end;
+ float lod_begin_hysteresis;
+ float lod_end_hysteresis;
+ RID lod_instance;
+
+ Instance *room;
+ SelfList<Instance> room_item;
+ bool visible_in_all_rooms;
+
+ uint64_t last_render_pass;
+ uint64_t last_frame_pass;
+
+ uint64_t version; // changes to this, and changes to base increase version
+
+ InstanceBaseData *base_data;
+
+ virtual void base_removed() {
+
+ singleton->instance_set_base(self,RID());
+ }
+
+ virtual void base_changed() {
+
+ singleton->_instance_queue_update(this,true,true);
+ }
+
+
+ Instance() : scenario_item(this), update_item(this), room_item(this) {
+
+ octree_id=0;
+ scenario=NULL;
+
+
+ update_aabb=false;
+ update_materials=false;
+
+ extra_margin=0;
+
+
+ object_ID=0;
+ visible=true;
+ layer_mask=1;
+
+ lod_begin=0;
+ lod_end=0;
+ lod_begin_hysteresis=0;
+ lod_end_hysteresis=0;
+
+ room=NULL;
+ visible_in_all_rooms=false;
+
+
+
+ last_render_pass=0;
+ last_frame_pass=0;
+ version=1;
+ base_data=NULL;
+
+ }
+
+ ~Instance() {
+
+ if (base_data)
+ memdelete(base_data);
+
+ }
+ };
+
+ SelfList<Instance>::List _instance_update_list;
+ void _instance_queue_update(Instance *p_instance,bool p_update_aabb,bool p_update_materials=false);
+
+
+ struct InstanceGeometryData : public InstanceBaseData {
+
+ List<Instance*> lighting;
+ bool lighting_dirty;
+
+ InstanceGeometryData() {
+
+ lighting_dirty=false;
+ }
+ };
+
+
+ struct InstanceLightData : public InstanceBaseData {
+
+ struct PairInfo {
+ List<Instance*>::Element *L; //light iterator in geometry
+ Instance *geometry;
+ };
+
+ RID instance;
+ uint64_t last_hash;
+ List<Instance*>::Element *D; // directional light in scenario
+
+ bool shadow_sirty;
+
+ List<PairInfo> geometries;
+
+ InstanceLightData() {
+
+ shadow_sirty=true;
+ D=NULL;
+ last_hash=0;
+ }
+ };
+
+
+ Instance *instance_cull_result[MAX_INSTANCE_CULL];
+ Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
+ Instance *light_cull_result[MAX_LIGHTS_CULLED];
+ RID light_instance_cull_result[MAX_LIGHTS_CULLED];
+ int light_cull_count;
+
+
+ RID_Owner<Instance> instance_owner;
+
+ // from can be mesh, light, area and portal so far.
+ virtual RID instance_create(); // from can be mesh, light, poly, area and portal so far.
+
+ virtual void instance_set_base(RID p_instance, RID p_base); // from can be mesh, light, poly, area and portal so far.
+ virtual void instance_set_scenario(RID p_instance, RID p_scenario); // from can be mesh, light, poly, area and portal so far.
+ virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
+ virtual void instance_set_transform(RID p_instance, const Transform& p_transform);
+ virtual void instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID);
+ virtual void instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight);
+ virtual void instance_set_surface_material(RID p_instance,int p_surface, RID p_material);
+
+ virtual void instance_attach_skeleton(RID p_instance,RID p_skeleton);
+ virtual void instance_set_exterior( RID p_instance, bool p_enabled );
+ virtual void instance_set_room( RID p_instance, RID p_room );
+
+ virtual void instance_set_extra_visibility_margin( RID p_instance, real_t p_margin );
+
+
+ // don't use these in a game!
+ virtual Vector<ObjectID> instances_cull_aabb(const AABB& p_aabb, RID p_scenario=RID()) const;
+ virtual Vector<ObjectID> instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario=RID()) const;
+ virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario=RID()) const;
+
+
+ virtual void instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled);
+ virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting);
+ virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
+
+
+ virtual void instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin);
+ virtual void instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance);
+
+
+ _FORCE_INLINE_ void _update_instance(Instance *p_instance);
+ _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
+ _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
+
+
+ void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size);
+ void update_dirty_instances();
+ bool free(RID p_rid);
+
+ VisualServerScene();
+};
+
+#endif // VISUALSERVERSCENE_H
diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp
index baf18b7a56..583b42bfc1 100644
--- a/servers/visual/visual_server_viewport.cpp
+++ b/servers/visual/visual_server_viewport.cpp
@@ -1,8 +1,11 @@
#include "visual_server_viewport.h"
#include "visual_server_global.h"
#include "visual_server_canvas.h"
+#include "visual_server_scene.h"
#include "globals.h"
+
+
void VisualServerViewport::_draw_viewport(Viewport *p_viewport) {
/* Camera should always be BEFORE any other 3D */
@@ -58,6 +61,12 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) {
}
}
+
+ if (!p_viewport->disable_3d && p_viewport->camera.is_valid()) {
+
+ VSG::scene->render_camera(p_viewport->camera,p_viewport->scenario,p_viewport->size);
+ }
+
if (!p_viewport->hide_canvas) {
int i=0;
@@ -248,6 +257,11 @@ void VisualServerViewport::draw_viewports() {
ERR_CONTINUE( !vp->render_target.is_valid() );
+ bool visible = vp->viewport_to_screen_rect!=Rect2() || vp->update_mode==VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode==VS::VIEWPORT_UPDATE_ONCE;
+
+ if (!visible)
+ continue;
+
VSG::rasterizer->set_current_render_target(vp->render_target);
_draw_viewport(vp);
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 175dfd47d1..97825c172b 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -345,8 +345,754 @@ RID VisualServer::get_white_texture() {
}
+Error VisualServer::_surface_set_data(Array p_arrays,uint32_t p_format,uint32_t *p_offsets,uint32_t p_stride,DVector<uint8_t> &r_vertex_array,int p_vertex_array_len,DVector<uint8_t> &r_index_array,int p_index_array_len,AABB &r_aabb,Vector<AABB> r_bone_aabb) {
+
+ DVector<uint8_t>::Write vw = r_vertex_array.write();
+
+ DVector<uint8_t>::Write iw;
+ if (r_index_array.size()) {
+ iw=r_index_array.write();
+ }
+
+ int max_bone=0;
+
+
+ for(int ai=0;ai<VS::ARRAY_MAX;ai++) {
+
+ if (!(p_format&(1<<ai))) // no array
+ continue;
+
+
+ switch(ai) {
+
+ case VS::ARRAY_VERTEX: {
+
+ if (p_format& VS::ARRAY_FLAG_USE_2D_VERTICES) {
+
+ DVector<Vector2> array = p_arrays[ai];
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+ DVector<Vector2>::Read read = array.read();
+ const Vector2* src=read.ptr();
+
+ // setting vertices means regenerating the AABB
+ Rect2 aabb;
+
+
+ if (p_format&ARRAY_COMPRESS_VERTEX) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ uint16_t vector[2]={ Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(uint16_t)*2);
+
+ if (i==0) {
+
+ aabb=Rect2(src[i],Vector2());
+ } else {
+
+ aabb.expand_to( src[i] );
+ }
+ }
+
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ float vector[2]={ src[i].x, src[i].y };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(float)*2);
+
+ if (i==0) {
+
+ aabb=Rect2(src[i],Vector2());
+ } else {
+
+ aabb.expand_to( src[i] );
+ }
+ }
+ }
+
+ r_aabb=AABB(Vector3(aabb.pos.x,aabb.pos.y,0),Vector3(aabb.size.x,aabb.size.y,0));
+
+
+ } else {
+ DVector<Vector3> array = p_arrays[ai];
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+ DVector<Vector3>::Read read = array.read();
+ const Vector3* src=read.ptr();
+
+ // setting vertices means regenerating the AABB
+ AABB aabb;
+
+
+ if (p_format&ARRAY_COMPRESS_VERTEX) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ uint16_t vector[3]={ Math::make_half_float(src[i].x), Math::make_half_float(src[i].y), Math::make_half_float(src[i].z) };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(uint16_t)*3);
+
+ if (i==0) {
+
+ aabb=AABB(src[i],Vector3());
+ } else {
+
+ aabb.expand_to( src[i] );
+ }
+ }
+
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ float vector[3]={ src[i].x, src[i].y, src[i].z };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(float)*3);
+
+ if (i==0) {
+
+ aabb=AABB(src[i],Vector3());
+ } else {
+
+ aabb.expand_to( src[i] );
+ }
+ }
+ }
+
+ r_aabb=aabb;
+
+ }
+
+
+ } break;
+ case VS::ARRAY_NORMAL: {
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<Vector3> array = p_arrays[ai];
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+ DVector<Vector3>::Read read = array.read();
+ const Vector3* src=read.ptr();
+
+ // setting vertices means regenerating the AABB
+
+ if (p_format&ARRAY_COMPRESS_NORMAL) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint8_t vector[4]={
+ CLAMP(src[i].x*127,-128,127),
+ CLAMP(src[i].y*127,-128,127),
+ CLAMP(src[i].z*127,-128,127),
+ 0,
+ };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], vector, 4);
+
+ }
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ float vector[3]={ src[i].x, src[i].y, src[i].z };
+ copymem(&vw[p_offsets[ai]+i*p_stride], vector, 3*4);
+
+ }
+ }
+
+ } break;
+
+ case VS::ARRAY_TANGENT: {
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<real_t> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len*4, ERR_INVALID_PARAMETER );
+
+
+ DVector<real_t>::Read read = array.read();
+ const real_t* src = read.ptr();
+
+ if (p_format&ARRAY_COMPRESS_TANGENT) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint8_t xyzw[4]={
+ CLAMP(src[i*4+0]*127,-128,127),
+ CLAMP(src[i*4+1]*127,-128,127),
+ CLAMP(src[i*4+2]*127,-128,127),
+ CLAMP(src[i*4+3]*127,-128,127)
+ };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], xyzw, 4);
+
+ }
+
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ float xyzw[4]={
+ src[i*4+0],
+ src[i*4+1],
+ src[i*4+2],
+ src[i*4+3]
+ };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], xyzw, 4*4);
+
+ }
+ }
+
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::COLOR_ARRAY, ERR_INVALID_PARAMETER );
+
+
+ DVector<Color> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+ DVector<Color>::Read read = array.read();
+ const Color* src = read.ptr();
+
+ if (p_format&ARRAY_COMPRESS_COLOR) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ uint8_t colors[4];
+
+ for(int j=0;j<4;j++) {
+
+ colors[j]=CLAMP( int((src[i][j])*255.0), 0,255 );
+ }
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], colors, 4);
+
+ }
+ } else {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], &src[i], 4*4);
+ }
+
+ }
+
+
+ } break;
+ case VS::ARRAY_TEX_UV: {
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::VECTOR2_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<Vector2> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len , ERR_INVALID_PARAMETER);
+
+ DVector<Vector2>::Read read = array.read();
+
+ const Vector2 * src=read.ptr();
+
+
+
+ if (p_format&ARRAY_COMPRESS_TEX_UV) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint16_t uv[2]={ Math::make_half_float(src[i].x) , Math::make_half_float(src[i].y) };
+ copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*2);
+ }
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ float uv[2]={ src[i].x , src[i].y };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*4);
+
+ }
+ }
+
+
+ } break;
+
+ case VS::ARRAY_TEX_UV2: {
+
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::VECTOR2_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<Vector2> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len , ERR_INVALID_PARAMETER);
+
+ DVector<Vector2>::Read read = array.read();
+
+ const Vector2 * src=read.ptr();
+
+
+
+ if (p_format&ARRAY_COMPRESS_TEX_UV2) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint16_t uv[2]={ Math::make_half_float(src[i].x) , Math::make_half_float(src[i].y) };
+ copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*2);
+ }
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ float uv[2]={ src[i].x , src[i].y };
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*4);
+
+ }
+ }
+ } break;
+ case VS::ARRAY_WEIGHTS: {
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<real_t> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER );
+
+
+ DVector<real_t>::Read read = array.read();
+
+ const real_t * src = read.ptr();
+
+ if (p_format&ARRAY_COMPRESS_WEIGHTS) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint16_t data[VS::ARRAY_WEIGHTS_SIZE];
+ for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+ data[j]=CLAMP(src[i*VS::ARRAY_WEIGHTS_SIZE+j]*65535,0,65535);
+ }
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], data, 2*4);
+ }
+ } else {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ float data[VS::ARRAY_WEIGHTS_SIZE];
+ for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+ data[j]=src[i*VS::ARRAY_WEIGHTS_SIZE+j];
+ }
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], data, 4*4);
+
+
+ }
+ }
+
+ } break;
+ case VS::ARRAY_BONES: {
+
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<int> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V( array.size() != p_vertex_array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER );
+
+
+ DVector<int>::Read read = array.read();
+
+ const int * src = read.ptr();
+
+
+ if (!(p_format&ARRAY_FLAG_USE_16_BIT_BONES)) {
+
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint8_t data[VS::ARRAY_WEIGHTS_SIZE];
+ for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+ data[j]=CLAMP(src[i*VS::ARRAY_WEIGHTS_SIZE+j],0,255);
+ max_bone=MAX(data[j],max_bone);
+
+ }
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], data, 4);
+
+
+ }
+
+ } else {
+ for (int i=0;i<p_vertex_array_len;i++) {
+
+ uint16_t data[VS::ARRAY_WEIGHTS_SIZE];
+ for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+ data[j]=src[i*VS::ARRAY_WEIGHTS_SIZE+j];
+ max_bone=MAX(data[j],max_bone);
+
+ }
+
+ copymem(&vw[p_offsets[ai]+i*p_stride], data, 2*4);
+
+
+ }
+ }
+
+
+ } break;
+ case VS::ARRAY_INDEX: {
+
+
+ ERR_FAIL_COND_V( p_index_array_len<=0, ERR_INVALID_DATA );
+ ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER );
+
+ DVector<int> indices = p_arrays[ai];
+ ERR_FAIL_COND_V( indices.size() == 0, ERR_INVALID_PARAMETER );
+ ERR_FAIL_COND_V( indices.size() != p_index_array_len, ERR_INVALID_PARAMETER );
+
+ /* determine wether using 16 or 32 bits indices */
+
+ DVector<int>::Read read = indices.read();
+ const int *src=read.ptr();
+
+ for (int i=0;i<p_index_array_len;i++) {
+
+
+ if (p_vertex_array_len<(1<<16)) {
+ uint16_t v=src[i];
+
+ copymem(&iw[i*2], &v, 2);
+ } else {
+ uint32_t v=src[i];
+
+ copymem(&iw[i*4], &v, 4);
+ }
+ }
+ } break;
+ default: {
+ ERR_FAIL_V( ERR_INVALID_DATA );
+ }
+ }
+ }
+
+
+ if (p_format&VS::ARRAY_FORMAT_BONES) {
+ //create AABBs for each detected bone
+ int total_bones = max_bone+1;
+
+ bool first = r_bone_aabb.size()==0;
+
+ r_bone_aabb.resize(total_bones);
+
+ if (first) {
+ for(int i=0;i<total_bones;i++) {
+ r_bone_aabb[i].size==Vector3(-1,-1,-1); //negative means unused
+ }
+ }
+
+ DVector<Vector3> vertices = p_arrays[VS::ARRAY_VERTEX];
+ DVector<int> bones = p_arrays[VS::ARRAY_BONES];
+ DVector<float> weights = p_arrays[VS::ARRAY_WEIGHTS];
+
+ bool any_valid=false;
+
+ if (vertices.size() && bones.size()==vertices.size()*4 && weights.size()==bones.size()) {
+
+ int vs = vertices.size();
+ DVector<Vector3>::Read rv =vertices.read();
+ DVector<int>::Read rb=bones.read();
+ DVector<float>::Read rw=weights.read();
+
+ AABB *bptr = r_bone_aabb.ptr();
+
+ for(int i=0;i<vs;i++) {
+
+ Vector3 v = rv[i];
+ for(int j=0;j<4;j++) {
+
+ int idx = rb[i*4+j];
+ float w = rw[i*4+j];
+ if (w==0)
+ continue;//break;
+ ERR_FAIL_INDEX_V(idx,total_bones,ERR_INVALID_DATA);
+
+ if (bptr->size.x<0) {
+ //first
+ bptr[idx]=AABB();
+ bptr[idx].pos=v;
+ any_valid=true;
+ } else {
+ bptr[idx].expand_to(v);
+ }
+ }
+ }
+ }
+
+ if (!any_valid && first) {
+
+ r_bone_aabb.clear();
+ }
+ }
+ return OK;
+}
+
+
void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,uint32_t p_compress_format) {
+ ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX );
+ ERR_FAIL_COND(p_arrays.size()!=VS::ARRAY_MAX);
+
+ uint32_t format=0;
+
+ // validation
+ int index_array_len=0;
+ int array_len=0;
+
+ for(int i=0;i<p_arrays.size();i++) {
+
+ if (p_arrays[i].get_type()==Variant::NIL)
+ continue;
+
+ format|=(1<<i);
+
+ if (i==VS::ARRAY_VERTEX) {
+
+ Variant var = p_arrays[i];
+ switch(var.get_type()) {
+ case Variant::VECTOR2_ARRAY: {
+ DVector<Vector2> v2 = var;
+ array_len=v2.size();
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+ DVector<Vector3> v3 = var;
+ array_len=v3.size();
+ } break;
+ default: {
+ Array v = var;
+ array_len=v.size();
+ } break;
+ }
+
+ array_len=Vector3Array(p_arrays[i]).size();
+ ERR_FAIL_COND(array_len==0);
+ } else if (i==VS::ARRAY_INDEX) {
+
+ index_array_len=IntArray(p_arrays[i]).size();
+ }
+ }
+
+ ERR_FAIL_COND((format&VS::ARRAY_FORMAT_VERTEX)==0); // mandatory
+
+
+ if (p_blend_shapes.size()) {
+ //validate format for morphs
+ for(int i=0;i<p_blend_shapes.size();i++) {
+
+ uint32_t bsformat=0;
+ Array arr = p_blend_shapes[i];
+ for(int j=0;j<arr.size();j++) {
+
+
+ if (arr[j].get_type()!=Variant::NIL)
+ bsformat|=(1<<j);
+ }
+
+ ERR_FAIL_COND( (bsformat)!=(format&(VS::ARRAY_FORMAT_BONES-1)));
+ }
+ }
+
+ uint32_t offsets[VS::ARRAY_MAX];
+
+ int total_elem_size=0;
+
+ for (int i=0;i<VS::ARRAY_MAX;i++) {
+
+
+ offsets[i]=0; //reset
+
+ if (!(format&(1<<i))) // no array
+ continue;
+
+
+ int elem_size=0;
+
+ switch(i) {
+
+ case VS::ARRAY_VERTEX: {
+
+ Variant arr = p_arrays[0];
+ if (arr.get_type()==Variant::VECTOR2_ARRAY) {
+ elem_size=2;
+ p_compress_format|=ARRAY_FLAG_USE_2D_VERTICES;
+ } else if (arr.get_type()==Variant::VECTOR3_ARRAY) {
+ p_compress_format&=~ARRAY_FLAG_USE_2D_VERTICES;
+ elem_size=3;
+ } else {
+ elem_size=(p_compress_format&ARRAY_FLAG_USE_2D_VERTICES)?2:3;
+ }
+
+ if (p_compress_format&ARRAY_COMPRESS_VERTEX) {
+ elem_size*=sizeof(int16_t);
+ } else {
+ elem_size*=sizeof(float);
+ }
+
+ } break;
+ case VS::ARRAY_NORMAL: {
+
+ if (p_compress_format&ARRAY_COMPRESS_NORMAL) {
+ elem_size=sizeof(uint32_t);
+ } else {
+ elem_size=sizeof(float)*3;
+ }
+
+ } break;
+
+ case VS::ARRAY_TANGENT: {
+ if (p_compress_format&ARRAY_COMPRESS_TANGENT) {
+ elem_size=sizeof(uint32_t);
+ } else {
+ elem_size=sizeof(float)*4;
+ }
+
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ if (p_compress_format&ARRAY_COMPRESS_COLOR) {
+ elem_size=sizeof(uint32_t);
+ } else {
+ elem_size=sizeof(float)*4;
+ }
+ } break;
+ case VS::ARRAY_TEX_UV: {
+ if (p_compress_format&ARRAY_COMPRESS_TEX_UV) {
+ elem_size=sizeof(uint32_t);
+ } else {
+ elem_size=sizeof(float)*2;
+ }
+
+ } break;
+
+ case VS::ARRAY_TEX_UV2: {
+ if (p_compress_format&ARRAY_COMPRESS_TEX_UV2) {
+ elem_size=sizeof(uint32_t);
+ } else {
+ elem_size=sizeof(float)*2;
+ }
+
+ } break;
+ case VS::ARRAY_WEIGHTS: {
+
+ if (p_compress_format&ARRAY_COMPRESS_WEIGHTS) {
+ elem_size=sizeof(uint16_t)*4;
+ } else {
+ elem_size=sizeof(float)*4;
+ }
+
+ } break;
+ case VS::ARRAY_BONES: {
+
+ if (p_compress_format&ARRAY_FLAG_USE_16_BIT_BONES) {
+ elem_size=sizeof(uint32_t);
+ } else {
+ elem_size=sizeof(uint16_t)*4;
+ }
+
+ } break;
+ case VS::ARRAY_INDEX: {
+
+ if (index_array_len<=0) {
+ ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
+ break;
+ }
+ /* determine wether using 16 or 32 bits indices */
+ if (array_len>(1<<16)) {
+
+ elem_size=4;
+
+ } else {
+ elem_size=2;
+ }
+ offsets[i]=elem_size;
+ continue;
+ } break;
+ default: {
+ ERR_FAIL( );
+ }
+ }
+
+ print_line("type "+itos(i)+" size: "+itos(elem_size)+" offset "+itos(total_elem_size));
+ offsets[i]=total_elem_size;
+ total_elem_size+=elem_size;
+
+
+ }
+
+ print_line("total elemn size: "+itos(total_elem_size));
+
+ uint32_t mask = (1<<ARRAY_MAX)-1;
+ format|=~mask&p_compress_format; //make the full format
+
+
+ int array_size = total_elem_size * array_len;
+
+ print_line("array size: "+itos(array_size));
+
+ DVector<uint8_t> vertex_array;
+ vertex_array.resize(array_size);
+
+ int index_array_size = offsets[VS::ARRAY_INDEX]*index_array_len;
+
+ print_line("index array size: "+itos(index_array_size));
+
+ DVector<uint8_t> index_array;
+ index_array.resize(index_array_size);
+
+ AABB aabb;
+ Vector<AABB> bone_aabb;
+
+ Error err = _surface_set_data(p_arrays,format,offsets,total_elem_size,vertex_array,array_len,index_array,index_array_len,aabb,bone_aabb);
+
+ if (err) {
+ ERR_EXPLAIN("Invalid array format for surface");
+ ERR_FAIL_COND(err!=OK);
+ }
+
+ Vector<DVector<uint8_t> > blend_shape_data;
+
+ for(int i=0;i<p_blend_shapes.size();i++) {
+
+ DVector<uint8_t> vertex_array_shape;
+ vertex_array_shape.resize(array_size);
+ DVector<uint8_t> noindex;
+
+ AABB laabb;
+ Error err = _surface_set_data(p_blend_shapes[i],format&~ARRAY_FORMAT_INDEX,offsets,total_elem_size,vertex_array,array_len,noindex,0,laabb,bone_aabb);
+ aabb.merge_with(laabb);
+ if (err) {
+ ERR_EXPLAIN("Invalid blend shape array format for surface");
+ ERR_FAIL_COND(err!=OK);
+ }
+
+ blend_shape_data.push_back(vertex_array_shape);
+ }
+
+ mesh_add_surface(p_mesh,format,p_primitive,vertex_array,array_len,index_array,index_array_len,aabb,blend_shape_data,bone_aabb);
}
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 90e99710fd..eb20355efb 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -59,6 +59,9 @@ protected:
RID test_material;
RID material_2d[16];
+
+ Error _surface_set_data(Array p_arrays,uint32_t p_format,uint32_t *p_offsets,uint32_t p_stride,DVector<uint8_t> &r_vertex_array,int p_vertex_array_len,DVector<uint8_t> &r_index_array,int p_index_array_len,AABB &r_aabb,Vector<AABB> r_bone_aabb);
+
static VisualServer* (*create_func)();
static void _bind_methods();
public:
@@ -207,6 +210,7 @@ public:
ARRAY_COMPRESS_INDEX=1<<(ARRAY_INDEX+ARRAY_COMPRESS_BASE),
ARRAY_FLAG_USE_2D_VERTICES=ARRAY_COMPRESS_INDEX<<1,
+ ARRAY_FLAG_USE_16_BIT_BONES=ARRAY_COMPRESS_INDEX<<2,
ARRAY_COMPRESS_DEFAULT=ARRAY_COMPRESS_VERTEX|ARRAY_COMPRESS_NORMAL|ARRAY_COMPRESS_TANGENT|ARRAY_COMPRESS_COLOR|ARRAY_COMPRESS_TEX_UV|ARRAY_COMPRESS_TEX_UV2|ARRAY_COMPRESS_BONES|ARRAY_COMPRESS_WEIGHTS|ARRAY_COMPRESS_INDEX
@@ -228,7 +232,7 @@ public:
virtual void mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array(),uint32_t p_compress_format=ARRAY_COMPRESS_DEFAULT);
- virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >())=0;
+ virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >(),const Vector<AABB>& p_bone_aabbs=Vector<AABB>())=0;
virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount)=0;
virtual int mesh_get_morph_target_count(RID p_mesh) const=0;
@@ -530,7 +534,6 @@ public:
virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode)=0;
virtual void scenario_set_environment(RID p_scenario, RID p_environment)=0;
- virtual RID scenario_get_environment(RID p_scenario, RID p_environment) const=0;
virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment)=0;
@@ -546,6 +549,7 @@ public:
INSTANCE_REFLECTION_PROBE,
INSTANCE_ROOM,
INSTANCE_PORTAL,
+ INSTANCE_MAX,
/*INSTANCE_BAKED_LIGHT,
INSTANCE_BAKED_LIGHT_SAMPLER,*/
diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp
index 55a4c6c934..38a7706acc 100644
--- a/tools/editor/plugins/spatial_editor_plugin.cpp
+++ b/tools/editor/plugins/spatial_editor_plugin.cpp
@@ -2349,6 +2349,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
spatial_editor=p_spatial_editor;
ViewportContainer *c=memnew(ViewportContainer);
+ c->set_stretch(true);
add_child(c);
c->set_area_as_parent_rect();
viewport = memnew( Viewport );