# include "BlenderStrokeRenderer.h" # include "../stroke/Canvas.h" # include "../application/AppConfig.h" # include "BlenderTextureManager.h" #ifdef __cplusplus extern "C" { #endif #include "MEM_guardedalloc.h" #include "DNA_camera_types.h" #include "DNA_customdata_types.h" #include "DNA_listBase.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_library.h" /* free_libblock */ #include "BKE_material.h" #include "BKE_main.h" /* struct Main */ #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" #include "RE_pipeline.h" #ifdef __cplusplus } #endif BlenderStrokeRenderer::BlenderStrokeRenderer(Render* re, int render_count) :StrokeRenderer(){ // TEMPORARY - need a texture manager _textureManager = new BlenderTextureManager; _textureManager->load(); _width = re->winx; _height = re->winy; // for stroke mesh generation // Scene.New("FreestyleStrokes") old_scene = re->scene; char name[22]; snprintf(name, sizeof(name), "FRS%d_%s", render_count, re->scene->id.name+2); freestyle_scene = BKE_scene_add(name); freestyle_scene->r.cfra = old_scene->r.cfra; freestyle_scene->r.mode= old_scene->r.mode & ~( R_EDGE_FRS | R_SHADOW | R_SSS | R_PANORAMA | R_ENVMAP | R_MBLUR | R_BORDER ); freestyle_scene->r.xsch= re->rectx; // old_scene->r.xsch freestyle_scene->r.ysch= re->recty; // old_scene->r.ysch freestyle_scene->r.xasp= 1.f; // old_scene->r.xasp; freestyle_scene->r.yasp= 1.f; // old_scene->r.yasp; freestyle_scene->r.tilex= old_scene->r.tilex; freestyle_scene->r.tiley= old_scene->r.tiley; freestyle_scene->r.size= 100; // old_scene->r.size freestyle_scene->r.maximsize= old_scene->r.maximsize; freestyle_scene->r.ocres = old_scene->r.ocres; freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag; freestyle_scene->r.scemode= old_scene->r.scemode & ~( R_SINGLE_LAYER ); freestyle_scene->r.flag= old_scene->r.flag; freestyle_scene->r.threads= old_scene->r.threads; freestyle_scene->r.border.xmin= old_scene->r.border.xmin; freestyle_scene->r.border.ymin= old_scene->r.border.ymin; freestyle_scene->r.border.xmax= old_scene->r.border.xmax; freestyle_scene->r.border.ymax= old_scene->r.border.ymax; strcpy(freestyle_scene->r.pic, old_scene->r.pic); freestyle_scene->r.safety.xmin= old_scene->r.safety.xmin; freestyle_scene->r.safety.ymin= old_scene->r.safety.ymin; freestyle_scene->r.safety.xmax= old_scene->r.safety.xmax; freestyle_scene->r.safety.ymax= old_scene->r.safety.ymax; freestyle_scene->r.osa= old_scene->r.osa; freestyle_scene->r.filtertype= old_scene->r.filtertype; freestyle_scene->r.gauss= old_scene->r.gauss; freestyle_scene->r.dither_intensity= old_scene->r.dither_intensity; BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine)); freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA; freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG; BKE_scene_disable_color_management(freestyle_scene); BKE_scene_set_background( G.main, freestyle_scene ); // Camera Object* object_camera = BKE_object_add(freestyle_scene, OB_CAMERA); Camera* camera = (Camera *) object_camera->data; camera->type = CAM_ORTHO; camera->ortho_scale = max(re->rectx, re->recty); camera->clipsta = 0.1f; camera->clipend = 100.0f; _z_delta = 0.00001f; _z = camera->clipsta + _z_delta; // test //_z = 999.90f; _z_delta = 0.01f; object_camera->loc[0] = re->disprect.xmin + 0.5f * re->rectx; object_camera->loc[1] = re->disprect.ymin + 0.5f * re->recty; object_camera->loc[2] = 1.f; freestyle_scene->camera = object_camera; // Material material = BKE_material_add("stroke_material"); material->mode |= MA_VERTEXCOLP; material->mode |= MA_TRANSP; material->mode |= MA_SHLESS; material->vcol_alpha = 1; } BlenderStrokeRenderer::~BlenderStrokeRenderer(){ if(0 != _textureManager) { delete _textureManager; _textureManager = 0; } // The freestyle_scene object is not released here. Instead, // the scene is released in free_all_freestyle_renders() in // source/blender/render/intern/source/pipeline.c, after the // compositor has finished. // release objects and data blocks Base *b = (Base *)freestyle_scene->base.first; while(b) { Object *ob = b->object; void *data = ob->data; char name[24]; strcpy(name, ob->id.name); //cout << "removing " << name[0] << name[1] << ":" << (name+2) << endl; switch (ob->type) { case OB_MESH: BKE_libblock_free( &G.main->object, ob ); BKE_libblock_free( &G.main->mesh, data ); break; case OB_CAMERA: BKE_libblock_free( &G.main->object, ob ); BKE_libblock_free( &G.main->camera, data ); freestyle_scene->camera = NULL; break; default: cerr << "Warning: unexpected object in the scene: " << name[0] << name[1] << ":" << (name+2) << endl; } b = b->next; } BLI_freelistN( &freestyle_scene->base ); // release material BKE_libblock_free( &G.main->mat, material ); BKE_scene_set_background( G.main, old_scene ); } float BlenderStrokeRenderer::get_stroke_vertex_z(void) const { float z = _z; BlenderStrokeRenderer *self = const_cast(this); if (!(_z < _z_delta * 100000.0f)) self->_z_delta *= 10.0f; self->_z += _z_delta; return -z; } void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const{ RenderStrokeRepBasic(iStrokeRep); } void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const{ //////////////////// // Build up scene //////////////////// vector& strips = iStrokeRep->getStrips(); Strip::vertex_container::iterator v[3]; StrokeVertexRep *svRep[3]; Vec3r color[3]; unsigned int vertex_index, edge_index, loop_index; Vec2r p; for(vector::iterator s=strips.begin(), send=strips.end(); s!=send; ++s){ Strip::vertex_container& strip_vertices = (*s)->vertices(); int strip_vertex_count = (*s)->sizeStrip(); int xl, xu, yl, yu, n, visible_faces, visible_segments; bool visible; // iterate over all vertices and count visible faces and strip segments // (note: a strip segment is a series of visible faces, while two strip // segments are separated by one or more invisible faces) v[0] = strip_vertices.begin(); v[1] = v[0]; ++(v[1]); v[2] = v[1]; ++(v[2]); visible_faces = visible_segments = 0; visible = false; for (n = 2; n < strip_vertex_count; n++) { svRep[0] = *(v[0]); svRep[1] = *(v[1]); svRep[2] = *(v[2]); xl = xu = yl = yu = 0; for (int j = 0; j < 3; j++) { p = svRep[j]->point2d(); if (p[0] < 0.0) xl++; else if (p[0] > _width) xu++; if (p[1] < 0.0) yl++; else if (p[1] > _height) yu++; } if (xl == 3 || xu == 3 || yl == 3 || yu == 3) { visible = false; } else { visible_faces++; if (!visible) visible_segments++; visible = true; } ++v[0]; ++v[1]; ++v[2]; } if (visible_faces == 0) continue; // me = Mesh.New() #if 0 Object* object_mesh = BKE_object_add(freestyle_scene, OB_MESH); #else Object* object_mesh = NewMesh(); #endif Mesh* mesh = (Mesh *) object_mesh->data; // MEM_freeN(mesh->bb); // mesh->bb= NULL; // mesh->id.us = 0; #if 1 // me.materials = [mat] mesh->mat = ( Material ** ) MEM_mallocN( 1 * sizeof( Material * ), "MaterialList" ); mesh->mat[0] = material; mesh->totcol = 1; test_object_materials( (ID*) mesh ); #else assign_material(object_mesh, material, object_mesh->totcol+1); object_mesh->actcol= object_mesh->totcol; #endif // vertices allocation mesh->totvert = visible_faces + visible_segments * 2; mesh->mvert = (MVert*) CustomData_add_layer( &mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); // edges allocation mesh->totedge = visible_faces * 2 + visible_segments; mesh->medge = (MEdge*) CustomData_add_layer( &mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); // faces allocation mesh->totpoly = visible_faces; mesh->mpoly= (MPoly*) CustomData_add_layer( &mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); // loops allocation mesh->totloop = visible_faces * 3; mesh->mloop= (MLoop*) CustomData_add_layer( &mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); // colors allocation mesh->mloopcol = (MLoopCol *) CustomData_add_layer( &mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop); //////////////////// // Data copy //////////////////// MVert* vertices = mesh->mvert; MEdge* edges = mesh->medge; MPoly* polys = mesh->mpoly; MLoop* loops = mesh->mloop; MLoopCol* colors = mesh->mloopcol; v[0] = strip_vertices.begin(); v[1] = v[0]; ++(v[1]); v[2] = v[1]; ++(v[2]); vertex_index = edge_index = loop_index = 0; visible = false; // Note: Mesh generation in the following loop assumes stroke strips // to be triangle strips. for (n = 2; n < strip_vertex_count; n++) { svRep[0] = *(v[0]); svRep[1] = *(v[1]); svRep[2] = *(v[2]); xl = xu = yl = yu = 0; for (int j = 0; j < 3; j++) { p = svRep[j]->point2d(); if (p[0] < 0.0) xl++; else if (p[0] > _width) xu++; if (p[1] < 0.0) yl++; else if (p[1] > _height) yu++; } if (xl == 3 || xu == 3 || yl == 3 || yu == 3) { 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; ++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; ++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; ++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; // loops if (n % 2 == 0) { 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; } else { 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; } loops += 3; loop_index += 3; // colors if (n % 2 == 0) { 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()); } 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[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()); } colors += 3; } ++v[0]; ++v[1]; ++v[2]; } // loop over strip vertices #if 0 BKE_mesh_validate(mesh, TRUE); #endif } // loop over strips } // A replacement of BKE_object_add() for better performance. Object* BlenderStrokeRenderer::NewMesh() const { Object *ob; Base *base; char name[MAX_ID_NAME]; static unsigned int mesh_id = 0xffffffff; BLI_snprintf(name, MAX_ID_NAME, "0%08xOB", mesh_id); ob = BKE_object_add_only_object(OB_MESH, name); BLI_snprintf(name, MAX_ID_NAME, "0%08xME", mesh_id); ob->data = BKE_mesh_add(name); ob->lay = 1; base = BKE_scene_base_add(freestyle_scene, ob); //BKE_scene_base_deselect_all(scene); //BKE_scene_base_select(scene, base); ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; --mesh_id; return ob; } Render* BlenderStrokeRenderer::RenderScene( Render *re ) { Camera *camera = (Camera *)freestyle_scene->camera->data; if (camera->clipend < _z) camera->clipend = _z + _z_delta * 100.0f; //cout << "clipsta " << camera->clipsta << ", clipend " << camera->clipend << endl; Render *freestyle_render = RE_NewRender(freestyle_scene->id.name); RE_RenderFreestyleStrokes(freestyle_render, G.main, freestyle_scene); return freestyle_render; }