Compare commits
16 Commits
node-add-a
...
lineart-fn
Author | SHA1 | Date | |
---|---|---|---|
a13126209e | |||
d13040a268 | |||
b7f684e2fc | |||
a9fe5cb859 | |||
c15fa13ea0 | |||
4c68db8b82 | |||
fc44a658e6 | |||
fc7e36ac60 | |||
965fabae99 | |||
f5d6d3bea5 | |||
e2c8be0b3f | |||
22cd17360e | |||
258e2b8985 | |||
f37e62c1ea | |||
9bf87bb96e | |||
209de896f1 |
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BLI_linklist.h"
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math.h" /* Needed here for inline functions. */
|
#include "BLI_math.h" /* Needed here for inline functions. */
|
||||||
#include "BLI_threads.h"
|
#include "BLI_threads.h"
|
||||||
@@ -226,6 +227,7 @@ typedef struct LineartRenderBuffer {
|
|||||||
int tile_count_x, tile_count_y;
|
int tile_count_x, tile_count_y;
|
||||||
double width_per_tile, height_per_tile;
|
double width_per_tile, height_per_tile;
|
||||||
double view_projection[4][4];
|
double view_projection[4][4];
|
||||||
|
double view[4][4];
|
||||||
|
|
||||||
struct LineartBoundingArea *initial_bounding_areas;
|
struct LineartBoundingArea *initial_bounding_areas;
|
||||||
unsigned int bounding_area_count;
|
unsigned int bounding_area_count;
|
||||||
@@ -310,7 +312,7 @@ typedef struct LineartRenderBuffer {
|
|||||||
#define DBL_TRIANGLE_LIM 1e-8
|
#define DBL_TRIANGLE_LIM 1e-8
|
||||||
#define DBL_EDGE_LIM 1e-9
|
#define DBL_EDGE_LIM 1e-9
|
||||||
|
|
||||||
#define LRT_MEMORY_POOL_64MB (1 << 26)
|
#define LRT_MEMORY_POOL_1MB (1 << 20)
|
||||||
|
|
||||||
typedef enum eLineartTriangleFlags {
|
typedef enum eLineartTriangleFlags {
|
||||||
LRT_CULL_DONT_CARE = 0,
|
LRT_CULL_DONT_CARE = 0,
|
||||||
@@ -343,6 +345,40 @@ typedef struct LineartRenderTaskInfo {
|
|||||||
|
|
||||||
} LineartRenderTaskInfo;
|
} LineartRenderTaskInfo;
|
||||||
|
|
||||||
|
struct BMesh;
|
||||||
|
|
||||||
|
typedef struct LineartObjectInfo {
|
||||||
|
struct LineartObjectInfo *next;
|
||||||
|
struct Object *original_ob;
|
||||||
|
struct Mesh *me;
|
||||||
|
struct BMesh *original_bm;
|
||||||
|
double new_mvp[4][4];
|
||||||
|
double new_mv[4][4];
|
||||||
|
double normal[4][4];
|
||||||
|
LineartElementLinkNode *v_reln;
|
||||||
|
int override_usage;
|
||||||
|
int global_i_offset;
|
||||||
|
|
||||||
|
/* Threads will add lines inside here, when all threads are done, we combine those into the ones
|
||||||
|
* in LineartRenderBuffer. */
|
||||||
|
ListBase contour;
|
||||||
|
ListBase intersection;
|
||||||
|
ListBase crease;
|
||||||
|
ListBase material;
|
||||||
|
ListBase edge_mark;
|
||||||
|
ListBase floating;
|
||||||
|
|
||||||
|
} LineartObjectInfo;
|
||||||
|
|
||||||
|
typedef struct LineartObjectLoadTaskInfo {
|
||||||
|
struct LineartRenderBuffer *rb;
|
||||||
|
struct Depsgraph *dg;
|
||||||
|
/* LinkNode styled list */
|
||||||
|
LineartObjectInfo *pending;
|
||||||
|
/* Used to spread the load across several threads. This can not overflow. */
|
||||||
|
long unsigned int total_faces;
|
||||||
|
} LineartObjectLoadTaskInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bounding area diagram:
|
* Bounding area diagram:
|
||||||
* \code{.txt}
|
* \code{.txt}
|
||||||
|
@@ -77,6 +77,7 @@ static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb)
|
|||||||
ec = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeChain));
|
ec = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeChain));
|
||||||
|
|
||||||
BLI_addtail(&rb->chains, ec);
|
BLI_addtail(&rb->chains, ec);
|
||||||
|
// printf("chain%d\n", ec);
|
||||||
|
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,8 @@
|
|||||||
#include "BLI_task.h"
|
#include "BLI_task.h"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
|
#include "PIL_time.h"
|
||||||
|
|
||||||
#include "BKE_camera.h"
|
#include "BKE_camera.h"
|
||||||
#include "BKE_collection.h"
|
#include "BKE_collection.h"
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
@@ -40,6 +42,7 @@
|
|||||||
#include "BKE_gpencil_modifier.h"
|
#include "BKE_gpencil_modifier.h"
|
||||||
#include "BKE_material.h"
|
#include "BKE_material.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
|
#include "BKE_mesh_runtime.h"
|
||||||
#include "BKE_scene.h"
|
#include "BKE_scene.h"
|
||||||
#include "DEG_depsgraph_query.h"
|
#include "DEG_depsgraph_query.h"
|
||||||
#include "DNA_camera_types.h"
|
#include "DNA_camera_types.h"
|
||||||
@@ -60,6 +63,8 @@
|
|||||||
|
|
||||||
#include "lineart_intern.h"
|
#include "lineart_intern.h"
|
||||||
|
|
||||||
|
#define LINEART_USE_LEGACY_LOADER
|
||||||
|
|
||||||
static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
|
static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
|
||||||
LineartEdge *e);
|
LineartEdge *e);
|
||||||
|
|
||||||
@@ -441,6 +446,8 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR
|
|||||||
while (lineart_occlusion_make_task_info(rb, rti)) {
|
while (lineart_occlusion_make_task_info(rb, rti)) {
|
||||||
|
|
||||||
for (eip = rti->contour.first; eip && eip != rti->contour.last; eip = eip->next) {
|
for (eip = rti->contour.first; eip && eip != rti->contour.last; eip = eip->next) {
|
||||||
|
// printf("eip l %d r %d t1 %d t2 %d fl %d\n", eip->v1, eip->v2, eip->t1, eip->t2,
|
||||||
|
// eip->flags);
|
||||||
lineart_occlusion_single_line(rb, eip, rti->thread_id);
|
lineart_occlusion_single_line(rb, eip, rti->thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1368,6 +1375,14 @@ static void lineart_main_perspective_division(LineartRenderBuffer *rb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct LineartMeshEdge {
|
||||||
|
int v1, v2;
|
||||||
|
LineartTriangle *t1, *t2;
|
||||||
|
int poly1, poly2;
|
||||||
|
int flags;
|
||||||
|
bool managed;
|
||||||
|
} LineartMeshEdge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform a single vert to it's viewing position.
|
* Transform a single vert to it's viewing position.
|
||||||
*/
|
*/
|
||||||
@@ -1381,6 +1396,16 @@ static void lineart_vert_transform(
|
|||||||
mul_v4_m4v3_db(vt->fbcoord, mvp_mat, co);
|
mul_v4_m4v3_db(vt->fbcoord, mvp_mat, co);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lineart_mvert_transform(
|
||||||
|
MVert *v, int index, LineartVert *RvBuf, double (*mv_mat)[4], double (*mvp_mat)[4])
|
||||||
|
{
|
||||||
|
double co[4];
|
||||||
|
LineartVert *vt = &RvBuf[index];
|
||||||
|
copy_v3db_v3fl(co, v->co);
|
||||||
|
mul_v3_m4v3_db(vt->gloc, mv_mat, co);
|
||||||
|
mul_v4_m4v3_db(vt->fbcoord, mvp_mat, co);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because we have a variable size for #LineartTriangle, we need an access helper.
|
* Because we have a variable size for #LineartTriangle, we need an access helper.
|
||||||
* See #LineartTriangleThread for more info.
|
* See #LineartTriangleThread for more info.
|
||||||
@@ -1394,6 +1419,74 @@ static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
|
|||||||
return (LineartTriangle *)b;
|
return (LineartTriangle *)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char lineart_identify_feature_line_me(LineartRenderBuffer *rb,
|
||||||
|
LineartMeshEdge *la_me,
|
||||||
|
LineartTriangle *rt_array,
|
||||||
|
LineartVert *rv_array,
|
||||||
|
float crease_threshold,
|
||||||
|
bool no_crease,
|
||||||
|
bool count_freestyle,
|
||||||
|
Mesh *me)
|
||||||
|
{
|
||||||
|
// return LRT_EDGE_FLAG_CONTOUR;
|
||||||
|
if (!la_me->managed) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (la_me->t1 == la_me->t2 || !la_me->t2) {
|
||||||
|
return LRT_EDGE_FLAG_CONTOUR;
|
||||||
|
}
|
||||||
|
|
||||||
|
LineartTriangle *tri1, *tri2;
|
||||||
|
LineartVert *l;
|
||||||
|
|
||||||
|
tri1 = la_me->t1;
|
||||||
|
tri2 = la_me->t2;
|
||||||
|
|
||||||
|
l = &rv_array[la_me->v1];
|
||||||
|
|
||||||
|
double vv[3];
|
||||||
|
double *view_vector = vv;
|
||||||
|
double dot_1 = 0, dot_2 = 0;
|
||||||
|
double result;
|
||||||
|
FreestyleEdge *fe;
|
||||||
|
|
||||||
|
if (rb->cam_is_persp) {
|
||||||
|
sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
view_vector = rb->view_vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
dot_1 = dot_v3v3_db(view_vector, tri1->gn);
|
||||||
|
dot_2 = dot_v3v3_db(view_vector, tri2->gn);
|
||||||
|
|
||||||
|
if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
|
||||||
|
return LRT_EDGE_FLAG_CONTOUR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rb->use_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < crease_threshold)) {
|
||||||
|
if (!no_crease) {
|
||||||
|
return LRT_EDGE_FLAG_CREASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rb->use_material &&
|
||||||
|
(me->mpoly[la_me->poly1].mat_nr != me->mpoly[la_me->poly2].mat_nr)) {
|
||||||
|
return LRT_EDGE_FLAG_MATERIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LINEART_HOLD_ON_THIS_IS_NOT_DONE_YET
|
||||||
|
else if (count_freestyle && rb->use_edge_marks) {
|
||||||
|
fe = CustomData_bmesh_get(&bm_if_freestyle->edata, e->head.data, CD_FREESTYLE_EDGE);
|
||||||
|
if (fe->flag & FREESTYLE_EDGE_MARK) {
|
||||||
|
return LRT_EDGE_FLAG_EDGE_MARK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static char lineart_identify_feature_line(LineartRenderBuffer *rb,
|
static char lineart_identify_feature_line(LineartRenderBuffer *rb,
|
||||||
BMEdge *e,
|
BMEdge *e,
|
||||||
LineartTriangle *rt_array,
|
LineartTriangle *rt_array,
|
||||||
@@ -1480,6 +1573,49 @@ static void lineart_add_edge_to_list(LineartRenderBuffer *rb, LineartEdge *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lineart_add_edge_to_list_thread(LineartObjectInfo *obi, LineartEdge *e)
|
||||||
|
{
|
||||||
|
|
||||||
|
#define LRT_ASSIGN_EDGE(name) \
|
||||||
|
lineart_prepend_edge_direct(&obi->name.first, e); \
|
||||||
|
if (!obi->name.last) { \
|
||||||
|
obi->name.last = e; \
|
||||||
|
}
|
||||||
|
switch (e->flags) {
|
||||||
|
case LRT_EDGE_FLAG_CONTOUR:
|
||||||
|
LRT_ASSIGN_EDGE(contour);
|
||||||
|
break;
|
||||||
|
case LRT_EDGE_FLAG_CREASE:
|
||||||
|
LRT_ASSIGN_EDGE(crease);
|
||||||
|
break;
|
||||||
|
case LRT_EDGE_FLAG_MATERIAL:
|
||||||
|
LRT_ASSIGN_EDGE(material);
|
||||||
|
break;
|
||||||
|
case LRT_EDGE_FLAG_EDGE_MARK:
|
||||||
|
LRT_ASSIGN_EDGE(edge_mark);
|
||||||
|
break;
|
||||||
|
case LRT_EDGE_FLAG_INTERSECTION:
|
||||||
|
LRT_ASSIGN_EDGE(intersection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef LRT_ASSIGN_EDGE
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lineart_finalize_object_edge_list(LineartRenderBuffer *rb, LineartObjectInfo *obi)
|
||||||
|
{
|
||||||
|
#define LRT_OBI_TO_RB(name) \
|
||||||
|
if (obi->name.last) { \
|
||||||
|
((LineartEdge *)obi->name.last)->next = rb->name.first; \
|
||||||
|
rb->name.first = obi->name.first; \
|
||||||
|
}
|
||||||
|
LRT_OBI_TO_RB(contour);
|
||||||
|
LRT_OBI_TO_RB(crease);
|
||||||
|
LRT_OBI_TO_RB(material);
|
||||||
|
LRT_OBI_TO_RB(edge_mark);
|
||||||
|
LRT_OBI_TO_RB(intersection);
|
||||||
|
#undef LRT_OBI_TO_RB
|
||||||
|
}
|
||||||
|
|
||||||
static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
|
static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
|
||||||
LineartTriangleAdjacent *ta,
|
LineartTriangleAdjacent *ta,
|
||||||
LineartEdge *e)
|
LineartEdge *e)
|
||||||
@@ -1495,85 +1631,330 @@ static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lineart_geometry_object_load(Depsgraph *dg,
|
static void lineart_triangle_adjacent_assign_me(LineartTriangle *tri,
|
||||||
Object *ob,
|
LineartTriangleAdjacent *ta,
|
||||||
double (*mv_mat)[4],
|
LineartEdge *e)
|
||||||
double (*mvp_mat)[4],
|
{
|
||||||
LineartRenderBuffer *rb,
|
if (lineart_edge_match(tri, e, 0, 1)) {
|
||||||
int override_usage,
|
ta->e[0] = e;
|
||||||
int *global_vindex)
|
}
|
||||||
|
else if (lineart_edge_match(tri, e, 1, 2)) {
|
||||||
|
ta->e[1] = e;
|
||||||
|
}
|
||||||
|
else if (lineart_edge_match(tri, e, 2, 0)) {
|
||||||
|
ta->e[2] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lineart_mesh_edge_get_or_insert_from_vpair(LineartMeshEdge *table,
|
||||||
|
int real_edge,
|
||||||
|
int orig_edge_count,
|
||||||
|
int max_edge_count,
|
||||||
|
int v1,
|
||||||
|
int v2,
|
||||||
|
LineartTriangle *from,
|
||||||
|
int poly)
|
||||||
|
{
|
||||||
|
if (real_edge >= 0) {
|
||||||
|
LineartMeshEdge *e = &table[real_edge];
|
||||||
|
if (!e->t1) {
|
||||||
|
e->t1 = from;
|
||||||
|
e->poly1 = poly;
|
||||||
|
// printf("old edge %d %d f %d\n", v1, v2, from);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
e->t2 = from;
|
||||||
|
e->poly2 = poly;
|
||||||
|
// printf("old_edge %d %d f %d\n", v1, v2, from);
|
||||||
|
}
|
||||||
|
return real_edge;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = orig_edge_count; i < max_edge_count; i++) {
|
||||||
|
LineartMeshEdge *e = &table[i];
|
||||||
|
if (e->managed) {
|
||||||
|
if ((e->v1 == v1 && e->v2 == v2) || (e->v1 == v2 && e->v2 == v1)) {
|
||||||
|
// printf("ext_edge %d %d f %d\n", v1, v2, from);
|
||||||
|
if (!e->t1) {
|
||||||
|
e->t1 = from;
|
||||||
|
e->poly1 = poly;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
e->t2 = from;
|
||||||
|
e->poly2 = poly;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// printf("new_edge %d %d f %d\n", v1, v2, from);
|
||||||
|
e->managed = true;
|
||||||
|
e->v1 = v1;
|
||||||
|
e->v2 = v2;
|
||||||
|
e->t1 = from;
|
||||||
|
e->poly1 = poly;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lineart_geometry_object_load_mesh(LineartObjectInfo *obi, LineartRenderBuffer *rb)
|
||||||
|
{
|
||||||
|
Mesh *me;
|
||||||
|
MVert *v;
|
||||||
|
MPoly *f;
|
||||||
|
MLoopTri *looptri;
|
||||||
|
MEdge *e;
|
||||||
|
MLoop *loop;
|
||||||
|
LineartMeshEdge *la_me;
|
||||||
|
LineartEdge *la_e;
|
||||||
|
LineartEdgeSegment *la_s;
|
||||||
|
LineartTriangle *tri;
|
||||||
|
LineartTriangleAdjacent *orta;
|
||||||
|
double(*new_mvp)[4] = obi->new_mvp, (*new_mv)[4] = obi->new_mv, (*normal)[4] = obi->normal;
|
||||||
|
LineartElementLinkNode *eln;
|
||||||
|
LineartVert *orv;
|
||||||
|
LineartEdge *o_la_e;
|
||||||
|
LineartEdgeSegment *o_la_s;
|
||||||
|
LineartTriangle *ort;
|
||||||
|
Object *orig_ob = obi->original_ob;
|
||||||
|
int CanFindFreestyle = 0;
|
||||||
|
int i;
|
||||||
|
float use_crease = 0;
|
||||||
|
|
||||||
|
int usage = obi->override_usage;
|
||||||
|
|
||||||
|
me = obi->me;
|
||||||
|
|
||||||
|
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
|
||||||
|
use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
use_crease = rb->crease_threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
|
||||||
|
* erroneous detection on creases. Future configuration should allow options. */
|
||||||
|
if (orig_ob->type == OB_FONT) {
|
||||||
|
eln->flags |= LRT_ELEMENT_BORDER_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_mesh_runtime_looptri_ensure(me);
|
||||||
|
|
||||||
|
int tri_count = BKE_mesh_runtime_looptri_len(me);
|
||||||
|
int max_edge_count = tri_count * 3;
|
||||||
|
int mesh_edge_count = me->totedge;
|
||||||
|
|
||||||
|
/* Only allocate memory for verts and tris as we don't know how many lines we will generate
|
||||||
|
* yet. */
|
||||||
|
orv = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartVert) * me->totvert);
|
||||||
|
ort = lineart_mem_acquire_thread(&rb->render_data_pool, tri_count * rb->triangle_size);
|
||||||
|
|
||||||
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
eln = lineart_list_append_pointer_pool_sized_thread(
|
||||||
|
&rb->vertex_buffer_pointers, &rb->render_data_pool, orv, sizeof(LineartElementLinkNode));
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
|
||||||
|
eln->element_count = me->totvert;
|
||||||
|
eln->object_ref = orig_ob;
|
||||||
|
obi->v_reln = eln;
|
||||||
|
|
||||||
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
eln = lineart_list_append_pointer_pool_sized_thread(
|
||||||
|
&rb->triangle_buffer_pointers, &rb->render_data_pool, ort, sizeof(LineartElementLinkNode));
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
|
||||||
|
eln->element_count = tri_count;
|
||||||
|
eln->object_ref = orig_ob;
|
||||||
|
eln->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
|
||||||
|
|
||||||
|
/* Note this memory is not from pool, will be deleted after culling. */
|
||||||
|
orta = MEM_callocN(sizeof(LineartTriangleAdjacent) * tri_count, "LineartTriangleAdjacent");
|
||||||
|
/* Link is minimal so we use pool anyway. */
|
||||||
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
lineart_list_append_pointer_pool_thread(
|
||||||
|
&rb->triangle_adjacent_pointers, &rb->render_data_pool, orta);
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
|
||||||
|
for (i = 0; i < me->totvert; i++) {
|
||||||
|
v = &me->mvert[i];
|
||||||
|
lineart_mvert_transform(v, i, orv, new_mv, new_mvp);
|
||||||
|
orv[i].index = i;
|
||||||
|
}
|
||||||
|
/* Register a global index increment. See #lineart_triangle_share_edge() and
|
||||||
|
* #lineart_main_load_geometries() for detailed. It's okay that global_vindex might eventually
|
||||||
|
* overflow, in such large scene it's virtually impossible for two vertex of the same numeric
|
||||||
|
* index to come close together. */
|
||||||
|
obi->global_i_offset = me->totvert;
|
||||||
|
|
||||||
|
/* Fill the "real edge" portion of edge table. */
|
||||||
|
LineartMeshEdge *table = MEM_callocN(sizeof(LineartMeshEdge) * max_edge_count,
|
||||||
|
"lineart mesh edge table");
|
||||||
|
for (i = 0; i < mesh_edge_count; i++) {
|
||||||
|
table[i].v1 = me->medge[i].v1;
|
||||||
|
table[i].v2 = me->medge[i].v2;
|
||||||
|
table[i].managed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tri = ort;
|
||||||
|
loop = me->mloop;
|
||||||
|
int real_edges[3];
|
||||||
|
|
||||||
|
for (i = 0; i < tri_count; i++) {
|
||||||
|
looptri = &me->runtime.looptris.array[i];
|
||||||
|
f = &me->mpoly[looptri->poly];
|
||||||
|
BKE_mesh_looptri_get_real_edges(me, &me->runtime.looptris.array[i], real_edges);
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
tri->v[j] = &orv[loop[looptri->tri[j]].v];
|
||||||
|
lineart_mesh_edge_get_or_insert_from_vpair(table,
|
||||||
|
real_edges[j],
|
||||||
|
mesh_edge_count,
|
||||||
|
max_edge_count,
|
||||||
|
loop[looptri->tri[j]].v,
|
||||||
|
loop[looptri->tri[(j > 1) ? 0 : (j + 1)]].v,
|
||||||
|
tri,
|
||||||
|
looptri->poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transparency bit assignment. */
|
||||||
|
Material *mat = BKE_object_material_get(orig_ob, f->mat_nr + 1);
|
||||||
|
tri->transparency_mask = ((mat && (mat->lineart.flags & LRT_MATERIAL_TRANSPARENCY_ENABLED)) ?
|
||||||
|
mat->lineart.transparency_mask :
|
||||||
|
0);
|
||||||
|
|
||||||
|
float fn[3];
|
||||||
|
normal_tri_v3(fn,
|
||||||
|
me->mvert[me->mloop[looptri->tri[0]].v].co,
|
||||||
|
me->mvert[me->mloop[looptri->tri[1]].v].co,
|
||||||
|
me->mvert[me->mloop[looptri->tri[2]].v].co);
|
||||||
|
double gn[3];
|
||||||
|
copy_v3db_v3fl(gn, fn);
|
||||||
|
mul_v3_mat3_m4v3_db(tri->gn, normal, gn);
|
||||||
|
normalize_v3_db(tri->gn);
|
||||||
|
|
||||||
|
if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
|
||||||
|
tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
|
||||||
|
}
|
||||||
|
else if (usage == OBJECT_LRT_NO_INTERSECTION || usage == OBJECT_LRT_OCCLUSION_ONLY) {
|
||||||
|
tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-use this field to refer to adjacent info, will be cleared after culling stage. */
|
||||||
|
tri->intersecting_verts = (void *)&orta[i];
|
||||||
|
|
||||||
|
tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int allocate_la_e = 0;
|
||||||
|
for (i = 0; i < max_edge_count; i++) {
|
||||||
|
la_me = &table[i];
|
||||||
|
|
||||||
|
if (!la_me->managed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */
|
||||||
|
char eflag = lineart_identify_feature_line_me(
|
||||||
|
rb, la_me, ort, orv, use_crease, orig_ob->type == OB_FONT, CanFindFreestyle, me);
|
||||||
|
if (eflag) {
|
||||||
|
/* Only allocate for feature lines (instead of all lines) to save memory. */
|
||||||
|
allocate_la_e++;
|
||||||
|
}
|
||||||
|
/* Here we just use bm's flag for when loading actual lines, then we don't need to call
|
||||||
|
* lineart_identify_feature_line() again, e->head.hflag deleted after loading anyway. Always
|
||||||
|
* set the flag, so hflag stays 0 for lines that are not feature lines. */
|
||||||
|
la_me->flags = eflag;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_la_e = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartEdge) * allocate_la_e);
|
||||||
|
o_la_s = lineart_mem_acquire_thread(&rb->render_data_pool,
|
||||||
|
sizeof(LineartEdgeSegment) * allocate_la_e);
|
||||||
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
eln = lineart_list_append_pointer_pool_sized_thread(
|
||||||
|
&rb->line_buffer_pointers, &rb->render_data_pool, o_la_e, sizeof(LineartElementLinkNode));
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
eln->element_count = allocate_la_e;
|
||||||
|
eln->object_ref = orig_ob;
|
||||||
|
|
||||||
|
la_e = o_la_e;
|
||||||
|
la_s = o_la_s;
|
||||||
|
for (i = 0; i < max_edge_count; i++) {
|
||||||
|
la_me = &table[i];
|
||||||
|
|
||||||
|
if (!la_me->managed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not a feature line, so we skip. */
|
||||||
|
if (!la_me->flags) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("la_me %d %d %d\n", la_me, la_me->v1, la_me->v2);
|
||||||
|
|
||||||
|
la_e->v1 = &orv[la_me->v1];
|
||||||
|
la_e->v2 = &orv[la_me->v2];
|
||||||
|
la_e->v1_obindex = la_e->v1->index;
|
||||||
|
la_e->v2_obindex = la_e->v2->index;
|
||||||
|
if (la_me->t1) {
|
||||||
|
la_e->t1 = la_me->t1;
|
||||||
|
lineart_triangle_adjacent_assign(
|
||||||
|
la_e->t1, (LineartTriangleAdjacent *)la_me->t1->intersecting_verts, la_e);
|
||||||
|
if (la_me->t2) {
|
||||||
|
la_e->t2 = la_me->t2;
|
||||||
|
lineart_triangle_adjacent_assign(
|
||||||
|
la_e->t2, (LineartTriangleAdjacent *)la_me->t2->intersecting_verts, la_e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
la_e->flags = la_me->flags;
|
||||||
|
la_e->object_ref = orig_ob;
|
||||||
|
BLI_addtail(&la_e->segments, la_s);
|
||||||
|
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
|
||||||
|
usage == OBJECT_LRT_NO_INTERSECTION) {
|
||||||
|
lineart_add_edge_to_list_thread(obi, la_e);
|
||||||
|
}
|
||||||
|
|
||||||
|
la_e++;
|
||||||
|
la_s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obi->original_ob->type != OB_MESH) {
|
||||||
|
BKE_mesh_free(obi->me);
|
||||||
|
MEM_freeN(obi->me);
|
||||||
|
}
|
||||||
|
MEM_freeN(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBuffer *rb)
|
||||||
{
|
{
|
||||||
BMesh *bm;
|
BMesh *bm;
|
||||||
|
Mesh *me;
|
||||||
BMVert *v;
|
BMVert *v;
|
||||||
BMFace *f;
|
BMFace *f;
|
||||||
BMEdge *e;
|
BMEdge *e;
|
||||||
BMLoop *loop;
|
BMLoop *loop;
|
||||||
LineartEdge *la_e;
|
LineartEdge *la_e;
|
||||||
|
LineartEdgeSegment *la_s;
|
||||||
LineartTriangle *tri;
|
LineartTriangle *tri;
|
||||||
LineartTriangleAdjacent *orta;
|
LineartTriangleAdjacent *orta;
|
||||||
double new_mvp[4][4], new_mv[4][4], normal[4][4];
|
double(*new_mvp)[4] = obi->new_mvp, (*new_mv)[4] = obi->new_mv, (*normal)[4] = obi->normal;
|
||||||
float imat[4][4];
|
|
||||||
LineartElementLinkNode *eln;
|
LineartElementLinkNode *eln;
|
||||||
LineartVert *orv;
|
LineartVert *orv;
|
||||||
LineartEdge *o_la_e;
|
LineartEdge *o_la_e;
|
||||||
|
LineartEdgeSegment *o_la_s;
|
||||||
LineartTriangle *ort;
|
LineartTriangle *ort;
|
||||||
Object *orig_ob;
|
Object *orig_ob;
|
||||||
int CanFindFreestyle = 0;
|
int CanFindFreestyle = 0;
|
||||||
int i, global_i = (*global_vindex);
|
int i;
|
||||||
Mesh *use_mesh;
|
|
||||||
float use_crease = 0;
|
float use_crease = 0;
|
||||||
|
|
||||||
int usage = override_usage ? override_usage : ob->lineart.usage;
|
int usage = obi->override_usage;
|
||||||
|
|
||||||
#define LRT_MESH_FINISH \
|
bm = obi->original_bm;
|
||||||
BM_mesh_free(bm); \
|
orig_ob = obi->original_ob;
|
||||||
if (ob->type != OB_MESH) { \
|
|
||||||
BKE_mesh_free(use_mesh); \
|
|
||||||
MEM_freeN(use_mesh); \
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usage == OBJECT_LRT_EXCLUDE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
|
|
||||||
|
|
||||||
if (ob->type == OB_MESH) {
|
|
||||||
use_mesh = DEG_get_evaluated_object(dg, ob)->data;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
use_mesh = BKE_mesh_new_from_object(NULL, ob, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In case we can not get any mesh geometry data from the object */
|
|
||||||
if (!use_mesh) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First we need to prepare the matrix used for transforming this specific object. */
|
|
||||||
mul_m4db_m4db_m4fl_uniq(new_mvp, mvp_mat, ob->obmat);
|
|
||||||
mul_m4db_m4db_m4fl_uniq(new_mv, mv_mat, ob->obmat);
|
|
||||||
|
|
||||||
invert_m4_m4(imat, ob->obmat);
|
|
||||||
transpose_m4(imat);
|
|
||||||
copy_m4d_m4(normal, imat);
|
|
||||||
|
|
||||||
if (use_mesh->edit_mesh) {
|
|
||||||
/* Do not use edit_mesh directly because we will modify it, so create a copy. */
|
|
||||||
bm = BM_mesh_copy(use_mesh->edit_mesh->bm);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(((Mesh *)(use_mesh)));
|
|
||||||
bm = BM_mesh_create(&allocsize,
|
|
||||||
&((struct BMeshCreateParams){
|
|
||||||
.use_toolflags = true,
|
|
||||||
}));
|
|
||||||
BM_mesh_bm_from_me(bm,
|
|
||||||
use_mesh,
|
|
||||||
&((struct BMeshFromMeshParams){
|
|
||||||
.calc_face_normal = true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rb->remove_doubles) {
|
if (rb->remove_doubles) {
|
||||||
BMEditMesh *em = BKE_editmesh_create(bm, false);
|
BMEditMesh *em = BKE_editmesh_create(bm, false);
|
||||||
@@ -1608,18 +1989,22 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
|
|
||||||
/* Only allocate memory for verts and tris as we don't know how many lines we will generate
|
/* Only allocate memory for verts and tris as we don't know how many lines we will generate
|
||||||
* yet. */
|
* yet. */
|
||||||
orv = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartVert) * bm->totvert);
|
orv = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartVert) * bm->totvert);
|
||||||
ort = lineart_mem_acquire(&rb->render_data_pool, bm->totface * rb->triangle_size);
|
ort = lineart_mem_acquire_thread(&rb->render_data_pool, bm->totface * rb->triangle_size);
|
||||||
|
|
||||||
orig_ob = ob->id.orig_id ? (Object *)ob->id.orig_id : ob;
|
orig_ob = obi->original_ob;
|
||||||
|
|
||||||
eln = lineart_list_append_pointer_pool_sized(
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
eln = lineart_list_append_pointer_pool_sized_thread(
|
||||||
&rb->vertex_buffer_pointers, &rb->render_data_pool, orv, sizeof(LineartElementLinkNode));
|
&rb->vertex_buffer_pointers, &rb->render_data_pool, orv, sizeof(LineartElementLinkNode));
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
|
||||||
eln->element_count = bm->totvert;
|
eln->element_count = bm->totvert;
|
||||||
eln->object_ref = orig_ob;
|
eln->object_ref = orig_ob;
|
||||||
|
obi->v_reln = eln;
|
||||||
|
|
||||||
if (ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
|
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
|
||||||
use_crease = cosf(M_PI - ob->lineart.crease_threshold);
|
use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
use_crease = rb->crease_threshold;
|
use_crease = rb->crease_threshold;
|
||||||
@@ -1627,12 +2012,15 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
|
|
||||||
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
|
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
|
||||||
* erroneous detection on creases. Future configuration should allow options. */
|
* erroneous detection on creases. Future configuration should allow options. */
|
||||||
if (ob->type == OB_FONT) {
|
if (orig_ob->type == OB_FONT) {
|
||||||
eln->flags |= LRT_ELEMENT_BORDER_ONLY;
|
eln->flags |= LRT_ELEMENT_BORDER_ONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
eln = lineart_list_append_pointer_pool_sized(
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
eln = lineart_list_append_pointer_pool_sized_thread(
|
||||||
&rb->triangle_buffer_pointers, &rb->render_data_pool, ort, sizeof(LineartElementLinkNode));
|
&rb->triangle_buffer_pointers, &rb->render_data_pool, ort, sizeof(LineartElementLinkNode));
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
|
||||||
eln->element_count = bm->totface;
|
eln->element_count = bm->totface;
|
||||||
eln->object_ref = orig_ob;
|
eln->object_ref = orig_ob;
|
||||||
eln->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
|
eln->flags |= (usage == OBJECT_LRT_NO_INTERSECTION ? LRT_ELEMENT_NO_INTERSECTION : 0);
|
||||||
@@ -1640,18 +2028,21 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
/* Note this memory is not from pool, will be deleted after culling. */
|
/* Note this memory is not from pool, will be deleted after culling. */
|
||||||
orta = MEM_callocN(sizeof(LineartTriangleAdjacent) * bm->totface, "LineartTriangleAdjacent");
|
orta = MEM_callocN(sizeof(LineartTriangleAdjacent) * bm->totface, "LineartTriangleAdjacent");
|
||||||
/* Link is minimal so we use pool anyway. */
|
/* Link is minimal so we use pool anyway. */
|
||||||
lineart_list_append_pointer_pool(&rb->triangle_adjacent_pointers, &rb->render_data_pool, orta);
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
lineart_list_append_pointer_pool_thread(
|
||||||
|
&rb->triangle_adjacent_pointers, &rb->render_data_pool, orta);
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
|
|
||||||
for (i = 0; i < bm->totvert; i++) {
|
for (i = 0; i < bm->totvert; i++) {
|
||||||
v = BM_vert_at_index(bm, i);
|
v = BM_vert_at_index(bm, i);
|
||||||
lineart_vert_transform(v, i, orv, new_mv, new_mvp);
|
lineart_vert_transform(v, i, orv, new_mv, new_mvp);
|
||||||
orv[i].index = i + global_i;
|
orv[i].index = i;
|
||||||
}
|
}
|
||||||
/* Register a global index increment. See #lineart_triangle_share_edge() and
|
/* Register a global index increment. See #lineart_triangle_share_edge() and
|
||||||
* #lineart_main_load_geometries() for detailed. It's okay that global_vindex might eventually
|
* #lineart_main_load_geometries() for detailed. It's okay that global_vindex might eventually
|
||||||
* overflow, in such large scene it's virtually impossible for two vertex of the same numeric
|
* overflow, in such large scene it's virtually impossible for two vertex of the same numeric
|
||||||
* index to come close together. */
|
* index to come close together. */
|
||||||
(*global_vindex) += bm->totvert;
|
obi->global_i_offset = bm->totvert;
|
||||||
|
|
||||||
tri = ort;
|
tri = ort;
|
||||||
for (i = 0; i < bm->totface; i++) {
|
for (i = 0; i < bm->totface; i++) {
|
||||||
@@ -1665,7 +2056,7 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
tri->v[2] = &orv[BM_elem_index_get(loop->v)];
|
tri->v[2] = &orv[BM_elem_index_get(loop->v)];
|
||||||
|
|
||||||
/* Transparency bit assignment. */
|
/* Transparency bit assignment. */
|
||||||
Material *mat = BKE_object_material_get(ob, f->mat_nr + 1);
|
Material *mat = BKE_object_material_get(orig_ob, f->mat_nr + 1);
|
||||||
tri->transparency_mask = ((mat && (mat->lineart.flags & LRT_MATERIAL_TRANSPARENCY_ENABLED)) ?
|
tri->transparency_mask = ((mat && (mat->lineart.flags & LRT_MATERIAL_TRANSPARENCY_ENABLED)) ?
|
||||||
mat->lineart.transparency_mask :
|
mat->lineart.transparency_mask :
|
||||||
0);
|
0);
|
||||||
@@ -1678,7 +2069,7 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
|
if (usage == OBJECT_LRT_INTERSECTION_ONLY) {
|
||||||
tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
|
tri->flags |= LRT_TRIANGLE_INTERSECTION_ONLY;
|
||||||
}
|
}
|
||||||
else if (ELEM(usage, OBJECT_LRT_NO_INTERSECTION, OBJECT_LRT_OCCLUSION_ONLY)) {
|
else if (usage == OBJECT_LRT_NO_INTERSECTION || usage == OBJECT_LRT_OCCLUSION_ONLY) {
|
||||||
tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
|
tri->flags |= LRT_TRIANGLE_NO_INTERSECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1696,7 +2087,7 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
|
|
||||||
/* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */
|
/* Because e->head.hflag is char, so line type flags should not exceed positive 7 bits. */
|
||||||
char eflag = lineart_identify_feature_line(
|
char eflag = lineart_identify_feature_line(
|
||||||
rb, e, ort, orv, use_crease, ob->type == OB_FONT, CanFindFreestyle, bm);
|
rb, e, ort, orv, use_crease, orig_ob->type == OB_FONT, CanFindFreestyle, bm);
|
||||||
if (eflag) {
|
if (eflag) {
|
||||||
/* Only allocate for feature lines (instead of all lines) to save memory. */
|
/* Only allocate for feature lines (instead of all lines) to save memory. */
|
||||||
allocate_la_e++;
|
allocate_la_e++;
|
||||||
@@ -1707,13 +2098,18 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
e->head.hflag = eflag;
|
e->head.hflag = eflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
o_la_e = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge) * allocate_la_e);
|
o_la_e = lineart_mem_acquire_thread(&rb->render_data_pool, sizeof(LineartEdge) * allocate_la_e);
|
||||||
eln = lineart_list_append_pointer_pool_sized(
|
o_la_s = lineart_mem_acquire_thread(&rb->render_data_pool,
|
||||||
|
sizeof(LineartEdgeSegment) * allocate_la_e);
|
||||||
|
BLI_spin_lock(&rb->lock_task);
|
||||||
|
eln = lineart_list_append_pointer_pool_sized_thread(
|
||||||
&rb->line_buffer_pointers, &rb->render_data_pool, o_la_e, sizeof(LineartElementLinkNode));
|
&rb->line_buffer_pointers, &rb->render_data_pool, o_la_e, sizeof(LineartElementLinkNode));
|
||||||
|
BLI_spin_unlock(&rb->lock_task);
|
||||||
eln->element_count = allocate_la_e;
|
eln->element_count = allocate_la_e;
|
||||||
eln->object_ref = orig_ob;
|
eln->object_ref = orig_ob;
|
||||||
|
|
||||||
la_e = o_la_e;
|
la_e = o_la_e;
|
||||||
|
la_s = o_la_s;
|
||||||
for (i = 0; i < bm->totedge; i++) {
|
for (i = 0; i < bm->totedge; i++) {
|
||||||
e = BM_edge_at_index(bm, i);
|
e = BM_edge_at_index(bm, i);
|
||||||
|
|
||||||
@@ -1724,8 +2120,8 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
|
|
||||||
la_e->v1 = &orv[BM_elem_index_get(e->v1)];
|
la_e->v1 = &orv[BM_elem_index_get(e->v1)];
|
||||||
la_e->v2 = &orv[BM_elem_index_get(e->v2)];
|
la_e->v2 = &orv[BM_elem_index_get(e->v2)];
|
||||||
la_e->v1_obindex = la_e->v1->index - global_i;
|
la_e->v1_obindex = la_e->v1->index;
|
||||||
la_e->v2_obindex = la_e->v2->index - global_i;
|
la_e->v2_obindex = la_e->v2->index;
|
||||||
if (e->l) {
|
if (e->l) {
|
||||||
int findex = BM_elem_index_get(e->l->f);
|
int findex = BM_elem_index_get(e->l->f);
|
||||||
la_e->t1 = lineart_triangle_from_index(rb, ort, findex);
|
la_e->t1 = lineart_triangle_from_index(rb, ort, findex);
|
||||||
@@ -1738,21 +2134,36 @@ static void lineart_geometry_object_load(Depsgraph *dg,
|
|||||||
}
|
}
|
||||||
la_e->flags = e->head.hflag;
|
la_e->flags = e->head.hflag;
|
||||||
la_e->object_ref = orig_ob;
|
la_e->object_ref = orig_ob;
|
||||||
|
BLI_addtail(&la_e->segments, la_s);
|
||||||
LineartEdgeSegment *es = lineart_mem_acquire(&rb->render_data_pool,
|
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
|
||||||
sizeof(LineartEdgeSegment));
|
usage == OBJECT_LRT_NO_INTERSECTION) {
|
||||||
BLI_addtail(&la_e->segments, es);
|
lineart_add_edge_to_list_thread(obi, la_e);
|
||||||
if (ELEM(usage, OBJECT_LRT_INHERIT, OBJECT_LRT_INCLUDE, OBJECT_LRT_NO_INTERSECTION)) {
|
|
||||||
lineart_add_edge_to_list(rb, la_e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
la_e++;
|
la_e++;
|
||||||
|
la_s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRT_MESH_FINISH
|
/* always free bm as it's a copy from before threading */
|
||||||
|
BM_mesh_free(bm);
|
||||||
|
|
||||||
|
if (obi->original_ob->type != OB_MESH) {
|
||||||
|
BKE_mesh_free(obi->me);
|
||||||
|
MEM_freeN(obi->me);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef LRT_MESH_FINISH
|
static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
|
||||||
|
LineartObjectLoadTaskInfo *olti)
|
||||||
|
{
|
||||||
|
LineartRenderBuffer *rb = olti->rb;
|
||||||
|
for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) {
|
||||||
|
#ifdef LINEART_USE_LEGACY_LOADER
|
||||||
|
lineart_geometry_object_load(obi, rb);
|
||||||
|
#else
|
||||||
|
lineart_geometry_object_load_mesh(obi, rb);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _lineart_object_not_in_source_collection(Collection *source, Object *ob)
|
static bool _lineart_object_not_in_source_collection(Collection *source, Object *ob)
|
||||||
@@ -1832,6 +2243,24 @@ static int lineart_usage_check(Collection *c, Object *ob, LineartRenderBuffer *_
|
|||||||
return OBJECT_LRT_INHERIT;
|
return OBJECT_LRT_INHERIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_list,
|
||||||
|
LineartObjectInfo *obi,
|
||||||
|
int thread_count,
|
||||||
|
int this_face_count)
|
||||||
|
{
|
||||||
|
LineartObjectLoadTaskInfo *use_olti = olti_list;
|
||||||
|
long unsigned int min_face = use_olti->total_faces;
|
||||||
|
for (int i = 0; i < thread_count; i++) {
|
||||||
|
if (olti_list[i].total_faces < min_face) {
|
||||||
|
min_face = olti_list[i].total_faces;
|
||||||
|
use_olti = &olti_list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use_olti->total_faces += this_face_count;
|
||||||
|
obi->next = use_olti->pending;
|
||||||
|
use_olti->pending = obi;
|
||||||
|
}
|
||||||
|
|
||||||
static void lineart_main_load_geometries(
|
static void lineart_main_load_geometries(
|
||||||
Depsgraph *depsgraph,
|
Depsgraph *depsgraph,
|
||||||
Scene *scene,
|
Scene *scene,
|
||||||
@@ -1848,6 +2277,12 @@ static void lineart_main_load_geometries(
|
|||||||
|
|
||||||
double asp = ((double)rb->w / (double)rb->h);
|
double asp = ((double)rb->w / (double)rb->h);
|
||||||
|
|
||||||
|
double t_start;
|
||||||
|
|
||||||
|
if (G.debug_value == 4000) {
|
||||||
|
t_start = PIL_check_seconds_timer();
|
||||||
|
}
|
||||||
|
|
||||||
if (cam->type == CAM_PERSP) {
|
if (cam->type == CAM_PERSP) {
|
||||||
if (cam->sensor_fit == CAMERA_SENSOR_FIT_AUTO) {
|
if (cam->sensor_fit == CAMERA_SENSOR_FIT_AUTO) {
|
||||||
if (asp < 1) {
|
if (asp < 1) {
|
||||||
@@ -1879,6 +2314,7 @@ static void lineart_main_load_geometries(
|
|||||||
copy_m4_m4_db(rb->view_projection, proj);
|
copy_m4_m4_db(rb->view_projection, proj);
|
||||||
|
|
||||||
unit_m4_db(view);
|
unit_m4_db(view);
|
||||||
|
copy_m4_m4_db(rb->view, view);
|
||||||
|
|
||||||
BLI_listbase_clear(&rb->triangle_buffer_pointers);
|
BLI_listbase_clear(&rb->triangle_buffer_pointers);
|
||||||
BLI_listbase_clear(&rb->vertex_buffer_pointers);
|
BLI_listbase_clear(&rb->vertex_buffer_pointers);
|
||||||
@@ -1891,16 +2327,110 @@ static void lineart_main_load_geometries(
|
|||||||
flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
|
flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is to serialize vertex index in the whole scene, so lineart_triangle_share_edge() can
|
int thread_count = rb->thread_count;
|
||||||
* work properly from the lack of triangle adjacent info. */
|
|
||||||
int global_i = 0;
|
/* This memory is in render buffer memory pool. so we don't need to free those after loading. */
|
||||||
|
LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
|
||||||
|
&rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
|
||||||
|
|
||||||
DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
|
DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
|
||||||
int usage = lineart_usage_check(scene->master_collection, ob, rb);
|
LineartObjectInfo *obi = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartObjectInfo));
|
||||||
|
obi->override_usage = lineart_usage_check(scene->master_collection, ob, rb);
|
||||||
|
|
||||||
lineart_geometry_object_load(depsgraph, ob, view, proj, rb, usage, &global_i);
|
/* TODO: We better make it so we can extract BMesh in parallel or at least for those objects
|
||||||
|
* who doesn't have instances or just simply have transformation channel set. */
|
||||||
|
Object *use_ob = DEG_get_evaluated_object(depsgraph, ob);
|
||||||
|
Mesh *use_mesh;
|
||||||
|
BMesh *bm;
|
||||||
|
|
||||||
|
if (obi->override_usage == OBJECT_LRT_EXCLUDE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(use_ob->type == OB_MESH || use_ob->type == OB_MBALL || use_ob->type == OB_CURVE ||
|
||||||
|
use_ob->type == OB_SURF || use_ob->type == OB_FONT)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (use_ob->type == OB_MESH) {
|
||||||
|
use_mesh = use_ob->data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
use_mesh = BKE_mesh_new_from_object(NULL, use_ob, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case we still can not get any mesh geometry data from the object */
|
||||||
|
if (!use_mesh) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef LINEART_USE_LEGACY_LOADER
|
||||||
|
if (use_mesh->edit_mesh) {
|
||||||
|
/* Do not use edit_mesh directly because we will modify it, so create a copy. */
|
||||||
|
bm = BM_mesh_copy(use_mesh->edit_mesh->bm);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(((Mesh *)(use_mesh)));
|
||||||
|
bm = BM_mesh_create(&allocsize,
|
||||||
|
&((struct BMeshCreateParams){
|
||||||
|
.use_toolflags = true,
|
||||||
|
}));
|
||||||
|
BM_mesh_bm_from_me(bm,
|
||||||
|
use_mesh,
|
||||||
|
&((struct BMeshFromMeshParams){
|
||||||
|
.calc_face_normal = true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
obi->original_bm = bm;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
obi->me = use_mesh;
|
||||||
|
|
||||||
|
/* Prepare the matrix used for transforming this specific object (instance). */
|
||||||
|
mul_m4db_m4db_m4fl_uniq(obi->new_mvp, rb->view_projection, ob->obmat);
|
||||||
|
mul_m4db_m4db_m4fl_uniq(obi->new_mv, rb->view, ob->obmat);
|
||||||
|
float imat[4][4];
|
||||||
|
invert_m4_m4(imat, ob->obmat);
|
||||||
|
transpose_m4(imat);
|
||||||
|
copy_m4d_m4(obi->normal, imat);
|
||||||
|
|
||||||
|
obi->original_ob = (ob->id.orig_id ? (Object *)ob->id.orig_id : (Object *)ob);
|
||||||
|
lineart_geometry_load_assign_thread(olti, obi, thread_count, use_mesh->totface);
|
||||||
}
|
}
|
||||||
DEG_OBJECT_ITER_END;
|
DEG_OBJECT_ITER_END;
|
||||||
|
|
||||||
|
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
|
||||||
|
|
||||||
|
for (int i = 0; i < thread_count; i++) {
|
||||||
|
olti[i].rb = rb;
|
||||||
|
olti[i].dg = depsgraph;
|
||||||
|
BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL);
|
||||||
|
}
|
||||||
|
BLI_task_pool_work_and_wait(tp);
|
||||||
|
BLI_task_pool_free(tp);
|
||||||
|
|
||||||
|
/* The step below is to serialize vertex index in the whole scene, so
|
||||||
|
* lineart_triangle_share_edge() can work properly from the lack of triangle adjacent info. */
|
||||||
|
int global_i = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < thread_count; i++) {
|
||||||
|
for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
|
||||||
|
if (!obi->v_reln) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LineartVert *v = (LineartVert *)obi->v_reln->pointer;
|
||||||
|
int v_count = obi->v_reln->element_count;
|
||||||
|
for (int vi = 0; vi < v_count; vi++) {
|
||||||
|
v[vi].index += global_i;
|
||||||
|
}
|
||||||
|
global_i += v_count;
|
||||||
|
lineart_finalize_object_edge_list(rb, obi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G.debug_value == 4000) {
|
||||||
|
double t_elapsed = PIL_check_seconds_timer() - t_start;
|
||||||
|
printf("Line art loading time: %lf\n", t_elapsed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2540,7 +3070,6 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3701,7 +4230,11 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
|
|||||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||||
int intersections_only = 0; /* Not used right now, but preserve for future. */
|
int intersections_only = 0; /* Not used right now, but preserve for future. */
|
||||||
|
|
||||||
BKE_scene_camera_switch_update(scene);
|
double t_start;
|
||||||
|
|
||||||
|
if (G.debug_value == 4000) {
|
||||||
|
t_start = PIL_check_seconds_timer();
|
||||||
|
}
|
||||||
|
|
||||||
if (!scene->camera) {
|
if (!scene->camera) {
|
||||||
return false;
|
return false;
|
||||||
@@ -3796,6 +4329,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, LineartGpencilModif
|
|||||||
|
|
||||||
if (G.debug_value == 4000) {
|
if (G.debug_value == 4000) {
|
||||||
lineart_count_and_print_render_buffer_memory(rb);
|
lineart_count_and_print_render_buffer_memory(rb);
|
||||||
|
|
||||||
|
double t_elapsed = PIL_check_seconds_timer() - t_start;
|
||||||
|
printf("Line art total time: %lf\n", t_elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@@ -43,6 +43,13 @@ void *lineart_list_append_pointer_pool_sized(ListBase *h,
|
|||||||
struct LineartStaticMemPool *smp,
|
struct LineartStaticMemPool *smp,
|
||||||
void *data,
|
void *data,
|
||||||
int size);
|
int size);
|
||||||
|
void *lineart_list_append_pointer_pool_thread(ListBase *h,
|
||||||
|
struct LineartStaticMemPool *smp,
|
||||||
|
void *data);
|
||||||
|
void *lineart_list_append_pointer_pool_sized_thread(ListBase *h,
|
||||||
|
LineartStaticMemPool *smp,
|
||||||
|
void *data,
|
||||||
|
int size);
|
||||||
void *list_push_pointer_static(ListBase *h, struct LineartStaticMemPool *smp, void *p);
|
void *list_push_pointer_static(ListBase *h, struct LineartStaticMemPool *smp, void *p);
|
||||||
void *list_push_pointer_static_sized(ListBase *h,
|
void *list_push_pointer_static_sized(ListBase *h,
|
||||||
struct LineartStaticMemPool *smp,
|
struct LineartStaticMemPool *smp,
|
||||||
|
@@ -62,6 +62,31 @@ void *lineart_list_append_pointer_pool_sized(ListBase *h,
|
|||||||
BLI_addtail(h, lip);
|
BLI_addtail(h, lip);
|
||||||
return lip;
|
return lip;
|
||||||
}
|
}
|
||||||
|
void *lineart_list_append_pointer_pool_thread(ListBase *h, LineartStaticMemPool *smp, void *data)
|
||||||
|
{
|
||||||
|
LinkData *lip;
|
||||||
|
if (h == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lip = lineart_mem_acquire_thread(smp, sizeof(LinkData));
|
||||||
|
lip->data = data;
|
||||||
|
BLI_addtail(h, lip);
|
||||||
|
return lip;
|
||||||
|
}
|
||||||
|
void *lineart_list_append_pointer_pool_sized_thread(ListBase *h,
|
||||||
|
LineartStaticMemPool *smp,
|
||||||
|
void *data,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
LinkData *lip;
|
||||||
|
if (h == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lip = lineart_mem_acquire_thread(smp, size);
|
||||||
|
lip->data = data;
|
||||||
|
BLI_addtail(h, lip);
|
||||||
|
return lip;
|
||||||
|
}
|
||||||
|
|
||||||
void *lineart_list_pop_pointer_no_free(ListBase *h)
|
void *lineart_list_pop_pointer_no_free(ListBase *h)
|
||||||
{
|
{
|
||||||
@@ -82,10 +107,10 @@ void lineart_list_remove_pointer_item_no_free(ListBase *h, LinkData *lip)
|
|||||||
LineartStaticMemPoolNode *lineart_mem_new_static_pool(LineartStaticMemPool *smp, size_t size)
|
LineartStaticMemPoolNode *lineart_mem_new_static_pool(LineartStaticMemPool *smp, size_t size)
|
||||||
{
|
{
|
||||||
size_t set_size = size;
|
size_t set_size = size;
|
||||||
if (set_size < LRT_MEMORY_POOL_64MB) {
|
if (set_size < LRT_MEMORY_POOL_1MB) {
|
||||||
set_size = LRT_MEMORY_POOL_64MB; /* Prevent too many small allocations. */
|
set_size = LRT_MEMORY_POOL_1MB; /* Prevent too many small allocations. */
|
||||||
}
|
}
|
||||||
size_t total_size = size + sizeof(LineartStaticMemPoolNode);
|
size_t total_size = set_size + sizeof(LineartStaticMemPoolNode);
|
||||||
LineartStaticMemPoolNode *smpn = MEM_callocN(total_size, "mempool");
|
LineartStaticMemPoolNode *smpn = MEM_callocN(total_size, "mempool");
|
||||||
smpn->size = total_size;
|
smpn->size = total_size;
|
||||||
smpn->used_byte = sizeof(LineartStaticMemPoolNode);
|
smpn->used_byte = sizeof(LineartStaticMemPoolNode);
|
||||||
@@ -211,7 +236,7 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
|
|||||||
|
|
||||||
LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) {
|
LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) {
|
||||||
count_this++;
|
count_this++;
|
||||||
sum_this += LRT_MEMORY_POOL_64MB;
|
sum_this += LRT_MEMORY_POOL_1MB;
|
||||||
}
|
}
|
||||||
printf("LANPR Memory allocated %zu Standalone nodes, total %zu Bytes.\n", count_this, sum_this);
|
printf("LANPR Memory allocated %zu Standalone nodes, total %zu Bytes.\n", count_this, sum_this);
|
||||||
total += sum_this;
|
total += sum_this;
|
||||||
|
Reference in New Issue
Block a user