summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2016-11-22 01:26:56 -0300
committerJuan Linietsky <reduzio@gmail.com>2016-11-22 01:26:56 -0300
commit943d27f46ded993105928c4a46414aa16d84115e (patch)
treea92784b738f4a25cd332afc725ac4f52523f2336 /drivers
parent70d095d8f201bd83a7106015f8f925ec54a8313c (diff)
Instancing is working! (hooray)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp92
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp540
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h42
-rw-r--r--drivers/gles3/shaders/scene.glsl26
5 files changed, 642 insertions, 59 deletions
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 63090e53a7..84fa349313 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -124,6 +124,7 @@ void RasterizerGLES3::begin_frame(){
storage->frame.time[3]=Math::fmod(time_total,60);
storage->frame.count++;
+ storage->update_dirty_multimeshes();
storage->update_dirty_skeletons();
storage->update_dirty_shaders();
storage->update_dirty_materials();
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e0a3dbd36e..54dc3b914b 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1098,6 +1098,55 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) {
glBindVertexArray(s->array_id); // everything is so easy nowadays
} break;
+
+ case VS::INSTANCE_MULTIMESH: {
+
+ RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh*>(e->owner);
+ RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+ glBindVertexArray(s->instancing_array_id); // use the instancing array ID
+ glBindBuffer(GL_ARRAY_BUFFER,multi_mesh->buffer); //modify the buffer
+
+ int stride = (multi_mesh->xform_floats+multi_mesh->color_floats)*4;
+ glEnableVertexAttribArray(8);
+ glVertexAttribPointer(8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+0);
+ glVertexAttribDivisorARB(8,1);
+ glEnableVertexAttribArray(9);
+ glVertexAttribPointer(9,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+4*4);
+ glVertexAttribDivisorARB(9,1);
+
+ int color_ofs;
+
+ if (multi_mesh->transform_format==VS::MULTIMESH_TRANSFORM_3D) {
+ glEnableVertexAttribArray(10);
+ glVertexAttribPointer(10,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+8*4);
+ glVertexAttribDivisorARB(10,1);
+ color_ofs=12*4;
+ } else {
+ glDisableVertexAttribArray(10);
+ glVertexAttrib4f(10,0,0,1,0);
+ color_ofs=8*4;
+ }
+
+ switch(multi_mesh->color_format) {
+
+ case VS::MULTIMESH_COLOR_NONE: {
+ glDisableVertexAttribArray(11);
+ glVertexAttrib4f(11,1,1,1,1);
+ } break;
+ case VS::MULTIMESH_COLOR_8BIT: {
+ glEnableVertexAttribArray(11);
+ glVertexAttribPointer(11,4,GL_UNSIGNED_BYTE,GL_TRUE,stride,((uint8_t*)NULL)+color_ofs);
+ glVertexAttribDivisorARB(11,1);
+
+ } break;
+ case VS::MULTIMESH_COLOR_FLOAT: {
+ glEnableVertexAttribArray(11);
+ glVertexAttribPointer(11,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+color_ofs);
+ glVertexAttribDivisorARB(11,1);
+ } break;
+ }
+
+ } break;
}
}
@@ -1133,6 +1182,25 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
}
} break;
+ case VS::INSTANCE_MULTIMESH: {
+
+ RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh*>(e->owner);
+ RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+
+ int amount = MAX(multi_mesh->size,multi_mesh->visible_instances);
+
+ if (s->index_array_len>0) {
+
+ glDrawElementsInstancedARB(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0,amount);
+
+ } else {
+
+ glDrawArraysInstancedARB(gl_primitive[s->primitive],0,s->array_len,amount);
+
+ }
+
+ } break;
+
}
}
@@ -1481,6 +1549,11 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
}
}
+ if ((prev_base_type==VS::INSTANCE_MULTIMESH) != (e->instance->base_type==VS::INSTANCE_MULTIMESH)) {
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING,e->instance->base_type==VS::INSTANCE_MULTIMESH);
+ rebind=true;
+ }
+
if (material!=prev_material || rebind) {
rebind = _setup_material(material,p_alpha_pass);
@@ -1519,6 +1592,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
glFrontFace(GL_CW);
glBindVertexArray(0);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false);
@@ -2414,6 +2488,24 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_
} break;
case VS::INSTANCE_MULTIMESH: {
+ RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getptr(inst->base);
+ ERR_CONTINUE(!multi_mesh);
+
+ if (multi_mesh->size==0 || multi_mesh->visible_instances==0)
+ continue;
+
+ RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(multi_mesh->mesh);
+ if (!mesh)
+ continue; //mesh not assigned
+
+ int ssize = mesh->surfaces.size();
+
+ for (int i=0;i<ssize;i++) {
+
+ RasterizerStorageGLES3::Surface *s = mesh->surfaces[i];
+ _add_geometry(s,inst,multi_mesh,-1,p_shadow);
+ }
+
} break;
case VS::INSTANCE_IMMEDIATE: {
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index c2598e458f..e5a0cded8e 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -2716,31 +2716,45 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
//generate arrays for faster state switching
- glGenVertexArrays(1,&surface->array_id);
- glBindVertexArray(surface->array_id);
- glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ for(int i=0;i<2;i++) {
- for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+ if (i==0) {
+ //for normal draw
+ glGenVertexArrays(1,&surface->array_id);
+ glBindVertexArray(surface->array_id);
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+ } else {
+ //for instancing draw (can be changed and no one cares)
+ glGenVertexArrays(1,&surface->instancing_array_id);
+ glBindVertexArray(surface->instancing_array_id);
+ glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
- if (!attribs[i].enabled)
- continue;
+ }
+
+
+ for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+ if (!attribs[i].enabled)
+ continue;
+
+ if (attribs[i].integer) {
+ glVertexAttribIPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+ } else {
+ glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+ }
+ glEnableVertexAttribArray(attribs[i].index);
- if (attribs[i].integer) {
- glVertexAttribIPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
- } else {
- glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
}
- glEnableVertexAttribArray(attribs[i].index);
- }
+ if (surface->index_id) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ }
- if (surface->index_id) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
}
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
-
}
{
@@ -3068,14 +3082,14 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
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) {
+
+ if (sk && sk->size!=0) {
for (int i=0;i<mesh->surfaces.size();i++) {
@@ -3088,21 +3102,67 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
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();
+ int sbs = sk->size;
ERR_CONTINUE(bs>sbs);
- Skeleton::Bone *skb = sk->bones.ptr();
+ float *skb = sk->bones.ptr();
+
+
bool first=true;
- for(int j=0;j<bs;j++) {
-
- if (!skused[j])
- continue;
- AABB baabb = skb[ j ].transform_aabb ( skbones[j] );
- if (first) {
- laabb=baabb;
- first=false;
- } else {
- laabb.merge_with(baabb);
+ if (sk->use_2d) {
+ for(int j=0;j<bs;j++) {
+
+ if (!skused[j])
+ continue;
+
+ float *dataptr = &skb[8*j];
+
+ Transform mtx;
+
+ mtx.basis.elements[0][0]=dataptr[ 0];
+ mtx.basis.elements[0][1]=dataptr[ 1];
+ mtx.origin[0]=dataptr[ 3];
+ mtx.basis.elements[1][0]=dataptr[ 4];
+ mtx.basis.elements[1][1]=dataptr[ 5];
+ mtx.origin[1]=dataptr[ 7];
+
+ AABB baabb = mtx.xform( skbones[j] );
+ if (first) {
+ laabb=baabb;
+ first=false;
+ } else {
+ laabb.merge_with(baabb);
+ }
+ }
+ } else {
+ for(int j=0;j<bs;j++) {
+
+ if (!skused[j])
+ continue;
+
+ float *dataptr = &skb[12*j];
+
+ Transform mtx;
+ mtx.basis.elements[0][0]=dataptr[ 0];
+ mtx.basis.elements[0][1]=dataptr[ 1];
+ mtx.basis.elements[0][2]=dataptr[ 2];
+ mtx.origin.x=dataptr[ 3];
+ mtx.basis.elements[1][0]=dataptr[ 4];
+ mtx.basis.elements[1][1]=dataptr[ 5];
+ mtx.basis.elements[1][2]=dataptr[ 6];
+ mtx.origin.y=dataptr[ 7];
+ mtx.basis.elements[2][0]=dataptr[ 8];
+ mtx.basis.elements[2][1]=dataptr[ 9];
+ mtx.basis.elements[2][2]=dataptr[10];
+ mtx.origin.z=dataptr[11];
+
+ AABB baabb = mtx.xform ( skbones[j] );
+ if (first) {
+ laabb=baabb;
+ first=false;
+ } else {
+ laabb.merge_with(baabb);
+ }
}
}
@@ -3117,7 +3177,7 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
aabb.merge_with(laabb);
}
} else {
-*/
+
for (int i=0;i<mesh->surfaces.size();i++) {
if (i==0)
@@ -3125,9 +3185,9 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
else
aabb.merge_with(mesh->surfaces[i]->aabb);
}
-/*
+
}
-*/
+
return aabb;
}
@@ -3146,75 +3206,431 @@ void RasterizerStorageGLES3::mesh_clear(RID p_mesh){
RID RasterizerStorageGLES3::multimesh_create(){
- return RID();
+ MultiMesh *multimesh = memnew( MultiMesh );
+ return multimesh_owner.make_rid(multimesh);
}
-void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb){
+void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format){
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ if (multimesh->size==p_instances && multimesh->transform_format==p_transform_format && multimesh->color_format==p_color_format)
+ return;
+
+ if (multimesh->buffer) {
+ glDeleteBuffers(1,&multimesh->buffer);
+ multimesh->data.resize(0);
+ }
+
+ multimesh->size=p_instances;
+ multimesh->transform_format=p_transform_format;
+ multimesh->color_format=p_color_format;
+
+ if (multimesh->size) {
+
+ if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) {
+ multimesh->xform_floats=8;
+ } else {
+ multimesh->xform_floats=12;
+
+ }
+
+ if (multimesh->color_format==VS::MULTIMESH_COLOR_NONE) {
+ multimesh->color_floats=0;
+ } else if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+ multimesh->color_floats=1;
+ } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+ multimesh->color_floats=4;
+ }
+
+ int format_floats = multimesh->color_floats+multimesh->xform_floats;
+ multimesh->data.resize(format_floats*p_instances);
+ for(int i=0;i<p_instances;i+=format_floats) {
+
+ int color_from=0;
+
+ if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) {
+ multimesh->data[i+0]=1.0;
+ multimesh->data[i+1]=0.0;
+ multimesh->data[i+2]=0.0;
+ multimesh->data[i+3]=0.0;
+ multimesh->data[i+4]=0.0;
+ multimesh->data[i+5]=1.0;
+ multimesh->data[i+6]=0.0;
+ multimesh->data[i+7]=0.0;
+ color_from=8;
+ } else {
+ multimesh->data[i+0]=1.0;
+ multimesh->data[i+1]=0.0;
+ multimesh->data[i+2]=0.0;
+ multimesh->data[i+3]=0.0;
+ multimesh->data[i+4]=0.0;
+ multimesh->data[i+5]=1.0;
+ multimesh->data[i+6]=0.0;
+ multimesh->data[i+7]=0.0;
+ multimesh->data[i+8]=0.0;
+ multimesh->data[i+9]=0.0;
+ multimesh->data[i+10]=1.0;
+ multimesh->data[i+11]=0.0;
+ color_from=12;
+ }
+
+ if (multimesh->color_format==VS::MULTIMESH_COLOR_NONE) {
+ //none
+ } else if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colu=0xFFFFFFFF;
+ multimesh->data[i+color_from+0]=cu.colf;
+
+ } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+ multimesh->data[i+color_from+0]=1.0;
+ multimesh->data[i+color_from+1]=1.0;
+ multimesh->data[i+color_from+2]=1.0;
+ multimesh->data[i+color_from+3]=1.0;
+ }
+ }
+
+ glGenBuffers(1,&multimesh->buffer);
+ glBindBuffer(GL_ARRAY_BUFFER,multimesh->buffer);
+ glBufferData(GL_ARRAY_BUFFER,multimesh->data.size()*sizeof(float),NULL,GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+
+ }
+
+ multimesh->dirty_data=true;
+ multimesh->dirty_aabb=true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
+
int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const{
- return 0;
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,0);
+
+ return multimesh->size;
}
void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh,RID p_mesh){
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
-}
-void RasterizerStorageGLES3::multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb){
+ multimesh->mesh=p_mesh;
+ multimesh->dirty_aabb=true;
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
-void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){
+void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index,multimesh->size);
+ ERR_FAIL_COND(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D);
+
+ int stride = multimesh->color_floats+multimesh->xform_floats;
+ float *dataptr=&multimesh->data[stride*p_index];
+
+ dataptr[ 0]=p_transform.basis.elements[0][0];
+ dataptr[ 1]=p_transform.basis.elements[0][1];
+ dataptr[ 2]=p_transform.basis.elements[0][2];
+ dataptr[ 3]=p_transform.origin.x;
+ dataptr[ 4]=p_transform.basis.elements[1][0];
+ dataptr[ 5]=p_transform.basis.elements[1][1];
+ dataptr[ 6]=p_transform.basis.elements[1][2];
+ dataptr[ 7]=p_transform.origin.y;
+ dataptr[ 8]=p_transform.basis.elements[2][0];
+ dataptr[ 9]=p_transform.basis.elements[2][1];
+ dataptr[10]=p_transform.basis.elements[2][2];
+ dataptr[11]=p_transform.origin.z;
+
+ multimesh->dirty_data=true;
+ multimesh->dirty_aabb=true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
+
void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform){
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index,multimesh->size);
+ ERR_FAIL_COND(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_3D);
+
+ int stride = multimesh->color_floats+multimesh->xform_floats;
+ float *dataptr=&multimesh->data[stride*p_index];
+
+ dataptr[ 0]=p_transform.elements[0][0];
+ dataptr[ 1]=p_transform.elements[1][0];
+ dataptr[ 2]=0;
+ dataptr[ 3]=p_transform.elements[2][0];
+ dataptr[ 4]=p_transform.elements[0][1];
+ dataptr[ 5]=p_transform.elements[1][1];
+ dataptr[ 6]=0;
+ dataptr[ 7]=p_transform.elements[2][1];
+
+ multimesh->dirty_data=true;
+ multimesh->dirty_aabb=true;
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color){
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index,multimesh->size);
+ ERR_FAIL_COND(multimesh->color_format==VS::MULTIMESH_COLOR_NONE);
+
+ int stride = multimesh->color_floats+multimesh->xform_floats;
+ float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats];
+
+ if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colu=p_color.to_32();
+ dataptr[ 0]=cu.colf;
+
+ } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+ dataptr[ 0]=p_color.r;
+ dataptr[ 1]=p_color.g;
+ dataptr[ 2]=p_color.b;
+ dataptr[ 3]=p_color.a;
+ }
+
+
+ multimesh->dirty_data=true;
+ multimesh->dirty_aabb=true;
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const{
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,RID());
- return RID();
+ return multimesh->mesh;
}
-AABB RasterizerStorageGLES3::multimesh_get_custom_aabb(RID p_multimesh) const{
- return AABB();
-}
Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh,int p_index) const{
- return Transform();
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,Transform());
+ ERR_FAIL_INDEX_V(p_index,multimesh->size,Transform());
+ ERR_FAIL_COND_V(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D,Transform());
+
+ int stride = multimesh->color_floats+multimesh->xform_floats;
+ float *dataptr=&multimesh->data[stride*p_index];
+
+ Transform xform;
+
+ xform.basis.elements[0][0]=dataptr[ 0];
+ xform.basis.elements[0][1]=dataptr[ 1];
+ xform.basis.elements[0][2]=dataptr[ 2];
+ xform.origin.x=dataptr[ 3];
+ xform.basis.elements[1][0]=dataptr[ 4];
+ xform.basis.elements[1][1]=dataptr[ 5];
+ xform.basis.elements[1][2]=dataptr[ 6];
+ xform.origin.y=dataptr[ 7];
+ xform.basis.elements[2][0]=dataptr[ 8];
+ xform.basis.elements[2][1]=dataptr[ 9];
+ xform.basis.elements[2][2]=dataptr[10];
+ xform.origin.z=dataptr[11];
+
+ return xform;
}
Matrix32 RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const{
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,Matrix32());
+ ERR_FAIL_INDEX_V(p_index,multimesh->size,Matrix32());
+ ERR_FAIL_COND_V(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_3D,Matrix32());
+
+ int stride = multimesh->color_floats+multimesh->xform_floats;
+ float *dataptr=&multimesh->data[stride*p_index];
+
+ Matrix32 xform;
+
+ xform.elements[0][0]=dataptr[ 0];
+ xform.elements[1][0]=dataptr[ 1];
+ xform.elements[2][0]=dataptr[ 3];
+ xform.elements[0][1]=dataptr[ 4];
+ xform.elements[1][1]=dataptr[ 5];
+ xform.elements[2][1]=dataptr[ 7];
- return Matrix32();
+ return xform;
}
+
Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p_index) const{
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,Color());
+ ERR_FAIL_INDEX_V(p_index,multimesh->size,Color());
+ ERR_FAIL_COND_V(multimesh->color_format==VS::MULTIMESH_COLOR_NONE,Color());
+
+ int stride = multimesh->color_floats+multimesh->xform_floats;
+ float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats];
+
+ if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ return Color::hex(cu.colu);
+
+ } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+ Color c;
+ c.r=dataptr[ 0];
+ c.g=dataptr[ 1];
+ c.b=dataptr[ 2];
+ c.a=dataptr[ 3];
+
+ return c;
+ }
+
return Color();
+
}
void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh,int p_visible){
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ multimesh->visible_instances=p_visible;
}
int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const{
- return 0;
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,-1);
+
+ return multimesh->visible_instances;
}
-AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_mesh) const{
+AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const{
- return AABB();
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh,AABB());
+
+ const_cast<RasterizerStorageGLES3*>(this)->update_dirty_multimeshes(); //update pending AABBs
+
+ return multimesh->aabb;
+}
+
+void RasterizerStorageGLES3::update_dirty_multimeshes() {
+
+ while(multimesh_update_list.first()) {
+
+ MultiMesh *multimesh = multimesh_update_list.first()->self();
+
+ if (multimesh->size && multimesh->dirty_data) {
+
+
+ glBindBuffer(GL_ARRAY_BUFFER,multimesh->buffer);
+ glBufferSubData(GL_ARRAY_BUFFER,0,multimesh->data.size()*sizeof(float),multimesh->data.ptr());
+ glBindBuffer(GL_ARRAY_BUFFER,0);
+
+
+ }
+
+
+
+ if (multimesh->size && multimesh->dirty_aabb) {
+
+ AABB mesh_aabb;
+
+ if (multimesh->mesh.is_valid()) {
+ mesh_aabb=mesh_get_aabb(multimesh->mesh,RID());
+ } else {
+ mesh_aabb.size+=Vector3(0.001,0.001,0.001);
+ }
+
+ int stride=multimesh->color_floats+multimesh->xform_floats;
+ int count = multimesh->data.size();
+ float *data=multimesh->data.ptr();
+
+ AABB aabb;
+
+ if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) {
+
+ for(int i=0;i<count;i+=stride) {
+
+ float *dataptr=&data[i];
+ Transform xform;
+ xform.basis[0][0]=dataptr[ 0];
+ xform.basis[0][1]=dataptr[ 1];
+ xform.origin[0]=dataptr[ 3];
+ xform.basis[1][0]=dataptr[ 4];
+ xform.basis[1][1]=dataptr[ 5];
+ xform.origin[1]=dataptr[ 7];
+
+ AABB laabb = xform.xform(mesh_aabb);
+ if (i==0)
+ aabb=laabb;
+ else
+ aabb.merge_with(laabb);
+ }
+ } else {
+
+ for(int i=0;i<count;i+=stride) {
+
+ float *dataptr=&data[i];
+ Transform xform;
+
+ xform.basis.elements[0][0]=dataptr[ 0];
+ xform.basis.elements[0][1]=dataptr[ 1];
+ xform.basis.elements[0][2]=dataptr[ 2];
+ xform.origin.x=dataptr[ 3];
+ xform.basis.elements[1][0]=dataptr[ 4];
+ xform.basis.elements[1][1]=dataptr[ 5];
+ xform.basis.elements[1][2]=dataptr[ 6];
+ xform.origin.y=dataptr[ 7];
+ xform.basis.elements[2][0]=dataptr[ 8];
+ xform.basis.elements[2][1]=dataptr[ 9];
+ xform.basis.elements[2][2]=dataptr[10];
+ xform.origin.z=dataptr[11];
+
+ AABB laabb = xform.xform(mesh_aabb);
+ if (i==0)
+ aabb=laabb;
+ else
+ aabb.merge_with(laabb);
+ }
+ }
+
+ multimesh->aabb=aabb;
+ }
+ multimesh->dirty_aabb=false;
+ multimesh->dirty_data=false;
+
+ multimesh->instance_change_notify();
+
+ multimesh_update_list.remove(multimesh_update_list.first());
+ }
}
/* IMMEDIATE API */
@@ -3957,6 +4373,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene:
inst = mesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
+ case VS::INSTANCE_MULTIMESH: {
+ inst = multimesh_owner.getornull(p_base);
+ ERR_FAIL_COND(!inst);
+ } break;
case VS::INSTANCE_REFLECTION_PROBE: {
inst = reflection_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
@@ -3988,6 +4408,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce
ERR_FAIL_COND(!inst);
} break;
+ case VS::INSTANCE_MULTIMESH: {
+ inst = multimesh_owner.getornull(p_base);
+ ERR_FAIL_COND(!inst);
+ } break;
case VS::INSTANCE_REFLECTION_PROBE: {
inst = reflection_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
@@ -4482,6 +4906,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
if (mesh_owner.owns(p_rid)) {
return VS::INSTANCE_MESH;
}
+ if (multimesh_owner.owns(p_rid)) {
+ return VS::INSTANCE_MULTIMESH;
+ }
if (light_owner.owns(p_rid)) {
return VS::INSTANCE_LIGHT;
}
@@ -4580,6 +5007,17 @@ bool RasterizerStorageGLES3::free(RID p_rid){
mesh_owner.free(p_rid);
memdelete(mesh);
+ } else if (multimesh_owner.owns(p_rid)) {
+
+ // delete the texture
+ MultiMesh *multimesh = multimesh_owner.get(p_rid);
+
+ multimesh_allocate(p_rid,0,VS::MULTIMESH_TRANSFORM_2D,VS::MULTIMESH_COLOR_NONE); //frees multimesh
+ update_dirty_multimeshes();
+
+ multimesh_owner.free(p_rid);
+ memdelete(multimesh);
+
} else if (light_owner.owns(p_rid)) {
// delete the texture
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index b5eacacb4e..c6712bd8ea 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -482,6 +482,7 @@ public:
uint32_t format;
GLuint array_id;
+ GLuint instancing_array_id;
GLuint vertex_id;
GLuint index_id;
@@ -591,20 +592,53 @@ public:
/* MULTIMESH API */
+ struct MultiMesh : public GeometryOwner {
+ RID mesh;
+ int size;
+ VS::MultimeshTransformFormat transform_format;
+ VS::MultimeshColorFormat color_format;
+ Vector<float> data;
+ AABB aabb;
+ SelfList<MultiMesh> update_list;
+ GLuint buffer;
+ int visible_instances;
+
+ int xform_floats;
+ int color_floats;
+
+ bool dirty_aabb;
+ bool dirty_data;
+
+ MultiMesh() : update_list(this) {
+ dirty_aabb=true;
+ dirty_data=true;
+ xform_floats=0;
+ color_floats=0;
+ visible_instances=-1;
+ size=0;
+ buffer=0;
+ transform_format=VS::MULTIMESH_TRANSFORM_2D;
+ color_format=VS::MULTIMESH_COLOR_NONE;
+ }
+ };
+
+ mutable RID_Owner<MultiMesh> multimesh_owner;
+
+ SelfList<MultiMesh>::List multimesh_update_list;
+
+ void update_dirty_multimeshes();
virtual RID multimesh_create();
- virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb=true);
+ virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format);
virtual int multimesh_get_instance_count(RID p_multimesh) const;
virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh);
- virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb);
virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform);
virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform);
virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color);
virtual RID multimesh_get_mesh(RID p_multimesh) const;
- virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const;
virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const;
virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const;
@@ -613,7 +647,7 @@ public:
virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible);
virtual int multimesh_get_visible_instances(RID p_multimesh) const;
- virtual AABB multimesh_get_aabb(RID p_mesh) const;
+ virtual AABB multimesh_get_aabb(RID p_multimesh) const;
/* IMMEDIATE API */
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index f3dade9e50..c198534728 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -45,7 +45,7 @@ layout(location=6) in ivec4 bone_indices; // attrib:6
layout(location=7) in vec4 bone_weights; // attrib:7
#endif
-#ifdef USE_ATTRIBUTE_INSTANCING
+#ifdef USE_INSTANCING
layout(location=8) in highp vec4 instance_xform0;
layout(location=9) in highp vec4 instance_xform1;
@@ -171,6 +171,10 @@ void main() {
float binormalf = tangent_attrib.a;
#endif
+#if defined(ENABLE_COLOR_INTERP)
+ color_interp = color_attrib;
+#endif
+
#ifdef USE_SKELETON
@@ -191,6 +195,23 @@ void main() {
#endif // USE_SKELETON1
+#ifdef USE_INSTANCING
+
+ {
+ highp mat3x4 m=mat3x4(instance_xform0,instance_xform1,instance_xform2);
+
+ vertex.xyz = vertex * m;
+ normal = vec4(normal,0.0) * m;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ tangent.xyz = vec4(tangent.xyz,0.0) * mn;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+ color_interp*=instance_color;
+#endif
+ }
+#endif //USE_INSTANCING
+
#if !defined(SKIP_TRANSFORM_USED)
vertex = modelview * vertex;
@@ -207,9 +228,6 @@ void main() {
-#if defined(ENABLE_COLOR_INTERP)
- color_interp = color_attrib;
-#endif
#if defined(ENABLE_UV_INTERP)
uv_interp = uv_attrib;