Freestyle: memory consumption optimization in stroke rendering.
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>
Fri, 8 Aug 2014 13:29:02 +0000 (22:29 +0900)
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>
Sat, 3 Jan 2015 12:54:56 +0000 (21:54 +0900)
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.

source/blender/freestyle/intern/application/Controller.cpp
source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
source/blender/freestyle/intern/stroke/Stroke.cpp
source/blender/freestyle/intern/stroke/Stroke.h

index 7c8a0c9d079bee44fcd226cb75f4327ba37dd3f8..f8931d32f56d2a3b0f841338a62dadbd3f300d28 100644 (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;
index 09701ab6acd149525a0b62bb6d7b1aef6ef08546..29f3bfe0d941e17f0e7aedfbdab575ad290e5346 100644 (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,127 +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();
+       for (it = strokeGroups.begin(), itend = strokeGroups.end();
+            it != itend; ++it)
+       {
+               delete (*it);
+       }
+       for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end();
+            it != itend; ++it)
+       {
+               delete (*it);
+       }
+}
 
-               // count visible faces and strip segments
-               test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
-               if (visible_faces == 0)
-                       continue;
+// Build a scene populated by mesh objects representing stylized strokes
+int BlenderStrokeRenderer::GenerateScene()
+{
+       vector<StrokeGroup*>::const_iterator it, itend;
 
-               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)
+       {
+               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);
+       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);
 
-       // 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
+       MVert *vertices = mesh->mvert;
+       MEdge *edges = mesh->medge;
+       MPoly *polys = mesh->mpoly;
+       MLoop *loops = mesh->mloop;
        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");
+       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;
+
+               // 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;
        }
 
        // 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;
 
-       BKE_mesh_update_customdata_pointers(mesh, true);
+       mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList");
 
        ////////////////////
        //  Data copy
        ////////////////////
 
-       MVert *vertices = mesh->mvert;
-       MEdge *edges = mesh->medge;
-       MPoly *polys = mesh->mpoly;
-       MLoop *loops = mesh->mloop;
+       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;
 
-       vertex_index = edge_index = loop_index = 0;
+       for (vector<StrokeRep*>::const_iterator it = group->strokes.begin(), itend = group->strokes.end();
+            it != itend; ++it)
+       {
+               mesh->mat[material_index] = (*it)->getMaterial();
+               material_index++;
 
-       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();
+               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;
+                       // 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;
+                       v[0] = strip_vertices.begin();
+                       v[1] = v[0] + 1;
+                       v[2] = v[0] + 2;
 
-               visible = false;
+                       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;
+                       // 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;
 
-                                       // second vertex
-                                       vertices->co[0] = svRep[1]->point2d()[0];
-                                       vertices->co[1] = svRep[1]->point2d()[1];
+                                       // 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;
@@ -706,140 +791,127 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
                                        ++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
-                               edges->v1 = vertex_index - 1;
-                               edges->v2 = vertex_index - 3;
-                               ++edges;
-                               ++edge_index;
-
-                               edges->v1 = vertex_index - 1;
-                               edges->v2 = vertex_index - 2;
-                               ++edges;
-                               ++edge_index;
-
-                               // poly
-                               polys->loopstart = loop_index;
-                               polys->totloop = 3;
-                               ++polys;
-
-                               // 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;
+                                       edges->v1 = vertex_index - 1;
+                                       edges->v2 = vertex_index - 2;
+                                       ++edges;
+                                       ++edge_index;
 
-                                       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();
+                                       // poly
+                                       polys->loopstart = loop_index;
+                                       polys->totloop = 3;
+                                       ++polys;
+
+                                       // 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;
 
-                                                       loopsuv[L][1].uv[0] = svRep[1]->texCoord(L).x();
-                                                       loopsuv[L][1].uv[1] = svRep[1]->texCoord(L).y();
+                                               loops[1].v = vertex_index - 3;
+                                               loops[1].e = edge_index - 3;
 
-                                                       loopsuv[L][2].uv[0] = svRep[0]->texCoord(L).x();
-                                                       loopsuv[L][2].uv[1] = svRep[0]->texCoord(L).y();
+                                               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;
                                                }
-                                               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());
+                                       // 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;
                                }
-                               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);
+                       } // loop over strip vertices
+               } // loop over strips
+       } // loop over strokes
+
+       test_object_materials(freestyle_bmain, (ID *)mesh);
+
+#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
 }
index 74e5d321df258c89f6f26a48b77ffe5f1f7cd67f..a381932e9e7f186deb5ea896f193e59afd3e6a95 100644 (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
index 863da0692596bc63989873e08669e8b7490587b0..244b20f6b89035f2184f045dcc413e39a0283fa8 100644 (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)
index 8ff801ed1443f92e44d3cf833930fae63797de0f..5f0b4eab309b65b2415f04235c54ab94e7bf7036 100644 (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: