Mesh Batch Cache: Add support for uv/vcol/tangent data layers.

This is a bad implementation waiting for some improvement that are :
- Gawain support for multiple names. -> will remove duplication of attribute alloc
- Glsl safe name string escaping. -> will remove any risk of hash colision.

Old glsl drawing was relying on attribute being choosen by DerivedMesh at drawing time.
For this reason, we declare all possible attrib "name" for each data layer inside the batches.
In the glsl code, we declare required data by type and name.
Then Gawain only bind vbos if names correspond.
This is way cleaner as we do not need to access the CD itself when drawing.

One other problem is that the hash maybe 11 caracters long and rapidly overload gawain's attrib name buffer.
This commit is contained in:
Clément Foucault 2017-05-01 17:58:15 +02:00
parent 27fc8ae1cb
commit 19f86a3d5f
3 changed files with 410 additions and 42 deletions

View File

@ -14,7 +14,7 @@
#include "common.h"
#define MAX_VERTEX_ATTRIBS 16
#define AVG_VERTEX_ATTRIB_NAME_LEN 5
#define AVG_VERTEX_ATTRIB_NAME_LEN 11
#define VERTEX_ATTRIB_NAMES_BUFFER_LEN ((AVG_VERTEX_ATTRIB_NAME_LEN + 1) * MAX_VERTEX_ATTRIBS)
#if defined(WITH_GL_PROFILE_CORE) || defined(_WIN32)

View File

@ -24,7 +24,7 @@ from rna_prop_ui import PropertyPanel
class MESH_MT_vertex_group_specials(Menu):
bl_label = "Vertex Group Specials"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -48,7 +48,7 @@ class MESH_MT_vertex_group_specials(Menu):
class MESH_MT_shape_key_specials(Menu):
bl_label = "Shape Key Specials"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -126,7 +126,7 @@ class MeshButtonsPanel:
class DATA_PT_context_mesh(MeshButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -143,7 +143,7 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel):
class DATA_PT_normals(MeshButtonsPanel, Panel):
bl_label = "Normals"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -164,7 +164,7 @@ class DATA_PT_normals(MeshButtonsPanel, Panel):
class DATA_PT_texture_space(MeshButtonsPanel, Panel):
bl_label = "Texture Space"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -183,7 +183,7 @@ class DATA_PT_texture_space(MeshButtonsPanel, Panel):
class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
bl_label = "Vertex Groups"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@ -229,7 +229,7 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
bl_label = "Shape Keys"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
@ -322,7 +322,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
bl_label = "UV Maps"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -341,7 +341,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
bl_label = "Vertex Colors"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -361,7 +361,7 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
class DATA_PT_customdata(MeshButtonsPanel, Panel):
bl_label = "Geometry Data"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -387,7 +387,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Mesh

View File

@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -115,13 +116,34 @@ typedef struct MeshRenderData {
MEdge *medge;
MLoop *mloop;
MPoly *mpoly;
float (*orco)[3];
MLoopUV **mloopuv;
MCol **mcol;
float (**mtangent)[4];
BMVert *eve_act;
BMEdge *eed_act;
BMFace *efa_act;
int uv_ct;
int vcol_ct;
bool *auto_vcol;
int uv_active;
int vcol_active;
int tangent_active;
int crease_ofs;
int bweight_ofs;
int *uv_ofs;
int *vcol_ofs;
int *tangent_ofs;
char (*auto_names)[32];
char (*uv_names)[32];
char (*vcol_names)[32];
char (*tangent_names)[32];
/* Data created on-demand (usually not for bmesh-based data). */
EdgeAdjacentPolys *edges_adjacent_polys;
@ -141,6 +163,7 @@ enum {
MR_DATATYPE_LOOP = 1 << 3,
MR_DATATYPE_POLY = 1 << 4,
MR_DATATYPE_OVERLAY = 1 << 5,
MR_DATATYPE_SHADING = 1 << 6,
};
/**
@ -277,35 +300,189 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
}
}
if (types & MR_DATATYPE_SHADING) {
rdata->uv_ct = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
rdata->vcol_ct = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
rdata->mloopuv = MEM_mallocN(sizeof(*rdata->mloopuv) * rdata->uv_ct, "rdata->mloopuv");
rdata->mcol = MEM_mallocN(sizeof(*rdata->mcol) * rdata->vcol_ct, "rdata->mcol");
rdata->mtangent = MEM_mallocN(sizeof(*rdata->mtangent) * rdata->uv_ct, "rdata->mtangent");
rdata->uv_names = MEM_mallocN(sizeof(*rdata->uv_names) * rdata->uv_ct, "rdata->uv_names");
rdata->vcol_names = MEM_mallocN(sizeof(*rdata->vcol_names) * rdata->vcol_ct, "rdata->vcol_names");
rdata->tangent_names = MEM_mallocN(sizeof(*rdata->tangent_names) * rdata->uv_ct, "rdata->tangent_names");
rdata->uv_ofs = MEM_mallocN(sizeof(*rdata->uv_ofs) * rdata->uv_ct, "rdata->uv_ofs");
rdata->vcol_ofs = MEM_mallocN(sizeof(*rdata->vcol_ofs) * rdata->vcol_ct, "rdata->vcol_ofs");
rdata->tangent_ofs = MEM_mallocN(sizeof(*rdata->tangent_ofs) * rdata->uv_ct, "rdata->tangent_ofs");
/* Allocate max */
rdata->auto_vcol = MEM_callocN(sizeof(*rdata->auto_vcol) * rdata->vcol_ct, "rdata->auto_vcol");
rdata->auto_names = MEM_mallocN(sizeof(*rdata->auto_names) * (rdata->vcol_ct + rdata->uv_ct), "rdata->auto_names");
/* XXX FIXME XXX */
/* We use a hash to identify each data layer based on its name.
* Gawain then search for this name in the current shader and bind if it exists.
* NOTE : This is prone to hash collision.
* One solution to hash collision would be to format the cd layer name
* to a safe glsl var name, but without name clash.
* NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
for (int i = 0; i < rdata->vcol_ct; ++i) {
const char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, i);
unsigned int hash = BLI_ghashutil_strhash_p(name);
BLI_snprintf(rdata->vcol_names[i], sizeof(*rdata->vcol_names), "c%u", hash);
rdata->mcol[i] = CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, i);
if (rdata->edit_bmesh) {
rdata->vcol_ofs[i] = CustomData_get_n_offset(&rdata->edit_bmesh->bm->ldata, CD_MLOOPCOL, i);
}
/* Gather number of auto layers. */
/* We only do vcols that are not overridden by uvs */
if (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPUV, name) == -1) {
BLI_snprintf(rdata->auto_names[rdata->uv_ct + i], sizeof(*rdata->auto_names), "a%u", hash);
rdata->auto_vcol[i] = true;
}
}
/* Start Fresh */
CustomData_free_layers(&me->ldata, CD_MLOOPTANGENT, me->totloop);
for (int i = 0; i < rdata->uv_ct; ++i) {
const char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i);
unsigned int hash = BLI_ghashutil_strhash_p(name);
{
/* UVs */
BLI_snprintf(rdata->uv_names[i], sizeof(*rdata->uv_names), "u%u", hash);
rdata->mloopuv[i] = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, i);
if (rdata->edit_bmesh) {
rdata->uv_ofs[i] = CustomData_get_n_offset(&rdata->edit_bmesh->bm->ldata, CD_MLOOPUV, i);
}
BLI_snprintf(rdata->auto_names[i], sizeof(*rdata->auto_names), "a%u", hash);
}
{
/* Tangents*/
BLI_snprintf(rdata->tangent_names[i], sizeof(*rdata->tangent_names), "t%u", hash);
if (rdata->edit_bmesh) {
#if 0 /* TODO Waiting for the port of emDM_calc_loop_tangents */
BMesh *bm = rdata->edit_bmesh->bm;
float (*loopnors)[3] = CustomData_get_layer(&bm->ldata, CD_NORMAL);
rdata->mtangent[i] = CustomData_add_layer(&bm->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, bm->totloop);
CustomData_set_layer_flag(&bm->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
BKE_mesh_loop_tangents_ex(bm->mvert, bm->totvert, bm->mloop, rdata->mtangent[i],
loopnors, rdata->mloopuv[i], bm->totloop, bm->mpoly, bm->totpoly, NULL);
rdata->tangent_ofs[i] = CustomData_get_n_offset(&bm->ldata, CD_MLOOPTANGENT, i);
#else
rdata->tangent_ofs[i] = -1;
#endif
}
else {
if (!CustomData_has_layer(&me->ldata, CD_NORMAL)) {
BKE_mesh_calc_normals_split(me);
}
float (*loopnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
rdata->mtangent[i] = CustomData_add_layer(&me->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, me->totloop);
CustomData_set_layer_flag(&me->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
BKE_mesh_loop_tangents_ex(me->mvert, me->totvert, me->mloop, rdata->mtangent[i],
loopnors, rdata->mloopuv[i], me->totloop, me->mpoly, me->totpoly, NULL);
}
}
}
rdata->uv_active = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV) - CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
rdata->vcol_active = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL) - CustomData_get_layer_index(&me->ldata, CD_MLOOPCOL);
rdata->tangent_active = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPTANGENT) - CustomData_get_layer_index(&me->ldata, CD_MLOOPTANGENT);
rdata->orco = CustomData_get_layer(&me->vdata, CD_ORCO);
/* If orco is not available compute it ourselves */
if (!rdata->orco) {
if (me->edit_btmesh) {
BMesh *bm = me->edit_btmesh->bm;
rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
BMVert **vtable = bm->vtable;
for (int i = 0; i < bm->totvert; i++) {
copy_v3_v3(rdata->orco[i], vtable[i]->co);
}
BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
}
else {
rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
MVert *mvert = rdata->mvert;
for (int a = 0; a < rdata->vert_len; a++, mvert++) {
copy_v3_v3(rdata->orco[a], mvert->co);
}
BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
}
}
}
return rdata;
}
static void mesh_render_data_free(MeshRenderData *rdata)
{
if (rdata->loose_verts) {
MEM_freeN(rdata->loose_verts);
}
if (rdata->loose_edges) {
MEM_freeN(rdata->loose_edges);
}
if (rdata->edges_adjacent_polys) {
MEM_freeN(rdata->edges_adjacent_polys);
}
if (rdata->mlooptri) {
MEM_freeN(rdata->mlooptri);
}
if (rdata->poly_normals) {
MEM_freeN(rdata->poly_normals);
}
if (rdata->poly_normals_short) {
MEM_freeN(rdata->poly_normals_short);
}
if (rdata->vert_normals_short) {
MEM_freeN(rdata->vert_normals_short);
}
MEM_SAFE_FREE(rdata->auto_vcol);
MEM_SAFE_FREE(rdata->auto_names);
MEM_SAFE_FREE(rdata->uv_ofs);
MEM_SAFE_FREE(rdata->vcol_ofs);
MEM_SAFE_FREE(rdata->tangent_ofs);
MEM_SAFE_FREE(rdata->orco);
MEM_SAFE_FREE(rdata->mloopuv);
MEM_SAFE_FREE(rdata->mcol);
MEM_SAFE_FREE(rdata->mtangent);
MEM_SAFE_FREE(rdata->loose_verts);
MEM_SAFE_FREE(rdata->loose_edges);
MEM_SAFE_FREE(rdata->edges_adjacent_polys);
MEM_SAFE_FREE(rdata->mlooptri);
MEM_SAFE_FREE(rdata->poly_normals);
MEM_SAFE_FREE(rdata->poly_normals_short);
MEM_SAFE_FREE(rdata->vert_normals_short);
MEM_SAFE_FREE(rdata->uv_names);
MEM_SAFE_FREE(rdata->vcol_names);
MEM_SAFE_FREE(rdata->tangent_names);
MEM_freeN(rdata);
}
static const char *mesh_render_data_uv_auto_layer_name_get(const MeshRenderData *rdata, int layer)
{
BLI_assert(rdata->types & MR_DATATYPE_SHADING);
return rdata->auto_names[layer];
}
static const char *mesh_render_data_vcol_auto_layer_name_get(const MeshRenderData *rdata, int layer)
{
BLI_assert(rdata->types & MR_DATATYPE_SHADING);
return rdata->auto_names[rdata->uv_ct + layer];
}
static const char *mesh_render_data_uv_layer_name_get(const MeshRenderData *rdata, int layer)
{
BLI_assert(rdata->types & MR_DATATYPE_SHADING);
return rdata->uv_names[layer];
}
static const char *mesh_render_data_vcol_layer_name_get(const MeshRenderData *rdata, int layer)
{
BLI_assert(rdata->types & MR_DATATYPE_SHADING);
return rdata->vcol_names[layer];
}
static const char *mesh_render_data_tangent_layer_name_get(const MeshRenderData *rdata, int layer)
{
BLI_assert(rdata->types & MR_DATATYPE_SHADING);
return rdata->tangent_names[layer];
}
static int mesh_render_data_verts_len_get(const MeshRenderData *rdata)
{
BLI_assert(rdata->types & MR_DATATYPE_VERT);
@ -619,6 +796,86 @@ static bool mesh_render_data_looptri_vert_edge_indices_get(
return true;
}
static void mesh_render_data_looptri_uvs_get(
MeshRenderData *rdata, const int tri_idx, const int uv_layer,
float *(*r_vert_uvs)[3])
{
if (rdata->edit_bmesh) {
const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
(*r_vert_uvs)[0] = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(bm_looptri[0], rdata->uv_ofs[uv_layer]))->uv;
(*r_vert_uvs)[1] = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(bm_looptri[1], rdata->uv_ofs[uv_layer]))->uv;
(*r_vert_uvs)[2] = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(bm_looptri[2], rdata->uv_ofs[uv_layer]))->uv;
}
else {
const MLoopTri *mlt = &rdata->mlooptri[tri_idx];
(*r_vert_uvs)[0] = rdata->mloopuv[uv_layer][mlt->tri[0]].uv;
(*r_vert_uvs)[1] = rdata->mloopuv[uv_layer][mlt->tri[1]].uv;
(*r_vert_uvs)[2] = rdata->mloopuv[uv_layer][mlt->tri[2]].uv;
}
}
static void mesh_render_data_looptri_cols_get(
MeshRenderData *rdata, const int tri_idx, const int vcol_layer,
unsigned char *(*r_vert_cols)[3])
{
if (rdata->edit_bmesh) {
const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
(*r_vert_cols)[0] = &((MCol *)BM_ELEM_CD_GET_VOID_P(bm_looptri[0], rdata->vcol_ofs[vcol_layer]))->a;
(*r_vert_cols)[1] = &((MCol *)BM_ELEM_CD_GET_VOID_P(bm_looptri[1], rdata->vcol_ofs[vcol_layer]))->a;
(*r_vert_cols)[2] = &((MCol *)BM_ELEM_CD_GET_VOID_P(bm_looptri[2], rdata->vcol_ofs[vcol_layer]))->a;
}
else {
const MLoopTri *mlt = &rdata->mlooptri[tri_idx];
(*r_vert_cols)[0] = &rdata->mcol[vcol_layer][mlt->tri[0]].a;
(*r_vert_cols)[1] = &rdata->mcol[vcol_layer][mlt->tri[1]].a;
(*r_vert_cols)[2] = &rdata->mcol[vcol_layer][mlt->tri[2]].a;
}
}
static void mesh_render_data_looptri_tans_get(
MeshRenderData *rdata, const int tri_idx, const int tangent_layer,
float *(*r_vert_tans)[3])
{
if (rdata->edit_bmesh) {
#if 0 /* waiting for edit mesh tangent calculation */
const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
(*r_vert_tans)[0] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[0], rdata->tangent_ofs[tangent_layer]));
(*r_vert_tans)[1] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[1], rdata->tangent_ofs[tangent_layer]));
(*r_vert_tans)[2] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[2], rdata->tangent_ofs[tangent_layer]));
#else
static float tan[4] = {0.0f};
(*r_vert_tans)[0] = tan;
(*r_vert_tans)[1] = tan;
(*r_vert_tans)[2] = tan;
#endif
}
else {
const MLoopTri *mlt = &rdata->mlooptri[tri_idx];
(*r_vert_tans)[0] = rdata->mtangent[tangent_layer][mlt->tri[0]];
(*r_vert_tans)[1] = rdata->mtangent[tangent_layer][mlt->tri[1]];
(*r_vert_tans)[2] = rdata->mtangent[tangent_layer][mlt->tri[2]];
}
}
static void mesh_render_data_looptri_orcos_get(
MeshRenderData *rdata, const int tri_idx,
float *(*r_vert_orcos)[3])
{
BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_SHADING));
if (rdata->edit_bmesh) {
const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
(*r_vert_orcos)[0] = rdata->orco[BM_elem_index_get(bm_looptri[0]->v)];
(*r_vert_orcos)[1] = rdata->orco[BM_elem_index_get(bm_looptri[1]->v)];
(*r_vert_orcos)[2] = rdata->orco[BM_elem_index_get(bm_looptri[2]->v)];
}
else {
const MLoopTri *mlt = &rdata->mlooptri[tri_idx];
(*r_vert_orcos)[0] = rdata->orco[rdata->mloop[mlt->tri[0]].v];
(*r_vert_orcos)[1] = rdata->orco[rdata->mloop[mlt->tri[1]].v];
(*r_vert_orcos)[2] = rdata->orco[rdata->mloop[mlt->tri[2]].v];
}
}
static bool mesh_render_data_looptri_cos_nors_smooth_get(
MeshRenderData *rdata, const int tri_idx,
float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3], bool *r_is_smooth)
@ -890,6 +1147,7 @@ typedef struct MeshBatchCache {
/* Maybe have shaded_triangles_data split into pos_nor and uv_tangent
* to minimise data transfer for skinned mesh. */
VertexFormat shaded_triangles_format;
VertexBuffer *shaded_triangles_data;
ElementList **shaded_triangles_in_order;
Batch **shaded_triangles;
@ -1064,19 +1322,57 @@ static VertexBuffer *mesh_batch_cache_get_shading_data(MeshRenderData *rdata, Me
if (cache->shaded_triangles_data == NULL) {
unsigned int vidx = 0, nidx = 0;
const char *attrib_name;
static VertexFormat format = { 0 };
static unsigned int pos_id, nor_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
/* TODO add tangent, UVs */
pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
nor_id = VertexFormat_add_attrib(&format, "nor", COMP_I16, 3, NORMALIZE_INT_TO_FLOAT);
VertexFormat *format = &cache->shaded_triangles_format;
VertexFormat_clear(format);
/* initialize vertex format */
unsigned int pos_id = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT);
unsigned int nor_id = VertexFormat_add_attrib(format, "nor", COMP_I16, 3, NORMALIZE_INT_TO_FLOAT);
unsigned int orco_id = VertexFormat_add_attrib(format, "orco", COMP_F32, 3, KEEP_FLOAT);
unsigned int *uv_id = MEM_mallocN(sizeof(*uv_id) * rdata->uv_ct, "UV attrib format");
unsigned int *uv_auto_id = MEM_mallocN(sizeof(*uv_id) * rdata->uv_ct, "UV attrib format");
unsigned int *vcol_id = MEM_mallocN(sizeof(*vcol_id) * rdata->vcol_ct, "Vcol attrib format");
unsigned int *vcol_auto_id = MEM_mallocN(sizeof(*vcol_id) * rdata->vcol_ct, "Vcol attrib format");
unsigned int *tangent_id = MEM_mallocN(sizeof(*tangent_id) * rdata->uv_ct, "Tangent attrib format");
/* XXX TODO : We are allocating for the active layers
* but we only need to bind the right layer to the default attrib.
* This is a gawain limitation to solve. */
unsigned int active_uv_id = VertexFormat_add_attrib(format, "u", COMP_F32, 2, KEEP_FLOAT);
unsigned int active_vcol_id = VertexFormat_add_attrib(format, "c", COMP_U8, 3, NORMALIZE_INT_TO_FLOAT);
unsigned int active_tangent_id = VertexFormat_add_attrib(format, "t", COMP_F32, 4, KEEP_FLOAT);
for (int i = 0; i < rdata->uv_ct; i++) {
/* UV */
attrib_name = mesh_render_data_uv_layer_name_get(rdata, i);
uv_id[i] = VertexFormat_add_attrib(format, attrib_name, COMP_F32, 2, KEEP_FLOAT);
/* Auto Name */
/* TODO Remove when when have aliases */
attrib_name = mesh_render_data_uv_auto_layer_name_get(rdata, i);
uv_auto_id[i] = VertexFormat_add_attrib(format, attrib_name, COMP_F32, 3, KEEP_FLOAT);
/* Tangent */
attrib_name = mesh_render_data_tangent_layer_name_get(rdata, i);
tangent_id[i] = VertexFormat_add_attrib(format, attrib_name, COMP_F32, 3, KEEP_FLOAT);
}
for (int i = 0; i < rdata->vcol_ct; i++) {
attrib_name = mesh_render_data_vcol_layer_name_get(rdata, i);
vcol_id[i] = VertexFormat_add_attrib(format, attrib_name, COMP_U8, 3, NORMALIZE_INT_TO_FLOAT);
/* Auto layer */
if (rdata->auto_vcol[i]) {
attrib_name = mesh_render_data_vcol_auto_layer_name_get(rdata, i);
vcol_auto_id[i] = VertexFormat_add_attrib(format, attrib_name, COMP_U8, 3, NORMALIZE_INT_TO_FLOAT);
}
}
const int tri_len = mesh_render_data_looptri_len_get(rdata);
VertexBuffer *vbo = cache->shaded_triangles_data = VertexBuffer_create_with_format(&format);
VertexBuffer *vbo = cache->shaded_triangles_data = VertexBuffer_create_with_format(format);
const int vbo_len_capacity = tri_len * 3;
int vbo_len_used = 0;
@ -1085,12 +1381,15 @@ static VertexBuffer *mesh_batch_cache_get_shading_data(MeshRenderData *rdata, Me
/* TODO deduplicate all verts and make use of ElementList in mesh_batch_cache_get_shaded_triangles_in_order. */
for (int i = 0; i < tri_len; i++) {
float *tri_vert_cos[3];
float *tri_uvs[3], *tri_tans[3], *tri_orcos[3];
unsigned char *tri_cols[3];
short *tri_nor, *tri_vert_nors[3];
bool is_smooth;
if (mesh_render_data_looptri_cos_nors_smooth_get(
rdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors, &is_smooth))
{
/* NORs */
if (is_smooth) {
VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[0]);
VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[1]);
@ -1102,6 +1401,68 @@ static VertexBuffer *mesh_batch_cache_get_shading_data(MeshRenderData *rdata, Me
VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor);
}
/* UVs & TANGENTs */
for (int j = 0; j < rdata->uv_ct; j++) {
mesh_render_data_looptri_uvs_get(rdata, i, j, &tri_uvs);
VertexBuffer_set_attrib(vbo, uv_id[j], vidx + 0, tri_uvs[0]);
VertexBuffer_set_attrib(vbo, uv_id[j], vidx + 1, tri_uvs[1]);
VertexBuffer_set_attrib(vbo, uv_id[j], vidx + 2, tri_uvs[2]);
/* TODO remove this when aliases will be implemented */
VertexBuffer_set_attrib(vbo, uv_auto_id[j], vidx + 0, tri_uvs[0]);
VertexBuffer_set_attrib(vbo, uv_auto_id[j], vidx + 1, tri_uvs[1]);
VertexBuffer_set_attrib(vbo, uv_auto_id[j], vidx + 2, tri_uvs[2]);
mesh_render_data_looptri_tans_get(rdata, i, j, &tri_tans);
VertexBuffer_set_attrib(vbo, tangent_id[j], vidx + 0, tri_tans[0]);
VertexBuffer_set_attrib(vbo, tangent_id[j], vidx + 1, tri_tans[1]);
VertexBuffer_set_attrib(vbo, tangent_id[j], vidx + 2, tri_tans[2]);
}
/* TODO remove this when aliases will be implemented */
if (rdata->uv_ct != 0) {
mesh_render_data_looptri_uvs_get(rdata, i, rdata->uv_active, &tri_uvs);
VertexBuffer_set_attrib(vbo, active_uv_id, vidx + 0, tri_uvs[0]);
VertexBuffer_set_attrib(vbo, active_uv_id, vidx + 1, tri_uvs[1]);
VertexBuffer_set_attrib(vbo, active_uv_id, vidx + 2, tri_uvs[2]);
mesh_render_data_looptri_tans_get(rdata, i, rdata->tangent_active, &tri_tans);
VertexBuffer_set_attrib(vbo, active_tangent_id, vidx + 0, tri_tans[0]);
VertexBuffer_set_attrib(vbo, active_tangent_id, vidx + 1, tri_tans[1]);
VertexBuffer_set_attrib(vbo, active_tangent_id, vidx + 2, tri_tans[2]);
}
/* VCOLs */
for (int j = 0; j < rdata->vcol_ct; j++) {
mesh_render_data_looptri_cols_get(rdata, i, j, &tri_cols);
VertexBuffer_set_attrib(vbo, vcol_id[j], vidx + 0, tri_cols[0]);
VertexBuffer_set_attrib(vbo, vcol_id[j], vidx + 1, tri_cols[1]);
VertexBuffer_set_attrib(vbo, vcol_id[j], vidx + 2, tri_cols[2]);
/* Auto layer */
if (rdata->auto_vcol[j]) {
/* TODO remove this when aliases will be implemented */
VertexBuffer_set_attrib(vbo, vcol_auto_id[j], vidx + 0, tri_cols[0]);
VertexBuffer_set_attrib(vbo, vcol_auto_id[j], vidx + 1, tri_cols[1]);
VertexBuffer_set_attrib(vbo, vcol_auto_id[j], vidx + 2, tri_cols[2]);
}
}
/* TODO remove this when aliases will be implemented */
if (rdata->vcol_ct != 0) {
mesh_render_data_looptri_cols_get(rdata, i, rdata->vcol_active, &tri_cols);
VertexBuffer_set_attrib(vbo, active_vcol_id, vidx + 0, tri_cols[0]);
VertexBuffer_set_attrib(vbo, active_vcol_id, vidx + 1, tri_cols[1]);
VertexBuffer_set_attrib(vbo, active_vcol_id, vidx + 2, tri_cols[2]);
}
/* ORCO */
mesh_render_data_looptri_orcos_get(rdata, i, &tri_orcos);
VertexBuffer_set_attrib(vbo, orco_id, vidx + 0, tri_orcos[0]);
VertexBuffer_set_attrib(vbo, orco_id, vidx + 1, tri_orcos[1]);
VertexBuffer_set_attrib(vbo, orco_id, vidx + 2, tri_orcos[2]);
/* COs */
VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[0]);
VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[1]);
VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[2]);
@ -1112,6 +1473,12 @@ static VertexBuffer *mesh_batch_cache_get_shading_data(MeshRenderData *rdata, Me
if (vbo_len_capacity != vbo_len_used) {
VertexBuffer_resize_data(vbo, vbo_len_used);
}
MEM_freeN(uv_id);
MEM_freeN(uv_auto_id);
MEM_freeN(vcol_id);
MEM_freeN(vcol_auto_id);
MEM_freeN(tangent_id);
}
return cache->shaded_triangles_data;
}
@ -1623,7 +1990,8 @@ Batch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me)
if (cache->shaded_triangles == NULL) {
/* create batch from DM */
MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY);
const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY | MR_DATATYPE_SHADING;
MeshRenderData *rdata = mesh_render_data_create(me, datatype);
const int mat_ct = mesh_render_data_mat_ct_get(rdata);