diff --git a/bin/tests/test_render.cpp b/bin/tests/test_render.cpp index 7bf833c8a72..b971d412aa9 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 fc76d96b2ee..c8ced0b306d 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 85a69ac0efa..92b7e6ee693 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(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 b2228a6cfa0..237b3ec3fc6 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 eaa9825605d..83c40edc1da 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 d461664ea22..f70dac506db 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 00000000000..121620594d0 --- /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;itexture_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(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(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;imaterial; + + 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)<sort_key|=uint64_t(e->instance->base_type)<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)<sort_key|=uint64_t(e->instance->depth_layer)<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)<sort_key|=uint64_t(0xFFFF)<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;isort_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;ilast_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;ibase_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;imaterials[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;ifx_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 00000000000..6fba777fc89 --- /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 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;istate.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(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_ADD); + shaders.actions_scene.render_mode_values["blend_mix"]=Pair(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MIX); + shaders.actions_scene.render_mode_values["blend_sub"]=Pair(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_SUB); + shaders.actions_scene.render_mode_values["blend_mul"]=Pair(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MUL); + + shaders.actions_scene.render_mode_values["depth_draw_opaque"]=Pair(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_OPAQUE); + shaders.actions_scene.render_mode_values["depth_draw_always"]=Pair(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_ALWAYS); + shaders.actions_scene.render_mode_values["depth_draw_never"]=Pair(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_NEVER); + shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"]=Pair(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS); + + shaders.actions_scene.render_mode_values["cull_front"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_FRONT); + shaders.actions_scene.render_mode_values["cull_back"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK); + shaders.actions_scene.render_mode_values["cull_disable"]=Pair(&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& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const Vector >& p_blend_shapes){ + +void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes,const Vector& 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=(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;imorph_target_count); + + for(int i=0;iactive=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;iskeleton_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;iattribs[i]=attribs[i]; + surface->morph_attribs[i]=morph_attribs[i]; + } + + { + + DVector::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::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;iindex_id) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + } + + { + + //blend shapes + + for(int i=0;i::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;imorph_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 RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int p_surface) const{ - return DVector(); + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,DVector()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),DVector()); + + 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()); + + DVector ret; + ret.resize(surface->array_len); + + { + + DVector::Write w = ret.write(); + copymem(w.ptr(),data,surface->array_len); + } + glUnmapBuffer(GL_ARRAY_BUFFER); + + + return ret; } -DVector RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const{ +DVector 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()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),DVector()); - return DVector(); + Surface *surface = mesh->surfaces[p_surface]; + + ERR_FAIL_COND_V(surface->index_array_len==0,DVector()); + + 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()); + + DVector ret; + ret.resize(surface->index_array_len); + + { + + DVector::Write w = ret.write(); + copymem(w.ptr(),data,surface->index_array_len); + } + + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + + 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;imorph_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;isurfaces.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;jsurfaces[i]->aabb; + } + + if (i==0) + aabb=laabb; + else + aabb.merge_with(laabb); + } + } else { +*/ + for (int i=0;isurfaces.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 b7b3e607c6a..950d65b9d06 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 dirty_list; Vector 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::List instance_list; + + _FORCE_INLINE_ void instance_change_notify() { + + SelfList *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 skeleton_bone_aabb; + Vector skeleton_bone_used; + + //bool packed; + + struct MorphTarget { + GLuint vertex_id; + GLuint array_id; + }; + + Vector 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 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_owner; + virtual RID mesh_create(); - virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const Vector >& p_blend_shapes=Vector >()); + virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes=Vector >(),const Vector& p_bone_aabbs=Vector()); 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& 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 35191fecf79..ebdf60cf423 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 628fa14e4e3..0fa0e3b73a7 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 00000000000..4183e828f55 --- /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 865298f64ec..d3f27687caf 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 materials; + Vector light_instances; + + Vector 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 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& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const Vector >& p_blend_shapes=Vector >())=0; + virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes=Vector >(),const Vector& p_bone_aabbs=Vector())=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& 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 diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 1a01a19021b..767d11bc845 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 d6e057bb520..70abfe2361a 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 VisualServerRaster::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{ - - return Vector(); -} - -Vector VisualServerRaster::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{ - - return Vector(); -} -Vector VisualServerRaster::instances_cull_convex(const Vector& p_convex, RID p_scenario) const { - - return Vector(); -} - - -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 2171998f3fe..62d45f8206d 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 */ @@ -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&,int ,const DVector& ,int ,const Vector >& ) + BIND10(mesh_add_surface,RID,uint32_t,PrimitiveType,const DVector&,int ,const DVector& ,int ,const AABB&,const Vector >&,const Vector& ) 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 - 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); + BIND0R(RID,environment_create) - 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); + 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_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); + BIND7(environment_set_glow,RID,bool ,int ,float ,float ,float ,EnvironmentGlowBlendMode ) + BIND5(environment_set_fog,RID,bool ,float ,float ,RID ) + + 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 instances_cull_aabb(const AABB& p_aabb, RID p_scenario=RID()) const; - virtual Vector instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario=RID()) const; - virtual Vector instances_cull_convex(const Vector& p_convex, RID p_scenario=RID()) const; + BIND2RC(Vector,instances_cull_aabb,const AABB& , RID) + BIND3RC(Vector,instances_cull_ray,const Vector3& , const Vector3& , RID ) + BIND2RC(Vector,instances_cull_convex,const Vector& , 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 00000000000..a3b1d76fb8e --- /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<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceLightData * light = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + + InstanceLightData::PairInfo pinfo; + pinfo.geometry=A; + pinfo.L = geom->lighting.push_back(B); + + List::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<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<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceLightData * light = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + List::Element *E = reinterpret_cast::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<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(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<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::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::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::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(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(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 VisualServerScene::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{ + + return Vector(); +} + +Vector VisualServerScene::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{ + + return Vector(); +} +Vector VisualServerScene::instances_cull_convex(const Vector& p_convex, RID p_scenario) const { + + return Vector(); +} + + +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(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<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceGeometryData *geom = static_cast(p_instance->base_data); + //make sure lights are updated + + for (List::Element *E=geom->lighting.front();E;E=E->next()) { + InstanceLightData *light = static_cast(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;iportal_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<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<base_type == VS::INSTANCE_BAKED_LIGHT_SAMPLER) { + + pairable_mask=(1<room && (1<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<base_type)&INSTANCE_GEOMETRY_MASK) { + + _instance_validate_autorooms(p_instance); + } + + if (p_instance->base_type == INSTANCE_ROOM) { + + for(Set::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;ishape.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 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;ilast_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< current_rooms; + Set portal_rooms; + //add to set + for(int i=0;ibase_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;iroom_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::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;ilayer_mask)==0) { + + //failure + } else if (ins->base_type==VS::INSTANCE_LIGHT && ins->visible) { + + if (light_cull_count(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<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=(ddraw_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::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 (mincull_range.max) + cull_range.max=max; + + if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) { + if (light_samplers_culledsampled_light; + ins->sampled_light->baked_light_sampler_info->last_pass=render_pass; + } + } + } +#endif + + + InstanceGeometryData * geom = static_cast(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::Element *E=geom->lighting.front();E;E=E->next()) { + + InstanceLightData * light = static_cast(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::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(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 sorter; + sorter.sort(light_cull_result,light_cull_count); + for (int i=0;ilight_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;itransform,light_sampler_cull_result[i],islinear); + } +#endif + /* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/ + +#if 0 + // add lights + + { + List::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;iadd_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 00000000000..ceec4af5989 --- /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 shape; + Rect2 bounds; + + + Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; } + }; + + struct BakedLight { + + Rasterizer::BakedLightData data; + DVector sampler; + AABB octree_aabb; + Size2i octree_tex_size; + Size2i light_tex_size; + + }; + + struct BakedLightSampler { + + float params[BAKED_LIGHT_SAMPLER_MAX]; + int resolution; + Vector 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_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 owned_geometry_instances; + List owned_portal_instances; + List owned_room_instances; + List owned_light_instances; //not used, but just for the sake of it + Set disconnected_child_portals; + Set owned_autoroom_geometry; + uint64_t last_visited_pass; + RoomInfo() { last_visited_pass=0; } + + }; + + struct InstancePortal { + + Portal *portal; + Set candidate_set; + Instance *connected; + uint64_t last_visited_pass; + + Plane plane_cache; + Vector 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 octree; + + List directional_lights; + RID environment; + RID fallback_environment; + + SelfList::List instances; + + Scenario() { debug=VS::SCENARIO_DEBUG_DISABLED; } + }; + + RID_Owner 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 scenario_item; + + //aabb stuff + bool update_aabb; + bool update_materials; + SelfList 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 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::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 lighting; + bool lighting_dirty; + + InstanceGeometryData() { + + lighting_dirty=false; + } + }; + + + struct InstanceLightData : public InstanceBaseData { + + struct PairInfo { + List::Element *L; //light iterator in geometry + Instance *geometry; + }; + + RID instance; + uint64_t last_hash; + List::Element *D; // directional light in scenario + + bool shadow_sirty; + + List 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_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 instances_cull_aabb(const AABB& p_aabb, RID p_scenario=RID()) const; + virtual Vector instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario=RID()) const; + virtual Vector instances_cull_convex(const Vector& 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 baf18b7a562..583b42bfc16 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 175dfd47d1d..97825c172b5 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 &r_vertex_array,int p_vertex_array_len,DVector &r_index_array,int p_index_array_len,AABB &r_aabb,Vector r_bone_aabb) { + + DVector::Write vw = r_vertex_array.write(); + + DVector::Write iw; + if (r_index_array.size()) { + iw=r_index_array.write(); + } + + int max_bone=0; + + + for(int ai=0;ai array = p_arrays[ai]; + ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER ); + + + DVector::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 array = p_arrays[ai]; + ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER ); + + + DVector::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 array = p_arrays[ai]; + ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER ); + + + DVector::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 array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_vertex_array_len*4, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + const real_t* src = read.ptr(); + + if (p_format&ARRAY_COMPRESS_TANGENT) { + + for (int i=0;i array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + const Color* src = read.ptr(); + + if (p_format&ARRAY_COMPRESS_COLOR) { + + for (int i=0;i array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_vertex_array_len , ERR_INVALID_PARAMETER); + + DVector::Read read = array.read(); + + const Vector2 * src=read.ptr(); + + + + if (p_format&ARRAY_COMPRESS_TEX_UV) { + + for (int i=0;i array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_vertex_array_len , ERR_INVALID_PARAMETER); + + DVector::Read read = array.read(); + + const Vector2 * src=read.ptr(); + + + + if (p_format&ARRAY_COMPRESS_TEX_UV2) { + + for (int i=0;i array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_vertex_array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + + const real_t * src = read.ptr(); + + if (p_format&ARRAY_COMPRESS_WEIGHTS) { + + for (int i=0;i array = p_arrays[ai]; + + ERR_FAIL_COND_V( array.size() != p_vertex_array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER ); + + + DVector::Read read = array.read(); + + const int * src = read.ptr(); + + + if (!(p_format&ARRAY_FLAG_USE_16_BIT_BONES)) { + + for (int i=0;i 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::Read read = indices.read(); + const int *src=read.ptr(); + + for (int i=0;i vertices = p_arrays[VS::ARRAY_VERTEX]; + DVector bones = p_arrays[VS::ARRAY_BONES]; + DVector 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::Read rv =vertices.read(); + DVector::Read rb=bones.read(); + DVector::Read rw=weights.read(); + + AABB *bptr = r_bone_aabb.ptr(); + + for(int i=0;isize.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 v2 = var; + array_len=v2.size(); + } break; + case Variant::VECTOR3_ARRAY: { + DVector 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(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< 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 index_array; + index_array.resize(index_array_size); + + AABB aabb; + Vector 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 > blend_shape_data; + + for(int i=0;i vertex_array_shape; + vertex_array_shape.resize(array_size); + DVector 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 90e99710fd8..eb20355efba 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 &r_vertex_array,int p_vertex_array_len,DVector &r_index_array,int p_index_array_len,AABB &r_aabb,Vector 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& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const Vector >& p_blend_shapes=Vector >())=0; + virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes=Vector >(),const Vector& p_bone_aabbs=Vector())=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 55a4c6c9347..38a7706acc1 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 );