From d8b00a3bf5c170c60e33a10c660820b35e2ec0a8 Mon Sep 17 00:00:00 2001 From: Tamito Kajiyama Date: Fri, 8 Aug 2014 22:29:02 +0900 Subject: [PATCH] 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. --- .../intern/application/Controller.cpp | 9 +- .../BlenderStrokeRenderer.cpp | 524 ++++++++++-------- .../blender_interface/BlenderStrokeRenderer.h | 19 + .../freestyle/intern/stroke/Stroke.cpp | 25 +- .../blender/freestyle/intern/stroke/Stroke.h | 1 + 5 files changed, 345 insertions(+), 233 deletions(-) diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 7c8a0c9d079..f8931d32f56 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -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; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 09701ab6acd..29f3bfe0d94 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -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& strips = iStrokeRep->getStrips(); + const bool hasTex = iStrokeRep->hasTex(); + int totvert = 0, totedge = 0, totpoly = 0, totloop = 0; + int visible_faces, visible_segments; + for (vector::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(this); // FIXME + vector *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& 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::const_iterator it, itend; - int totvert = 0, totedge = 0, totpoly = 0, totloop = 0; - int visible_faces, visible_segments; - - bool visible; - for (vector::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::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::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::const_iterator it = group->strokes.begin(), itend = group->strokes.end(); + it != itend; ++it) + { + mesh->mat[material_index] = (*it)->getMaterial(); + material_index++; + + vector& strips = (*it)->getStrips(); + for (vector::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 } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h index 74e5d321df2..a381932e9e7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h @@ -53,6 +53,21 @@ public: Object *NewMesh() const; + struct StrokeGroup { + explicit StrokeGroup() : totvert(0), totedge(0), totpoly(0), totloop(0), totcol(0) {} + vector strokes; + int totvert; + int totedge; + int totpoly; + int totloop; + int totcol; + }; + vector 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 _strokeReps; + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStrokeRenderer") #endif diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp index 863da069259..244b20f6b89 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.cpp +++ b/source/blender/freestyle/intern/stroke/Stroke.cpp @@ -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) diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index 8ff801ed144..5f0b4eab309 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -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: