Freestyle: memory consumption optimization in stroke rendering.

Previously individual strokes were represented by distinct mesh objects
no matter how many vertices and materials each stroke has, although
the vertex and material counts can be quite small depending on the input
scene data.  Now stroke meshes are packed into a minimum number of
mesh objects, so as to reduce the overheads of Blender object creation.
This commit is contained in:
Tamito Kajiyama 2014-08-08 22:29:02 +09:00
parent babfec9e8f
commit d8b00a3bf5
Notes: blender-bot 2023-02-14 10:02:29 +01:00
Referenced by commit a0fa3de267, Fix T43624: Freestyle uses wrong colour on second Line Set with textured lines in Cycles.
Referenced by issue #43624, Freestyle uses wrong colour on second Line Set with textured lines in Cycles
Referenced by issue #41964, 2.72 Freestyle renders two times longer on Linux
5 changed files with 345 additions and 233 deletions

View File

@ -882,10 +882,13 @@ void Controller::ResetRenderCount()
Render *Controller::RenderStrokes(Render *re, bool render)
{
int totmesh = 0;
_Chrono.start();
BlenderStrokeRenderer *blenderRenderer = new BlenderStrokeRenderer(re, ++_render_count);
if (render)
if (render) {
_Canvas->Render(blenderRenderer);
totmesh = blenderRenderer->GenerateScene();
}
real d = _Chrono.stop();
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Temporary scene generation: " << d << endl;
@ -904,8 +907,8 @@ Render *Controller::RenderStrokes(Render *re, bool render)
float mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
float megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
printf("%d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n",
freestyle_render->i.totvert, freestyle_render->i.totface,
printf("%d objs, %d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n",
totmesh, freestyle_render->i.totvert, freestyle_render->i.totface,
megs_used_memory, mmap_used_memory, megs_peak_memory);
}
delete blenderRenderer;

View File

@ -66,6 +66,8 @@ extern "C" {
namespace Freestyle {
const char *BlenderStrokeRenderer::uvNames[] = {"along_stroke", "along_stroke_tips"};
BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : StrokeRenderer()
{
freestyle_bmain = re->freestyle_bmain;
@ -208,6 +210,8 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
if (_use_shading_nodes)
BLI_ghash_free(_nodetree_hash, NULL, NULL);
FreeStrokeGroups();
}
float BlenderStrokeRenderer::get_stroke_vertex_z(void) const
@ -414,10 +418,10 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr
input_uvmap->locy = node->locy;
NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage;
if (node->custom1 & 1) { // use_tips
BLI_strncpy(storage->uv_map, "along_stroke_tips", sizeof(storage->uv_map));
BLI_strncpy(storage->uv_map, uvNames[1], sizeof(storage->uv_map));
}
else {
BLI_strncpy(storage->uv_map, "along_stroke", sizeof(storage->uv_map));
BLI_strncpy(storage->uv_map, uvNames[0], sizeof(storage->uv_map));
}
fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV
@ -439,6 +443,11 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr
}
void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
{
RenderStrokeRepBasic(iStrokeRep);
}
void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
{
if (_use_shading_nodes) {
bNodeTree *nt = iStrokeRep->getNodeTree();
@ -509,10 +518,10 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
// We'll generate both with tips and without tips
// coordinates, on two different UV layers.
if (ma->mtex[a]->texflag & MTEX_TIPS) {
BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname));
BLI_strncpy(ma->mtex[a]->uvname, uvNames[1], sizeof(ma->mtex[a]->uvname));
}
else {
BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname));
BLI_strncpy(ma->mtex[a]->uvname, uvNames[0], sizeof(ma->mtex[a]->uvname));
}
a++;
}
@ -521,7 +530,42 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
}
}
RenderStrokeRepBasic(iStrokeRep);
const vector<Strip*>& strips = iStrokeRep->getStrips();
const bool hasTex = iStrokeRep->hasTex();
int totvert = 0, totedge = 0, totpoly = 0, totloop = 0;
int visible_faces, visible_segments;
for (vector<Strip*>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
Strip::vertex_container& strip_vertices = (*s)->vertices();
// count visible faces and strip segments
test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
if (visible_faces == 0)
continue;
totvert += visible_faces + visible_segments * 2;
totedge += visible_faces * 2 + visible_segments;
totpoly += visible_faces;
totloop += visible_faces * 3;
}
BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this); // FIXME
vector<StrokeGroup*> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups;
StrokeGroup *group;
if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS &&
groups->back()->totcol + 1 < MAXMAT))
{
group = new StrokeGroup;
groups->push_back(group);
}
else {
group = groups->back();
}
group->strokes.push_back(iStrokeRep);
group->totvert += totvert;
group->totedge += totedge;
group->totpoly += totpoly;
group->totloop += totloop;
group->totcol++;
}
// Check if the triangle is visible (i.e., within the render image boundary)
@ -578,117 +622,168 @@ void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container& strip
}
}
// Build a mesh object representing a stroke
void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// Release allocated memory for stroke groups
void BlenderStrokeRenderer::FreeStrokeGroups()
{
vector<Strip*>& strips = iStrokeRep->getStrips();
const bool hasTex = iStrokeRep->hasTex();
Strip::vertex_container::iterator v[3];
StrokeVertexRep *svRep[3];
unsigned int vertex_index, edge_index, loop_index;
Vec2r p;
vector<StrokeGroup*>::const_iterator it, itend;
int totvert = 0, totedge = 0, totpoly = 0, totloop = 0;
int visible_faces, visible_segments;
bool visible;
for (vector<Strip*>::iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
Strip::vertex_container& strip_vertices = (*s)->vertices();
// count visible faces and strip segments
test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
if (visible_faces == 0)
continue;
totvert += visible_faces + visible_segments * 2;
totedge += visible_faces * 2 + visible_segments;
totpoly += visible_faces;
totloop += visible_faces * 3;
for (it = strokeGroups.begin(), itend = strokeGroups.end();
it != itend; ++it)
{
delete (*it);
}
for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end();
it != itend; ++it)
{
delete (*it);
}
}
// Build a scene populated by mesh objects representing stylized strokes
int BlenderStrokeRenderer::GenerateScene()
{
vector<StrokeGroup*>::const_iterator it, itend;
for (it = strokeGroups.begin(), itend = strokeGroups.end();
it != itend; ++it)
{
GenerateStrokeMesh(*it, false);
}
for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end();
it != itend; ++it)
{
GenerateStrokeMesh(*it, true);
}
return strokeGroups.size() + texturedStrokeGroups.size();
}
// Build a mesh object representing a group of stylized strokes
void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
{
#if 0
Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH);
#else
Object *object_mesh = NewMesh();
#endif
Mesh *mesh = (Mesh *)object_mesh->data;
mesh->mat = (Material **)MEM_mallocN(1 * sizeof(Material *), "MaterialList");
mesh->mat[0] = iStrokeRep->getMaterial();
mesh->totcol = 1;
test_object_materials(freestyle_bmain, (ID *)mesh);
// vertices allocation
mesh->totvert = totvert; // visible_faces + visible_segments * 2;
CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
mesh->totvert = group->totvert;
mesh->totedge = group->totedge;
mesh->totpoly = group->totpoly;
mesh->totloop = group->totloop;
mesh->totcol = group->totcol;
// edges allocation
mesh->totedge = totedge; // visible_faces * 2 + visible_segments;
CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
// faces allocation
mesh->totpoly = totpoly; // visible_faces;
CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
// loops allocation
mesh->totloop = totloop; // visible_faces * 3;
CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
// uv maps
MLoopUV *loopsuv[2] = { NULL };
if (hasTex) {
loopsuv[0] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke");
loopsuv[1] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips");
CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke");
CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips");
}
// colors and transparency (the latter represented by grayscale colors)
MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Color");
MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Alpha");
BKE_mesh_update_customdata_pointers(mesh, true);
////////////////////
// Data copy
////////////////////
mesh->mvert = (MVert *)CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
mesh->medge = (MEdge *)CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
mesh->mpoly = (MPoly *)CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
mesh->mloop = (MLoop *)CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
MVert *vertices = mesh->mvert;
MEdge *edges = mesh->medge;
MPoly *polys = mesh->mpoly;
MLoop *loops = mesh->mloop;
MLoopUV *loopsuv[2] = { NULL };
vertex_index = edge_index = loop_index = 0;
if (hasTex) {
// First UV layer
CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[0]);
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[0]);
CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 0);
CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0);
BKE_mesh_update_customdata_pointers(mesh, true);
loopsuv[0] = mesh->mloopuv;
for (vector<Strip*>::iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
Strip::vertex_container& strip_vertices = (*s)->vertices();
int strip_vertex_count = strip_vertices.size();
// Second UV layer
CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[1]);
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[1]);
CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 1);
CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1);
BKE_mesh_update_customdata_pointers(mesh, true);
loopsuv[1] = mesh->mloopuv;
}
// count visible faces and strip segments
test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
if (visible_faces == 0)
continue;
// colors and transparency (the latter represented by grayscale colors)
MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Color");
MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Alpha");
mesh->mloopcol = colors;
v[0] = strip_vertices.begin();
v[1] = v[0] + 1;
v[2] = v[0] + 2;
mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList");
visible = false;
////////////////////
// Data copy
////////////////////
// Note: Mesh generation in the following loop assumes stroke strips
// to be triangle strips.
for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
svRep[0] = *(v[0]);
svRep[1] = *(v[1]);
svRep[2] = *(v[2]);
if (!test_triangle_visibility(svRep)) {
visible = false;
}
else {
if (!visible) {
// first vertex
vertices->co[0] = svRep[0]->point2d()[0];
vertices->co[1] = svRep[0]->point2d()[1];
int vertex_index = 0, edge_index = 0, loop_index = 0, material_index = 0;
int visible_faces, visible_segments;
bool visible;
Strip::vertex_container::iterator v[3];
StrokeVertexRep *svRep[3];
Vec2r p;
for (vector<StrokeRep*>::const_iterator it = group->strokes.begin(), itend = group->strokes.end();
it != itend; ++it)
{
mesh->mat[material_index] = (*it)->getMaterial();
material_index++;
vector<Strip*>& strips = (*it)->getStrips();
for (vector<Strip*>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
Strip::vertex_container& strip_vertices = (*s)->vertices();
int strip_vertex_count = strip_vertices.size();
// count visible faces and strip segments
test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
if (visible_faces == 0)
continue;
v[0] = strip_vertices.begin();
v[1] = v[0] + 1;
v[2] = v[0] + 2;
visible = false;
// Note: Mesh generation in the following loop assumes stroke strips
// to be triangle strips.
for (int n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
svRep[0] = *(v[0]);
svRep[1] = *(v[1]);
svRep[2] = *(v[2]);
if (!test_triangle_visibility(svRep)) {
visible = false;
}
else {
if (!visible) {
// first vertex
vertices->co[0] = svRep[0]->point2d()[0];
vertices->co[1] = svRep[0]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
vertices->no[0] = 0;
vertices->no[1] = 0;
vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
// second vertex
vertices->co[0] = svRep[1]->point2d()[0];
vertices->co[1] = svRep[1]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
vertices->no[0] = 0;
vertices->no[1] = 0;
vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
// first edge
edges->v1 = vertex_index - 2;
edges->v2 = vertex_index - 1;
++edges;
++edge_index;
}
visible = true;
// vertex
vertices->co[0] = svRep[2]->point2d()[0];
vertices->co[1] = svRep[2]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
vertices->no[0] = 0;
vertices->no[1] = 0;
@ -696,150 +791,127 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
++vertices;
++vertex_index;
// second vertex
vertices->co[0] = svRep[1]->point2d()[0];
vertices->co[1] = svRep[1]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
vertices->no[0] = 0;
vertices->no[1] = 0;
vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
// first edge
edges->v1 = vertex_index - 2;
edges->v2 = vertex_index - 1;
// edges
edges->v1 = vertex_index - 1;
edges->v2 = vertex_index - 3;
++edges;
++edge_index;
}
visible = true;
// vertex
vertices->co[0] = svRep[2]->point2d()[0];
vertices->co[1] = svRep[2]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
vertices->no[0] = 0;
vertices->no[1] = 0;
vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
edges->v1 = vertex_index - 1;
edges->v2 = vertex_index - 2;
++edges;
++edge_index;
// edges
edges->v1 = vertex_index - 1;
edges->v2 = vertex_index - 3;
++edges;
++edge_index;
// poly
polys->loopstart = loop_index;
polys->totloop = 3;
++polys;
edges->v1 = vertex_index - 1;
edges->v2 = vertex_index - 2;
++edges;
++edge_index;
// Even and odd loops connect triangles vertices differently
bool is_odd = n % 2;
// loops
if (is_odd) {
loops[0].v = vertex_index - 1;
loops[0].e = edge_index - 2;
// poly
polys->loopstart = loop_index;
polys->totloop = 3;
++polys;
loops[1].v = vertex_index - 3;
loops[1].e = edge_index - 3;
// Even and odd loops connect triangles vertices differently
bool is_odd = n % 2;
// loops
if (is_odd) {
loops[0].v = vertex_index - 1;
loops[0].e = edge_index - 2;
loops[1].v = vertex_index - 3;
loops[1].e = edge_index - 3;
loops[2].v = vertex_index - 2;
loops[2].e = edge_index - 1;
}
else {
loops[0].v = vertex_index - 1;
loops[0].e = edge_index - 1;
loops[1].v = vertex_index - 2;
loops[1].e = edge_index - 3;
loops[2].v = vertex_index - 3;
loops[2].e = edge_index - 2;
}
loops += 3;
loop_index += 3;
// UV
if (hasTex) {
// First UV layer (loopsuv[0]) has no tips (texCoord(0)).
// Second UV layer (loopsuv[1]) has tips: (texCoord(1)).
for (int L = 0; L < 2; L++) {
if (is_odd) {
loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x();
loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y();
loopsuv[L][1].uv[0] = svRep[0]->texCoord(L).x();
loopsuv[L][1].uv[1] = svRep[0]->texCoord(L).y();
loopsuv[L][2].uv[0] = svRep[1]->texCoord(L).x();
loopsuv[L][2].uv[1] = svRep[1]->texCoord(L).y();
}
else {
loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x();
loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y();
loopsuv[L][1].uv[0] = svRep[1]->texCoord(L).x();
loopsuv[L][1].uv[1] = svRep[1]->texCoord(L).y();
loopsuv[L][2].uv[0] = svRep[0]->texCoord(L).x();
loopsuv[L][2].uv[1] = svRep[0]->texCoord(L).y();
}
loopsuv[L] += 3;
loops[2].v = vertex_index - 2;
loops[2].e = edge_index - 1;
}
else {
loops[0].v = vertex_index - 1;
loops[0].e = edge_index - 1;
loops[1].v = vertex_index - 2;
loops[1].e = edge_index - 3;
loops[2].v = vertex_index - 3;
loops[2].e = edge_index - 2;
}
loops += 3;
loop_index += 3;
// UV
if (hasTex) {
// First UV layer (loopsuv[0]) has no tips (texCoord(0)).
// Second UV layer (loopsuv[1]) has tips: (texCoord(1)).
for (int L = 0; L < 2; L++) {
if (is_odd) {
loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x();
loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y();
loopsuv[L][1].uv[0] = svRep[0]->texCoord(L).x();
loopsuv[L][1].uv[1] = svRep[0]->texCoord(L).y();
loopsuv[L][2].uv[0] = svRep[1]->texCoord(L).x();
loopsuv[L][2].uv[1] = svRep[1]->texCoord(L).y();
}
else {
loopsuv[L][0].uv[0] = svRep[2]->texCoord(L).x();
loopsuv[L][0].uv[1] = svRep[2]->texCoord(L).y();
loopsuv[L][1].uv[0] = svRep[1]->texCoord(L).x();
loopsuv[L][1].uv[1] = svRep[1]->texCoord(L).y();
loopsuv[L][2].uv[0] = svRep[0]->texCoord(L).x();
loopsuv[L][2].uv[1] = svRep[0]->texCoord(L).y();
}
loopsuv[L] += 3;
}
}
// colors and alpha transparency
if (is_odd) {
colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
colors[0].a = (short)(255.0f * svRep[2]->alpha());
colors[1].r = (short)(255.0f * svRep[0]->color()[0]);
colors[1].g = (short)(255.0f * svRep[0]->color()[1]);
colors[1].b = (short)(255.0f * svRep[0]->color()[2]);
colors[1].a = (short)(255.0f * svRep[0]->alpha());
colors[2].r = (short)(255.0f * svRep[1]->color()[0]);
colors[2].g = (short)(255.0f * svRep[1]->color()[1]);
colors[2].b = (short)(255.0f * svRep[1]->color()[2]);
colors[2].a = (short)(255.0f * svRep[1]->alpha());
}
else {
colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
colors[0].a = (short)(255.0f * svRep[2]->alpha());
colors[1].r = (short)(255.0f * svRep[1]->color()[0]);
colors[1].g = (short)(255.0f * svRep[1]->color()[1]);
colors[1].b = (short)(255.0f * svRep[1]->color()[2]);
colors[1].a = (short)(255.0f * svRep[1]->alpha());
colors[2].r = (short)(255.0f * svRep[0]->color()[0]);
colors[2].g = (short)(255.0f * svRep[0]->color()[1]);
colors[2].b = (short)(255.0f * svRep[0]->color()[2]);
colors[2].a = (short)(255.0f * svRep[0]->alpha());
}
transp[0].r = transp[0].g = transp[0].b = colors[0].a;
transp[1].r = transp[1].g = transp[1].b = colors[1].a;
transp[2].r = transp[2].g = transp[2].b = colors[2].a;
colors += 3;
transp += 3;
}
} // loop over strip vertices
} // loop over strips
} // loop over strokes
// colors and alpha transparency
if (is_odd) {
colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
colors[0].a = (short)(255.0f * svRep[2]->alpha());
test_object_materials(freestyle_bmain, (ID *)mesh);
colors[1].r = (short)(255.0f * svRep[0]->color()[0]);
colors[1].g = (short)(255.0f * svRep[0]->color()[1]);
colors[1].b = (short)(255.0f * svRep[0]->color()[2]);
colors[1].a = (short)(255.0f * svRep[0]->alpha());
colors[2].r = (short)(255.0f * svRep[1]->color()[0]);
colors[2].g = (short)(255.0f * svRep[1]->color()[1]);
colors[2].b = (short)(255.0f * svRep[1]->color()[2]);
colors[2].a = (short)(255.0f * svRep[1]->alpha());
}
else {
colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
colors[0].a = (short)(255.0f * svRep[2]->alpha());
colors[1].r = (short)(255.0f * svRep[1]->color()[0]);
colors[1].g = (short)(255.0f * svRep[1]->color()[1]);
colors[1].b = (short)(255.0f * svRep[1]->color()[2]);
colors[1].a = (short)(255.0f * svRep[1]->alpha());
colors[2].r = (short)(255.0f * svRep[0]->color()[0]);
colors[2].g = (short)(255.0f * svRep[0]->color()[1]);
colors[2].b = (short)(255.0f * svRep[0]->color()[2]);
colors[2].a = (short)(255.0f * svRep[0]->alpha());
}
transp[0].r = transp[0].g = transp[0].b = colors[0].a;
transp[1].r = transp[1].g = transp[1].b = colors[1].a;
transp[2].r = transp[2].g = transp[2].b = colors[2].a;
colors += 3;
transp += 3;
}
} // loop over strip vertices
} // loop over strips
#if 0
BLI_assert(totvert == vertex_index);
BLI_assert(totedge == edge_index);
BLI_assert(totloop == loop_index);
#if 0 // XXX
BLI_assert(mesh->totvert == vertex_index);
BLI_assert(mesh->totedge == edge_index);
BLI_assert(mesh->totloop == loop_index);
BLI_assert(mesh->totcol == material_index);
BKE_mesh_validate(mesh, true);
#endif
}

View File

@ -53,6 +53,21 @@ public:
Object *NewMesh() const;
struct StrokeGroup {
explicit StrokeGroup() : totvert(0), totedge(0), totpoly(0), totloop(0), totcol(0) {}
vector<StrokeRep*> strokes;
int totvert;
int totedge;
int totpoly;
int totloop;
int totcol;
};
vector<StrokeGroup*> strokeGroups, texturedStrokeGroups;
int GenerateScene();
void GenerateStrokeMesh(StrokeGroup *group, bool hasTex);
void FreeStrokeGroups();
Render *RenderScene(Render *re, bool render);
static Material* GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user);
@ -68,12 +83,16 @@ protected:
bool _use_shading_nodes;
struct GHash *_nodetree_hash;
static const char *uvNames[];
float get_stroke_vertex_z(void) const;
unsigned int get_stroke_mesh_id(void) const;
bool test_triangle_visibility(StrokeVertexRep *svRep[3]) const;
void test_strip_visibility(Strip::vertex_container& strip_vertices,
int *visible_faces, int *visible_segments) const;
vector<StrokeRep *> _strokeReps;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStrokeRenderer")
#endif

View File

@ -400,6 +400,7 @@ Stroke::Stroke()
}
_nodeTree = NULL;
_tips = false;
_rep = NULL;
}
Stroke::Stroke(const Stroke& iBrother)
@ -427,6 +428,10 @@ Stroke::Stroke(const Stroke& iBrother)
}
_nodeTree = iBrother._nodeTree;
_tips = iBrother._tips;
if (iBrother._rep)
_rep = new StrokeRep(*(iBrother._rep));
else
_rep = NULL;
}
Stroke::~Stroke()
@ -439,6 +444,10 @@ Stroke::~Stroke()
}
_ViewEdges.clear();
if (_rep) {
delete _rep;
_rep = NULL;
}
}
Stroke& Stroke::operator=(const Stroke& iBrother)
@ -456,6 +465,12 @@ Stroke& Stroke::operator=(const Stroke& iBrother)
_id = iBrother._id;
_ViewEdges = iBrother._ViewEdges;
_sampling = iBrother._sampling;
if (_rep)
delete _rep;
if (iBrother._rep)
_rep = new StrokeRep(*(iBrother._rep));
else
_rep = NULL;
return *this;
}
@ -757,14 +772,16 @@ void Stroke::ScaleThickness(float iFactor)
void Stroke::Render(const StrokeRenderer *iRenderer)
{
StrokeRep rep(this);
iRenderer->RenderStrokeRep(&rep);
if (!_rep)
_rep = new StrokeRep(this);
iRenderer->RenderStrokeRep(_rep);
}
void Stroke::RenderBasic(const StrokeRenderer *iRenderer)
{
StrokeRep rep(this);
iRenderer->RenderStrokeRepBasic(&rep);
if (!_rep)
_rep = new StrokeRep(this);
iRenderer->RenderStrokeRep(_rep);
}
Stroke::vertex_iterator Stroke::vertices_begin(float sampling)

View File

@ -549,6 +549,7 @@ private:
MTex *_mtex[MAX_MTEX];
bNodeTree *_nodeTree;
bool _tips;
StrokeRep *_rep;
Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity
public: