Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h4
-rw-r--r--source/blender/blenkernel/BKE_scene.h5
-rw-r--r--source/blender/blenkernel/intern/customdata.c12
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c12
-rw-r--r--source/blender/blenkernel/intern/gpencil.c25
-rw-r--r--source/blender/blenkernel/intern/library_query.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c60
-rw-r--r--source/blender/blenloader/intern/readfile.c50
-rw-r--r--source/blender/blenloader/intern/versioning_280.c26
-rw-r--r--source/blender/blenloader/intern/writefile.c9
-rw-r--r--source/blender/draw/CMakeLists.txt20
-rw-r--r--source/blender/draw/engines/lanpr/lanpr_all.h266
-rw-r--r--source/blender/draw/engines/lanpr/lanpr_chain_draw.c196
-rw-r--r--source/blender/draw/engines/lanpr/lanpr_cpu.c513
-rw-r--r--source/blender/draw/engines/lanpr/lanpr_dpix.c553
-rw-r--r--source/blender/draw/engines/lanpr/lanpr_engine.c810
-rw-r--r--source/blender/draw/engines/lanpr/lanpr_snake.c623
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_frag.glsl6
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_geom.glsl193
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_clip_frag.glsl495
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_passthrough_vert.glsl6
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_snake_edge_frag.glsl88
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_snake_image_peel_frag.glsl329
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_frag.glsl6
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_geom.glsl114
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_vert.glsl10
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_snake_multichannel_frag.glsl19
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_software_chain_geom.glsl291
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_software_line_chain_geom.glsl185
-rw-r--r--source/blender/draw/engines/lanpr/shaders/lanpr_software_passthrough_vert.glsl21
-rw-r--r--source/blender/draw/intern/DRW_render.h11
-rw-r--r--source/blender/draw/intern/draw_common.c4
-rw-r--r--source/blender/draw/intern/draw_manager.c5
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c33
-rw-r--r--source/blender/editors/CMakeLists.txt1
-rw-r--r--source/blender/editors/include/ED_lanpr.h622
-rw-r--r--source/blender/editors/include/UI_resources.h4
-rw-r--r--source/blender/editors/interface/resources.c4
-rw-r--r--source/blender/editors/lanpr/CMakeLists.txt46
-rw-r--r--source/blender/editors/lanpr/lanpr_chain.c817
-rw-r--r--source/blender/editors/lanpr/lanpr_cpu.c4350
-rw-r--r--source/blender/editors/lanpr/lanpr_intern.h64
-rw-r--r--source/blender/editors/lanpr/lanpr_ops.c50
-rw-r--r--source/blender/editors/lanpr/lanpr_util.c197
-rw-r--r--source/blender/editors/mesh/editmesh_path.c27
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c32
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c57
-rw-r--r--source/blender/editors/mesh/mesh_intern.h6
-rw-r--r--source/blender/editors/mesh/mesh_ops.c9
-rw-r--r--source/blender/editors/render/render_update.c5
-rw-r--r--source/blender/editors/space_api/spacetypes.c4
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c37
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c6
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c1
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp10
-rw-r--r--source/blender/makesdna/DNA_collection_types.h46
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_lanpr_types.h138
-rw-r--r--source/blender/makesdna/DNA_material_types.h1
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h16
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h44
-rw-r--r--source/blender/makesdna/DNA_object_types.h13
-rw-r--r--source/blender/makesdna/DNA_scene_types.h76
-rw-r--r--source/blender/makesdna/DNA_space_types.h2
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/makesrna/RNA_access.h4
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/makesrna.c1
-rw-r--r--source/blender/makesrna/intern/rna_collection.c89
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_lanpr.c235
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c24
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c91
-rw-r--r--source/blender/makesrna/intern/rna_object.c39
-rw-r--r--source/blender/makesrna/intern/rna_scene.c284
-rw-r--r--source/blender/makesrna/intern/rna_space.c38
-rw-r--r--source/blender/modifiers/CMakeLists.txt3
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_featureline.c124
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c4
82 files changed, 12502 insertions, 138 deletions
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 011590100de..398e465fa57 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -146,6 +146,10 @@ struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl,
struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe);
bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+struct bGPDlayer *BKE_gpencil_layer_get_index(struct bGPdata *gpd,
+ int index,
+ int first_if_not_found);
+
struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index d25288fc240..7d564a232a7 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -254,6 +254,11 @@ void BKE_scene_cursor_from_mat4(struct View3DCursor *cursor,
*/
void BKE_scene_eval_sequencer_sequences(struct Depsgraph *depsgraph, struct Scene *scene);
+/* LANPR */
+
+void BKE_lanpr_copy_data(const struct Scene *from, struct Scene *to);
+void BKE_lanpr_free_everything(struct Scene *s);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 59dbfc293dd..bc982140b29 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1611,10 +1611,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerInterp_mvert_skin,
NULL,
layerDefault_mvert_skin},
- /* 37: CD_FREESTYLE_EDGE */
- {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 38: CD_FREESTYLE_FACE */
- {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 37: CD_LANPR_EDGE */
+ {sizeof(LanprEdge), "LanprEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 38: CD_LANPR_FACE */
+ {sizeof(LanprFace), "LanprFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 39: CD_MLOOPTANGENT */
{sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 40: CD_TESSLOOPNORMAL */
@@ -1663,8 +1663,8 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPaintMask",
/* 35-36 */ "CDGridPaintMask",
"CDMVertSkin",
- /* 37-38 */ "CDFreestyleEdge",
- "CDFreestyleFace",
+ /* 37-38 */ "CDLanprEdge",
+ "CDLanprFace",
/* 39-41 */ "CDMLoopTangent",
"CDTessLoopNormal",
"CDCustomLoopNormal",
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 0414c6d0a02..3dc025bdcf2 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -222,14 +222,14 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_BWEIGHT_EDGE:
return CD_FAKE_BWEIGHT;
case DT_TYPE_FREESTYLE_EDGE:
- return CD_FREESTYLE_EDGE;
+ return CD_LANPR_EDGE;
case DT_TYPE_UV:
return CD_FAKE_UV;
case DT_TYPE_SHARP_FACE:
return CD_FAKE_SHARP;
case DT_TYPE_FREESTYLE_FACE:
- return CD_FREESTYLE_FACE;
+ return CD_LANPR_FACE;
case DT_TYPE_VCOL:
return CD_MLOOPCOL;
@@ -519,11 +519,11 @@ static void data_transfer_layersmapping_add_item_cd(ListBase *r_map,
{
uint64_t data_flag = 0;
- if (cddata_type == CD_FREESTYLE_EDGE) {
- data_flag = FREESTYLE_EDGE_MARK;
+ if (cddata_type == CD_LANPR_EDGE) {
+ data_flag = LANPR_EDGE_MARK;
}
- else if (cddata_type == CD_FREESTYLE_FACE) {
- data_flag = FREESTYLE_FACE_MARK;
+ else if (cddata_type == CD_LANPR_FACE) {
+ data_flag = LANPR_FACE_MARK;
}
data_transfer_layersmapping_add_item(r_map,
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 47ed9f3bd83..8ca1fa82908 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -991,6 +991,31 @@ bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd)
return NULL;
}
+bGPDlayer *BKE_gpencil_layer_get_index(bGPdata *gpd, int index, int first_if_not_found)
+{
+ bGPDlayer *gpl;
+ int i = 0;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->layers.first)) {
+ return NULL;
+ }
+
+ /* loop over layers until found (assume only one active) */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (i == index) {
+ return gpl;
+ }
+ i++;
+ }
+
+ /* no such layer */
+ if (first_if_not_found) {
+ return gpd->layers.first;
+ }
+ return NULL;
+}
+
/* set the active gp-layer */
void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
{
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index ca3da0d89c7..c36d5b27b54 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -493,6 +493,8 @@ static void library_foreach_ID_link(Main *bmain,
CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
}
+ CALLBACK_INVOKE(scene->master_collection->lanpr.target, IDWALK_CB_USER);
+
ViewLayer *view_layer;
for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 885ce415ade..65d2e0d15c4 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -105,6 +105,7 @@
const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
const char *RE_engine_id_BLENDER_WORKBENCH = "BLENDER_WORKBENCH";
+const char *RE_engine_id_BLENDER_LANPR = "BLENDER_LANPR";
const char *RE_engine_id_CYCLES = "CYCLES";
void free_avicodecdata(AviCodecData *acd)
@@ -225,6 +226,32 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
MEM_freeN(toolsettings);
}
+void BKE_lanpr_copy_data(const Scene *from, Scene *to)
+{
+ const SceneLANPR *lanpr = &from->lanpr;
+ LANPR_LineLayer *ll, *new_ll;
+ LANPR_LineLayerComponent *llc, *new_llc;
+
+ to->lanpr.line_layers.first = to->lanpr.line_layers.last = NULL;
+ memset(&to->lanpr.line_layers, 0, sizeof(ListBase));
+
+ for (ll = lanpr->line_layers.first; ll; ll = ll->next) {
+ new_ll = MEM_callocN(sizeof(LANPR_LineLayer), "Copied Line Layer");
+ memcpy(new_ll, ll, sizeof(LANPR_LineLayer));
+ memset(&new_ll->components, 0, sizeof(ListBase));
+ new_ll->next = new_ll->prev = NULL;
+ BLI_addtail(&to->lanpr.line_layers, new_ll);
+ for (llc = ll->components.first; llc; llc = llc->next) {
+ new_llc = MEM_callocN(sizeof(LANPR_LineLayerComponent), "Copied Line Layer Component");
+ memcpy(new_llc, llc, sizeof(LANPR_LineLayerComponent));
+ new_llc->next = new_llc->prev = NULL;
+ BLI_addtail(&new_ll->components, new_llc);
+ }
+ }
+
+ /* render_buffer now only accessible from lanpr_share */
+}
+
/**
* Only copy internal data of Scene ID from source
* to already allocated/initialized destination.
@@ -340,6 +367,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
sce_dst->eevee.light_cache = NULL;
sce_dst->eevee.light_cache_info[0] = '\0';
/* TODO Copy the cache. */
+
+ /* lanpr data */
+
+ BKE_lanpr_copy_data(sce_src, sce_dst);
}
Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
@@ -476,6 +507,20 @@ void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
BKE_id_make_local_generic(bmain, &sce->id, true, lib_local);
}
+void BKE_lanpr_free_everything(Scene *s)
+{
+ SceneLANPR *lanpr = &s->lanpr;
+ LANPR_LineLayer *ll;
+ LANPR_LineLayerComponent *llc;
+
+ while ((ll = BLI_pophead(&lanpr->line_layers)) != NULL) {
+ while ((llc = BLI_pophead(&ll->components)) != NULL) {
+ MEM_freeN(llc);
+ }
+ MEM_freeN(ll);
+ }
+}
+
/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
{
@@ -548,6 +593,8 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
sce->eevee.light_cache = NULL;
}
+ BKE_lanpr_free_everything(sce);
+
/* These are freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@@ -973,6 +1020,19 @@ void BKE_scene_init(Scene *sce)
sce->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS |
SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION |
SCE_EEVEE_SSR_HALF_RESOLUTION;
+
+ /* SceneLANPR */
+
+ sce->lanpr.crease_threshold = 0.7;
+
+ sce->lanpr.line_color[0] = 1;
+ sce->lanpr.line_color[1] = 1;
+ sce->lanpr.line_color[2] = 1;
+ sce->lanpr.line_color[3] = 1;
+
+ sce->lanpr.flags |= (LANPR_USE_CHAINING | LANPR_USE_INTERSECTIONS);
+ sce->lanpr.chaining_image_threshold = 0.01;
+ sce->lanpr.chaining_geometry_threshold = 0.1;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a133dd30c9b..64a6c09a13d 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -78,6 +78,7 @@
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
#include "DNA_lightprobe_types.h"
+#include "DNA_lanpr_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
@@ -5798,6 +5799,10 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
}
}
+ else if (md->type == eModifierType_FeatureLine) {
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+ UNUSED_VARS(flmd);
+ }
}
}
@@ -6246,6 +6251,8 @@ static void lib_link_collection_data(FileData *fd, Library *lib, Collection *col
child->collection = newlibadr_us(fd, lib, child->collection);
}
+ collection->lanpr.target = newlibadr_us(fd, lib, collection->lanpr.target);
+
BKE_collection_parent_relations_rebuild(collection);
}
@@ -6550,6 +6557,16 @@ static void lib_link_scene(FileData *fd, Main *main)
fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
}
}
+
+ for (LANPR_LineLayer *ll = sce->lanpr.line_layers.first; ll; ll = ll->next) {
+ for (LANPR_LineLayerComponent *llc = ll->components.first; llc; llc = llc->next) {
+ llc->object_select = newlibadr_us(fd, sce->id.lib, llc->object_select);
+ llc->material_select = newlibadr_us(fd, sce->id.lib, llc->material_select);
+ llc->collection_select = newlibadr_us(fd, sce->id.lib, llc->collection_select);
+ }
+ ll->normal_control_object = newlibadr_us(fd, sce->id.lib, ll->normal_control_object);
+ }
+
/* Motion Tracking */
sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip);
@@ -6987,6 +7004,21 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
}
+ /* LANPR things */
+ sce->lanpr.active_layer = newdataadr(fd, sce->lanpr.active_layer);
+ link_list(fd, &sce->lanpr.line_layers);
+ for (LANPR_LineLayer *ll = sce->lanpr.line_layers.first; ll; ll = ll->next) {
+ link_list(fd, &ll->components);
+ for (LANPR_LineLayerComponent *llc = ll->components.first; llc; llc = llc->next) {
+ // llc->object_select = newlibadr(fd, sce->id.lib, llc->object_select);
+ // llc->material_select = newlibadr(fd, sce->id.lib, llc->material_select);
+ // llc->collection_select = newlibadr(fd, sce->id.lib, llc->collection_select);
+ }
+ ll->batch = NULL;
+ ll->shgrp = NULL;
+ // ll->normal_control_object = newlibadr(fd, sce->id.lib, ll->normal_control_object);
+ }
+
sce->layer_properties = newdataadr(fd, sce->layer_properties);
IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
@@ -10311,6 +10343,8 @@ static void expand_collection(FileData *fd, Main *mainvar, Collection *collectio
expand_doit(fd, mainvar, child->collection);
}
+ expand_doit(fd, mainvar, collection->lanpr.target);
+
#ifdef USE_COLLECTION_COMPAT_28
if (collection->collection != NULL) {
expand_scene_collection(fd, mainvar, collection->collection);
@@ -10768,10 +10802,22 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
}
}
- if (sce->gpd) {
- expand_doit(fd, mainvar, sce->gpd);
+ for (LANPR_LineLayer *ll = sce->lanpr.line_layers.first; ll; ll = ll->next) {
+ for (LANPR_LineLayerComponent *llc = ll->components.first; llc; llc = llc->next) {
+ if (llc->object_select)
+ expand_doit(fd, mainvar, llc->object_select);
+ if (llc->material_select)
+ expand_doit(fd, mainvar, llc->material_select);
+ if (llc->collection_select)
+ expand_doit(fd, mainvar, llc->collection_select);
+ }
+ if (ll->normal_control_object)
+ expand_doit(fd, mainvar, ll->normal_control_object);
}
+ if (sce->gpd)
+ expand_doit(fd, mainvar, sce->gpd);
+
if (sce->ed) {
Sequence *seq;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index a735b399ce3..5b303a9e5b3 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1916,6 +1916,20 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!DNA_struct_find(fd->filesdna, "SceneLANPR")) {
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+
+ scene->lanpr.crease_threshold = 0.7;
+
+ scene->lanpr.flags |= (LANPR_USE_CHAINING | LANPR_USE_INTERSECTIONS);
+
+ scene->lanpr.line_color[0] = 0.39;
+ scene->lanpr.line_color[1] = 0.12;
+ scene->lanpr.line_color[2] = 0.04;
+ scene->lanpr.line_color[3] = 1;
+ }
+ }
+
if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
scene->display.matcap_ssao_distance = 0.2f;
@@ -3618,6 +3632,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
do_versions_seq_alloc_transform_and_crop(&scene->ed->seqbase);
}
}
+ for (Scene *sce = bmain->scenes.first; sce; sce = sce->id.next) {
+ sce->lanpr.crease_threshold = 0.7;
+
+ zero_v4(sce->lanpr.line_color);
+
+ sce->lanpr.flags |= (LANPR_USE_CHAINING | LANPR_USE_INTERSECTIONS);
+ sce->lanpr.chaining_image_threshold = 0.01f;
+ sce->lanpr.chaining_geometry_threshold = 0.0f;
+ }
+ for (Collection *co = bmain->collections.first; co; co = co->id.next) {
+ co->lanpr.types = COLLECTION_FEATURE_LINE_ALL;
+ }
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 75)) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0ff7ba0034f..e81fa9fd2ff 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -121,6 +121,7 @@
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
#include "DNA_lightprobe_types.h"
+#include "DNA_lanpr_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sdna_types.h"
@@ -2684,6 +2685,14 @@ static void write_scene(WriteData *wd, Scene *sce)
write_lightcache(wd, sce->eevee.light_cache);
}
+ /* LANPR Line Layers */
+ for (LANPR_LineLayer *ll = sce->lanpr.line_layers.first; ll; ll = ll->next) {
+ writestruct(wd, DATA, LANPR_LineLayer, 1, ll);
+ for (LANPR_LineLayerComponent *llc = ll->components.first; llc; llc = llc->next) {
+ writestruct(wd, DATA, LANPR_LineLayerComponent, 1, llc);
+ }
+ }
+
/* Freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 19ab96868ef..3b808fabacb 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -129,6 +129,10 @@ set(SRC
engines/gpencil/gpencil_engine.h
engines/gpencil/gpencil_render.c
engines/gpencil/gpencil_shader_fx.c
+ engines/lanpr/lanpr_dpix.c
+ engines/lanpr/lanpr_engine.c
+ engines/lanpr/lanpr_cpu.c
+ engines/lanpr/lanpr_chain_draw.c
engines/select/select_draw_utils.c
engines/select/select_engine.c
@@ -157,6 +161,7 @@ set(SRC
engines/external/external_engine.h
engines/workbench/workbench_engine.h
engines/workbench/workbench_private.h
+ engines/lanpr/lanpr_all.h
engines/select/select_engine.h
engines/select/select_private.h
)
@@ -258,6 +263,21 @@ data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_dpix_preview_geom.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_dpix_preview_frag.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_dpix_project_clip_frag.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_dpix_project_passthrough_vert.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_snake_image_peel_frag.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_snake_line_connection_vert.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_snake_line_connection_geom.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_snake_line_connection_frag.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_snake_edge_frag.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_snake_multichannel_frag.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_software_line_chain_geom.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_software_passthrough_vert.glsl SRC)
+data_to_c_simple(engines/lanpr/shaders/lanpr_software_chain_geom.glsl SRC)
+
+
data_to_c_simple(modes/shaders/common_colormanagement_lib.glsl SRC)
data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC)
data_to_c_simple(modes/shaders/common_hair_lib.glsl SRC)
diff --git a/source/blender/draw/engines/lanpr/lanpr_all.h b/source/blender/draw/engines/lanpr/lanpr_all.h
new file mode 100644
index 00000000000..eb12f71a08d
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/lanpr_all.h
@@ -0,0 +1,266 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ *
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#ifndef __LANPR_ALL_H__
+#define __LANPR_ALL_H__
+
+#include "BLI_mempool.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_customdata.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_listBase.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "DRW_render.h"
+
+#include "ED_lanpr.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "bmesh.h"
+
+#define LANPR_ENGINE "BLENDER_LANPR"
+
+#define deg(r) r / M_PI * 180.0
+#define rad(d) d *M_PI / 180.0
+
+#define tMatDist2v(p1, p2) \
+ sqrt(((p1)[0] - (p2)[0]) * ((p1)[0] - (p2)[0]) + ((p1)[1] - (p2)[1]) * ((p1)[1] - (p2)[1]))
+
+extern struct RenderEngineType DRW_engine_viewport_lanpr_type;
+extern struct DrawEngineType draw_engine_lanpr_type;
+
+typedef struct LANPR_RenderBuffer LANPR_RenderBuffer;
+
+typedef struct LANPR_PassList {
+ /* Image filtering */
+ struct DRWPass *depth_pass;
+ struct DRWPass *color_pass;
+ struct DRWPass *normal_pass;
+ struct DRWPass *edge_intermediate;
+ struct DRWPass *edge_thinning;
+ struct DRWPass *snake_pass;
+
+ /* GPU */
+ struct DRWPass *dpix_transform_pass;
+ struct DRWPass *dpix_preview_pass;
+
+ /* SOFTWARE */
+ struct DRWPass *software_pass;
+
+} LANPR_PassList;
+
+typedef struct LANPR_FramebufferList {
+
+ /* CPU */
+ struct GPUFrameBuffer *passes;
+ struct GPUFrameBuffer *edge_intermediate;
+ struct GPUFrameBuffer *edge_thinning;
+
+ /* GPU */
+ struct GPUFrameBuffer *dpix_transform;
+ struct GPUFrameBuffer *dpix_preview;
+
+ /* Image filtering */
+ struct GPUFrameBuffer *software_ms;
+
+} LANPR_FramebufferList;
+
+typedef struct LANPR_TextureList {
+
+ struct GPUTexture *color;
+ struct GPUTexture *normal;
+ struct GPUTexture *depth;
+ struct GPUTexture *edge_intermediate;
+
+ struct GPUTexture *dpix_in_pl;
+ struct GPUTexture *dpix_in_pr;
+ struct GPUTexture *dpix_in_nl;
+ struct GPUTexture *dpix_in_nr;
+
+ /** RGBA texture format,
+ * R:Material, G: Freestyle Edge Mark,
+ * BA:Reserved for future usages */
+ struct GPUTexture *dpix_in_edge_mask;
+
+ struct GPUTexture *dpix_out_pl;
+ struct GPUTexture *dpix_out_pr;
+ struct GPUTexture *dpix_out_length;
+
+ /** Multisample resolve */
+ struct GPUTexture *ms_resolve_depth;
+ struct GPUTexture *ms_resolve_color;
+
+} LANPR_TextureList;
+
+typedef struct LANPR_PrivateData {
+ DRWShadingGroup *multipass_shgrp;
+ DRWShadingGroup *edge_detect_shgrp;
+ DRWShadingGroup *edge_thinning_shgrp;
+ DRWShadingGroup *snake_shgrp;
+
+ DRWShadingGroup *dpix_transform_shgrp;
+ DRWShadingGroup *dpix_preview_shgrp;
+
+ DRWShadingGroup *debug_shgrp;
+
+ /* Image filtering */
+
+ float normal_clamp;
+ float normal_strength;
+ float depth_clamp;
+ float depth_strength;
+
+ float zfar;
+ float znear;
+
+ /** Thinning stage */
+ int stage;
+
+ float *line_result;
+ unsigned char *line_result_8bit;
+
+ /** If not match then recreate buffer. */
+ int width, height;
+ void **sample_table;
+
+ ListBase pending_samples;
+ ListBase erased_samples;
+ ListBase line_strips;
+
+ /* dpix data */
+
+ void *atlas_pl;
+ void *atlas_pr;
+ void *atlas_nl;
+ void *atlas_nr;
+ void *atlas_edge_mask;
+
+ int begin_index;
+
+ int dpix_sample_step;
+ int dpix_is_perspective;
+ float dpix_viewport[4];
+ float output_viewport[4];
+ int dpix_buffer_width;
+ float dpix_depth_offset;
+
+ float dpix_znear;
+ float dpix_zfar;
+
+ /* drawing */
+
+ unsigned v_buf;
+ unsigned i_buf;
+ unsigned l_buf;
+
+ GPUVertFormat snake_gwn_format;
+ GPUBatch *snake_batch;
+} LANPR_PrivateData;
+
+typedef struct LANPR_StorageList {
+ LANPR_PrivateData *g_data;
+} LANPR_StorageList;
+
+typedef struct LANPR_BatchItem {
+ Link item;
+ GPUBatch *dpix_transform_batch;
+ GPUBatch *dpix_preview_batch;
+ Object *ob;
+} LANPR_BatchItem;
+
+typedef struct LANPR_Data {
+ void *engine_type;
+ LANPR_FramebufferList *fbl;
+ LANPR_TextureList *txl;
+ LANPR_PassList *psl;
+ LANPR_StorageList *stl;
+} LANPR_Data;
+
+/* functions */
+
+void lanpr_init_atlas_inputs(void *ved);
+void lanpr_destroy_atlas(void *ved);
+int lanpr_feed_atlas_data_obj(void *vedata,
+ float *AtlasPointsL,
+ float *AtlasPointsR,
+ float *AtlasFaceNormalL,
+ float *AtlasFaceNormalR,
+ float *AtlasEdgeMask,
+ Object *ob,
+ int begin_index);
+
+int lanpr_feed_atlas_data_intersection_cache(void *vedata,
+ float *AtlasPointsL,
+ float *AtlasPointsR,
+ float *AtlasFaceNormalL,
+ float *AtlasFaceNormalR,
+ float *AtlasEdgeMask,
+ int begin_index);
+
+int lanpr_feed_atlas_trigger_preview_obj(void *vedata, Object *ob, int begin_index);
+void lanpr_create_atlas_intersection_preview(void *vedata, int begin_index);
+
+void lanpr_dpix_draw_scene(LANPR_TextureList *txl,
+ LANPR_FramebufferList *fbl,
+ LANPR_PassList *psl,
+ LANPR_PrivateData *pd,
+ SceneLANPR *lanpr,
+ GPUFrameBuffer *DefaultFB,
+ int is_render);
+
+void lanpr_snake_draw_scene(LANPR_TextureList *txl,
+ LANPR_FramebufferList *fbl,
+ LANPR_PassList *psl,
+ LANPR_PrivateData *pd,
+ SceneLANPR *lanpr,
+ GPUFrameBuffer *DefaultFB,
+ int is_render);
+
+void lanpr_software_draw_scene(void *vedata, GPUFrameBuffer *dfb, int is_render);
+
+int lanpr_dpix_texture_size(SceneLANPR *lanpr);
+
+void lanpr_chain_generate_draw_command(struct LANPR_RenderBuffer *rb);
+
+#endif
diff --git a/source/blender/draw/engines/lanpr/lanpr_chain_draw.c b/source/blender/draw/engines/lanpr/lanpr_chain_draw.c
new file mode 100644
index 00000000000..f036a8940a4
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/lanpr_chain_draw.c
@@ -0,0 +1,196 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ *
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "BKE_customdata.h"
+#include "BKE_object.h"
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "lanpr_all.h"
+#include "bmesh.h"
+
+#include <math.h>
+
+static float ED_lanpr_compute_chain_length_draw(LANPR_RenderLineChain *rlc,
+ float *lengths,
+ int begin_index)
+{
+ LANPR_RenderLineChainItem *rlci;
+ int i = 0;
+ float offset_accum = 0;
+ float dist;
+ float last_point[2];
+
+ rlci = rlc->chain.first;
+ copy_v2_v2(last_point, rlci->pos);
+ for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
+ dist = len_v2v2(rlci->pos, last_point);
+ offset_accum += dist;
+ lengths[begin_index + i] = offset_accum;
+ copy_v2_v2(last_point, rlci->pos);
+ i++;
+ }
+ return offset_accum;
+}
+
+static int lanpr_get_gpu_line_type(LANPR_RenderLineChainItem *rlci)
+{
+ switch (rlci->line_type) {
+ case LANPR_EDGE_FLAG_CONTOUR:
+ return 0;
+ case LANPR_EDGE_FLAG_CREASE:
+ return 1;
+ case LANPR_EDGE_FLAG_MATERIAL:
+ return 2;
+ case LANPR_EDGE_FLAG_EDGE_MARK:
+ return 3;
+ case LANPR_EDGE_FLAG_INTERSECTION:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+void lanpr_chain_generate_draw_command(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLineChain *rlc;
+ LANPR_RenderLineChainItem *rlci;
+ int vert_count = 0;
+ int i = 0;
+ int arg;
+ float total_length;
+ float *lengths;
+ float length_target[2];
+
+ static GPUVertFormat format = {0};
+ static struct {
+ uint pos, uvs, normal, type, level;
+ } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.normal = GPU_vertformat_attr_add(&format, "normal", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.type = GPU_vertformat_attr_add(&format, "type", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ attr_id.level = GPU_vertformat_attr_add(&format, "level", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ for (rlc = rb->chains.first; rlc; rlc = rlc->next) {
+ int count = ED_lanpr_count_chain(rlc);
+ /* printf("seg contains %d verts\n", count); */
+ vert_count += count;
+ }
+
+ GPU_vertbuf_data_alloc(vbo, vert_count + 1); /* serve as end point's adj. */
+
+ lengths = MEM_callocN(sizeof(float) * vert_count, "chain lengths");
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINES_ADJ, vert_count * 4, vert_count);
+
+ for (rlc = rb->chains.first; rlc; rlc = rlc->next) {
+
+ total_length = ED_lanpr_compute_chain_length_draw(rlc, lengths, i);
+
+ for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
+
+ length_target[0] = lengths[i];
+ length_target[1] = total_length - lengths[i];
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rlci->pos);
+ GPU_vertbuf_attr_set(vbo, attr_id.normal, i, rlci->normal);
+ GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, length_target);
+
+ arg = lanpr_get_gpu_line_type(rlci);
+ GPU_vertbuf_attr_set(vbo, attr_id.type, i, &arg);
+
+ arg = (int)rlci->occlusion;
+ GPU_vertbuf_attr_set(vbo, attr_id.level, i, &arg);
+
+ if (rlci == rlc->chain.last) {
+ if (rlci->prev == rlc->chain.first) {
+ length_target[1] = total_length;
+ GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, length_target);
+ }
+ i++;
+ continue;
+ }
+
+ if (rlci == rlc->chain.first) {
+ if (rlci->next == rlc->chain.last) {
+ GPU_indexbuf_add_line_adj_verts(&elb, vert_count, i, i + 1, vert_count);
+ }
+ else {
+ GPU_indexbuf_add_line_adj_verts(&elb, vert_count, i, i + 1, i + 2);
+ }
+ }
+ else {
+ if (rlci->next == rlc->chain.last) {
+ GPU_indexbuf_add_line_adj_verts(&elb, i - 1, i, i + 1, vert_count);
+ }
+ else {
+ GPU_indexbuf_add_line_adj_verts(&elb, i - 1, i, i + 1, i + 2);
+ }
+ }
+
+ i++;
+ }
+ }
+ /* set end point flag value. */
+ length_target[0] = 3e30f;
+ length_target[1] = 3e30f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vert_count, length_target);
+
+ MEM_freeN(lengths);
+
+ if (rb->chain_draw_batch) {
+ GPU_BATCH_DISCARD_SAFE(rb->chain_draw_batch);
+ }
+ rb->chain_draw_batch = GPU_batch_create_ex(GPU_PRIM_LINES_ADJ,
+ vbo,
+ GPU_indexbuf_build(&elb),
+ GPU_USAGE_DYNAMIC | GPU_BATCH_OWNS_VBO |
+ GPU_BATCH_OWNS_INDEX);
+}
diff --git a/source/blender/draw/engines/lanpr/lanpr_cpu.c b/source/blender/draw/engines/lanpr/lanpr_cpu.c
new file mode 100644
index 00000000000..7db25fb80f7
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/lanpr_cpu.c
@@ -0,0 +1,513 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ *
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "DNA_camera_types.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_text_types.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_lanpr.h"
+
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math_matrix.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_camera.h"
+#include "BKE_customdata.h"
+#include "BKE_collection.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+#include "BKE_text.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "bmesh.h"
+#include "bmesh_class.h"
+#include "bmesh_tools.h"
+
+#include "lanpr_all.h"
+
+#include <math.h>
+
+extern LANPR_SharedResource lanpr_share;
+extern const char *RE_engine_id_BLENDER_LANPR;
+
+static void lanpr_rebuild_render_draw_command(LANPR_RenderBuffer *rb, LANPR_LineLayer *ll)
+{
+ int Count = 0;
+ float *v, *tv, *N, *tn;
+ int i;
+ int vertCount;
+
+ static GPUVertFormat format = {0};
+ static struct {
+ uint pos, normal;
+ } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.normal = GPU_vertformat_attr_add(&format, "normal", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ if (ll->contour.use) {
+ Count += ED_lanpr_count_leveled_edge_segment_count(&rb->contours, ll);
+ }
+ if (ll->crease.use) {
+ Count += ED_lanpr_count_leveled_edge_segment_count(&rb->crease_lines, ll);
+ }
+ if (ll->intersection.use) {
+ Count += ED_lanpr_count_leveled_edge_segment_count(&rb->intersection_lines, ll);
+ }
+ if (ll->edge_mark.use) {
+ Count += ED_lanpr_count_leveled_edge_segment_count(&rb->edge_marks, ll);
+ }
+ if (ll->material_separate.use) {
+ Count += ED_lanpr_count_leveled_edge_segment_count(&rb->material_lines, ll);
+ }
+
+ vertCount = Count * 2;
+
+ if (!vertCount) {
+ return;
+ }
+
+ GPU_vertbuf_data_alloc(vbo, vertCount);
+
+ tv = v = MEM_callocN(sizeof(float) * 6 * Count, "temp v data");
+ tn = N = MEM_callocN(sizeof(float) * 6 * Count, "temp n data");
+
+ if (ll->contour.use) {
+ tv = ED_lanpr_make_leveled_edge_vertex_array(rb, &rb->contours, tv, tn, &tn, ll, 1.0f);
+ }
+ if (ll->crease.use) {
+ tv = ED_lanpr_make_leveled_edge_vertex_array(rb, &rb->crease_lines, tv, tn, &tn, ll, 2.0f);
+ }
+ if (ll->material_separate.use) {
+ tv = ED_lanpr_make_leveled_edge_vertex_array(rb, &rb->material_lines, tv, tn, &tn, ll, 3.0f);
+ }
+ if (ll->edge_mark.use) {
+ tv = ED_lanpr_make_leveled_edge_vertex_array(rb, &rb->edge_marks, tv, tn, &tn, ll, 4.0f);
+ }
+ if (ll->intersection.use) {
+ tv = ED_lanpr_make_leveled_edge_vertex_array(rb, &rb->intersection_lines, tv, tn, &tn, ll, 5.0f);
+ }
+
+ for (i = 0; i < vertCount; i++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, &v[i * 3]);
+ GPU_vertbuf_attr_set(vbo, attr_id.normal, i, &N[i * 3]);
+ }
+
+ MEM_freeN(v);
+ MEM_freeN(N);
+
+ ll->batch = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, 0, GPU_USAGE_DYNAMIC | GPU_BATCH_OWNS_VBO);
+}
+void ED_lanpr_rebuild_all_command(SceneLANPR *lanpr)
+{
+ LANPR_LineLayer *ll;
+ if (!lanpr || !lanpr_share.render_buffer_shared) {
+ return;
+ }
+
+ if (lanpr->flags & LANPR_USE_CHAINING) {
+ lanpr_chain_generate_draw_command(lanpr_share.render_buffer_shared);
+ }
+ else {
+ for (ll = lanpr->line_layers.first; ll; ll = ll->next) {
+ if (ll->batch) {
+ GPU_batch_discard(ll->batch);
+ }
+ lanpr_rebuild_render_draw_command(lanpr_share.render_buffer_shared, ll);
+ }
+ }
+
+ DEG_id_tag_update(&lanpr_share.render_buffer_shared->scene->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_lanpr_calculate_normal_object_vector(LANPR_LineLayer *ll, float *normal_object_direction)
+{
+ Object *ob;
+ if (!(ll->flags & LANPR_LINE_LAYER_NORMAL_ENABLED)) {
+ return;
+ }
+ switch (ll->normal_mode) {
+ case LANPR_NORMAL_DIRECTIONAL:
+ if (!(ob = ll->normal_control_object)) {
+ normal_object_direction[0] = 0;
+ normal_object_direction[1] = 0;
+ normal_object_direction[2] = 1; /* default z up direction */
+ }
+ else {
+ float dir[3] = {0, 0, 1};
+ float mat[3][3];
+ copy_m3_m4(mat, ob->obmat);
+ mul_v3_m3v3(normal_object_direction, mat, dir);
+ normalize_v3(normal_object_direction);
+ }
+ return;
+ case LANPR_NORMAL_POINT:
+ if (!(ob = ll->normal_control_object)) {
+ normal_object_direction[0] = 0;
+ normal_object_direction[1] = 0;
+ normal_object_direction[2] = 0; /* default origin position */
+ }
+ else {
+ normal_object_direction[0] = ob->obmat[3][0];
+ normal_object_direction[1] = ob->obmat[3][1];
+ normal_object_direction[2] = ob->obmat[3][2];
+ }
+ return;
+ }
+}
+
+void lanpr_software_draw_scene(void *vedata, GPUFrameBuffer *dfb, int is_render)
+{
+ LANPR_LineLayer *ll;
+ LANPR_PassList *psl = ((LANPR_Data *)vedata)->psl;
+ LANPR_TextureList *txl = ((LANPR_Data *)vedata)->txl;
+ LANPR_StorageList *stl = ((LANPR_Data *)vedata)->stl;
+ LANPR_FramebufferList *fbl = ((LANPR_Data *)vedata)->fbl;
+ LANPR_PrivateData *pd = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ SceneLANPR *lanpr = &scene->lanpr;
+ View3D *v3d = draw_ctx->v3d;
+ float indentity_mat[4][4];
+ static float normal_object_direction[3] = {0, 0, 1};
+ float use_background_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ static float camdx, camdy, camzoom;
+
+ if (is_render) {
+ ED_lanpr_rebuild_all_command(lanpr);
+ }
+
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0xFF;
+ eGPUFrameBufferBits clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT;
+ static int zero_value = 0;
+
+ copy_v3_v3(use_background_color, &scene->world->horr);
+ use_background_color[3] = scene->r.alphamode ? 0.0f : 1.0f;
+
+ GPU_framebuffer_bind(fbl->software_ms);
+ GPU_framebuffer_clear(
+ fbl->software_ms, clear_bits, use_background_color, clear_depth, clear_stencil);
+
+ if (lanpr_share.render_buffer_shared) {
+
+ int texw = GPU_texture_width(txl->ms_resolve_color),
+ texh = GPU_texture_height(txl->ms_resolve_color);
+ ;
+ pd->output_viewport[2] = scene->r.xsch;
+ pd->output_viewport[3] = scene->r.ysch;
+ pd->dpix_viewport[2] = texw;
+ pd->dpix_viewport[3] = texh;
+
+ unit_m4(indentity_mat);
+
+ DRWView *view = DRW_view_create(indentity_mat, indentity_mat, NULL, NULL, NULL);
+ if (is_render) {
+ DRW_view_default_set(view);
+ }
+ else {
+ DRW_view_set_active(view);
+ }
+
+ RegionView3D *rv3d = v3d ? draw_ctx->rv3d : NULL;
+ if (rv3d) {
+ camdx = rv3d->camdx;
+ camdy = rv3d->camdy;
+ camzoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
+ }
+ else {
+ camdx = camdy = 0.0f;
+ camzoom = 1.0f;
+ }
+
+ if ((lanpr->flags & LANPR_USE_CHAINING) &&
+ lanpr_share.render_buffer_shared->chain_draw_batch) {
+ for (ll = lanpr->line_layers.last; ll; ll = ll->prev) {
+ LANPR_RenderBuffer *rb;
+ psl->software_pass = DRW_pass_create("Software Render Preview",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL);
+ rb = lanpr_share.render_buffer_shared;
+ rb->ChainShgrp = DRW_shgroup_create(lanpr_share.software_chaining_shader,
+ psl->software_pass);
+
+ ED_lanpr_calculate_normal_object_vector(ll, normal_object_direction);
+
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "camdx", &camdx, 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "camdy", &camdy, 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "camzoom", &camzoom, 1);
+
+ DRW_shgroup_uniform_vec4(rb->ChainShgrp,
+ "contour_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color :
+ ll->contour.color,
+ 1);
+ DRW_shgroup_uniform_vec4(rb->ChainShgrp,
+ "crease_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color :
+ ll->crease.color,
+ 1);
+ DRW_shgroup_uniform_vec4(rb->ChainShgrp,
+ "material_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ ll->color :
+ ll->material_separate.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ rb->ChainShgrp,
+ "edge_mark_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->edge_mark.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ rb->ChainShgrp,
+ "intersection_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->intersection.color,
+ 1);
+ static float unit_thickness = 1.0f;
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "thickness", &ll->thickness, 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp,
+ "thickness_contour",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->contour.thickness,
+ 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp,
+ "thickness_crease",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->crease.thickness,
+ 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp,
+ "thickness_material",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->material_separate.thickness,
+ 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp,
+ "thickness_edge_mark",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->edge_mark.thickness,
+ 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp,
+ "thickness_intersection",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->intersection.thickness,
+ 1);
+ DRW_shgroup_uniform_int(rb->ChainShgrp, "use_contour", &ll->contour.use, 1);
+ DRW_shgroup_uniform_int(rb->ChainShgrp, "use_crease", &ll->crease.use, 1);
+ DRW_shgroup_uniform_int(rb->ChainShgrp, "use_material", &ll->material_separate.use, 1);
+ DRW_shgroup_uniform_int(rb->ChainShgrp, "use_edge_mark", &ll->edge_mark.use, 1);
+ DRW_shgroup_uniform_int(rb->ChainShgrp, "use_intersection", &ll->intersection.use, 1);
+
+ static int normal_effect_inverse;
+ normal_effect_inverse = (ll->flags & LANPR_LINE_LAYER_NORMAL_INVERSE) ? 1 : 0;
+ DRW_shgroup_uniform_int(rb->ChainShgrp,
+ "normal_mode",
+ (ll->flags & LANPR_LINE_LAYER_NORMAL_ENABLED) ? &ll->normal_mode :
+ &zero_value,
+ 1);
+ DRW_shgroup_uniform_int(
+ rb->ChainShgrp, "normal_effect_inverse", &normal_effect_inverse, 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "normal_ramp_begin", &ll->normal_ramp_begin, 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "normal_ramp_end", &ll->normal_ramp_end, 1);
+ DRW_shgroup_uniform_float(
+ rb->ChainShgrp, "normal_thickness_start", &ll->normal_thickness_start, 1);
+ DRW_shgroup_uniform_float(
+ rb->ChainShgrp, "normal_thickness_end", &ll->normal_thickness_end, 1);
+ DRW_shgroup_uniform_vec3(rb->ChainShgrp, "normal_direction", normal_object_direction, 1);
+
+ DRW_shgroup_uniform_int(rb->ChainShgrp, "occlusion_level_start", &ll->level_start, 1);
+ DRW_shgroup_uniform_int(rb->ChainShgrp,
+ "occlusion_level_end",
+ (ll->flags & LANPR_LINE_LAYER_USE_MULTIPLE_LEVELS) ? &ll->level_end :
+ &ll->level_start,
+ 1);
+
+ DRW_shgroup_uniform_vec4(
+ rb->ChainShgrp, "preview_viewport", stl->g_data->dpix_viewport, 1);
+ DRW_shgroup_uniform_vec4(
+ rb->ChainShgrp, "output_viewport", stl->g_data->output_viewport, 1);
+
+ float *tld = &lanpr->taper_left_distance, *tls = &lanpr->taper_left_strength,
+ *trd = &lanpr->taper_right_distance, *trs = &lanpr->taper_right_strength;
+
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "taper_l_dist", tld, 1);
+ DRW_shgroup_uniform_float(rb->ChainShgrp, "taper_l_strength", tls, 1);
+ DRW_shgroup_uniform_float(
+ rb->ChainShgrp, "taper_r_dist", (lanpr->flags & LANPR_SAME_TAPER) ? tld : trd, 1);
+ DRW_shgroup_uniform_float(
+ rb->ChainShgrp, "taper_r_strength", (lanpr->flags & LANPR_SAME_TAPER) ? tls : trs, 1);
+
+ /* need to add component enable/disable option. */
+ DRW_shgroup_call(rb->ChainShgrp, lanpr_share.render_buffer_shared->chain_draw_batch, NULL);
+ /* debug purpose */
+ /* DRW_draw_pass(psl->color_pass); */
+ /* DRW_draw_pass(psl->color_pass); */
+ DRW_draw_pass(psl->software_pass);
+ }
+ }
+ else if (!(lanpr->flags & LANPR_USE_CHAINING)) {
+ for (ll = lanpr->line_layers.last; ll; ll = ll->prev) {
+ if (ll->batch) {
+ psl->software_pass = DRW_pass_create("Software Render Preview",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL);
+ ll->shgrp = DRW_shgroup_create(lanpr_share.software_shader, psl->software_pass);
+
+ ED_lanpr_calculate_normal_object_vector(ll, normal_object_direction);
+
+ DRW_shgroup_uniform_float(ll->shgrp, "camdx", &camdx, 1);
+ DRW_shgroup_uniform_float(ll->shgrp, "camdy", &camdy, 1);
+ DRW_shgroup_uniform_float(ll->shgrp, "camzoom", &camzoom, 1);
+
+ DRW_shgroup_uniform_vec4(
+ ll->shgrp,
+ "contour_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->contour.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ ll->shgrp,
+ "crease_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->crease.color,
+ 1);
+ DRW_shgroup_uniform_vec4(ll->shgrp,
+ "material_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ ll->color :
+ ll->material_separate.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ ll->shgrp,
+ "edge_mark_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->edge_mark.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ ll->shgrp,
+ "intersection_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->intersection.color,
+ 1);
+ static float uniform_thickness = 1.0f;
+ DRW_shgroup_uniform_float(ll->shgrp, "thickness", &ll->thickness, 1);
+ DRW_shgroup_uniform_float(ll->shgrp,
+ "thickness_contour",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &uniform_thickness :
+ &ll->contour.thickness,
+ 1);
+ DRW_shgroup_uniform_float(ll->shgrp,
+ "thickness_crease",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &uniform_thickness :
+ &ll->crease.thickness,
+ 1);
+ DRW_shgroup_uniform_float(ll->shgrp,
+ "thickness_material",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &uniform_thickness :
+ &ll->material_separate.thickness,
+ 1);
+ DRW_shgroup_uniform_float(ll->shgrp,
+ "thickness_edge_mark",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &uniform_thickness :
+ &ll->edge_mark.thickness,
+ 1);
+ DRW_shgroup_uniform_float(ll->shgrp,
+ "thickness_intersection",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &uniform_thickness :
+ &ll->intersection.thickness,
+ 1);
+ DRW_shgroup_uniform_vec4(ll->shgrp, "preview_viewport", stl->g_data->dpix_viewport, 1);
+ DRW_shgroup_uniform_vec4(ll->shgrp, "output_viewport", stl->g_data->output_viewport, 1);
+
+ static int normal_effect_inverse;
+ normal_effect_inverse = (ll->flags & LANPR_LINE_LAYER_NORMAL_INVERSE) ? 1 : 0;
+ DRW_shgroup_uniform_int(
+ ll->shgrp,
+ "normal_mode",
+ (ll->flags & LANPR_LINE_LAYER_NORMAL_ENABLED) ? &ll->normal_mode : &zero_value,
+ 1);
+ DRW_shgroup_uniform_int(ll->shgrp, "normal_effect_inverse", &normal_effect_inverse, 1);
+ DRW_shgroup_uniform_float(ll->shgrp, "normal_ramp_begin", &ll->normal_ramp_begin, 1);
+ DRW_shgroup_uniform_float(ll->shgrp, "normal_ramp_end", &ll->normal_ramp_end, 1);
+ DRW_shgroup_uniform_float(
+ ll->shgrp, "normal_thickness_start", &ll->normal_thickness_start, 1);
+ DRW_shgroup_uniform_float(
+ ll->shgrp, "normal_thickness_end", &ll->normal_thickness_end, 1);
+ DRW_shgroup_uniform_vec3(ll->shgrp, "normal_direction", normal_object_direction, 1);
+
+ DRW_shgroup_call(ll->shgrp, ll->batch, NULL);
+ DRW_draw_pass(psl->software_pass);
+ }
+ }
+ }
+ }
+
+ GPU_framebuffer_blit(fbl->software_ms, 0, dfb, 0, GPU_COLOR_BIT);
+
+ if (!is_render) {
+ DRW_view_set_active(NULL);
+ }
+}
+
+void ED_lanpr_update_render_progress(const char *text)
+{
+ if (lanpr_share.re_render) {
+ RE_engine_update_stats(lanpr_share.re_render, NULL, text);
+ }
+}
diff --git a/source/blender/draw/engines/lanpr/lanpr_dpix.c b/source/blender/draw/engines/lanpr/lanpr_dpix.c
new file mode 100644
index 00000000000..7ebb28d2b2e
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/lanpr_dpix.c
@@ -0,0 +1,553 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ *
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "BKE_customdata.h"
+#include "BKE_object.h"
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "lanpr_all.h"
+#include "bmesh.h"
+
+#include <math.h>
+
+extern LANPR_SharedResource lanpr_share;
+extern char datatoc_lanpr_dpix_project_passthrough_vert_glsl[];
+extern char datatoc_lanpr_dpix_project_clip_frag_glsl[];
+extern char datatoc_lanpr_dpix_preview_geom_glsl[];
+extern char datatoc_lanpr_dpix_preview_frag_glsl[];
+
+int lanpr_dpix_texture_size(SceneLANPR *lanpr)
+{
+ switch (lanpr->gpu_cache_size) {
+ case LANPR_GPU_CACHE_SIZE_512:
+ return 512;
+ case LANPR_GPU_CACHE_SIZE_1K:
+ return 1024;
+ case LANPR_GPU_CACHE_SIZE_2K:
+ return 2048;
+ case LANPR_GPU_CACHE_SIZE_4K:
+ return 4096;
+ }
+ return 512;
+}
+
+void lanpr_init_atlas_inputs(void *ved)
+{
+ lanpr_share.ved_viewport = ved;
+ LANPR_Data *vedata = (LANPR_Data *)ved;
+ LANPR_TextureList *txl = vedata->txl;
+ LANPR_FramebufferList *fbl = vedata->fbl;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ SceneLANPR *lanpr = &draw_ctx->scene->lanpr;
+
+ int texture_size = lanpr_dpix_texture_size(lanpr);
+ lanpr_share.texture_size = texture_size;
+
+ if (txl->dpix_in_pl && GPU_texture_width(txl->dpix_in_pl) != texture_size) {
+ DRW_texture_free(txl->dpix_in_pl);
+ txl->dpix_in_pl = NULL;
+ DRW_texture_free(txl->dpix_in_pr);
+ txl->dpix_in_pr = NULL;
+ DRW_texture_free(txl->dpix_in_nl);
+ txl->dpix_in_nl = NULL;
+ DRW_texture_free(txl->dpix_in_nr);
+ txl->dpix_in_nr = NULL;
+ DRW_texture_free(txl->dpix_out_pl);
+ txl->dpix_out_pl = NULL;
+ DRW_texture_free(txl->dpix_out_pr);
+ txl->dpix_out_pr = NULL;
+ DRW_texture_free(txl->dpix_out_length);
+ txl->dpix_out_length = NULL;
+ }
+
+ if (lanpr_share.dpix_reloaded || !txl->dpix_in_pl) {
+ DRW_texture_ensure_2d(&txl->dpix_in_pl, texture_size, texture_size, GPU_RGBA32F, 0);
+ DRW_texture_ensure_2d(&txl->dpix_in_pr, texture_size, texture_size, GPU_RGBA32F, 0);
+ DRW_texture_ensure_2d(&txl->dpix_in_nl, texture_size, texture_size, GPU_RGBA32F, 0);
+ DRW_texture_ensure_2d(&txl->dpix_in_nr, texture_size, texture_size, GPU_RGBA32F, 0);
+ DRW_texture_ensure_2d(&txl->dpix_in_edge_mask, texture_size, texture_size, GPU_RGBA8, 0);
+ DRW_texture_ensure_2d(&txl->dpix_out_pl, texture_size, texture_size, GPU_RGBA32F, 0);
+ DRW_texture_ensure_2d(&txl->dpix_out_pr, texture_size, texture_size, GPU_RGBA32F, 0);
+ DRW_texture_ensure_2d(&txl->dpix_out_length, texture_size, texture_size, GPU_RGBA32F, 0);
+ }
+
+ GPU_framebuffer_ensure_config(&fbl->dpix_transform,
+ {GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_TEXTURE(txl->dpix_out_pl),
+ GPU_ATTACHMENT_TEXTURE(txl->dpix_out_pr),
+ GPU_ATTACHMENT_TEXTURE(txl->dpix_out_length),
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE});
+
+ GPU_framebuffer_ensure_config(&fbl->dpix_preview,
+ {GPU_ATTACHMENT_TEXTURE(txl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->color),
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE});
+
+ if (!lanpr_share.dpix_transform_shader) {
+ lanpr_share.dpix_transform_shader = DRW_shader_create(
+ datatoc_lanpr_dpix_project_passthrough_vert_glsl,
+ NULL,
+ datatoc_lanpr_dpix_project_clip_frag_glsl,
+ NULL);
+ if (!lanpr_share.dpix_transform_shader) {
+ lanpr_share.dpix_shader_error = 1;
+ printf("LANPR: DPIX transform shader compile error.");
+ }
+ }
+ if (!lanpr_share.dpix_preview_shader) {
+ lanpr_share.dpix_preview_shader = DRW_shader_create(
+ datatoc_lanpr_dpix_project_passthrough_vert_glsl,
+ datatoc_lanpr_dpix_preview_geom_glsl,
+ datatoc_lanpr_dpix_preview_frag_glsl,
+ NULL);
+ if (!lanpr_share.dpix_transform_shader) {
+ lanpr_share.dpix_shader_error = 1;
+ printf("LANPR: DPIX transform shader compile error.");
+ }
+ }
+}
+void lanpr_destroy_atlas(void *UNUSED(ved))
+{
+ /* no need to free things, no custom data. */
+}
+
+int lanpr_feed_atlas_data_obj(void *UNUSED(vedata),
+ float *AtlasPointsL,
+ float *AtlasPointsR,
+ float *AtlasFaceNormalL,
+ float *AtlasFaceNormalR,
+ float *AtlasEdgeMask,
+ Object *ob,
+ int begin_index)
+{
+ if (!DRW_object_is_renderable(ob)) {
+ return begin_index;
+ }
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ if (ob == draw_ctx->object_edit) {
+ return begin_index;
+ }
+ if (ob->type != OB_MESH) {
+ return begin_index;
+ }
+
+ Mesh *me = ob->data;
+ BMesh *bm;
+ struct BMFace *f1, *f2;
+ struct BMVert *v1, *v2;
+ struct BMEdge *e;
+ struct BMLoop *l1, *l2;
+ LanprEdge *fe;
+ int CanFindFreestyle = 0;
+ int edge_count = me->totedge;
+ int i, idx;
+
+ int cache_total = lanpr_share.texture_size * lanpr_share.texture_size;
+
+ /* Don't overflow the cache. */
+ if ((edge_count + begin_index) > (cache_total - 1)) {
+ return begin_index;
+ }
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+ BM_mesh_bm_from_me(bm,
+ me,
+ &((struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+
+ if (CustomData_has_layer(&bm->edata, CD_LANPR_EDGE)) {
+ CanFindFreestyle = 1;
+ }
+
+ for (i = 0; i < edge_count; i++) {
+ f1 = 0;
+ f2 = 0;
+ e = BM_edge_at_index(bm, i);
+ v1 = e->v1;
+ v2 = e->v2;
+ l1 = e->l;
+ l2 = e->l ? e->l->radial_next : 0;
+ if (l1) {
+ f1 = l1->f;
+ }
+ if (l2) {
+ f2 = l2->f;
+ }
+
+ idx = (begin_index + i) * 4;
+
+ AtlasPointsL[idx + 0] = v1->co[0];
+ AtlasPointsL[idx + 1] = v1->co[1];
+ AtlasPointsL[idx + 2] = v1->co[2];
+ AtlasPointsL[idx + 3] = 1;
+
+ AtlasPointsR[idx + 0] = v2->co[0];
+ AtlasPointsR[idx + 1] = v2->co[1];
+ AtlasPointsR[idx + 2] = v2->co[2];
+ AtlasPointsR[idx + 3] = 1;
+
+ if (CanFindFreestyle) {
+ fe = CustomData_bmesh_get(&bm->edata, e->head.data, CD_LANPR_EDGE);
+ if (fe->flag & LANPR_EDGE_MARK) {
+ AtlasEdgeMask[idx + 1] = 1; /* channel G */
+ }
+ }
+
+ if (f1) {
+ AtlasFaceNormalL[idx + 0] = f1->no[0];
+ AtlasFaceNormalL[idx + 1] = f1->no[1];
+ AtlasFaceNormalL[idx + 2] = f1->no[2];
+ AtlasFaceNormalL[idx + 3] = 1;
+ }
+ else {
+ AtlasFaceNormalL[idx + 0] = 0;
+ AtlasFaceNormalL[idx + 1] = 0;
+ AtlasFaceNormalL[idx + 2] = 0;
+ AtlasFaceNormalL[idx + 3] = 0;
+ }
+
+ if (f2 && f2 != f1) { /* this is for edge condition */
+ AtlasFaceNormalR[idx + 0] = f2->no[0];
+ AtlasFaceNormalR[idx + 1] = f2->no[1];
+ AtlasFaceNormalR[idx + 2] = f2->no[2];
+ AtlasFaceNormalR[idx + 3] = 1;
+
+ if (f2->mat_nr != f1->mat_nr) {
+ AtlasEdgeMask[idx] = 1; /* channel r */
+ }
+ }
+ else {
+ AtlasFaceNormalR[idx + 0] = 0;
+ AtlasFaceNormalR[idx + 1] = 0;
+ AtlasFaceNormalR[idx + 2] = 0;
+ AtlasFaceNormalR[idx + 3] = 0;
+ }
+ }
+
+ BM_mesh_free(bm);
+
+ return begin_index + edge_count;
+}
+
+int lanpr_feed_atlas_data_intersection_cache(void *UNUSED(vedata),
+ float *AtlasPointsL,
+ float *AtlasPointsR,
+ float *AtlasFaceNormalL,
+ float *AtlasFaceNormalR,
+ float *AtlasEdgeMask,
+ int begin_index)
+{
+ LANPR_RenderBuffer *rb = lanpr_share.render_buffer_shared;
+ LinkData *lip;
+ LANPR_RenderLine *rl;
+ int i, idx;
+
+ i = 0;
+
+ if (!rb) {
+ return 0;
+ }
+
+ int cache_total = lanpr_share.texture_size * lanpr_share.texture_size;
+
+ /* Don't overflow the cache. */
+ if ((rb->intersection_count + begin_index) > (cache_total - 1)) {
+ return 0;
+ }
+
+ for (lip = rb->intersection_lines.first; lip; lip = lip->next) {
+ rl = lip->data;
+
+ idx = (begin_index + i) * 4;
+ AtlasEdgeMask[idx + 2] = 1; /* channel B */
+
+ AtlasPointsL[idx + 0] = rl->l->gloc[0];
+ AtlasPointsL[idx + 1] = rl->l->gloc[1];
+ AtlasPointsL[idx + 2] = rl->l->gloc[2];
+ AtlasPointsL[idx + 3] = 1;
+
+ AtlasPointsR[idx + 0] = rl->r->gloc[0];
+ AtlasPointsR[idx + 1] = rl->r->gloc[1];
+ AtlasPointsR[idx + 2] = rl->r->gloc[2];
+ AtlasPointsR[idx + 3] = 1;
+
+ AtlasFaceNormalL[idx + 0] = 0;
+ AtlasFaceNormalL[idx + 1] = 0;
+ AtlasFaceNormalL[idx + 2] = 1;
+ AtlasFaceNormalL[idx + 3] = 0;
+
+ AtlasFaceNormalR[idx + 0] = 0;
+ AtlasFaceNormalR[idx + 1] = 0;
+ AtlasFaceNormalR[idx + 2] = 1;
+ AtlasFaceNormalR[idx + 3] = 0;
+
+ i++;
+ }
+
+ return begin_index + i;
+}
+
+static void lanpr_dpix_index_to_coord(int index, float *x, float *y)
+{
+ int texture_size = lanpr_share.texture_size;
+ (*x) = interpf(1, -1, (float)(index % texture_size + 0.5) / (float)texture_size);
+ (*y) = interpf(1, -1, (float)(index / texture_size + 0.5) / (float)texture_size);
+}
+
+static void lanpr_dpix_index_to_coord_absolute(int index, float *x, float *y)
+{
+ int texture_size = lanpr_share.texture_size;
+ (*x) = (float)(index % texture_size) + 0.5;
+ (*y) = (float)(index / texture_size) + 0.5;
+}
+
+int lanpr_feed_atlas_trigger_preview_obj(void *UNUSED(vedata), Object *ob, int begin_index)
+{
+ Mesh *me = ob->data;
+ if (ob->type != OB_MESH) {
+ return begin_index;
+ }
+ int edge_count = me->totedge;
+ int i;
+ float co[2];
+
+ int cache_total = lanpr_share.texture_size * lanpr_share.texture_size;
+
+ /* Don't overflow the cache. */
+ if ((edge_count + begin_index) > (cache_total - 1)) {
+ return begin_index;
+ }
+
+ static GPUVertFormat format = {0};
+ static struct {
+ uint pos, uvs;
+ } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ static GPUVertFormat format2 = {0};
+ static struct {
+ uint pos, uvs;
+ } attr_id2;
+ if (format2.attr_len == 0) {
+ attr_id2.pos = GPU_vertformat_attr_add(&format2, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPUVertBuf *vbo2 = GPU_vertbuf_create_with_format(&format2);
+ GPU_vertbuf_data_alloc(vbo, edge_count);
+ GPU_vertbuf_data_alloc(vbo2, edge_count);
+
+ for (i = 0; i < edge_count; i++) {
+ lanpr_dpix_index_to_coord(i + begin_index, &co[0], &co[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, co);
+ lanpr_dpix_index_to_coord_absolute(i + begin_index, &co[0], &co[1]);
+ GPU_vertbuf_attr_set(vbo2, attr_id2.pos, i, co);
+ }
+
+ GPUBatch *gb = GPU_batch_create_ex(
+ GPU_PRIM_POINTS, vbo, 0, GPU_USAGE_DYNAMIC | GPU_BATCH_OWNS_VBO);
+ GPUBatch *gb2 = GPU_batch_create_ex(
+ GPU_PRIM_POINTS, vbo2, 0, GPU_USAGE_DYNAMIC | GPU_BATCH_OWNS_VBO);
+
+ LANPR_BatchItem *bi = BLI_mempool_alloc(lanpr_share.mp_batch_list);
+ BLI_addtail(&lanpr_share.dpix_batch_list, bi);
+ bi->dpix_transform_batch = gb;
+ bi->dpix_preview_batch = gb2;
+ bi->ob = ob;
+
+ return begin_index + edge_count;
+}
+
+void lanpr_create_atlas_intersection_preview(void *UNUSED(vedata), int begin_index)
+{
+ LANPR_RenderBuffer *rb = lanpr_share.render_buffer_shared;
+ float co[2];
+ int i;
+
+ if (!rb) {
+ return;
+ }
+
+ if (rb->DPIXIntersectionBatch) {
+ GPU_BATCH_DISCARD_SAFE(rb->DPIXIntersectionBatch);
+ }
+ rb->DPIXIntersectionBatch = 0;
+
+ if (!rb->intersection_count) {
+ return;
+ }
+
+ int cache_total = lanpr_share.texture_size * lanpr_share.texture_size;
+
+ /* Don't overflow the cache. */
+ if ((rb->intersection_count + begin_index) > (cache_total - 1)) {
+ return;
+ }
+
+ static GPUVertFormat format = {0};
+ static struct {
+ uint pos, uvs;
+ } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ static GPUVertFormat format2 = {0};
+ static struct {
+ uint pos, uvs;
+ } attr_id2;
+ if (format2.attr_len == 0) {
+ attr_id2.pos = GPU_vertformat_attr_add(&format2, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, rb->intersection_count);
+
+ GPUVertBuf *vbo2 = GPU_vertbuf_create_with_format(&format2);
+ GPU_vertbuf_data_alloc(vbo2, rb->intersection_count);
+
+ for (i = 0; i < rb->intersection_count; i++) {
+ lanpr_dpix_index_to_coord(i + begin_index, &co[0], &co[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, co);
+ lanpr_dpix_index_to_coord_absolute(i + begin_index, &co[0], &co[1]);
+ GPU_vertbuf_attr_set(vbo2, attr_id2.pos, i, co);
+ }
+ rb->DPIXIntersectionTransformBatch = GPU_batch_create_ex(
+ GPU_PRIM_POINTS, vbo, 0, GPU_USAGE_DYNAMIC | GPU_BATCH_OWNS_VBO);
+ rb->DPIXIntersectionBatch = GPU_batch_create_ex(
+ GPU_PRIM_POINTS, vbo2, 0, GPU_USAGE_DYNAMIC | GPU_BATCH_OWNS_VBO);
+}
+
+void lanpr_dpix_draw_scene(LANPR_TextureList *txl,
+ LANPR_FramebufferList *fbl,
+ LANPR_PassList *psl,
+ LANPR_PrivateData *pd,
+ SceneLANPR *lanpr,
+ GPUFrameBuffer *DefaultFB,
+ int is_render)
+{
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0xFF;
+ int is_persp = 1;
+ float use_background_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ ;
+
+ if (!lanpr->active_layer) {
+ return; /* return early in case we don't have line layers. DPIX only use the first layer. */
+ }
+ int texw = GPU_texture_width(txl->edge_intermediate),
+ texh = GPU_texture_height(txl->edge_intermediate);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ View3D *v3d = draw_ctx->v3d;
+ Object *camera = 0;
+ if (v3d) {
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ camera = (rv3d && rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+ is_persp = rv3d->is_persp;
+ }
+ if (!camera) {
+ camera = scene->camera;
+ if (!v3d) {
+ is_persp = ((Camera *)camera->data)->type == CAM_PERSP ? 1 : 0;
+ }
+ }
+ if (is_render && !camera) {
+ return;
+ }
+ /* XXX: should implement view angle functions for ortho camera. */
+
+ int texture_size = lanpr_share.texture_size;
+
+ pd->dpix_viewport[2] = texw;
+ pd->dpix_viewport[3] = texh;
+ pd->dpix_is_perspective = is_persp;
+ pd->dpix_sample_step = 1;
+ pd->dpix_buffer_width = texture_size;
+ pd->dpix_depth_offset = 0.0001;
+ pd->dpix_znear = camera ? ((Camera *)camera->data)->clip_start : v3d->clip_start;
+ pd->dpix_zfar = camera ? ((Camera *)camera->data)->clip_end : v3d->clip_end;
+
+ copy_v3_v3(use_background_color, &scene->world->horr);
+ use_background_color[3] = scene->r.alphamode ? 0.0f : 1.0f;
+
+ GPU_point_size(1);
+ /* GPU_line_width(2); */
+ GPU_framebuffer_bind(fbl->dpix_transform);
+ DRW_draw_pass(psl->dpix_transform_pass);
+
+ GPU_framebuffer_bind(fbl->dpix_preview);
+ eGPUFrameBufferBits clear_bits = GPU_COLOR_BIT;
+ GPU_framebuffer_clear(fbl->dpix_preview, clear_bits, clear_col, clear_depth, clear_stencil);
+ DRW_draw_pass(psl->dpix_preview_pass);
+
+ if (is_render) {
+ mul_v3_v3fl(clear_col, use_background_color, use_background_color[3]);
+ clear_col[3] = use_background_color[3];
+ }
+ else {
+ copy_v4_v4(clear_col, use_background_color);
+ }
+
+ GPU_framebuffer_bind(DefaultFB);
+ GPU_framebuffer_clear(DefaultFB, clear_bits, clear_col, clear_depth, clear_stencil);
+ DRW_multisamples_resolve(txl->depth, txl->color, 0);
+}
diff --git a/source/blender/draw/engines/lanpr/lanpr_engine.c b/source/blender/draw/engines/lanpr/lanpr_engine.c
new file mode 100644
index 00000000000..295e1f12411
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/lanpr_engine.c
@@ -0,0 +1,810 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ *
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math_matrix.h"
+#include "BLI_rect.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_mesh_types.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "RE_pipeline.h"
+
+#include "bmesh.h"
+#include "lanpr_all.h"
+
+#include <math.h>
+
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern char datatoc_lanpr_snake_multichannel_frag_glsl[];
+extern char datatoc_lanpr_snake_edge_frag_glsl[];
+extern char datatoc_lanpr_snake_image_peel_frag_glsl[];
+extern char datatoc_lanpr_snake_line_connection_vert_glsl[];
+extern char datatoc_lanpr_snake_line_connection_frag_glsl[];
+extern char datatoc_lanpr_snake_line_connection_geom_glsl[];
+extern char datatoc_lanpr_software_line_chain_geom_glsl[];
+extern char datatoc_lanpr_software_chain_geom_glsl[];
+extern char datatoc_lanpr_dpix_project_passthrough_vert_glsl[];
+extern char datatoc_lanpr_dpix_project_clip_frag_glsl[];
+extern char datatoc_lanpr_dpix_preview_frag_glsl[];
+extern char datatoc_lanpr_software_passthrough_vert_glsl[];
+extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[];
+extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[];
+
+LANPR_SharedResource lanpr_share;
+
+static void lanpr_engine_init(void *ved)
+{
+ lanpr_share.ved_viewport = ved;
+ LANPR_Data *vedata = (LANPR_Data *)ved;
+ LANPR_TextureList *txl = vedata->txl;
+ LANPR_FramebufferList *fbl = vedata->fbl;
+
+ if (!lanpr_share.init_complete) {
+ BLI_spin_init(&lanpr_share.lock_render_status);
+ }
+
+#if 0 /* Deprecated: snake mode */
+ GPU_framebuffer_ensure_config(&fbl->edge_thinning,
+ {GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_TEXTURE(txl->color)});
+
+ if (!lanpr_share.edge_detect_shader) {
+ lanpr_share.edge_detect_shader = DRW_shader_create(
+ datatoc_common_fullscreen_vert_glsl, NULL, datatoc_lanpr_snake_edge_frag_glsl, NULL);
+ }
+ if (!lanpr_share.edge_thinning_shader) {
+ lanpr_share.edge_thinning_shader = DRW_shader_create(
+ datatoc_common_fullscreen_vert_glsl, NULL, datatoc_lanpr_snake_image_peel_frag_glsl, NULL);
+ }
+ if (!lanpr_share.snake_connection_shader) {
+ lanpr_share.snake_connection_shader = DRW_shader_create(
+ datatoc_lanpr_snake_line_connection_vert_glsl,
+ datatoc_lanpr_snake_line_connection_geom_glsl,
+ datatoc_lanpr_snake_line_connection_frag_glsl,
+ NULL);
+ }
+#endif
+
+ DRW_texture_ensure_fullscreen_2D_multisample(&txl->depth, GPU_DEPTH_COMPONENT32F, 8, 0);
+ DRW_texture_ensure_fullscreen_2D_multisample(&txl->color, GPU_RGBA32F, 8, 0);
+ DRW_texture_ensure_fullscreen_2D_multisample(&txl->normal, GPU_RGBA32F, 8, 0);
+ DRW_texture_ensure_fullscreen_2D_multisample(&txl->edge_intermediate, GPU_RGBA32F, 8, 0);
+
+ DRW_texture_ensure_fullscreen_2D_multisample(
+ &txl->ms_resolve_depth, GPU_DEPTH_COMPONENT32F, 8, 0);
+ DRW_texture_ensure_fullscreen_2D_multisample(&txl->ms_resolve_color, GPU_RGBA32F, 8, 0);
+
+ GPU_framebuffer_ensure_config(&fbl->passes,
+ {GPU_ATTACHMENT_TEXTURE(txl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->color),
+ GPU_ATTACHMENT_TEXTURE(txl->normal)});
+
+ GPU_framebuffer_ensure_config(
+ &fbl->edge_intermediate,
+ {GPU_ATTACHMENT_TEXTURE(txl->depth), GPU_ATTACHMENT_TEXTURE(txl->edge_intermediate)});
+
+ if (!lanpr_share.multichannel_shader) {
+ lanpr_share.multichannel_shader = DRW_shader_create(
+ datatoc_gpu_shader_3D_smooth_color_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ NULL);
+ }
+
+ /* DPIX */
+ lanpr_init_atlas_inputs(ved);
+
+ /* SOFTWARE */
+ if (!lanpr_share.software_shader) {
+ lanpr_share.software_shader = DRW_shader_create(datatoc_lanpr_software_passthrough_vert_glsl,
+ datatoc_lanpr_software_line_chain_geom_glsl,
+ datatoc_lanpr_dpix_preview_frag_glsl,
+ NULL);
+ }
+
+ if (!lanpr_share.software_chaining_shader) {
+ lanpr_share.software_chaining_shader = DRW_shader_create(
+ datatoc_lanpr_software_passthrough_vert_glsl,
+ datatoc_lanpr_software_chain_geom_glsl,
+ datatoc_lanpr_dpix_preview_frag_glsl,
+ NULL);
+ }
+
+ GPU_framebuffer_ensure_config(&fbl->software_ms,
+ {GPU_ATTACHMENT_TEXTURE(txl->ms_resolve_depth),
+ GPU_ATTACHMENT_TEXTURE(txl->ms_resolve_color)});
+
+ lanpr_share.init_complete = 1;
+}
+
+static void lanpr_dpix_batch_free(void)
+{
+ LANPR_BatchItem *dpbi;
+ while ((dpbi = BLI_pophead(&lanpr_share.dpix_batch_list)) != NULL) {
+ GPU_BATCH_DISCARD_SAFE(dpbi->dpix_preview_batch);
+ GPU_BATCH_DISCARD_SAFE(dpbi->dpix_transform_batch);
+ }
+ LANPR_RenderBuffer *rb = lanpr_share.render_buffer_shared;
+ if (rb) {
+ if (rb->DPIXIntersectionBatch) {
+ GPU_BATCH_DISCARD_SAFE(rb->DPIXIntersectionBatch);
+ }
+ if (rb->DPIXIntersectionTransformBatch) {
+ GPU_BATCH_DISCARD_SAFE(rb->DPIXIntersectionTransformBatch);
+ }
+ }
+}
+
+static void lanpr_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(lanpr_share.multichannel_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.snake_connection_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.software_chaining_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.dpix_preview_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.dpix_transform_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.edge_detect_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.edge_thinning_shader);
+ DRW_SHADER_FREE_SAFE(lanpr_share.software_shader);
+
+ lanpr_dpix_batch_free();
+
+ if (lanpr_share.render_buffer_shared) {
+ LANPR_RenderBuffer *rb = lanpr_share.render_buffer_shared;
+ ED_lanpr_destroy_render_data(rb);
+
+ GPU_BATCH_DISCARD_SAFE(rb->chain_draw_batch);
+
+ MEM_freeN(rb);
+ lanpr_share.render_buffer_shared = NULL;
+ }
+
+ BLI_mempool *mp = lanpr_share.mp_batch_list;
+
+ if (mp) {
+ BLI_mempool_destroy(mp);
+ }
+}
+
+static void lanpr_cache_init(void *vedata)
+{
+
+ LANPR_PassList *psl = ((LANPR_Data *)vedata)->psl;
+ LANPR_StorageList *stl = ((LANPR_Data *)vedata)->stl;
+ LANPR_TextureList *txl = ((LANPR_Data *)vedata)->txl;
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ static float normal_object_direction[3] = {0, 0, 1};
+
+ /* Transfer reload state */
+ lanpr_share.dpix_reloaded = lanpr_share.dpix_reloaded_deg;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+
+ if (!lanpr_share.mp_batch_list) {
+ lanpr_share.mp_batch_list = BLI_mempool_create(
+ sizeof(LANPR_BatchItem), 0, 128, BLI_MEMPOOL_NOP);
+ }
+
+ LANPR_PrivateData *pd = stl->g_data;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ int texture_size = lanpr_dpix_texture_size(lanpr);
+ lanpr_share.texture_size = texture_size;
+
+ psl->color_pass = DRW_pass_create(
+ "color Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH);
+ stl->g_data->multipass_shgrp = DRW_shgroup_create(lanpr_share.multichannel_shader,
+ psl->color_pass);
+
+ if (lanpr->master_mode == LANPR_MASTER_MODE_SNAKE) {
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ psl->edge_intermediate = DRW_pass_create("Edge Detection", DRW_STATE_WRITE_COLOR);
+ stl->g_data->edge_detect_shgrp = DRW_shgroup_create(lanpr_share.edge_detect_shader,
+ psl->edge_intermediate);
+ DRW_shgroup_uniform_texture_ref(stl->g_data->edge_detect_shgrp, "tex_sample_0", &txl->depth);
+ DRW_shgroup_uniform_texture_ref(stl->g_data->edge_detect_shgrp, "tex_sample_1", &txl->color);
+ DRW_shgroup_uniform_texture_ref(stl->g_data->edge_detect_shgrp, "tex_sample_2", &txl->normal);
+
+ DRW_shgroup_uniform_float(stl->g_data->edge_detect_shgrp, "z_near", &stl->g_data->znear, 1);
+ DRW_shgroup_uniform_float(stl->g_data->edge_detect_shgrp, "z_far", &stl->g_data->zfar, 1);
+
+ DRW_shgroup_uniform_float(stl->g_data->edge_detect_shgrp,
+ "normal_clamp",
+ &stl->g_data->normal_clamp,
+ 1); /* normal clamp */
+ DRW_shgroup_uniform_float(stl->g_data->edge_detect_shgrp,
+ "normal_strength",
+ &stl->g_data->normal_strength,
+ 1); /* normal strength */
+ DRW_shgroup_uniform_float(stl->g_data->edge_detect_shgrp,
+ "depth_clamp",
+ &stl->g_data->depth_clamp,
+ 1); /* depth clamp */
+ DRW_shgroup_uniform_float(stl->g_data->edge_detect_shgrp,
+ "depth_strength",
+ &stl->g_data->depth_strength,
+ 1); /* depth strength */
+ DRW_shgroup_call(stl->g_data->edge_detect_shgrp, quad, NULL);
+
+ psl->edge_thinning = DRW_pass_create("Edge Thinning Stage 1", DRW_STATE_WRITE_COLOR);
+ stl->g_data->edge_thinning_shgrp = DRW_shgroup_create(lanpr_share.edge_thinning_shader,
+ psl->edge_thinning);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->edge_thinning_shgrp, "tex_sample_0", &dtxl->color);
+ DRW_shgroup_uniform_int(stl->g_data->edge_thinning_shgrp, "stage", &stl->g_data->stage, 1);
+ DRW_shgroup_call(stl->g_data->edge_thinning_shgrp, quad, NULL);
+ }
+ else if (lanpr->master_mode == LANPR_MASTER_MODE_DPIX && lanpr->active_layer &&
+ !lanpr_share.dpix_shader_error) {
+ LANPR_LineLayer *ll = lanpr->line_layers.first;
+ psl->dpix_transform_pass = DRW_pass_create("DPIX Transform Stage", DRW_STATE_WRITE_COLOR);
+ stl->g_data->dpix_transform_shgrp = DRW_shgroup_create(lanpr_share.dpix_transform_shader,
+ psl->dpix_transform_pass);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_transform_shgrp, "vert0_tex", &txl->dpix_in_pl);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_transform_shgrp, "vert1_tex", &txl->dpix_in_pr);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_transform_shgrp, "face_normal0_tex", &txl->dpix_in_nl);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_transform_shgrp, "face_normal1_tex", &txl->dpix_in_nr);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_transform_shgrp, "edge_mask_tex", &txl->dpix_in_edge_mask);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_transform_shgrp, "sample_step", &stl->g_data->dpix_sample_step, 1);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_transform_shgrp, "is_perspective", &stl->g_data->dpix_is_perspective, 1);
+ DRW_shgroup_uniform_vec4(
+ stl->g_data->dpix_transform_shgrp, "viewport", stl->g_data->dpix_viewport, 1);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_transform_shgrp, "buffer_width", &stl->g_data->dpix_buffer_width, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_transform_shgrp, "crease_threshold", &lanpr->crease_threshold, 1);
+ DRW_shgroup_uniform_float(stl->g_data->dpix_transform_shgrp,
+ "crease_fade_threshold",
+ &lanpr->crease_fade_threshold,
+ 1);
+ DRW_shgroup_uniform_int(stl->g_data->dpix_transform_shgrp, "use_contour", &ll->contour.use, 1);
+ DRW_shgroup_uniform_int(stl->g_data->dpix_transform_shgrp, "use_crease", &ll->crease.use, 1);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_transform_shgrp, "use_material", &ll->material_separate.use, 1);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_transform_shgrp, "use_edge_mark", &ll->edge_mark.use, 1);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_transform_shgrp, "use_intersection", &ll->intersection.use, 1);
+
+ psl->dpix_preview_pass = DRW_pass_create("DPIX Preview",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL);
+ stl->g_data->dpix_preview_shgrp = DRW_shgroup_create(lanpr_share.dpix_preview_shader,
+ psl->dpix_preview_pass);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_preview_shgrp, "vert0_tex", &txl->dpix_out_pl);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_preview_shgrp, "vert1_tex", &txl->dpix_out_pr);
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_preview_shgrp, "face_normal0_tex", &txl->dpix_in_nl);
+ DRW_shgroup_uniform_texture_ref(stl->g_data->dpix_preview_shgrp,
+ "face_normal1_tex",
+ &txl->dpix_in_nr); /* these are for normal shading */
+ DRW_shgroup_uniform_texture_ref(
+ stl->g_data->dpix_preview_shgrp, "edge_mask_tex", &txl->dpix_in_edge_mask);
+ DRW_shgroup_uniform_vec4(
+ stl->g_data->dpix_preview_shgrp, "viewport", stl->g_data->dpix_viewport, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->dpix_preview_shgrp,
+ "contour_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color :
+ ll->contour.color,
+ 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->dpix_preview_shgrp,
+ "crease_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color :
+ ll->crease.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ stl->g_data->dpix_preview_shgrp,
+ "material_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->material_separate.color,
+ 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->dpix_preview_shgrp,
+ "edge_mark_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color :
+ ll->edge_mark.color,
+ 1);
+ DRW_shgroup_uniform_vec4(
+ stl->g_data->dpix_preview_shgrp,
+ "intersection_color",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? ll->color : ll->intersection.color,
+ 1);
+ static float use_background_color[4];
+ copy_v3_v3(use_background_color, &scene->world->horr);
+ use_background_color[3] = scene->r.alphamode ? 0.0f : 1.0f;
+
+ DRW_shgroup_uniform_vec4(
+ stl->g_data->dpix_preview_shgrp, "background_color", use_background_color, 1);
+
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "depth_offset", &stl->g_data->dpix_depth_offset, 1);
+ DRW_shgroup_uniform_float(stl->g_data->dpix_preview_shgrp,
+ "depth_width_influence",
+ &lanpr->depth_width_influence,
+ 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "depth_width_curve", &lanpr->depth_width_curve, 1);
+ DRW_shgroup_uniform_float(stl->g_data->dpix_preview_shgrp,
+ "depth_alpha_influence",
+ &lanpr->depth_alpha_influence,
+ 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "depth_alpha_curve", &lanpr->depth_alpha_curve, 1);
+ static float unit_thickness = 1.0f;
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "line_thickness", &ll->thickness, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp,
+ "line_thickness_contour",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? &unit_thickness : &ll->contour.thickness,
+ 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp,
+ "line_thickness_crease",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? &unit_thickness : &ll->crease.thickness,
+ 1);
+ DRW_shgroup_uniform_float(stl->g_data->dpix_preview_shgrp,
+ "line_thickness_material",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->material_separate.thickness,
+ 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp,
+ "line_thickness_edge_mark",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ? &unit_thickness : &ll->edge_mark.thickness,
+ 1);
+ DRW_shgroup_uniform_float(stl->g_data->dpix_preview_shgrp,
+ "line_thickness_intersection",
+ (ll->flags & LANPR_LINE_LAYER_USE_SAME_STYLE) ?
+ &unit_thickness :
+ &ll->intersection.thickness,
+ 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "z_near", &stl->g_data->dpix_znear, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "z_far", &stl->g_data->dpix_zfar, 1);
+
+ ED_lanpr_calculate_normal_object_vector(ll, normal_object_direction);
+
+ static int normal_effect_inverse;
+ normal_effect_inverse = (ll->flags & LANPR_LINE_LAYER_NORMAL_INVERSE);
+
+ DRW_shgroup_uniform_int(stl->g_data->dpix_preview_shgrp, "normal_mode", &ll->normal_mode, 1);
+ DRW_shgroup_uniform_int(
+ stl->g_data->dpix_preview_shgrp, "normal_effect_inverse", &normal_effect_inverse, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "normal_ramp_begin", &ll->normal_ramp_begin, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "normal_ramp_end", &ll->normal_ramp_end, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "normal_thickness_start", &ll->normal_thickness_start, 1);
+ DRW_shgroup_uniform_float(
+ stl->g_data->dpix_preview_shgrp, "normal_thickness_end", &ll->normal_thickness_end, 1);
+ DRW_shgroup_uniform_vec3(
+ stl->g_data->dpix_preview_shgrp, "normal_direction", normal_object_direction, 1);
+
+ pd->begin_index = 0;
+ int fsize = sizeof(float) * 4 * texture_size * texture_size;
+
+ if (lanpr_share.dpix_reloaded) {
+ pd->atlas_pl = MEM_callocN(fsize, "atlas_point_l");
+ pd->atlas_pr = MEM_callocN(fsize, "atlas_point_r");
+ pd->atlas_nl = MEM_callocN(fsize, "atlas_normal_l");
+ pd->atlas_nr = MEM_callocN(fsize, "atlas_normal_l");
+ pd->atlas_edge_mask = MEM_callocN(fsize, "atlas_edge_mask"); /* should always be float */
+
+ lanpr_dpix_batch_free();
+
+ BLI_mempool_clear(lanpr_share.mp_batch_list);
+ }
+ }
+ else if (lanpr->master_mode == LANPR_MASTER_MODE_SOFTWARE) {
+ ;
+ }
+
+ /* Intersection cache must be calculated before drawing. */
+ int updated = 0;
+ if ((draw_ctx->scene->lanpr.flags & LANPR_AUTO_UPDATE) &&
+ (!lanpr_share.render_buffer_shared ||
+ lanpr_share.render_buffer_shared->cached_for_frame != draw_ctx->scene->r.cfra)) {
+ if (draw_ctx->scene->lanpr.master_mode == LANPR_MASTER_MODE_SOFTWARE) {
+
+ ED_lanpr_compute_feature_lines_background(draw_ctx->depsgraph, 0);
+ }
+ else if (draw_ctx->scene->lanpr.master_mode == LANPR_MASTER_MODE_DPIX) {
+ ED_lanpr_compute_feature_lines_background(draw_ctx->depsgraph, 1);
+ }
+ }
+
+ if (ED_lanpr_calculation_flag_check(LANPR_RENDER_FINISHED)) {
+ ED_lanpr_rebuild_all_command(&draw_ctx->scene->lanpr);
+ ED_lanpr_calculation_set_flag(LANPR_RENDER_IDLE);
+ }
+ else {
+ DRW_viewport_request_redraw();
+ }
+}
+
+static void lanpr_cache_populate(void *vedata, Object *ob)
+{
+
+ LANPR_StorageList *stl = ((LANPR_Data *)vedata)->stl;
+ LANPR_PrivateData *pd = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ SceneLANPR *lanpr = &draw_ctx->scene->lanpr;
+ int usage = OBJECT_FEATURE_LINE_INHERENT, dpix_ok = 0;
+
+ if (!DRW_object_is_renderable(ob)) {
+ return;
+ }
+ if (ob == draw_ctx->object_edit) {
+ return;
+ }
+ if (ob->type != OB_MESH) {
+ return;
+ }
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ if ((dpix_ok = (lanpr->master_mode == LANPR_MASTER_MODE_DPIX && lanpr->active_layer &&
+ !lanpr_share.dpix_shader_error)) != 0) {
+ usage = ED_lanpr_object_collection_usage_check(draw_ctx->scene->master_collection, ob);
+ if (usage == OBJECT_FEATURE_LINE_EXCLUDE) {
+ return;
+ }
+ }
+ DRW_shgroup_call_no_cull(stl->g_data->multipass_shgrp, geom, ob);
+ }
+
+ if (dpix_ok) {
+
+ /* usage already set */
+ if (usage == OBJECT_FEATURE_LINE_OCCLUSION_ONLY) {
+ return;
+ }
+
+ int idx = pd->begin_index;
+ if (lanpr_share.dpix_reloaded) {
+ pd->begin_index = lanpr_feed_atlas_data_obj(vedata,
+ pd->atlas_pl,
+ pd->atlas_pr,
+ pd->atlas_nl,
+ pd->atlas_nr,
+ pd->atlas_edge_mask,
+ ob,
+ idx);
+ lanpr_feed_atlas_trigger_preview_obj(vedata, ob, idx);
+ }
+ }
+}
+
+static void lanpr_cache_finish(void *vedata)
+{
+ LANPR_StorageList *stl = ((LANPR_Data *)vedata)->stl;
+ LANPR_PrivateData *pd = stl->g_data;
+ LANPR_TextureList *txl = ((LANPR_Data *)vedata)->txl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ SceneLANPR *lanpr = &draw_ctx->scene->lanpr;
+ float mat[4][4];
+ unit_m4(mat);
+
+ if (lanpr->master_mode == LANPR_MASTER_MODE_DPIX && lanpr->active_layer &&
+ !lanpr_share.dpix_shader_error) {
+ if (lanpr_share.dpix_reloaded) {
+ if (lanpr_share.render_buffer_shared) {
+ lanpr_feed_atlas_data_intersection_cache(vedata,
+ pd->atlas_pl,
+ pd->atlas_pr,
+ pd->atlas_nl,
+ pd->atlas_nr,
+ pd->atlas_edge_mask,
+ pd->begin_index);
+ lanpr_create_atlas_intersection_preview(vedata, pd->begin_index);
+ }
+ GPU_texture_update(txl->dpix_in_pl, GPU_DATA_FLOAT, pd->atlas_pl);
+ GPU_texture_update(txl->dpix_in_pr, GPU_DATA_FLOAT, pd->atlas_pr);
+ GPU_texture_update(txl->dpix_in_nl, GPU_DATA_FLOAT, pd->atlas_nl);
+ GPU_texture_update(txl->dpix_in_nr, GPU_DATA_FLOAT, pd->atlas_nr);
+ GPU_texture_update(txl->dpix_in_edge_mask, GPU_DATA_FLOAT, pd->atlas_edge_mask);
+
+ MEM_freeN(pd->atlas_pl);
+ MEM_freeN(pd->atlas_pr);
+ MEM_freeN(pd->atlas_nl);
+ MEM_freeN(pd->atlas_nr);
+ MEM_freeN(pd->atlas_edge_mask);
+ pd->atlas_pl = 0;
+ lanpr_share.dpix_reloaded = 0;
+ }
+
+ LANPR_BatchItem *bi;
+ for (bi = lanpr_share.dpix_batch_list.first; bi; bi = (void *)bi->item.next) {
+ DRW_shgroup_call_ex(
+ pd->dpix_transform_shgrp, 0, bi->ob->obmat, bi->dpix_transform_batch, 0, 0, true, NULL);
+ DRW_shgroup_call(pd->dpix_preview_shgrp, bi->dpix_preview_batch, 0);
+ }
+
+ if (lanpr_share.render_buffer_shared &&
+ lanpr_share.render_buffer_shared->DPIXIntersectionBatch) {
+ DRW_shgroup_call(pd->dpix_transform_shgrp,
+ lanpr_share.render_buffer_shared->DPIXIntersectionTransformBatch,
+ 0);
+ DRW_shgroup_call(
+ pd->dpix_preview_shgrp, lanpr_share.render_buffer_shared->DPIXIntersectionBatch, 0);
+ }
+ }
+}
+
+static void lanpr_draw_scene_exec(void *vedata, GPUFrameBuffer *dfb, int is_render)
+{
+ LANPR_PassList *psl = ((LANPR_Data *)vedata)->psl;
+ LANPR_TextureList *txl = ((LANPR_Data *)vedata)->txl;
+ LANPR_StorageList *stl = ((LANPR_Data *)vedata)->stl;
+ LANPR_FramebufferList *fbl = ((LANPR_Data *)vedata)->fbl;
+
+ float clear_col[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0xFF;
+
+ GPU_framebuffer_bind(fbl->passes);
+ eGPUFrameBufferBits clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT;
+ GPU_framebuffer_clear(fbl->passes, clear_bits, clear_col, clear_depth, clear_stencil);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ if (lanpr->master_mode == LANPR_MASTER_MODE_DPIX && !lanpr_share.dpix_shader_error) {
+ DRW_draw_pass(psl->color_pass);
+ lanpr_dpix_draw_scene(txl, fbl, psl, stl->g_data, lanpr, dfb, is_render);
+ }
+ /* Deprecated
+ else if (lanpr->master_mode == LANPR_MASTER_MODE_SNAKE) {
+ DRW_draw_pass(psl->color_pass);
+ lanpr_snake_draw_scene(txl, fbl, psl, stl->g_data, lanpr, dfb, is_render);
+ }
+ */
+ else if (lanpr->master_mode == LANPR_MASTER_MODE_SOFTWARE) {
+ /* should isolate these into a seperate function. */
+ lanpr_software_draw_scene(vedata, dfb, is_render);
+ }
+}
+
+static void lanpr_draw_scene(void *vedata)
+{
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ lanpr_draw_scene_exec(vedata, dfbl->default_fb, 0);
+}
+
+static void lanpr_render_cache(void *vedata,
+ struct Object *ob,
+ struct RenderEngine *UNUSED(engine),
+ struct Depsgraph *UNUSED(depsgraph))
+{
+
+ lanpr_cache_populate(vedata, ob);
+}
+
+static void lanpr_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph)
+{
+ /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ float frame = BKE_scene_frame_get(scene);
+
+ /* Set the persective, view and window matrix. */
+ float winmat[4][4], wininv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float persmat[4][4], persinv[4][4];
+ float unitmat[4][4];
+
+ RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat);
+ RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv);
+
+ invert_m4_m4(viewmat, viewinv);
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ invert_m4_m4(persinv, persmat);
+ invert_m4_m4(wininv, winmat);
+
+ unit_m4(unitmat);
+
+ DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL);
+ DRW_view_default_set(view);
+ DRW_view_set_active(view);
+}
+
+static int LANPR_GLOBAL_update_tag;
+
+static void lanpr_id_update(void *UNUSED(vedata), ID *id)
+{
+ /* if (vedata->engine_type != &draw_engine_lanpr_type) return; */
+
+ /* Handle updates based on ID type. */
+ switch (GS(id->name)) {
+ case ID_WO:
+ case ID_OB:
+ case ID_ME:
+ LANPR_GLOBAL_update_tag = 1;
+ default:
+ /* pass */
+ break;
+ }
+}
+
+static void lanpr_render_to_image(void *vedata,
+ RenderEngine *engine,
+ struct RenderLayer *render_layer,
+ const rcti *rect)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ /* int update_mark = DEG_id_type_any_updated(draw_ctx->depsgraph); */
+ Scene *scene = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ lanpr_share.re_render = engine;
+
+ RE_engine_update_stats(engine, NULL, "LANPR: Initializing");
+
+ if (lanpr->master_mode == LANPR_MASTER_MODE_SOFTWARE ||
+ (lanpr->master_mode == LANPR_MASTER_MODE_DPIX && (lanpr->flags & LANPR_USE_INTERSECTIONS))) {
+ if (!lanpr_share.render_buffer_shared) {
+ ED_lanpr_create_render_buffer();
+ }
+ if (lanpr_share.render_buffer_shared->cached_for_frame != scene->r.cfra ||
+ LANPR_GLOBAL_update_tag) {
+ int intersections_only = (lanpr->master_mode != LANPR_MASTER_MODE_SOFTWARE);
+ ED_lanpr_compute_feature_lines_internal(draw_ctx->depsgraph, intersections_only);
+ }
+ }
+
+ lanpr_render_matrices_init(engine, draw_ctx->depsgraph);
+
+ /* refered to eevee's code */
+
+ /* Init default FB and render targets:
+ * In render mode the default framebuffer is not generated
+ * because there is no viewport. So we need to manually create it or
+ * not use it. For code clarity we just allocate it make use of it. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth, GPU_DEPTH_COMPONENT32F, 0);
+ DRW_texture_ensure_fullscreen_2d(&dtxl->color, GPU_RGBA32F, 0);
+
+ GPU_framebuffer_ensure_config(
+ &dfbl->default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+
+ lanpr_engine_init(vedata);
+ lanpr_share.dpix_reloaded_deg = 1; /* force dpix batch to re-create */
+ lanpr_cache_init(vedata);
+ DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, lanpr_render_cache);
+ lanpr_cache_finish(vedata);
+
+ /* get ref for destroy data */
+ /* lanpr_share.rb_ref = lanpr->render_buffer; */
+
+ DRW_render_instance_buffer_finish();
+
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0xFF;
+ eGPUFrameBufferBits clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT;
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear(dfbl->default_fb, clear_bits, clear_col, clear_depth, clear_stencil);
+
+ lanpr_draw_scene_exec(vedata, dfbl->default_fb, 1);
+
+ /* read it back so we can again display and save it. */
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_read_color(dfbl->default_fb,
+ rect->xmin,
+ rect->ymin,
+ BLI_rcti_size_x(rect),
+ BLI_rcti_size_y(rect),
+ 4,
+ 0,
+ rp->rect);
+
+ /* Must clear to avoid other problems. */
+ lanpr_share.re_render = NULL;
+}
+
+static void lanpr_view_update(void *UNUSED(vedata))
+{
+ lanpr_share.dpix_reloaded_deg = 1; /* very bad solution, this will slow down animation. */
+}
+
+static const DrawEngineDataSize lanpr_data_size = DRW_VIEWPORT_DATA_SIZE(LANPR_Data);
+
+DrawEngineType draw_engine_lanpr_type = {
+ NULL,
+ NULL,
+ N_("LANPR"),
+ &lanpr_data_size,
+ &lanpr_engine_init,
+ &lanpr_engine_free,
+ &lanpr_cache_init,
+ &lanpr_cache_populate,
+ &lanpr_cache_finish,
+ NULL, /* draw background */
+ &lanpr_draw_scene, /* draw scene */
+ &lanpr_view_update,
+ &lanpr_id_update,
+ &lanpr_render_to_image,
+};
+
+RenderEngineType DRW_engine_viewport_lanpr_type = {NULL,
+ NULL,
+ LANPR_ENGINE,
+ N_("LANPR"),
+ RE_INTERNAL,
+ NULL, /* update */
+ &DRW_render_to_image, /* render to img */
+ NULL, /* bake */
+ NULL, /* view update */
+ NULL, /* render to view */
+ NULL, /* update in script */
+ NULL, /* update in render pass */
+ &draw_engine_lanpr_type,
+ {NULL, NULL, NULL}};
diff --git a/source/blender/draw/engines/lanpr/lanpr_snake.c b/source/blender/draw/engines/lanpr/lanpr_snake.c
new file mode 100644
index 00000000000..4a570964a2a
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/lanpr_snake.c
@@ -0,0 +1,623 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ *
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "lanpr_all.h"
+#include "DRW_render.h"
+#include "BKE_object.h"
+#include "DNA_mesh_types.h"
+#include "DNA_camera_types.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_framebuffer.h"
+#include "DNA_lanpr_types.h"
+#include "DEG_depsgraph_query.h"
+#include "GPU_draw.h"
+#include "GPU_batch.h"
+#include "GPU_framebuffer.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+#include "bmesh.h"
+
+extern struct LANPR_SharedResource lanpr_share;
+
+int _TNS_colOffsets[] = {-1, 0, 1, 1, 1, 0, -1, -1};
+int _TNS_rowOffsets[] = {-1, -1, -1, 0, 1, 1, 1, 0};
+
+int _TNS_Deviates[8][8] = {{0, 1, 2, 3, 4, 3, 2, 1},
+ {1, 0, 1, 2, 3, 4, 3, 2},
+ {2, 1, 0, 1, 2, 3, 4, 3},
+ {3, 2, 1, 0, 1, 2, 3, 4},
+ {4, 3, 2, 1, 0, 1, 2, 3},
+ {3, 4, 3, 2, 1, 0, 1, 2},
+ {2, 3, 4, 3, 2, 1, 0, 1},
+ {1, 2, 3, 4, 3, 2, 1, 0}};
+
+#define TNS_CLAMP_TEXTURE_W(t, col) \
+ { \
+ if (col >= t->width) \
+ col = t->width - 1; \
+ if (col < 0) \
+ col = 0; \
+ }
+
+#define TNS_CLAMP_TEXTURE_H(t, row) \
+ { \
+ if (row >= t->height) \
+ row = t->height - 1; \
+ if (row < 0) \
+ row = 0; \
+ }
+
+#define TNS_CLAMP_TEXTURE_CONTINUE(t, col, row) \
+ { \
+ if (col >= t->width) \
+ continue; \
+ if (col < 0) \
+ continue; \
+ if (row >= t->height) \
+ continue; \
+ if (row < 0) \
+ continue; \
+ }
+
+static LANPR_TextureSample *lanpr_any_uncovered_samples(LANPR_PrivateData *pd)
+{
+ return BLI_pophead(&pd->pending_samples);
+}
+
+int lanpr_direction_deviate(int From, int To)
+{
+ return _TNS_Deviates[From - 1][To - 1];
+}
+
+int lanpr_detect_direction(LANPR_PrivateData *pd, int col, int row, int LastDirection)
+{
+ int Deviate[9] = {100};
+ int MinDeviate = 0;
+ int i;
+ LANPR_TextureSample *ts;
+
+ for (i = 0; i < 8; i++) {
+ TNS_CLAMP_TEXTURE_CONTINUE(pd, (_TNS_colOffsets[i] + col), (_TNS_rowOffsets[i] + row));
+ if (ts = pd->sample_table[(_TNS_colOffsets[i] + col) +
+ (_TNS_rowOffsets[i] + row) * pd->width]) {
+ if (!LastDirection) {
+ return i + 1;
+ }
+ Deviate[i + 1] = lanpr_direction_deviate(i, LastDirection);
+ if (!MinDeviate || Deviate[MinDeviate] > Deviate[i + 1]) {
+ MinDeviate = i + 1;
+ }
+ }
+ }
+
+ return MinDeviate;
+}
+
+LANPR_LineStrip *lanpr_create_line_strip(LANPR_PrivateData *pd)
+{
+ LANPR_LineStrip *ls = BLI_mempool_calloc(lanpr_share.mp_line_strip);
+ return ls;
+}
+LANPR_LineStripPoint *lanpr_append_point(
+ LANPR_PrivateData *pd, LANPR_LineStrip *ls, real X, real Y, real Z)
+{
+ LANPR_LineStripPoint *lsp = BLI_mempool_calloc(lanpr_share.mp_line_strip_point);
+
+ lsp->P[0] = X;
+ lsp->P[1] = Y;
+ lsp->P[2] = Z;
+
+ BLI_addtail(&ls->points, lsp);
+
+ ls->point_count++;
+
+ return lsp;
+}
+LANPR_LineStripPoint *lanpr_push_point(
+ LANPR_PrivateData *pd, LANPR_LineStrip *ls, real X, real Y, real Z)
+{
+ LANPR_LineStripPoint *lsp = BLI_mempool_calloc(lanpr_share.mp_line_strip_point);
+
+ lsp->P[0] = X;
+ lsp->P[1] = Y;
+ lsp->P[2] = Z;
+
+ BLI_addhead(&ls->points, lsp);
+
+ ls->point_count++;
+
+ return lsp;
+}
+
+void lanpr_destroy_line_strip(LANPR_PrivateData *pd, LANPR_LineStrip *ls)
+{
+ LANPR_LineStripPoint *lsp;
+ while (lsp = BLI_pophead(&ls->points)) {
+ BLI_mempool_free(lanpr_share.mp_line_strip_point, lsp);
+ }
+ BLI_mempool_free(lanpr_share.mp_line_strip, ls);
+}
+
+void lanpr_remove_sample(LANPR_PrivateData *pd, int row, int col)
+{
+ LANPR_TextureSample *ts;
+ ts = pd->sample_table[row * pd->width + col];
+ pd->sample_table[row * pd->width + col] = NULL;
+
+ BLI_remlink(&pd->pending_samples, ts);
+ ts->prev = NULL;
+ ts->next = NULL;
+ BLI_addtail(&pd->erased_samples, ts);
+}
+
+void lanpr_grow_snake_r(LANPR_PrivateData *pd,
+ LANPR_LineStrip *ls,
+ LANPR_LineStripPoint *ThisP,
+ int Direction)
+{
+ LANPR_LineStripPoint *NewP = ThisP, *p2;
+ int Length = 5;
+ int l = 0;
+ int Deviate, Dir = Direction, NewDir;
+ int AddPoint;
+ int TX = NewP->P[0], TY = NewP->P[1];
+
+ while (NewDir = lanpr_detect_direction(pd, TX, TY, Dir)) {
+ AddPoint = 0;
+ Deviate = lanpr_direction_deviate(NewDir, Dir);
+ Dir = NewDir;
+
+ l++;
+ TX += _TNS_colOffsets[NewDir - 1];
+ TY += _TNS_rowOffsets[NewDir - 1];
+
+ if (Deviate < 2) {
+ lanpr_remove_sample(pd, TY, TX);
+ }
+ else if (Deviate < 3) {
+ lanpr_remove_sample(pd, TY, TX);
+ AddPoint = 1;
+ }
+ else {
+ lanpr_remove_sample(pd, TY, TX);
+ return;
+ }
+
+ if (AddPoint || l == Length) {
+ p2 = lanpr_append_point(pd, ls, TX, TY, 0);
+ NewP = p2;
+ l = 0;
+ }
+ }
+ if (TX != ThisP->P[0] || TY != ThisP->P[1]) {
+ lanpr_append_point(pd, ls, TX, TY, 0);
+ }
+}
+
+void lanpr_grow_snake_l(LANPR_PrivateData *pd,
+ LANPR_LineStrip *ls,
+ LANPR_LineStripPoint *ThisP,
+ int Direction)
+{
+ LANPR_LineStripPoint *NewP = ThisP, *p2;
+ int Length = 5;
+ int l = 0;
+ int Deviate, Dir = Direction, NewDir;
+ int AddPoint;
+ int TX = NewP->P[0], TY = NewP->P[1];
+
+ while (NewDir = lanpr_detect_direction(pd, TX, TY, Dir)) {
+ AddPoint = 0;
+ Deviate = lanpr_direction_deviate(NewDir, Dir);
+ Dir = NewDir;
+
+ l++;
+ TX += _TNS_colOffsets[NewDir - 1];
+ TY += _TNS_rowOffsets[NewDir - 1];
+
+ if (Deviate < 2) {
+ lanpr_remove_sample(pd, TY, TX);
+ }
+ else if (Deviate < 4) {
+ lanpr_remove_sample(pd, TY, TX);
+ AddPoint = 1;
+ }
+ else {
+ lanpr_remove_sample(pd, TY, TX);
+ return;
+ }
+
+ if (AddPoint || l == Length) {
+ p2 = lanpr_push_point(pd, ls, TX, TY, 0);
+ NewP = p2;
+ l = 0;
+ }
+ }
+ if (TX != ThisP->P[0] || TY != ThisP->P[1]) {
+ lanpr_push_point(pd, ls, TX, TY, 0);
+ }
+}
+
+int lanpr_reverse_direction(int From)
+{
+ From -= 4;
+ if (From <= 0) {
+ From += 8;
+ }
+ return From;
+}
+
+void lanpr_texture_to_ndc(int x, int y, int w, int h, float *x_ndc, float *y_ndc)
+{
+ *x_ndc = interpf(1, -1, (float)x / (float)w);
+ *y_ndc = interpf(1, -1, (float)y / (float)h);
+}
+
+void lanpr_count_drawing_elements(LANPR_PrivateData *pd,
+ int *vert_count,
+ int *index_adjacent_count)
+{
+ int v_count = 0;
+ int e_count = 0;
+ LANPR_LineStrip *ls;
+ for (ls = (LANPR_LineStrip *)(pd->line_strips.first); ls; ls = (ls->next)) {
+ v_count += (ls->point_count);
+ e_count += ((ls->point_count - 1) * 4);
+ }
+ *vert_count = v_count;
+ *index_adjacent_count = e_count;
+}
+
+GPUBatch *lanpr_get_snake_batch(LANPR_PrivateData *pd)
+{
+ LANPR_LineStrip *ls;
+ LANPR_LineStripPoint *lsp, *plsp;
+ int i;
+ float *Verts;
+ float *Lengths;
+ float TotalLength = 0;
+ int v_count, e_count;
+
+ lanpr_count_drawing_elements(pd, &v_count, &e_count);
+
+ Verts = MEM_callocN(sizeof(float) * v_count * 2, "Verts buffer pre alloc");
+ Lengths = MEM_callocN(sizeof(float) * v_count * 2, "Length buffer pre alloc");
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINES_ADJ, e_count, v_count);
+
+ int vert_offset = 0;
+
+ for (ls = (LANPR_LineStrip *)(pd->line_strips.first); ls; ls = (ls->next)) {
+ for (i = 0; i < ls->point_count - 1; i++) {
+ int v1 = i + vert_offset - 1;
+ int v2 = i + vert_offset;
+ int v3 = i + vert_offset + 1;
+ int v4 = i + vert_offset + 2;
+ if (v1 < 0) {
+ v1 = 0;
+ }
+ if (v4 >= v_count) {
+ v4 = v_count - 1;
+ }
+ GPU_indexbuf_add_line_adj_verts(&elb, v1, v2, v3, v4);
+ }
+
+ i = 0;
+ float xf, yf;
+ TotalLength = 0;
+ for (lsp = (LANPR_LineStripPoint *)(ls->points.first); lsp; lsp = (lsp->next)) {
+ lanpr_texture_to_ndc(lsp->P[0], lsp->P[1], pd->width, pd->height, &xf, &yf);
+ Verts[vert_offset * 2 + i * 2 + 0] = xf;
+ Verts[vert_offset * 2 + i * 2 + 1] = yf;
+ if (plsp = (LANPR_LineStripPoint *)(lsp->prev)) {
+ TotalLength += tMatDist2v(plsp->P, lsp->P);
+ Lengths[(vert_offset + i) * 2] = TotalLength;
+ }
+ i++;
+ }
+
+ ls->total_length = TotalLength;
+ i = 0;
+ for (lsp = (LANPR_LineStripPoint *)(ls->points.first); lsp; lsp = (lsp->next)) {
+ if (plsp = (LANPR_LineStripPoint *)(lsp->prev)) {
+ Lengths[(vert_offset + i) * 2 + 1] = ls->total_length - Lengths[(vert_offset + i) * 2];
+ }
+ i++;
+ }
+
+ vert_offset += (ls->point_count);
+ }
+
+ static GPUVertFormat format = {0};
+ static struct {
+ uint pos, uvs;
+ } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, v_count);
+
+ for (int i = 0; i < v_count; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, &Verts[i * 2]);
+ GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, &Lengths[i * 2]);
+ }
+
+ MEM_freeN(Verts);
+ MEM_freeN(Lengths);
+
+ return GPU_batch_create_ex(
+ GPU_PRIM_LINES_ADJ, vbo, GPU_indexbuf_build(&elb), GPU_USAGE_STATIC | GPU_BATCH_OWNS_VBO);
+}
+
+void lanpr_snake_prepare_cache(LANPR_PrivateData *pd)
+{
+ if (pd->line_result_8bit) {
+ MEM_freeN(pd->line_result_8bit);
+ }
+ pd->line_result_8bit = 0;
+ if (pd->line_result) {
+ MEM_freeN(pd->line_result);
+ }
+ pd->line_result = 0;
+ lanpr_share.mp_sample = BLI_mempool_create(sizeof(LANPR_TextureSample), 0, 512, BLI_MEMPOOL_NOP);
+ lanpr_share.mp_line_strip = BLI_mempool_create(sizeof(LANPR_LineStrip), 0, 512, BLI_MEMPOOL_NOP);
+ lanpr_share.mp_line_strip_point = BLI_mempool_create(
+ sizeof(LANPR_LineStripPoint), 0, 1024, BLI_MEMPOOL_NOP);
+}
+void lanpe_sanke_free_cache(LANPR_PrivateData *pd)
+{
+ if (pd->line_result_8bit) {
+ MEM_freeN(pd->line_result_8bit);
+ }
+ pd->line_result_8bit = 0;
+ if (pd->line_result) {
+ MEM_freeN(pd->line_result);
+ }
+ pd->line_result = 0;
+
+ BLI_mempool_destroy(lanpr_share.mp_line_strip);
+ BLI_mempool_destroy(lanpr_share.mp_line_strip_point);
+ BLI_mempool_destroy(lanpr_share.mp_sample);
+}
+void lanpr_snake_free_readback_data(LANPR_PrivateData *pd)
+{
+ if (pd->line_result_8bit) {
+ MEM_freeN(pd->line_result_8bit);
+ }
+ pd->line_result_8bit = 0;
+ if (pd->line_result) {
+ MEM_freeN(pd->line_result);
+ }
+ pd->line_result = 0;
+}
+
+void lanpr_snake_draw_scene(LANPR_TextureList *txl,
+ LANPR_FramebufferList *fbl,
+ LANPR_PassList *psl,
+ LANPR_PrivateData *pd,
+ SceneLANPR *lanpr,
+ GPUFrameBuffer *DefaultFB,
+ int is_render)
+{
+ eGPUFrameBufferBits clear_bits = GPU_COLOR_BIT | GPU_DEPTH_BIT;
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0xFF;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ View3D *v3d = draw_ctx->v3d;
+ Object *camera;
+ if (v3d) {
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+ }
+ else {
+ camera = scene->camera;
+ }
+
+ pd->znear = camera ? ((Camera *)camera->data)->clip_start : 0.1;
+ pd->zfar = camera ? ((Camera *)camera->data)->clip_end : 100;
+ pd->normal_clamp = lanpr->normal_clamp;
+ pd->normal_strength = lanpr->normal_strength;
+ pd->depth_clamp = lanpr->depth_clamp;
+ pd->depth_strength = lanpr->depth_strength;
+
+ GPU_framebuffer_bind(fbl->edge_intermediate);
+ DRW_draw_pass(psl->edge_intermediate);
+
+ if ((!lanpr->enable_vector_trace) && (!lanpr->display_thinning_result)) {
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->edge_intermediate, 1);
+ return;
+ }
+
+ if (lanpr->display_thinning_result || lanpr->enable_vector_trace) {
+ pd->stage = 0;
+
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->edge_intermediate, 1);
+
+ GPU_framebuffer_bind(fbl->edge_thinning);
+ DRW_draw_pass(psl->edge_thinning);
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->color, 1);
+
+ pd->stage = 1;
+ GPU_framebuffer_bind(fbl->edge_thinning);
+ DRW_draw_pass(psl->edge_thinning);
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->color, 1);
+
+ pd->stage = 0;
+ GPU_framebuffer_bind(fbl->edge_thinning);
+ DRW_draw_pass(psl->edge_thinning);
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->color, 1);
+
+ pd->stage = 1;
+ GPU_framebuffer_bind(fbl->edge_thinning);
+ DRW_draw_pass(psl->edge_thinning);
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->color, 1);
+
+ if (!lanpr->enable_vector_trace) {
+ return;
+ }
+ }
+
+ int texw = GPU_texture_width(txl->edge_intermediate),
+ texh = GPU_texture_height(txl->edge_intermediate);
+ ;
+ int tsize = texw * texh;
+ int recreate = 0;
+ if (tsize != pd->width * pd->height) {
+ recreate = 1;
+ }
+
+ if (recreate || !pd->line_result) {
+ if (pd->line_result) {
+ MEM_freeN(pd->line_result);
+ }
+ pd->line_result = MEM_callocN(sizeof(float) * tsize, "Texture readback buffer");
+
+ if (pd->line_result_8bit) {
+ MEM_freeN(pd->line_result_8bit);
+ }
+ pd->line_result_8bit = MEM_callocN(sizeof(unsigned char) * tsize,
+ "Texture readback buffer 8bit");
+
+ if (pd->sample_table) {
+ MEM_freeN(pd->sample_table);
+ }
+ pd->sample_table = MEM_callocN(sizeof(void *) * tsize, "Texture readback buffer 8bit");
+
+ pd->width = texw;
+ pd->height = texh;
+ }
+
+ GPU_framebuffer_bind(DefaultFB);
+ GPU_framebuffer_read_color(DefaultFB, 0, 0, texw, texh, 1, 0, pd->line_result);
+
+ float sample;
+ int h, w;
+ for (h = 0; h < texh; h++) {
+ for (w = 0; w < texw; w++) {
+ int index = h * texw + w;
+ if ((sample = pd->line_result[index]) > 0.9) {
+ pd->line_result_8bit[index] = 255;
+ LANPR_TextureSample *ts = BLI_mempool_calloc(lanpr_share.mp_sample);
+ BLI_addtail(&pd->pending_samples, ts);
+ pd->sample_table[index] = ts;
+ ts->X = w;
+ ts->Y = h;
+ }
+ else {
+ pd->sample_table[index] = 0;
+ }
+ }
+ }
+
+ LANPR_TextureSample *ts;
+ LANPR_LineStrip *ls;
+ LANPR_LineStripPoint *lsp;
+ while (ts = lanpr_any_uncovered_samples(pd)) {
+ int Direction = 0;
+ LANPR_LineStripPoint tlsp = {0};
+
+ tlsp.P[0] = ts->X;
+ tlsp.P[1] = ts->Y;
+
+ if (Direction = lanpr_detect_direction(pd, ts->X, ts->Y, Direction)) {
+ BLI_addtail(&pd->line_strips, (ls = lanpr_create_line_strip(pd)));
+ lsp = lanpr_append_point(pd, ls, ts->X, ts->Y, 0);
+ lanpr_remove_sample(pd, ts->Y, ts->X);
+
+ lanpr_grow_snake_r(pd, ls, lsp, Direction);
+
+ lanpr_grow_snake_l(pd, ls, lsp, lanpr_reverse_direction(Direction));
+ }
+ }
+
+ float use_background_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ copy_v3_v3(use_background_color, &scene->world->horr);
+ use_background_color[3] = scene->r.alphamode ? 0.0f : 1.0f;
+
+ GPU_framebuffer_bind(DefaultFB);
+ GPU_framebuffer_clear(DefaultFB, clear_bits, use_background_color, clear_depth, clear_stencil);
+
+ GPU_framebuffer_bind(fbl->edge_intermediate);
+ clear_bits = GPU_COLOR_BIT;
+ GPU_framebuffer_clear(
+ fbl->edge_intermediate, clear_bits, use_background_color, clear_depth, clear_stencil);
+
+ float *tld = &lanpr->taper_left_distance, *tls = &lanpr->taper_left_strength,
+ *trd = &lanpr->taper_right_distance, *trs = &lanpr->taper_right_strength;
+
+ GPUBatch *snake_batch = lanpr_get_snake_batch(pd);
+
+ lanpr_snake_prepare_cache(pd);
+
+ psl->snake_pass = DRW_pass_create("Snake Visualization Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_ALWAYS);
+ pd->snake_shgrp = DRW_shgroup_create(lanpr_share.snake_connection_shader, psl->snake_pass);
+ DRW_shgroup_uniform_float(pd->snake_shgrp, "line_width", &lanpr->line_thickness, 1);
+ DRW_shgroup_uniform_float(pd->snake_shgrp, "taper_l_dist", tld, 1);
+ DRW_shgroup_uniform_float(pd->snake_shgrp, "taper_r_dist", tls, 1);
+ DRW_shgroup_uniform_float(
+ pd->snake_shgrp, "taper_l_strength", (lanpr->flags & LANPR_SAME_TAPER) ? tld : trd, 1);
+ DRW_shgroup_uniform_float(
+ pd->snake_shgrp, "taper_r_strength", (lanpr->flags & LANPR_SAME_TAPER) ? tls : trs, 1);
+ DRW_shgroup_uniform_vec4(pd->snake_shgrp, "line_color", lanpr->line_color, 1);
+
+ DRW_shgroup_call(pd->snake_shgrp, snake_batch, NULL);
+ GPU_framebuffer_bind(fbl->edge_intermediate);
+
+ DRW_draw_pass(psl->snake_pass);
+ GPU_BATCH_DISCARD_SAFE(snake_batch);
+
+ BLI_mempool_clear(lanpr_share.mp_sample);
+ BLI_mempool_clear(lanpr_share.mp_line_strip);
+ BLI_mempool_clear(lanpr_share.mp_line_strip_point);
+
+ pd->pending_samples.first = pd->pending_samples.last = 0;
+ pd->erased_samples.first = pd->erased_samples.last = 0;
+ pd->line_strips.first = pd->line_strips.last = 0;
+
+ GPU_framebuffer_bind(DefaultFB);
+ DRW_multisamples_resolve(txl->depth, txl->edge_intermediate, 1);
+
+ lanpe_sanke_free_cache(pd);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_frag.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_frag.glsl
new file mode 100644
index 00000000000..87bcf1698b9
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_frag.glsl
@@ -0,0 +1,6 @@
+in vec4 out_color;
+
+void main()
+{
+ gl_FragData[0] = vec4(out_color.rgb, 1);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_geom.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_geom.glsl
new file mode 100644
index 00000000000..4d83d47e4fc
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_preview_geom.glsl
@@ -0,0 +1,193 @@
+layout(points) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+uniform sampler2D vert0_tex; // L
+uniform sampler2D vert1_tex; // R
+uniform sampler2D face_normal0_tex;
+uniform sampler2D face_normal1_tex; // caution: these are face normals!
+uniform sampler2D edge_mask_tex;
+
+// uniform float uValue0; // buffer_w
+uniform vec4 viewport; // viewport
+uniform float depth_offset;
+
+// these are for depth related thickness control;
+uniform float line_thickness;
+uniform float depth_width_influence;
+uniform float depth_width_curve;
+uniform float depth_alpha_influence;
+uniform float depth_alpha_curve;
+uniform float z_near;
+uniform float z_far;
+
+uniform vec4 background_color;
+
+uniform vec4 contour_color;
+uniform vec4 crease_color;
+uniform vec4 material_color;
+uniform vec4 edge_mark_color;
+uniform vec4 intersection_color;
+
+uniform float line_thickness_contour;
+uniform float line_thickness_crease;
+uniform float line_thickness_material;
+uniform float line_thickness_edge_mark;
+uniform float line_thickness_intersection;
+
+// the same as software mode
+uniform int normal_mode;
+uniform int normal_effect_inverse;
+uniform vec3 normal_direction; // also used as point position
+uniform float normal_ramp_begin;
+uniform float normal_ramp_end;
+uniform float normal_thickness_start;
+uniform float normal_thickness_end;
+
+float use_thickness;
+
+out vec4 out_color;
+
+vec4 use_color;
+
+float get_linear_depth(float z)
+{
+ float ze = 2.0 * z_near * z_far / (z_far + z_near - z * (z_far - z_near));
+ return (ze - z_near) / (z_far - z_near);
+}
+
+float curve_01(float z, float factor)
+{
+ return pow(z, 1 - factor); // factor is -inf~1-eps
+}
+
+vec4 apply_scale(vec4 center, vec4 a)
+{
+ float lz = get_linear_depth(center.z);
+ float depth_factor = mix(0, curve_01(lz, depth_width_curve), depth_width_influence);
+
+ return mix(a, center, depth_factor);
+}
+
+void emit_color_and_alpha(vec4 a, int is_crease, float crease_fading)
+{
+ float lz = get_linear_depth(a.z);
+ float alpha_factor = mix(0, curve_01(lz, depth_alpha_curve), depth_alpha_influence);
+ float alpha_crease_fading = alpha_factor;
+ if (is_crease > 0)
+ alpha_crease_fading = mix(alpha_factor, 1, crease_fading * 2); // fading=0.5 -> fade all
+ out_color = vec4(use_color.rgb, mix(1, 0, alpha_crease_fading));
+}
+
+void draw_line(vec4 p1, vec4 p2, int is_crease)
+{
+
+ vec4 Line = p2 - p1;
+ vec4 Normal = normalize(vec4(-Line.y, Line.x, 0, 0));
+
+ vec4 a, b, c, d;
+
+ vec4 offset = Normal * use_thickness * 0.001;
+
+ // correct thickness
+ offset.x *= viewport.w / viewport.z;
+
+ a = p1 + offset;
+ b = p1 - offset;
+ c = p2 + offset;
+ d = p2 - offset;
+
+ a = apply_scale(p1, a);
+ b = apply_scale(p1, b);
+ c = apply_scale(p2, c);
+ d = apply_scale(p2, d);
+
+ gl_Position = vec4(a.xy, a.z - depth_offset, 1);
+ emit_color_and_alpha(a, is_crease, p2.w);
+ EmitVertex();
+ gl_Position = vec4(b.xy, b.z - depth_offset, 1);
+ emit_color_and_alpha(b, is_crease, p2.w);
+ EmitVertex();
+ gl_Position = vec4(c.xy, c.z - depth_offset, 1);
+ emit_color_and_alpha(c, is_crease, p2.w);
+ EmitVertex();
+
+ gl_Position = vec4(b.xy, b.z - depth_offset, 1);
+ emit_color_and_alpha(b, is_crease, p2.w);
+ EmitVertex();
+ gl_Position = vec4(c.xy, c.z - depth_offset, 1);
+ emit_color_and_alpha(c, is_crease, p2.w);
+ EmitVertex();
+ gl_Position = vec4(d.xy, d.z - depth_offset, 1);
+ emit_color_and_alpha(d, is_crease, p2.w);
+ EmitVertex();
+
+ EndPrimitive();
+}
+
+float factor_to_thickness(float factor)
+{
+ float r = (factor - normal_ramp_begin) / (normal_ramp_end - normal_ramp_begin);
+ if (r > 1)
+ r = 1;
+ if (r < 0)
+ r = 0;
+ float thickness = normal_effect_inverse == 1 ?
+ mix(normal_thickness_start, normal_thickness_end, r) :
+ mix(normal_thickness_end, normal_thickness_start, r);
+ return thickness;
+}
+
+void main()
+{
+ vec4 p1 = texelFetch(vert0_tex, ivec2(gl_in[0].gl_Position.xy), 0);
+ vec4 p2 = texelFetch(vert1_tex, ivec2(gl_in[0].gl_Position.xy), 0);
+
+ vec4 n1 = texelFetch(face_normal0_tex, ivec2(gl_in[0].gl_Position.xy), 0);
+ vec4 n2 = texelFetch(face_normal1_tex, ivec2(gl_in[0].gl_Position.xy), 0);
+
+ vec3 use_normal = normalize(mix(n1, n2, 0.5).xyz);
+
+ if (p1.w == 0 && p2.w == 0)
+ return;
+
+ vec4 edge_mask = texelFetch(edge_mask_tex, ivec2(gl_in[0].gl_Position.xy), 0);
+
+ int is_crease = 0;
+
+ float th = line_thickness;
+ if (normal_mode == 0) {
+ th = line_thickness;
+ }
+ else if (normal_mode == 1) {
+ float factor = dot(use_normal, normal_direction);
+ th = factor_to_thickness(factor);
+ }
+ else if (normal_mode == 2) {
+ float factor = dot(use_normal, normal_direction);
+ th = factor_to_thickness(factor);
+ }
+
+ if (edge_mask.g > 0) {
+ use_color = edge_mark_color;
+ use_thickness = th * line_thickness_edge_mark;
+ }
+ else if (edge_mask.r > 0) {
+ use_color = material_color;
+ use_thickness = th * line_thickness_material;
+ }
+ else if (edge_mask.b > 0) {
+ use_color = intersection_color;
+ use_thickness = th * line_thickness_intersection;
+ }
+ else if (p2.w != p1.w) {
+ use_color = crease_color;
+ use_thickness = th * line_thickness_crease;
+ is_crease = 1;
+ }
+ else {
+ use_color = contour_color;
+ use_thickness = th * line_thickness_contour;
+ }
+
+ draw_line(p1, p2, is_crease);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_clip_frag.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_clip_frag.glsl
new file mode 100644
index 00000000000..66012d447d6
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_clip_frag.glsl
@@ -0,0 +1,495 @@
+uniform mat4 ModelMatrix;
+uniform mat4 ViewMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ProjectionMatrix;
+uniform mat4 ProjectionMatrixInverse;
+
+uniform int use_contour;
+uniform int use_crease;
+uniform int use_material;
+uniform int use_edge_mark;
+uniform int use_intersection;
+
+uniform float crease_threshold;
+uniform float crease_fade_threshold;
+
+uniform int is_perspective; // persp and orth use different crease line determin method
+
+// uniform float sample_step; // length calculation unused now.
+// uniform int buffer_width;
+
+uniform vec4 viewport;
+
+uniform sampler2D vert0_tex;
+uniform sampler2D vert1_tex;
+uniform sampler2D face_normal0_tex;
+uniform sampler2D face_normal1_tex;
+uniform sampler2D edge_mask_tex;
+
+// uniform sampler2D TexSample4;
+//#define path_start_end_ptrs TexSample4 // edge adjacent data
+
+// calculate in shader
+
+vec3 view_pos;
+vec3 view_dir;
+
+int is_crease; // we calculate crease in GPU because it's faster and we have normal data anyway.
+ // and we need to indicate crease test success result using p1.w==1 && p2.w==0
+
+float crease_strength;
+
+// these are for adapting argument names...
+#define modelview (ViewMatrix * ModelMatrix)
+#define projection ProjectionMatrix
+#define inverse_projection ProjectionMatrixInverse
+
+// ivec2 getTexturePix(vec2 fb_coord){
+// vec2 n = ((fb_coord+vec2(1,1))/2).xy;
+// return ivec2(n.x*buffer_width,n.y*buffer_width);
+//}
+
+// Amount of padding around a segment in the segment atlas.
+// The amount of padding rolls off to zero for short segments,
+// and is zero for segments in the middle of paths.
+
+vec2 segmentPadding(float num_samples, float index, float start_index, float end_index)
+{
+ const float MAX_PADDING = 10.0;
+
+ float amount = floor(clamp((num_samples - 2.0) * 0.5, 0.0, MAX_PADDING));
+
+ float left = amount * max(1.0 + start_index - index, 0.0);
+ float right = amount * max(1.0 + index - end_index, 0.0);
+
+ return vec2(left, right);
+}
+
+// Converting from linear indices to 2D coordinates and back:
+
+float coordinateToIndex(vec2 coord, float buf_size)
+{
+ vec2 floor_coord = floor(coord);
+ return floor_coord.x + floor_coord.y * buf_size;
+}
+
+vec2 indexToCoordinate(float index, float buf_size)
+{
+ return vec2(mod(index, buf_size), floor(index / buf_size));
+}
+
+// Packing and unpacking values in the segment atlas offset texture:
+
+float unpackNumSamples(vec4 offset_texel)
+{
+ return offset_texel.b;
+}
+
+float unpackArcLength(vec4 offset_texel)
+{
+ return offset_texel.a;
+}
+
+float unpackSampleOffset(vec4 offset_texel)
+{
+ return offset_texel.r;
+}
+
+float unpackArcLengthOffset(vec4 offset_texel)
+{
+ return offset_texel.g;
+}
+
+vec4 packOffsetTexel(float num_samples, float arc_length)
+{
+ return vec4(num_samples, arc_length, num_samples, arc_length);
+}
+
+vec4 packOffsetTexel(float num_samples,
+ float arc_length,
+ float num_samples_offset,
+ float arc_length_offset)
+{
+ return vec4(num_samples_offset, arc_length_offset, num_samples, arc_length);
+}
+
+// Packing and unpacking values in the 3D vertex positions:
+
+float unpackPathStart(vec4 texel)
+{
+ return texel.r;
+}
+
+float unpackPathEnd(vec4 texel)
+{
+ return texel.g;
+}
+
+float unpackPathLength(vec4 texel)
+{
+ return texel.b;
+}
+
+// Projecting and unprojecting:
+
+vec2 clipToWindow(sampler2D clip_positions, vec4 viewport, ivec2 coordinate)
+{
+ vec4 clip = texelFetch(clip_positions, coordinate, 0);
+ vec3 post_div = clip.xyz / clip.w;
+ return (post_div.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw;
+}
+
+vec2 clipToWindow(vec4 clip, vec4 viewport)
+{
+ vec3 post_div = clip.xyz / clip.w;
+ return (post_div.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw;
+}
+
+// Path id encoding and decoding.
+
+bool idEqualGreaterThan(vec3 a, vec3 b)
+{
+ float ida = a.b * 256.0 * 256.0 + a.g * 256.0 + a.r;
+ float idb = b.b * 256.0 * 256.0 + b.g * 256.0 + b.r;
+ const float small = 0.001;
+ return ida - idb > -small;
+}
+
+bool idsEqual(vec3 a, vec3 b)
+{
+ float ida = a.b * 256.0 * 256.0 + a.g * 256.0 + a.r;
+ float idb = b.b * 256.0 * 256.0 + b.g * 256.0 + b.r;
+ const float small = 0.001;
+ return abs(ida - idb) < small;
+}
+
+vec3 idToColor(float id)
+{
+ id = id + 1.0;
+ float blue = floor(id / (256.0 * 256.0));
+ float green = floor(id / 256.0) - blue * 256.0;
+ float red = id - green * 256.0 - blue * 256.0 * 256.0;
+ return vec3(red, green, blue) / 255.0;
+}
+
+struct segment {
+ vec3 p1;
+ vec3 p2;
+ bool on_screen;
+};
+
+float epsilon = 0.00001;
+float xmin = -1.1;
+float xmax = 1.1;
+float ymin = -1.1;
+float ymax = 1.1;
+
+// this is a conservative offscreen rejection test ... catches most cases
+bool segmentOffScreen(vec3 p0, vec3 p1)
+{
+ return ((p0[0] < xmin && p1[0] < xmin) || (p0[0] > xmax && p1[0] > xmax) ||
+ (p0[1] < ymin && p1[1] < ymin) || (p0[1] > ymax && p1[1] > ymax));
+}
+
+bool pointOffScreen(vec3 p)
+{
+ return (p[0] < xmin || p[0] > xmax || p[1] < ymin || p[1] > ymax);
+}
+
+vec3 clipMinMaxX(vec3 outv, vec3 inv)
+{
+ vec3 ret = outv;
+ if (outv.x < xmin) {
+ float t = (xmin - outv.x) / (inv.x - outv.x);
+ ret = t * inv + (1.0 - t) * outv;
+ }
+ else if (outv.x > xmax) {
+ float t = (xmax - inv.x) / (outv.x - inv.x);
+ ret = t * outv + (1.0 - t) * inv;
+ }
+ return ret;
+}
+
+vec3 clipMinMaxY(vec3 outv, vec3 inv)
+{
+ vec3 ret = outv;
+ if (outv.y < ymin) {
+ float t = (ymin - outv.y) / (inv.y - outv.y);
+ ret = t * inv + (1.0 - t) * outv;
+ }
+ else if (outv.y > ymax) {
+ float t = (ymax - inv.y) / (outv.y - inv.y);
+ ret = t * outv + (1.0 - t) * inv;
+ }
+ return ret;
+}
+
+vec3 clipSegmentOneOut(vec3 off_screen, vec3 on_screen)
+{
+ vec3 outv = off_screen;
+
+ // first clip against the x coords
+ outv = clipMinMaxX(outv, on_screen);
+
+ // now clip against the y coords using the newly clipped point
+ outv = clipMinMaxY(outv, on_screen);
+
+ return outv;
+}
+
+segment clipToMin(float min, segment inseg, float p1val, float p2val)
+{
+ float minPos = min + epsilon;
+ float minNeg = min - epsilon;
+ segment outseg = segment(inseg.p1, inseg.p2, inseg.on_screen);
+
+ // trivial reject
+ if ((p1val < minPos && p2val < minPos) || inseg.on_screen == false) {
+ outseg.on_screen = false;
+ }
+
+ // cut at min
+ if (p1val < minPos) {
+ float t = (min - p1val) / (p2val - p1val);
+ outseg.p1 = t * inseg.p2 + (1.0 - t) * inseg.p1;
+ }
+ else if (p2val < minPos) {
+ float t = (min - p2val) / (p1val - p2val);
+ outseg.p2 = t * inseg.p1 + (1.0 - t) * inseg.p2;
+ }
+ return outseg;
+}
+
+segment clipToMax(float max, segment inseg, float p1val, float p2val)
+{
+ float maxPos = max + epsilon;
+ float maxNeg = max - epsilon;
+ segment outseg = segment(inseg.p1, inseg.p2, inseg.on_screen);
+
+ // trivial reject
+ if ((p1val > maxNeg && p2val > maxNeg) || inseg.on_screen == false) {
+ outseg.on_screen = false;
+ }
+
+ // cut at max
+ if (p1val > maxNeg) {
+ float t = (max - p2val) / (p1val - p2val);
+ outseg.p1 = t * inseg.p1 + (1.0 - t) * inseg.p2;
+ }
+ else if (p2val > maxNeg) {
+ float t = (max - p1val) / (p2val - p1val);
+ outseg.p2 = t * inseg.p2 + (1.0 - t) * inseg.p1;
+ }
+ return outseg;
+}
+
+segment clipSegmentBothOut(vec3 p1, vec3 p2)
+{
+ segment seg = segment(p1, p2, true);
+
+ seg = clipToMin(xmin, seg, seg.p1.x, seg.p2.x);
+ seg = clipToMax(xmax, seg, seg.p1.x, seg.p2.x);
+ seg = clipToMin(ymin, seg, seg.p1.y, seg.p2.y);
+ seg = clipToMax(ymax, seg, seg.p1.y, seg.p2.y);
+
+ return seg;
+}
+
+vec3 clipSegmentToNear(vec3 off_screen, vec3 on_screen)
+{
+ // see http://members.tripod.com/~Paul_Kirby/vector/Vplanelineint.html
+
+ vec3 a = off_screen;
+ vec3 b = on_screen;
+ vec3 c = view_pos + view_dir;
+ vec3 n = view_dir;
+ float t = dot((c - a), n) / dot((b - a), n);
+
+ vec3 clipped = a + (b - a) * t;
+ return clipped;
+}
+
+bool pointBeyondNear(vec3 p)
+{
+ vec3 offset = p - view_pos;
+ bool beyond = dot(offset, view_dir) > 0.0;
+ return beyond;
+}
+
+// 1 for contour 2 for others
+int testProfileEdge(ivec2 texcoord, vec3 world_position)
+{
+ // This should really be the inverse transpose of the modelview matrix, but
+ // that only matters if the camera has a weird anisotropic scale or skew.
+
+ mat3 nm = mat3(transpose(inverse(ModelMatrix)));
+ vec3 face_normal_0 = mat3(nm) * texelFetch(face_normal0_tex, texcoord, 0).xyz;
+ vec3 face_normal_1 = mat3(nm) * texelFetch(face_normal1_tex, texcoord, 0).xyz;
+ vec3 camera_to_line = is_perspective == 1 ? world_position - view_pos :
+ view_dir; // modelview * vec4(world_position, 1.0);
+
+ vec4 edge_mask = texelFetch(edge_mask_tex, texcoord, 0);
+
+ float dot0 = dot(camera_to_line.xyz, vec3(face_normal_0.xyz));
+ float dot1 = dot(camera_to_line.xyz, vec3(face_normal_1.xyz));
+ float dot2 = dot(normalize(vec3(face_normal_0.xyz)), normalize(vec3(face_normal_1.xyz)));
+
+ bool contour = (dot0 >= 0.0 && dot1 <= 0.0) || (dot0 <= 0.0 && dot1 >= 0.0);
+
+ is_crease = (((use_contour > 0 && !contour) || use_contour == 0) &&
+ ((dot2 < crease_threshold) || (dot2 < crease_fade_threshold))) ?
+ 1 :
+ 0;
+
+ crease_strength = (is_crease > 0 && dot2 > crease_threshold) ?
+ ((dot2 - crease_threshold) / (crease_fade_threshold - crease_threshold) /
+ 2) :
+ 0;
+ // use 0 to 0.5 to repesent the range, because 1 will represent another meaning
+
+ if (use_contour > 0 && contour)
+ return 1;
+ if (((use_crease > 0) && (is_crease > 0)) || ((use_material > 0) && (edge_mask.r > 0)) ||
+ ((use_edge_mark > 0) && (edge_mask.g > 0)) ||
+ ((use_intersection > 0) && (edge_mask.b > 0)) || false)
+ return 2;
+ return 0;
+}
+
+void main()
+{
+
+ view_dir = -mat3(ViewMatrixInverse) * vec3(0, 0, 1);
+ view_pos = (ViewMatrixInverse)[3].xyz;
+
+ xmin *= viewport.z / viewport.w;
+ xmax *= viewport.z / viewport.w;
+
+ // look up the world positions of the segment vertices
+ ivec2 texcoord = ivec2(gl_FragCoord.xy);
+
+ vec4 v0_world_pos = texelFetch(vert0_tex, texcoord, 0);
+ vec4 v1_world_pos = texelFetch(vert1_tex, texcoord, 0);
+ v0_world_pos = ModelMatrix * vec4(v0_world_pos.xyz, 1);
+ v1_world_pos = ModelMatrix * vec4(v1_world_pos.xyz, 1);
+
+ // early exit if there are no vertices here to process
+ if (v0_world_pos.w < 0.5) {
+ // no vertex data to process
+ gl_FragData[0] = vec4(0.5, 0.0, 0.0, 0.0);
+ gl_FragData[1] = vec4(0.5, 0.5, 0.0, 0.0);
+ // must write something into fragdata[2] to prevent
+ // buffer 2 from getting filled with garbage? (very weird)
+ gl_FragData[2] = vec4(0.0, 1.0, 0.0, 0.0);
+ return;
+ }
+
+ vec3 v0_clipped_near = v0_world_pos.xyz;
+ vec3 v1_clipped_near = v1_world_pos.xyz;
+
+ if (is_perspective == 1) {
+ // clip to the near plane
+ bool v0_beyond_near = pointBeyondNear(v0_world_pos.xyz);
+ bool v1_beyond_near = pointBeyondNear(v1_world_pos.xyz);
+
+ if (!v0_beyond_near && !v1_beyond_near) {
+ // segment entirely behind the camera
+ gl_FragData[0] = vec4(0.0, 1.0, 0.0, 0.0);
+ gl_FragData[1] = vec4(0.0, 0.0, 1.0, 0.0);
+ gl_FragData[2] = vec4(0.0, 1.0, 0.0, 0.0);
+ return;
+ }
+ else if (!v0_beyond_near) {
+ v0_clipped_near = clipSegmentToNear(v0_world_pos.xyz, v1_clipped_near);
+ }
+ else if (!v1_beyond_near) {
+ v1_clipped_near = clipSegmentToNear(v1_world_pos.xyz, v0_clipped_near);
+ }
+ }
+
+ // If this segment is a profile edge, test to see if it should be turned on.
+ // if (v1_world_pos.w > 0.5)
+ //{
+ int profile_on = testProfileEdge(texcoord, v0_clipped_near);
+ if (profile_on == 0) {
+ // Profile edge should be off.
+ gl_FragData[0] = vec4(0.0, 1.0, 0.5, 0.0);
+ gl_FragData[1] = vec4(0.0, 0.5, 1.0, 0.0);
+ gl_FragData[2] = vec4(0.0, 1.0, 0.0, 0.0);
+ return;
+ }
+ //}
+
+ // project
+ vec4 v0_pre_div = projection * ViewMatrix * vec4(v0_clipped_near, 1.0);
+ vec4 v1_pre_div = projection * ViewMatrix * vec4(v1_clipped_near, 1.0);
+
+ // perspective divide
+ vec3 v0_clip_pos = v0_pre_div.xyz;
+ vec3 v1_clip_pos = v1_pre_div.xyz;
+ if (is_perspective == 1) {
+ v0_clip_pos /= v0_pre_div.w;
+ v1_clip_pos /= v1_pre_div.w;
+ }
+ // clip to frustum
+ bool v0_on_screen = !pointOffScreen(v0_clip_pos);
+ bool v1_on_screen = !pointOffScreen(v1_clip_pos);
+
+ if (!v0_on_screen && !v1_on_screen) {
+ segment ret = clipSegmentBothOut(v0_clip_pos, v1_clip_pos);
+ if (ret.on_screen == false) {
+ // segment entirely off screen: BLUE / MAGENTA / BLACK
+ gl_FragData[0] = vec4(0.0, 0.0, 1.0, 0.0);
+ gl_FragData[1] = vec4(1.0, 0.0, 1.0, 0.0);
+ gl_FragData[2] = vec4(0.0, 0.0, 0.0, 0.0);
+ return;
+ }
+ v0_clip_pos = ret.p1;
+ v1_clip_pos = ret.p2;
+ }
+ else if (!v0_on_screen) {
+ v0_clip_pos = clipSegmentOneOut(v0_clip_pos, v1_clip_pos);
+ }
+ else if (!v1_on_screen) {
+ v1_clip_pos = clipSegmentOneOut(v1_clip_pos, v0_clip_pos);
+ }
+
+ // convert to window coordinates
+ vec2 v0_screen = (v0_clip_pos.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw;
+ vec2 v1_screen = (v1_clip_pos.xy + vec2(1.0, 1.0)) * 0.5 * viewport.zw;
+
+ // if(v1_screen == v0_screen){ gl_FragData[0] = vec4(1,0,0,1); return; }
+
+ float segment_screen_length = length(v0_screen - v1_screen);
+
+ // scale the length by sample_step to get the number of samples
+ // float num_samples = segment_screen_length / sample_step;
+ // num_samples = ceil(num_samples);
+
+ // Unproject and reproject the final clipped positions
+ // so that interpolation is perspective correct later on.
+ vec4 v0_world = inverse_projection * vec4(v0_clip_pos, 1.0);
+ vec4 v1_world = inverse_projection * vec4(v1_clip_pos, 1.0);
+ vec4 v0_clipped_pre_div = projection * v0_world;
+ vec4 v1_clipped_pre_div = projection * v1_world;
+
+ // Add some padding to the number of samples so that filters
+ // that work along the segment length (such as overshoot)
+ // have some room to work with at the end of each segment.
+ // vec4 path_texel = texelFetch(path_start_end_ptrs, texcoord,0);
+ // vec2 padding = segmentPadding(num_samples,
+ // coordinateToIndex(texcoord, buffer_width),
+ // unpackPathStart(path_texel),
+ // unpackPathEnd(path_texel));
+ // float total_padding = padding.x + padding.y;
+
+ // if(v0_clipped_pre_div == v1_clipped_pre_div)gl_FragData[0] =vec4(1);
+ // else gl_FragData[0] = vec4(v0_clipped_pre_div.xyz,1);
+
+ gl_FragData[0] = vec4(v0_clipped_pre_div.xyz,
+ 1); // contour has priority, modification cause trouble
+ gl_FragData[1] = vec4(v1_clipped_pre_div.xyz, is_crease > 0 ? crease_strength : 1);
+ // gl_FragData[2] = packOffsetTexel(num_samples, segment_screen_length,
+ // num_samples, segment_screen_length);
+ // num_samples + total_padding, segment_screen_length);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_passthrough_vert.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_passthrough_vert.glsl
new file mode 100644
index 00000000000..dabca7f56d3
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_dpix_project_passthrough_vert.glsl
@@ -0,0 +1,6 @@
+in vec4 pos;
+
+void main()
+{
+ gl_Position = pos;
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_snake_edge_frag.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_edge_frag.glsl
new file mode 100644
index 00000000000..045089c6675
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_edge_frag.glsl
@@ -0,0 +1,88 @@
+in vec4 uvcoordsvar;
+uniform sampler2DMS tex_sampe_0; // depth
+uniform sampler2DMS tex_sample_1; // color
+uniform sampler2DMS tex_sample_2; // normal
+uniform float normal_clamp; // normal clamp
+uniform float normal_strength; // normal strength
+uniform float depth_clamp; // depth clamp
+uniform float depth_strength; // depth strength
+uniform float z_near; // z_near
+uniform float z_far; // z_far
+
+mat3 sx = mat3(1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0);
+mat3 sy = mat3(1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0);
+vec3 rgb2hsv(vec3 c)
+{
+ vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
+ vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
+ vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
+ float d = q.x - min(q.w, q.y);
+ float e = 1.0e-10;
+ return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
+}
+float linearDepth(float depthSample)
+{
+ float d = 2.0 * depthSample - 1.0;
+ float zLinear = 2.0 * z_near * z_far / (z_far + z_near - d * (z_far - z_near));
+ return zLinear;
+}
+
+vec4 DetectEdge(sampler2DMS tex, float clamp, float strength)
+{
+ mat3 I = mat3(0);
+ mat3 J = mat3(0);
+ mat3 K = mat3(0);
+
+ ivec2 texSize = textureSize(tex);
+ ivec2 sp = ivec2(uvcoordsvar.xy * texSize);
+ vec4 cs = vec4(0);
+
+ // sample hardcoded (8) now
+ for (int s = 0; s < 8; s++) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ vec4 col = texelFetch(tex, sp + ivec2(i - 1, j - 1), s);
+ vec3 sample1 = vec3((col.r));
+ vec3 sample2 = vec3((col.g));
+ vec3 sample3 = vec3((col.b));
+ I[i][j] += length(sample1) / 8;
+ J[i][j] += length(sample2) / 8;
+ K[i][j] += length(sample3) / 8;
+ }
+ }
+ cs += texelFetch(tex_sample_1, sp, s) / 8;
+ }
+
+ float gx1 = dot(sx[0], I[0]) + dot(sx[1], I[1]) + dot(sx[2], I[2]);
+ float gy1 = dot(sy[0], I[0]) + dot(sy[1], I[1]) + dot(sy[2], I[2]);
+ float g1 = sqrt(pow(gx1, 2.0) + pow(gy1, 2.0));
+
+ float gx2 = dot(sx[0], J[0]) + dot(sx[1], J[1]) + dot(sx[2], J[2]);
+ float gy2 = dot(sy[0], J[0]) + dot(sy[1], J[1]) + dot(sy[2], J[2]);
+ float g2 = sqrt(pow(gx2, 2.0) + pow(gy2, 2.0));
+
+ float gx3 = dot(sx[0], K[0]) + dot(sx[1], K[1]) + dot(sx[2], K[2]);
+ float gy3 = dot(sy[0], K[0]) + dot(sy[1], K[1]) + dot(sy[2], K[2]);
+ float g3 = sqrt(pow(gx3, 2.0) + pow(gy3, 2.0));
+
+ float value = max(max(g1, g2), g3);
+
+ value = value > clamp ? value : 0;
+ return vec4(vec3(value * strength), 1);
+
+ // if(value<clamp) value=0;
+
+ // return vec4(pow(value,strength));
+}
+
+void main()
+{
+ float nc = normal_clamp; //(normal_clamp==0? 0.01:normal_clamp);
+ float ns = normal_strength; //(normal_strength==0? 5: normal_strength);
+ float dc = depth_clamp; //(depth_clamp==0? 0.2: depth_clamp);
+ float ds = depth_strength; //(depth_strength==0? 2.5: depth_strength);
+
+ vec4 diffuse = vec4(1, 1, 1, 1);
+ vec4 color = (DetectEdge(tex_sampe_0, dc, ds) + DetectEdge(tex_sample_2, nc, ns));
+ gl_FragColor = color;
+};
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_snake_image_peel_frag.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_image_peel_frag.glsl
new file mode 100644
index 00000000000..c2a83cab0b8
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_image_peel_frag.glsl
@@ -0,0 +1,329 @@
+
+in vec4 uvcoordsvar;
+uniform sampler2D tex_sample_0;
+uniform int stage;
+
+int decisions[256] = int[](0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0);
+
+int PickPixel(ivec2 sp)
+{
+ vec4 accum = vec4(0);
+ // for(int i=0;i<4;i++){
+ accum += texelFetch(tex_sample_0, sp, 0);
+ //}
+ return (accum.r > 0.9) ? 1 : 0;
+}
+
+// MZS Thinning method, implemented by YimingWu
+
+void main()
+{
+
+ ivec2 texSize = textureSize(tex_sample_0, 0);
+ ivec2 sp = ivec2(uvcoordsvar.xy * texSize);
+ vec4 OriginalColor = texelFetch(tex_sample_0, sp, 0);
+
+ int p2 = PickPixel(sp + ivec2(0, +1));
+ int p3 = PickPixel(sp + ivec2(+1, +1));
+ int p4 = PickPixel(sp + ivec2(+1, 0));
+ int p5 = PickPixel(sp + ivec2(+1, -1));
+ int p6 = PickPixel(sp + ivec2(0, -1));
+ int p7 = PickPixel(sp + ivec2(-1, -1));
+ int p8 = PickPixel(sp + ivec2(-1, 0));
+ int p9 = PickPixel(sp + ivec2(-1, +1));
+
+ int Bp1 = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+
+ bool bp2 = bool(p2);
+ bool bp3 = bool(p3);
+ bool bp4 = bool(p4);
+ bool bp5 = bool(p5);
+ bool bp6 = bool(p6);
+ bool bp7 = bool(p7);
+ bool bp8 = bool(p8);
+ bool bp9 = bool(p9);
+
+ int Cp1 = int(!bp2 && (bp3 || bp4)) + int(!bp4 && (bp5 || bp6)) + int(!bp6 && (bp7 || bp8)) +
+ int(!bp8 && (bp9 || bp2));
+
+ if (stage == 0) {
+ if (((sp.x + sp.y) % 2 == 0) && (Cp1 == 1) && (Bp1 >= 2 && Bp1 <= 7) && (p2 * p4 * p6 == 0) &&
+ (p4 * p6 * p8 == 0)) {
+ gl_FragColor = vec4(0, 0, 0, 1);
+ return;
+ }
+ gl_FragColor = OriginalColor;
+ }
+ else {
+ if (((sp.x + sp.y) % 2 != 0) && (Cp1 == 1) && (Bp1 >= 1 && Bp1 <= 7) && (p2 * p4 * p8 == 0) &&
+ (p2 * p6 * p8 == 0)) {
+ gl_FragColor = vec4(0, 0, 0, 1);
+ return;
+ }
+ gl_FragColor = OriginalColor;
+ }
+
+ // int test = PickPixel(sp+ivec2(-1,-1))*1 + PickPixel(sp+ivec2(0 ,-1))*2 +
+ // PickPixel(sp+ivec2(+1,-1))*4
+ // + PickPixel(sp+ivec2(-1, 0))*8 + PickPixel(sp+ivec2(+1, 0))*16
+ // + PickPixel(sp+ivec2(-1,+1))*32 + PickPixel(sp+ivec2( 0,+1))*64 +
+ // PickPixel(sp+ivec2(+1,+1))*128;
+
+ // if(decisions[test]==1) gl_FragColor=vec4(1,0,0,1);
+ // else gl_FragColor=texelFetch(tex_sample_0, sp, 0);//vec4(1,1,1,1);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_frag.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_frag.glsl
new file mode 100644
index 00000000000..f27713b4262
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_frag.glsl
@@ -0,0 +1,6 @@
+uniform vec4 line_color;
+
+void main()
+{
+ gl_FragColor = line_color;
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_geom.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_geom.glsl
new file mode 100644
index 00000000000..f795c6d30aa
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_geom.glsl
@@ -0,0 +1,114 @@
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+in vec2 gOffset[];
+
+uniform float line_width;
+uniform float taper_l_dist;
+uniform float taper_r_dist;
+uniform float taper_l_strength;
+uniform float taper_r_strength;
+
+#define M_PI 3.1415926535897932384626433832795
+
+vec4 MakeLeftTaperLinear(vec4 L, vec4 a, float offset)
+{
+ if (offset >= taper_l_dist)
+ return a;
+ a = mix(mix(a, L, taper_l_strength), a, offset / taper_l_dist);
+ return a;
+}
+
+vec4 MakeRightTaperLinear(vec4 R, vec4 c, float offset)
+{
+ if (offset >= taper_r_dist)
+ return c;
+ c = mix(mix(c, R, taper_r_strength), c, offset / taper_r_dist);
+ return c;
+}
+
+void main()
+{
+
+ float LAngle, RAngle;
+
+ vec4 LL = gl_in[0].gl_Position, L = gl_in[1].gl_Position, R = gl_in[2].gl_Position,
+ RR = gl_in[3].gl_Position;
+
+ float OffsetL = gOffset[1].x;
+ float OffsetR = gOffset[2].x;
+ float OffsetL2 = gOffset[1].y;
+ float OffsetR2 = gOffset[2].y;
+
+ if (L == R || L == LL || R == RR || LL == RR || L == RR || R == LL)
+ return;
+
+ vec4 a;
+ vec4 b;
+ vec4 c;
+ vec4 d;
+ vec4 Line = R - L;
+ vec4 Normal = normalize(vec4(-Line.y, Line.x, 0, 0));
+
+ a = L - line_width * Normal * 0.001;
+ b = L + line_width * Normal * 0.001;
+ c = R - line_width * Normal * 0.001;
+ d = R + line_width * Normal * 0.001;
+
+ float lim = line_width * 0.002;
+
+ {
+ vec4 Tangent = normalize(normalize(L - LL) + normalize(R - L));
+ vec4 Minter = normalize(vec4(-Tangent.y, Tangent.x, 0, 0));
+ float length = line_width / (dot(Minter, Normal)) * 0.001;
+ a = L - length * Minter;
+ b = L + length * Minter;
+ if (distance(a, b) > 2 * lim) {
+ a = L - lim * Minter;
+ b = L + lim * Minter;
+ }
+ }
+
+ {
+ vec4 Tangent = normalize(normalize(RR - R) + normalize(R - L));
+ vec4 Minter = normalize(vec4(-Tangent.y, Tangent.x, 0, 0));
+ float length = line_width / (dot(Minter, Normal)) * 0.001;
+ c = R - length * Minter;
+ d = R + length * Minter;
+ if (distance(c, d) > 2 * lim) {
+ c = R - lim * Minter;
+ d = R + lim * Minter;
+ }
+ }
+
+ a = MakeLeftTaperLinear(L, a, OffsetL);
+ b = MakeLeftTaperLinear(L, b, OffsetL);
+ c = MakeLeftTaperLinear(R, c, OffsetR);
+ d = MakeLeftTaperLinear(R, d, OffsetR);
+
+ a = MakeRightTaperLinear(L, a, OffsetL2);
+ b = MakeRightTaperLinear(L, b, OffsetL2);
+ c = MakeRightTaperLinear(R, c, OffsetR2);
+ d = MakeRightTaperLinear(R, d, OffsetR2);
+
+ a.w = 1;
+ b.w = 1;
+ c.w = 1;
+ d.w = 1;
+
+ gl_Position = a;
+ EmitVertex();
+ gl_Position = b;
+ EmitVertex();
+ gl_Position = c;
+ EmitVertex();
+ EndPrimitive();
+
+ gl_Position = c;
+ EmitVertex();
+ gl_Position = d;
+ EmitVertex();
+ gl_Position = b;
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_vert.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_vert.glsl
new file mode 100644
index 00000000000..8e745e20988
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_line_connection_vert.glsl
@@ -0,0 +1,10 @@
+in vec2 pos;
+in vec2 uvs;
+
+out vec2 gOffset;
+
+void main()
+{
+ gl_Position = vec4(pos, 0.0, 1.0);
+ gOffset = uvs;
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_snake_multichannel_frag.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_multichannel_frag.glsl
new file mode 100644
index 00000000000..3a9a7267b28
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_snake_multichannel_frag.glsl
@@ -0,0 +1,19 @@
+in vec3 normal;
+in vec4 finalColor;
+
+float Interpolate(float between1, float between2, float value1, float value2, float key)
+{
+ float i = (key - between1) / (between2 - between1);
+ return value1 * (1 - i) + value2 * i;
+}
+
+void main()
+{
+ float value = dot(vec3(0, 0, 1), normal);
+ // if(value<0.65) value=0.15;
+ // else if(value>=0.65 && value<0.85) value=Interpolate(0.65,0.85,0.15,0.75,value);
+ // else if(value>=0.85 && value<0.95) value=0.75;
+ // else if(value>=0.95) value=0.9;
+ gl_FragData[0] = vec4(finalColor.rgb * value, 1);
+ gl_FragData[1] = vec4(normal, 1); // vec4((normal+vec3(1))*0.5,1);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_software_chain_geom.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_software_chain_geom.glsl
new file mode 100644
index 00000000000..a538261d01c
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_software_chain_geom.glsl
@@ -0,0 +1,291 @@
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+in vec2 gOffset[];
+in int gType[];
+in int gLevel[];
+
+in vec3 gNormal[];
+uniform int normal_mode;
+uniform int normal_effect_inverse;
+uniform vec3 normal_direction; // also used as point position
+uniform float normal_ramp_begin;
+uniform float normal_ramp_end;
+uniform float normal_thickness_start;
+uniform float normal_thickness_end;
+
+uniform float thickness;
+uniform float thickness_contour;
+uniform float thickness_crease;
+uniform float thickness_material;
+uniform float thickness_edge_mark;
+uniform float thickness_intersection;
+
+uniform int use_contour;
+uniform int use_crease;
+uniform int use_material;
+uniform int use_edge_mark;
+uniform int use_intersection;
+
+uniform int occlusion_level_start;
+uniform int occlusion_level_end;
+
+// implement these later.
+// uniform float depth_width_influence;
+// uniform float depth_width_curve;
+// uniform float depth_alpha_influence;
+// uniform float depth_alpha_curve;
+// uniform float zNear;
+// uniform float zFar;
+
+uniform vec4 contour_color;
+uniform vec4 crease_color;
+uniform vec4 material_color;
+uniform vec4 edge_mark_color;
+uniform vec4 intersection_color;
+
+uniform float taper_l_dist;
+uniform float taper_r_dist;
+uniform float taper_l_strength;
+uniform float taper_r_strength;
+
+// for line width correction
+uniform vec4 output_viewport;
+uniform vec4 preview_viewport;
+
+uniform float camdx;
+uniform float camdy;
+uniform float camzoom;
+
+out vec4 out_color;
+
+float use_thickness;
+
+#define M_PI 3.1415926535897932384626433832795
+
+vec4 END_POINT = vec4(vec2(3e30f), 0, 1); // end point flag
+
+vec4 MakeLeftTaperLinear(vec4 L, vec4 a, float offset)
+{
+ if (offset >= taper_l_dist)
+ return a;
+ a = mix(mix(a, L, taper_l_strength), a, offset / taper_l_dist);
+ return a;
+}
+
+vec4 MakeRightTaperLinear(vec4 R, vec4 c, float offset)
+{
+ if (offset >= taper_r_dist)
+ return c;
+ c = mix(mix(c, R, taper_r_strength), c, offset / taper_r_dist);
+ return c;
+}
+
+void draw_line(vec4 LL, vec4 L, vec4 R, vec4 RR)
+{
+
+ float LAngle, RAngle;
+
+ float OffsetL = gOffset[1].x;
+ float OffsetR = gOffset[2].x;
+ float OffsetL2 = gOffset[1].y;
+ float OffsetR2 = gOffset[2].y;
+
+ if (L == R)
+ return;
+
+ vec4 a;
+ vec4 b;
+ vec4 c;
+ vec4 d;
+ vec4 Line = R - L;
+ vec4 Normal = normalize(vec4(-Line.y, Line.x, 0, 0));
+
+ a = L - use_thickness * Normal * 0.001;
+ b = L + use_thickness * Normal * 0.001;
+ c = R - use_thickness * Normal * 0.001;
+ d = R + use_thickness * Normal * 0.001;
+
+ float lim = use_thickness * 0.002;
+
+ float x_scale = preview_viewport.w / preview_viewport.z;
+
+ if (LL.x < 3e20) {
+ vec4 avg = normalize(L - LL) + normalize(R - L);
+ if (length(avg) > 0.001) {
+ vec4 Tangent = normalize(avg);
+ vec4 Minter = normalize(vec4(-Tangent.y, Tangent.x, 0, 0));
+ float length = use_thickness / (dot(Minter, Normal)) * 0.001;
+ if (length < 4 * lim) {
+ Minter.x *= x_scale;
+ a = L - length * Minter;
+ b = L + length * Minter;
+ }
+ }
+ }
+
+ if (RR.x < 3e20) {
+ vec4 avg = normalize(RR - R) + normalize(R - L);
+ if (length(avg) > 0.001) {
+ vec4 Tangent = normalize(avg);
+ vec4 Minter = normalize(vec4(-Tangent.y, Tangent.x, 0, 0));
+ float length = use_thickness / (dot(Minter, Normal)) * 0.001;
+ if (length < 4 * lim) {
+ Minter.x *= x_scale;
+ c = R - length * Minter;
+ d = R + length * Minter;
+ }
+ }
+ }
+
+ a = MakeLeftTaperLinear(L, a, OffsetL);
+ b = MakeLeftTaperLinear(L, b, OffsetL);
+ c = MakeLeftTaperLinear(R, c, OffsetR);
+ d = MakeLeftTaperLinear(R, d, OffsetR);
+
+ a = MakeRightTaperLinear(L, a, OffsetL2);
+ b = MakeRightTaperLinear(L, b, OffsetL2);
+ c = MakeRightTaperLinear(R, c, OffsetR2);
+ d = MakeRightTaperLinear(R, d, OffsetR2);
+
+ a.w = 1;
+ b.w = 1;
+ c.w = 1;
+ d.w = 1;
+
+ gl_Position = a;
+ EmitVertex();
+ gl_Position = b;
+ EmitVertex();
+ gl_Position = c;
+ EmitVertex();
+ EndPrimitive();
+
+ gl_Position = c;
+ EmitVertex();
+ gl_Position = d;
+ EmitVertex();
+ gl_Position = b;
+ EmitVertex();
+ EndPrimitive();
+}
+
+float factor_to_thickness(float factor)
+{
+ float r = (factor - normal_ramp_begin) / (normal_ramp_end - normal_ramp_begin);
+ if (r > 1)
+ r = 1;
+ if (r < 0)
+ r = 0;
+ float thickness = normal_effect_inverse == 1 ?
+ mix(normal_thickness_start, normal_thickness_end, r) :
+ mix(normal_thickness_end, normal_thickness_start, r);
+ return thickness;
+}
+
+void decide_line_style(int component_id)
+{
+ float th = thickness;
+ if (normal_mode == 0) {
+ th = thickness;
+ }
+ else if (normal_mode == 1) {
+ float factor = dot(gNormal[0], normal_direction);
+ th = factor_to_thickness(factor);
+ }
+ else if (normal_mode == 2) {
+ float factor = dot(gNormal[0], normal_direction);
+ th = factor_to_thickness(factor);
+ }
+
+ if (component_id == 0) {
+ out_color = contour_color;
+ use_thickness = th * thickness_contour * use_contour;
+ return;
+ }
+ if (component_id == 1) {
+ out_color = crease_color;
+ use_thickness = th * thickness_crease * use_crease;
+ return;
+ }
+ if (component_id == 2) {
+ out_color = material_color;
+ use_thickness = th * thickness_material * use_material;
+ return;
+ }
+ if (component_id == 3) {
+ out_color = edge_mark_color;
+ use_thickness = th * thickness_edge_mark * use_edge_mark;
+ return;
+ }
+ if (component_id == 4) {
+ out_color = intersection_color;
+ use_thickness = th * thickness_intersection * use_intersection;
+ return;
+ }
+}
+
+vec4 correct_camera_scale(vec4 p)
+{
+
+ p.x -= camdx * 4;
+ p.y -= camdy * 4;
+ p.xy *= camzoom;
+ return p;
+}
+
+void main()
+{
+ int level = gLevel[1];
+
+ if (occlusion_level_start > level || occlusion_level_end < level)
+ return;
+
+ float asp1 = output_viewport.z / output_viewport.w;
+ float asp2 = preview_viewport.z / preview_viewport.w;
+ float x_scale;
+ float y_scale;
+ if (asp1 > 1) {
+ if (asp2 < 1) {
+ x_scale = 1 / asp2;
+ y_scale = 1 / asp1;
+ }
+ else {
+ x_scale = 1;
+ y_scale = asp2 / asp1;
+ }
+ }
+ else {
+ if (asp2 < 1) {
+ x_scale = asp1 / asp2;
+ y_scale = 1;
+ }
+ else {
+ x_scale = asp1;
+ y_scale = asp2;
+ }
+ }
+
+ vec4 LL = vec4(gl_in[0].gl_Position.xy, 0, 1), L = vec4(gl_in[1].gl_Position.xy, 0, 1),
+ R = vec4(gl_in[2].gl_Position.xy, 0, 1), RR = vec4(gl_in[3].gl_Position.xy, 0, 1);
+
+ LL.x *= x_scale;
+ LL.y *= y_scale;
+ L.x *= x_scale;
+ L.y *= y_scale;
+ R.x *= x_scale;
+ R.y *= y_scale;
+ RR.x *= x_scale;
+ RR.y *= y_scale;
+
+ LL = correct_camera_scale(LL);
+ L = correct_camera_scale(L);
+ R = correct_camera_scale(R);
+ RR = correct_camera_scale(RR);
+
+ int type = gType[1];
+
+ decide_line_style(type);
+
+ draw_line(LL, L, R, RR);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_software_line_chain_geom.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_software_line_chain_geom.glsl
new file mode 100644
index 00000000000..88268b2aea7
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_software_line_chain_geom.glsl
@@ -0,0 +1,185 @@
+layout(lines) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+in vec3 gNormal[];
+uniform int normal_mode;
+uniform int normal_effect_inverse;
+uniform vec3 normal_direction; // also used as point position
+uniform float normal_ramp_begin;
+uniform float normal_ramp_end;
+uniform float normal_thickness_start;
+uniform float normal_thickness_end;
+
+uniform float thickness;
+uniform float thickness_contour;
+uniform float thickness_crease;
+uniform float thickness_material;
+uniform float thickness_edge_mark;
+uniform float thickness_intersection;
+
+// implement these later.
+// uniform float depth_width_influence;
+// uniform float depth_width_curve;
+// uniform float depth_alpha_influence;
+// uniform float depth_alpha_curve;
+// uniform float zNear;
+// uniform float zFar;
+
+uniform vec4 contour_color;
+uniform vec4 crease_color;
+uniform vec4 material_color;
+uniform vec4 edge_mark_color;
+uniform vec4 intersection_color;
+
+// for line width correction
+uniform vec4 output_viewport;
+uniform vec4 preview_viewport;
+
+uniform float camdx;
+uniform float camdy;
+uniform float camzoom;
+
+out vec4 out_color;
+
+float use_thickness;
+
+void draw_line(vec4 p1, vec4 p2)
+{
+
+ vec4 Line = p2 - p1;
+ vec4 Normal = normalize(vec4(-Line.y, Line.x, 0, 0));
+
+ vec4 a, b, c, d;
+
+ float x_scale = preview_viewport.w / preview_viewport.z;
+ Normal.x *= x_scale;
+ vec4 offset = Normal * use_thickness * 0.001;
+
+ a = p1 + offset;
+ b = p1 - offset;
+ c = p2 + offset;
+ d = p2 - offset;
+
+ gl_Position = vec4(a.xy, 0, 1);
+ EmitVertex();
+ gl_Position = vec4(b.xy, 0, 1);
+ EmitVertex();
+ gl_Position = vec4(c.xy, 0, 1);
+ EmitVertex();
+
+ gl_Position = vec4(b.xy, 0, 1);
+ EmitVertex();
+ gl_Position = vec4(c.xy, 0, 1);
+ EmitVertex();
+ gl_Position = vec4(d.xy, 0, 1);
+ EmitVertex();
+
+ EndPrimitive();
+}
+
+float factor_to_thickness(float factor)
+{
+ float r = (factor - normal_ramp_begin) / (normal_ramp_end - normal_ramp_begin);
+ if (r > 1)
+ r = 1;
+ if (r < 0)
+ r = 0;
+ float thickness = normal_effect_inverse == 1 ?
+ mix(normal_thickness_start, normal_thickness_end, r) :
+ mix(normal_thickness_end, normal_thickness_start, r);
+ return thickness;
+}
+
+void decide_color_and_thickness(float component_id)
+{
+ float th = thickness;
+ if (normal_mode == 0) {
+ th = thickness;
+ }
+ else if (normal_mode == 1) {
+ float factor = dot(gNormal[0], normal_direction);
+ th = factor_to_thickness(factor);
+ }
+ else if (normal_mode == 2) {
+ float factor = dot(gNormal[0], normal_direction);
+ th = factor_to_thickness(factor);
+ }
+
+ if (component_id < 1.5) {
+ out_color = contour_color;
+ use_thickness = th * thickness_contour;
+ return;
+ }
+ if (component_id < 2.5) {
+ out_color = crease_color;
+ use_thickness = th * thickness_crease;
+ return;
+ }
+ if (component_id < 3.5) {
+ out_color = material_color;
+ use_thickness = th * thickness_material;
+ return;
+ }
+ if (component_id < 4.5) {
+ out_color = edge_mark_color;
+ use_thickness = th * thickness_edge_mark;
+ return;
+ }
+ if (component_id < 5.5) {
+ out_color = intersection_color;
+ use_thickness = th * thickness_intersection;
+ return;
+ }
+}
+
+vec4 correct_camera_scale(vec4 p)
+{
+ p.x -= camdx * 4;
+ p.y -= camdy * 4;
+ p.xy *= camzoom;
+ return p;
+}
+
+void main()
+{
+
+ float asp1 = output_viewport.z / output_viewport.w;
+ float asp2 = preview_viewport.z / preview_viewport.w;
+ float x_scale;
+ float y_scale;
+ if (asp1 > 1) {
+ if (asp2 < 1) {
+ x_scale = 1 / asp2;
+ y_scale = 1 / asp1;
+ }
+ else {
+ x_scale = 1;
+ y_scale = asp2 / asp1;
+ }
+ }
+ else {
+ if (asp2 < 1) {
+ x_scale = asp1 / asp2;
+ y_scale = 1;
+ }
+ else {
+ x_scale = asp1;
+ y_scale = asp2;
+ }
+ }
+
+ vec4 p1 = vec4(gl_in[0].gl_Position.xy, 0, 1);
+ vec4 p2 = vec4(gl_in[1].gl_Position.xy, 0, 1);
+
+ p1.x *= x_scale;
+ p2.x *= x_scale;
+ p1.y *= y_scale;
+ p2.y *= y_scale;
+
+ p1 = correct_camera_scale(p1);
+ p2 = correct_camera_scale(p2);
+
+ decide_color_and_thickness(gl_in[0].gl_Position.z);
+
+ draw_line(p1, p2);
+}
diff --git a/source/blender/draw/engines/lanpr/shaders/lanpr_software_passthrough_vert.glsl b/source/blender/draw/engines/lanpr/shaders/lanpr_software_passthrough_vert.glsl
new file mode 100644
index 00000000000..e802bcbc582
--- /dev/null
+++ b/source/blender/draw/engines/lanpr/shaders/lanpr_software_passthrough_vert.glsl
@@ -0,0 +1,21 @@
+in vec4 pos;
+in vec2 uvs;
+in vec3 normal;
+in int type;
+in int level;
+
+out vec2 gOffset;
+out int gType;
+out int gLevel;
+out vec3 gNormal;
+
+void main()
+{
+ vec4 p = pos;
+
+ gOffset = uvs;
+ gType = type;
+ gLevel = level;
+ gNormal = normal;
+ gl_Position = vec4(vec3(p), 1);
+}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 10ab7c13631..a289152807c 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -225,6 +225,17 @@ void DRW_texture_ensure_fullscreen_2d(struct GPUTexture **tex,
void DRW_texture_ensure_2d(
struct GPUTexture **tex, int w, int h, eGPUTextureFormat format, DRWTextureFlag flags);
+void DRW_texture_ensure_fullscreen_2D_multisample(struct GPUTexture **tex,
+ eGPUTextureFormat format,
+ int samples,
+ DRWTextureFlag flags);
+void DRW_texture_ensure_2D_multisample(struct GPUTexture **tex,
+ int w,
+ int h,
+ eGPUTextureFormat format,
+ int samples,
+ DRWTextureFlag flags);
+
void DRW_texture_generate_mipmaps(struct GPUTexture *tex);
void DRW_texture_free(struct GPUTexture *tex);
#define DRW_TEXTURE_FREE_SAFE(tex) \
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 096e1c2aeca..2f4a08d4525 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -97,8 +97,8 @@ void DRW_globals_update(void)
interp_v4_v4v4(gb->colorDupli, gb->colorBackground, gb->colorWire, 0.3f);
#ifdef WITH_FREESTYLE
- UI_GetThemeColor4fv(TH_FREESTYLE_EDGE_MARK, gb->colorEdgeFreestyle);
- UI_GetThemeColor4fv(TH_FREESTYLE_FACE_MARK, gb->colorFaceFreestyle);
+ UI_GetThemeColor4fv(TH_LANPR_EDGE_MARK, gb->colorEdgeFreestyle);
+ UI_GetThemeColor4fv(TH_LANPR_FACE_MARK, gb->colorFaceFreestyle);
#else
zero_v4(gb->colorEdgeFreestyle);
zero_v4(gb->colorFaceFreestyle);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 6719bd7943f..73981e62ada 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -90,6 +90,7 @@
#include "engines/basic/basic_engine.h"
#include "engines/workbench/workbench_engine.h"
#include "engines/external/external_engine.h"
+#include "engines/lanpr/lanpr_all.h"
#include "engines/gpencil/gpencil_engine.h"
#include "engines/select/select_engine.h"
@@ -2848,7 +2849,9 @@ void DRW_engine_register(DrawEngineType *draw_engine_type)
void DRW_engines_register(void)
{
RE_engines_register(&DRW_engine_viewport_eevee_type);
- RE_engines_register(&DRW_engine_viewport_workbench_type);
+ // RE_engines_register(&DRW_engine_viewport_workbench_type); //registered as two DRW_engines
+ // below.
+ RE_engines_register(&DRW_engine_viewport_lanpr_type);
DRW_engine_register(&draw_engine_workbench_solid);
DRW_engine_register(&draw_engine_workbench_transparent);
diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c
index 373810b2f7f..587007a83f4 100644
--- a/source/blender/draw/intern/draw_manager_texture.c
+++ b/source/blender/draw/intern/draw_manager_texture.c
@@ -103,6 +103,19 @@ GPUTexture *DRW_texture_create_2d_array(
return tex;
}
+GPUTexture *DRW_texture_create_2d_multisample(int w,
+ int h,
+ eGPUTextureFormat format,
+ int samples,
+ DRWTextureFlag flags,
+ const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_2d_multisample(w, h, format, fpixels, samples, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
GPUTexture *DRW_texture_create_3d(
int w, int h, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
{
@@ -152,6 +165,26 @@ void DRW_texture_ensure_2d(
}
}
+void DRW_texture_ensure_fullscreen_2D_multisample(GPUTexture **tex,
+ eGPUTextureFormat format,
+ int samples,
+ DRWTextureFlag flags)
+{
+ if (*(tex) == NULL) {
+ const float *size = DRW_viewport_size_get();
+ *(tex) = DRW_texture_create_2d_multisample(
+ (int)size[0], (int)size[1], format, samples, flags, NULL);
+ }
+}
+
+void DRW_texture_ensure_2D_multisample(
+ GPUTexture **tex, int w, int h, eGPUTextureFormat format, int samples, DRWTextureFlag flags)
+{
+ if (*(tex) == NULL) {
+ *(tex) = DRW_texture_create_2d_multisample(w, h, format, samples, flags, NULL);
+ }
+}
+
void DRW_texture_generate_mipmaps(GPUTexture *tex)
{
GPU_texture_bind(tex, 0);
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 7910cf47a33..f7d10278cfb 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -27,6 +27,7 @@ if(WITH_BLENDER)
add_subdirectory(interface)
add_subdirectory(io)
add_subdirectory(lattice)
+ add_subdirectory(lanpr)
add_subdirectory(gizmo_library)
add_subdirectory(mask)
add_subdirectory(mesh)
diff --git a/source/blender/editors/include/ED_lanpr.h b/source/blender/editors/include/ED_lanpr.h
new file mode 100644
index 00000000000..857b22fe07d
--- /dev/null
+++ b/source/blender/editors/include/ED_lanpr.h
@@ -0,0 +1,622 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#ifndef __ED_LANPR_H__
+#define __ED_LANPR_H__
+
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "DNA_lanpr_types.h"
+
+#include <math.h>
+#include <string.h>
+
+typedef double real;
+
+typedef real tnsVector2d[2];
+typedef real tnsVector3d[3];
+typedef real tnsVector4d[4];
+typedef float tnsVector3f[3];
+typedef float tnsVector4f[4];
+typedef int tnsVector2i[2];
+
+typedef struct LANPR_StaticMemPoolNode {
+ Link item;
+ int used_byte;
+ /* User memory starts here */
+} LANPR_StaticMemPoolNode;
+
+typedef struct LANPR_StaticMemPool {
+ int each_size;
+ ListBase pools;
+ SpinLock lock_mem;
+} LANPR_StaticMemPool;
+
+typedef struct LANPR_TextureSample {
+ struct LANPR_TextureSample *next, *prev;
+ int X, Y;
+ /** For future usage */
+ float Z;
+} LANPR_TextureSample;
+
+typedef struct LANPR_LineStripPoint {
+ struct LANPR_LineStripPoint *next, *prev;
+ float P[3];
+} LANPR_LineStripPoint;
+
+typedef struct LANPR_LineStrip {
+ struct LANPR_LineStrip *next, *prev;
+ ListBase points;
+ int point_count;
+ float total_length;
+} LANPR_LineStrip;
+
+typedef struct LANPR_RenderTriangle {
+ struct LANPR_RenderTriangle *next, *prev;
+ struct LANPR_RenderVert *v[3];
+ struct LANPR_RenderLine *rl[3];
+ real gn[3];
+ real gc[3];
+ /* struct BMFace *F; */
+ short material_id;
+ ListBase intersecting_verts;
+ char cull_status;
+ /** Should be testing** , Use testing[NumOfThreads] to access. */
+ struct LANPR_RenderTriangle *testing;
+} LANPR_RenderTriangle;
+
+typedef struct LANPR_RenderTriangleThread {
+ struct LANPR_RenderTriangle base;
+ struct LANPR_RenderLine *testing[127];
+} LANPR_RenderTriangleThread;
+
+typedef struct LANPR_RenderElementLinkNode {
+ struct LANPR_RenderElementLinkNode *next, *prev;
+ void *pointer;
+ int element_count;
+ void *object_ref;
+ char additional;
+} LANPR_RenderElementLinkNode;
+
+typedef struct LANPR_RenderLineSegment {
+ struct LANPR_RenderLineSegment *next, *prev;
+ /** at==0: left at==1: right (this is in 2D projected space) */
+ real at;
+ /** This is used to reconstruct 3d stroke (TODO: implement global space?) */
+ real at_global;
+ /** Occlusion level after "at" point */
+ unsigned char occlusion;
+ /** For determining lines beind a glass window material. (TODO: implement this) */
+ short material_mask_mark;
+} LANPR_RenderLineSegment;
+
+typedef struct LANPR_RenderVert {
+ struct LANPR_RenderVert *next, *prev;
+ real gloc[4];
+ real fbcoord[4];
+ int fbcoordi[2];
+ /** Used as "r" when intersecting */
+ struct BMVert *v;
+ struct LANPR_RenderLine *intersecting_line;
+ struct LANPR_RenderLine *intersecting_line2;
+ struct LANPR_RenderTriangle *intersecting_with;
+
+ /** positive 1 Negative 0
+ * <| |>
+ * l---->|----->r l---->|----->r
+ * <| |>
+ * this means dot(r-l,face_normal)<0 then 1 otherwise 0
+ */
+ char positive;
+ char edge_used;
+} LANPR_RenderVert;
+
+typedef enum LANPR_EdgeFlag {
+ LANPR_EDGE_FLAG_EDGE_MARK = (1 << 0),
+ LANPR_EDGE_FLAG_CONTOUR = (1 << 1),
+ LANPR_EDGE_FLAG_CREASE = (1 << 2),
+ LANPR_EDGE_FLAG_MATERIAL = (1 << 3),
+ LANPR_EDGE_FLAG_INTERSECTION = (1 << 4),
+ /** floating edge, unimplemented yet */
+ LANPR_EDGE_FLAG_FLOATING = (1 << 5),
+ LANPR_EDGE_FLAG_CHAIN_PICKED = (1 << 6),
+} LANPR_EdgeFlag;
+
+#define LANPR_EDGE_FLAG_ALL_TYPE 0x3f
+
+typedef struct LANPR_RenderLine {
+ struct LANPR_RenderLine *next, *prev;
+ struct LANPR_RenderVert *l, *r;
+ struct LANPR_RenderTriangle *tl, *tr;
+ ListBase segments;
+ char min_occ;
+
+ /** Also for line type determination on chainning */
+ char flags;
+
+ /** Still need this entry because culled lines will not add to object reln node */
+ struct Object *object_ref;
+
+ /** For gpencil stroke modifier */
+ int edge_idx;
+} LANPR_RenderLine;
+
+typedef struct LANPR_RenderLineChain {
+ struct LANPR_RenderLineChain *next, *prev;
+ ListBase chain;
+
+ /** Calculated before draw cmd. */
+ float length;
+
+ /** Used when re-connecting and gp stroke generation */
+ char picked;
+ char level;
+
+ /** Chain now only contains one type of segments */
+ int type;
+ struct Object *object_ref;
+} LANPR_RenderLineChain;
+
+typedef struct LANPR_RenderLineChainItem {
+ struct LANPR_RenderLineChainItem *next, *prev;
+ /** Need z value for fading */
+ float pos[3];
+ /** For restoring position to 3d space */
+ float gpos[3];
+ float normal[3];
+ char line_type;
+ char occlusion;
+} LANPR_RenderLineChainItem;
+
+typedef struct LANPR_ChainRegisterEntry {
+ struct LANPR_ChainRegisterEntry *next, *prev;
+ LANPR_RenderLineChain *rlc;
+ LANPR_RenderLineChainItem *rlci;
+ char picked;
+
+ /** left/right mark.
+ * Because we revert list in chaining so we need the flag. */
+ char is_left;
+} LANPR_ChainRegisterEntry;
+
+typedef struct LANPR_RenderBuffer {
+ struct LANPR_RenderBuffer *prev, *next;
+
+ /** For render. */
+ int is_copied;
+
+ int w, h;
+ int tile_size_w, tile_size_h;
+ int tile_count_x, tile_count_y;
+ real width_per_tile, height_per_tile;
+ double view_projection[4][4];
+
+ int output_mode;
+ int output_aa_level;
+
+ struct LANPR_BoundingArea *initial_bounding_areas;
+ unsigned int bounding_area_count;
+
+ ListBase vertex_buffer_pointers;
+ ListBase line_buffer_pointers;
+ ListBase triangle_buffer_pointers;
+ ListBase all_render_lines;
+
+ ListBase intersecting_vertex_buffer;
+
+ struct GPUBatch *DPIXIntersectionTransformBatch;
+ struct GPUBatch *DPIXIntersectionBatch;
+
+ /** Use the one comes with LANPR. */
+ LANPR_StaticMemPool render_data_pool;
+
+ struct Material *material_pointers[2048];
+
+ /* Render status */
+
+ int cached_for_frame;
+
+ real view_vector[3];
+
+ int triangle_size;
+
+ unsigned int contour_count;
+ unsigned int contour_processed;
+ LinkData *contour_managed;
+ ListBase contours;
+
+ unsigned int intersection_count;
+ unsigned int intersection_processed;
+ LinkData *intersection_managed;
+ ListBase intersection_lines;
+
+ unsigned int crease_count;
+ unsigned int crease_processed;
+ LinkData *crease_managed;
+ ListBase crease_lines;
+
+ unsigned int material_line_count;
+ unsigned int material_processed;
+ LinkData *material_managed;
+ ListBase material_lines;
+
+ unsigned int edge_mark_count;
+ unsigned int edge_mark_processed;
+ LinkData *edge_mark_managed;
+ ListBase edge_marks;
+
+ ListBase chains;
+ struct GPUBatch *chain_draw_batch;
+
+ struct DRWShadingGroup *ChainShgrp;
+
+ /** For managing calculation tasks for multiple threads. */
+ SpinLock lock_task;
+
+ /* settings */
+
+ int max_occlusion_level;
+ real crease_angle;
+ real crease_cos;
+ int thread_count;
+
+ int draw_material_preview;
+ real material_transparency;
+
+ int show_line;
+ int show_fast;
+ int show_material;
+ int override_display;
+
+ struct Scene *scene;
+ struct Object *camera;
+
+ int use_intersections;
+ int _pad;
+
+} LANPR_RenderBuffer;
+
+typedef enum LANPR_RenderStatus {
+ LANPR_RENDER_IDLE = 0,
+ LANPR_RENDER_RUNNING = 1,
+ LANPR_RENDER_INCOMPELTE = 2,
+ LANPR_RENDER_FINISHED = 3,
+} LANPR_RenderStatus;
+
+typedef struct LANPR_SharedResource {
+
+ /* We only allocate once for all */
+ LANPR_RenderBuffer *render_buffer_shared;
+
+ /* cache */
+ struct BLI_mempool *mp_sample;
+ struct BLI_mempool *mp_line_strip;
+ struct BLI_mempool *mp_line_strip_point;
+ struct BLI_mempool *mp_batch_list;
+
+ /* Image filtering */
+ struct GPUShader *multichannel_shader;
+ struct GPUShader *edge_detect_shader;
+ struct GPUShader *edge_thinning_shader;
+ struct GPUShader *snake_connection_shader;
+
+ /* GPU */
+ struct GPUShader *dpix_transform_shader;
+ struct GPUShader *dpix_preview_shader;
+ int dpix_shader_error;
+ int texture_size;
+ ListBase dpix_batch_list;
+ int dpix_reloaded;
+ int dpix_reloaded_deg;
+
+ /* CPU */
+ struct GPUShader *software_shader;
+ struct GPUShader *software_chaining_shader;
+
+ void *ved_viewport;
+ void *ved_render;
+
+ int init_complete;
+
+ /** To bypass or cancel rendering. */
+ SpinLock lock_render_status;
+ LANPR_RenderStatus flag_render_status;
+
+ /** Set before rendering and cleared upon finish! */
+ struct RenderEngine *re_render;
+} LANPR_SharedResource;
+
+#define DBL_TRIANGLE_LIM 1e-8
+#define DBL_EDGE_LIM 1e-9
+
+#define LANPR_MEMORY_POOL_1MB 1048576
+#define LANPR_MEMORY_POOL_128MB 134217728
+#define LANPR_MEMORY_POOL_256MB 268435456
+#define LANPR_MEMORY_POOL_512MB 536870912
+
+typedef enum LANPR_CullState {
+ LANPR_CULL_DONT_CARE = 0,
+ LANPR_CULL_USED = 1,
+ LANPR_CULL_DISCARD = 2,
+} LANPR_CullState;
+
+#define TNS_THREAD_LINE_COUNT 10000
+
+typedef struct LANPR_RenderTaskInfo {
+ int thread_id;
+
+ LinkData *contour;
+ ListBase contour_pointers;
+
+ LinkData *intersection;
+ ListBase intersection_pointers;
+
+ LinkData *crease;
+ ListBase crease_pointers;
+
+ LinkData *material;
+ ListBase material_pointers;
+
+ LinkData *edge_mark;
+ ListBase edge_mark_pointers;
+
+} LANPR_RenderTaskInfo;
+
+typedef struct LANPR_BoundingArea {
+ real l, r, u, b;
+ real cx, cy;
+
+ /** 1,2,3,4 quadrant */
+ struct LANPR_BoundingArea *child;
+
+ ListBase lp;
+ ListBase rp;
+ ListBase up;
+ ListBase bp;
+
+ int triangle_count;
+ ListBase linked_triangles;
+ ListBase linked_lines;
+
+ /** Reserved for image space reduction && multithread chainning */
+ ListBase linked_chains;
+} LANPR_BoundingArea;
+
+#define TNS_COMMAND_LINE 0
+#define TNS_COMMAND_MATERIAL 1
+#define TNS_COMMAND_EDGE 2
+
+#define TNS_TRANSPARENCY_DRAW_SIMPLE 0
+#define TNS_TRANSPARENCY_DRAW_LAYERED 1
+
+#define TNS_OVERRIDE_ONLY 0
+#define TNS_OVERRIDE_EXCLUDE 1
+/* #define TNS_OVERRIDE_ALL_OTHERS_OUTSIDE_GROUP 2 */
+/* #define TNS_OVERRIDE_ALL_OTHERS_IN_GROUP 3 */
+/* #define TNS_OVERRIDE_ALL_OTHERS 4 */
+
+#define TNS_TILE(tile, r, c, CCount) tile[r * CCount + c]
+
+#define TNS_CLAMP(a, Min, Max) a = a < Min ? Min : (a > Max ? Max : a)
+
+#define TNS_MAX3_INDEX(a, b, c) (a > b ? (a > c ? 0 : (b > c ? 1 : 2)) : (b > c ? 1 : 2))
+
+#define TNS_MIN3_INDEX(a, b, c) (a < b ? (a < c ? 0 : (b < c ? 1 : 2)) : (b < c ? 1 : 2))
+
+#define TNS_MAX3_INDEX_ABC(x, y, z) (x > y ? (x > z ? a : (y > z ? b : c)) : (y > z ? b : c))
+
+#define TNS_MIN3_INDEX_ABC(x, y, z) (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
+
+#define TNS_ABC(index) (index == 0 ? a : (index == 1 ? b : c))
+
+#define TNS_DOUBLE_CLOSE_ENOUGH(a, b) (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
+
+/* #define TNS_DOUBLE_CLOSE_ENOUGH(a,b)\ */
+/* //(((a)+0.00000000001)>=(b) && ((a)-0.0000000001)<=(b)) */
+
+#define TNS_FLOAT_CLOSE_ENOUGH_WIDER(a, b) (((a) + 0.0000001) >= (b) && ((a)-0.0000001) <= (b))
+
+#define TNS_IN_TILE_X(RenderTile, Fx) (RenderTile->FX <= Fx && RenderTile->FXLim >= Fx)
+
+#define TNS_IN_TILE_Y(RenderTile, Fy) (RenderTile->FY <= Fy && RenderTile->FYLim >= Fy)
+
+#define TNS_IN_TILE(RenderTile, Fx, Fy) \
+ (TNS_IN_TILE_X(RenderTile, Fx) && TNS_IN_TILE_Y(RenderTile, Fy))
+
+BLI_INLINE int lanpr_TrangleLineBoundBoxTest(LANPR_RenderTriangle *rt, LANPR_RenderLine *rl)
+{
+ if (MAX3(rt->v[0]->fbcoord[2], rt->v[1]->fbcoord[2], rt->v[2]->fbcoord[2]) >
+ MIN2(rl->l->fbcoord[2], rl->r->fbcoord[2]))
+ return 0;
+ if (MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]) <
+ MIN2(rl->l->fbcoord[0], rl->r->fbcoord[0]))
+ return 0;
+ if (MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]) >
+ MAX2(rl->l->fbcoord[0], rl->r->fbcoord[0]))
+ return 0;
+ if (MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]) <
+ MIN2(rl->l->fbcoord[1], rl->r->fbcoord[1]))
+ return 0;
+ if (MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]) >
+ MAX2(rl->l->fbcoord[1], rl->r->fbcoord[1]))
+ return 0;
+ return 1;
+}
+
+BLI_INLINE double tMatGetLinearRatio(real l, real r, real FromL);
+BLI_INLINE int lanpr_LineIntersectTest2d(
+ const double *a1, const double *a2, const double *b1, const double *b2, double *aRatio)
+{
+ double k1, k2;
+ double x;
+ double y;
+ double Ratio;
+ double xDiff = (a2[0] - a1[0]); /* +DBL_EPSILON; */
+ double xDiff2 = (b2[0] - b1[0]);
+
+ if (xDiff == 0) {
+ if (xDiff2 == 0) {
+ *aRatio = 0;
+ return 0;
+ }
+ double r2 = tMatGetLinearRatio(b1[0], b2[0], a1[0]);
+ x = interpd(b2[0], b1[0], r2);
+ y = interpd(b2[1], b1[1], r2);
+ *aRatio = Ratio = tMatGetLinearRatio(a1[1], a2[1], y);
+ }
+ else {
+ if (xDiff2 == 0) {
+ Ratio = tMatGetLinearRatio(a1[0], a2[0], b1[0]);
+ x = interpd(a2[0], a1[0], Ratio);
+ *aRatio = Ratio;
+ }
+ else {
+ k1 = (a2[1] - a1[1]) / xDiff;
+ k2 = (b2[1] - b1[1]) / xDiff2;
+
+ if ((k1 == k2))
+ return 0;
+
+ x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
+
+ Ratio = (x - a1[0]) / xDiff;
+
+ *aRatio = Ratio;
+ }
+ }
+
+ if (b1[0] == b2[0]) {
+ y = interpd(a2[1], a1[1], Ratio);
+ if (y > MAX2(b1[1], b2[1]) || y < MIN2(b1[1], b2[1]))
+ return 0;
+ }
+ else if (Ratio <= 0 || Ratio > 1 || (b1[0] > b2[0] && x > b1[0]) ||
+ (b1[0] < b2[0] && x < b1[0]) || (b2[0] > b1[0] && x > b2[0]) ||
+ (b2[0] < b1[0] && x < b2[0]))
+ return 0;
+
+ return 1;
+}
+BLI_INLINE double lanpr_GetLineZ(tnsVector3d l, tnsVector3d r, real Ratio)
+{
+ double z = interpd(r[2], l[2], Ratio);
+ return z;
+}
+BLI_INLINE double lanpr_GetLineZPoint(tnsVector3d l, tnsVector3d r, tnsVector3d FromL)
+{
+ double ra = (FromL[0] - l[0]) / (r[0] - l[0]);
+ return interpd(r[2], l[2], ra);
+}
+BLI_INLINE double lanpr_GetLinearRatio(tnsVector3d l, tnsVector3d r, tnsVector3d FromL)
+{
+ double ra = (FromL[0] - l[0]) / (r[0] - l[0]);
+ return ra;
+}
+
+BLI_INLINE double tMatGetLinearRatio(real l, real r, real FromL)
+{
+ double ra = (FromL - l) / (r - l);
+ return ra;
+}
+
+int ED_lanpr_point_inside_triangled(tnsVector2d v, tnsVector2d v0, tnsVector2d v1, tnsVector2d v2);
+
+struct Depsgraph;
+struct SceneLANPR;
+
+int ED_lanpr_object_collection_usage_check(struct Collection *c, struct Object *o);
+
+void ED_lanpr_NO_THREAD_chain_feature_lines(LANPR_RenderBuffer *rb);
+void ED_lanpr_split_chains_for_fixed_occlusion(LANPR_RenderBuffer *rb);
+void ED_lanpr_connect_chains(LANPR_RenderBuffer *rb, int do_geometry_space);
+void ED_lanpr_discard_short_chains(LANPR_RenderBuffer *rb, float threshold);
+int ED_lanpr_count_chain(LANPR_RenderLineChain *rlc);
+void ED_lanpr_chain_clear_picked_flag(struct LANPR_RenderBuffer *rb);
+
+int ED_lanpr_count_leveled_edge_segment_count(ListBase *LineList, struct LANPR_LineLayer *ll);
+void *ED_lanpr_make_leveled_edge_vertex_array(struct LANPR_RenderBuffer *rb,
+ ListBase *LineList,
+ float *vertexArray,
+ float *NormalArray,
+ float **NextNormal,
+ LANPR_LineLayer *ll,
+ float componet_id);
+
+void ED_lanpr_calculation_set_flag(LANPR_RenderStatus flag);
+bool ED_lanpr_calculation_flag_check(LANPR_RenderStatus flag);
+
+int ED_lanpr_compute_feature_lines_internal(struct Depsgraph *depsgraph, int instersections_only);
+
+void ED_lanpr_compute_feature_lines_background(struct Depsgraph *dg, int intersection_only);
+
+LANPR_RenderBuffer *ED_lanpr_create_render_buffer(void);
+void ED_lanpr_destroy_render_data(struct LANPR_RenderBuffer *rb);
+
+void ED_lanpr_calculation_set_flag(LANPR_RenderStatus flag);
+bool ED_lanpr_calculation_flag_check(LANPR_RenderStatus flag);
+
+bool ED_lanpr_dpix_shader_error(void);
+
+int ED_lanpr_max_occlusion_in_line_layers(struct SceneLANPR *lanpr);
+LANPR_LineLayer *ED_lanpr_new_line_layer(struct SceneLANPR *lanpr);
+LANPR_LineLayerComponent *ED_lanpr_new_line_component(struct SceneLANPR *lanpr);
+
+LANPR_BoundingArea *ED_lanpr_get_point_bounding_area(LANPR_RenderBuffer *rb, real x, real y);
+LANPR_BoundingArea *ED_lanpr_get_point_bounding_area_deep(LANPR_RenderBuffer *rb, real x, real y);
+
+void ED_lanpr_post_frame_update_external(struct Scene *s, struct Depsgraph *dg);
+
+struct SceneLANPR;
+
+void ED_lanpr_rebuild_all_command(struct SceneLANPR *lanpr);
+
+void ED_lanpr_update_render_progress(const char *text);
+
+void ED_lanpr_calculate_normal_object_vector(LANPR_LineLayer *ll, float *normal_object_direction);
+
+float ED_lanpr_compute_chain_length(LANPR_RenderLineChain *rlc);
+
+struct wmOperatorType;
+
+/* Operator types */
+void SCENE_OT_lanpr_calculate_feature_lines(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_add_line_layer(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_delete_line_layer(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_rebuild_all_commands(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_auto_create_line_layer(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_move_line_layer(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_add_line_component(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_delete_line_component(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_enable_all_line_types(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_update_gp_strokes(struct wmOperatorType *ot);
+void SCENE_OT_lanpr_bake_gp_strokes(struct wmOperatorType *ot);
+
+void OBJECT_OT_lanpr_update_gp_target(struct wmOperatorType *ot);
+void OBJECT_OT_lanpr_update_gp_source(struct wmOperatorType *ot);
+
+void ED_operatortypes_lanpr(void);
+
+#endif /* __ED_LANPR_H__ */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 29022adac6c..a73e2655b7d 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -250,8 +250,8 @@ typedef enum ThemeColorID {
TH_UV_SHADOW,
TH_UV_OTHERS,
- TH_FREESTYLE_EDGE_MARK,
- TH_FREESTYLE_FACE_MARK,
+ TH_LANPR_EDGE_MARK,
+ TH_LANPR_FACE_MARK,
TH_MATCH, /* highlight color for search matches */
TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 7c5d5401d08..93a93fb6918 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -537,10 +537,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_HANDLE_SEL_ALIGN:
cp = ts->handle_sel_align;
break;
- case TH_FREESTYLE_EDGE_MARK:
+ case TH_LANPR_EDGE_MARK:
cp = ts->freestyle_edge_mark;
break;
- case TH_FREESTYLE_FACE_MARK:
+ case TH_LANPR_FACE_MARK:
cp = ts->freestyle_face_mark;
break;
diff --git a/source/blender/editors/lanpr/CMakeLists.txt b/source/blender/editors/lanpr/CMakeLists.txt
new file mode 100644
index 00000000000..3c1b0b389f6
--- /dev/null
+++ b/source/blender/editors/lanpr/CMakeLists.txt
@@ -0,0 +1,46 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../depsgraph
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ lanpr_ops.c
+ lanpr_cpu.c
+ lanpr_chain.c
+ lanpr_util.c
+
+ lanpr_intern.h
+)
+
+set(LIB
+)
+
+blender_add_lib(bf_editor_lanpr "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/lanpr/lanpr_chain.c b/source/blender/editors/lanpr/lanpr_chain.c
new file mode 100644
index 00000000000..8c090e6046d
--- /dev/null
+++ b/source/blender/editors/lanpr/lanpr_chain.c
@@ -0,0 +1,817 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+
+#include "BKE_customdata.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "ED_lanpr.h"
+
+#include "bmesh.h"
+
+#include "lanpr_intern.h"
+
+#include <math.h>
+
+#define LANPR_OTHER_RV(rl, rv) ((rv) == (rl)->l ? (rl)->r : (rl)->l)
+
+static LANPR_RenderLine *lanpr_get_connected_render_line(LANPR_BoundingArea *ba,
+ LANPR_RenderVert *rv,
+ LANPR_RenderVert **new_rv,
+ int match_flag)
+{
+ LinkData *lip;
+ LANPR_RenderLine *nrl;
+
+ for (lip = ba->linked_lines.first; lip; lip = lip->next) {
+ nrl = lip->data;
+
+ if ((!(nrl->flags & LANPR_EDGE_FLAG_ALL_TYPE)) ||
+ (nrl->flags & LANPR_EDGE_FLAG_CHAIN_PICKED)) {
+ continue;
+ }
+
+ if (match_flag && ((nrl->flags & LANPR_EDGE_FLAG_ALL_TYPE) & match_flag) == 0) {
+ continue;
+ }
+
+ /* always chain connected lines for now. */
+ /* simplification will take care of the sharp points. */
+ /* if(cosine whatever) continue; */
+
+ if (rv != nrl->l && rv != nrl->r) {
+ if (nrl->flags & LANPR_EDGE_FLAG_INTERSECTION) {
+ if (rv->fbcoord[0] == nrl->l->fbcoord[0] && rv->fbcoord[1] == nrl->l->fbcoord[1]) {
+ *new_rv = LANPR_OTHER_RV(nrl, nrl->l);
+ return nrl;
+ }
+ else {
+ if (rv->fbcoord[0] == nrl->r->fbcoord[0] && rv->fbcoord[1] == nrl->r->fbcoord[1]) {
+ *new_rv = LANPR_OTHER_RV(nrl, nrl->r);
+ return nrl;
+ }
+ }
+ }
+ continue;
+ }
+
+ *new_rv = LANPR_OTHER_RV(nrl, rv);
+ return nrl;
+ }
+
+ return 0;
+}
+
+static LANPR_RenderLineChain *lanpr_create_render_line_chain(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLineChain *rlc;
+ rlc = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineChain));
+
+ BLI_addtail(&rb->chains, rlc);
+
+ return rlc;
+}
+
+static LANPR_RenderLineChainItem *lanpr_append_render_line_chain_point(LANPR_RenderBuffer *rb,
+ LANPR_RenderLineChain *rlc,
+ float x,
+ float y,
+ float gx,
+ float gy,
+ float gz,
+ float *normal,
+ char type,
+ int level)
+{
+ LANPR_RenderLineChainItem *rlci;
+ rlci = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineChainItem));
+
+ rlci->pos[0] = x;
+ rlci->pos[1] = y;
+ rlci->gpos[0] = gx;
+ rlci->gpos[1] = gy;
+ rlci->gpos[2] = gz;
+ copy_v3_v3(rlci->normal, normal);
+ rlci->line_type = type & LANPR_EDGE_FLAG_ALL_TYPE;
+ rlci->occlusion = level;
+ BLI_addtail(&rlc->chain, rlci);
+
+ /* printf("a %f,%f %d\n", x, y, level); */
+
+ return rlci;
+}
+
+static LANPR_RenderLineChainItem *lanpr_push_render_line_chain_point(LANPR_RenderBuffer *rb,
+ LANPR_RenderLineChain *rlc,
+ float x,
+ float y,
+ float gx,
+ float gy,
+ float gz,
+ float *normal,
+ char type,
+ int level)
+{
+ LANPR_RenderLineChainItem *rlci;
+ rlci = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineChainItem));
+
+ rlci->pos[0] = x;
+ rlci->pos[1] = y;
+ rlci->gpos[0] = gx;
+ rlci->gpos[1] = gy;
+ rlci->gpos[2] = gz;
+ copy_v3_v3(rlci->normal, normal);
+ rlci->line_type = type & LANPR_EDGE_FLAG_ALL_TYPE;
+ rlci->occlusion = level;
+ BLI_addhead(&rlc->chain, rlci);
+
+ /* printf("data %f,%f %d\n", x, y, level); */
+
+ return rlci;
+}
+
+/* refer to http://karthaus.nl/rdp/ for description */
+static void lanpr_reduce_render_line_chain_recursive(LANPR_RenderLineChain *rlc,
+ LANPR_RenderLineChainItem *from,
+ LANPR_RenderLineChainItem *to,
+ float dist_threshold)
+{
+ LANPR_RenderLineChainItem *rlci, *next_rlci;
+ float max_dist = 0;
+ LANPR_RenderLineChainItem *max_rlci = 0;
+
+ /* find the max distance item */
+ for (rlci = from->next; rlci != to; rlci = next_rlci) {
+ next_rlci = rlci->next;
+
+ if (next_rlci &&
+ (next_rlci->occlusion != rlci->occlusion || next_rlci->line_type != rlci->line_type)) {
+ continue;
+ }
+
+ float dist = dist_to_line_segment_v2(rlci->pos, from->pos, to->pos);
+ if (dist > dist_threshold && dist > max_dist) {
+ max_dist = dist;
+ max_rlci = rlci;
+ }
+ /* if (dist <= dist_threshold) BLI_remlink(&rlc->chain, (void*)rlci); */
+ }
+
+ if (!max_rlci) {
+ if (from->next == to) {
+ return;
+ }
+ for (rlci = from->next; rlci != to; rlci = next_rlci) {
+ next_rlci = rlci->next;
+ if (next_rlci &&
+ (next_rlci->occlusion != rlci->occlusion || next_rlci->line_type != rlci->line_type)) {
+ continue;
+ }
+ BLI_remlink(&rlc->chain, (void *)rlci);
+ }
+ }
+ else {
+ if (from->next != max_rlci) {
+ lanpr_reduce_render_line_chain_recursive(rlc, from, max_rlci, dist_threshold);
+ }
+ if (to->prev != max_rlci) {
+ lanpr_reduce_render_line_chain_recursive(rlc, max_rlci, to, dist_threshold);
+ }
+ }
+}
+
+void ED_lanpr_NO_THREAD_chain_feature_lines(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLineChain *rlc;
+ LANPR_RenderLineChainItem *rlci;
+ LANPR_RenderLine *rl;
+ LANPR_BoundingArea *ba;
+ LANPR_RenderLineSegment *rls;
+ int last_occlusion;
+
+ for (rl = rb->all_render_lines.first; rl; rl = rl->next) {
+
+ if ((!(rl->flags & LANPR_EDGE_FLAG_ALL_TYPE)) || (rl->flags & LANPR_EDGE_FLAG_CHAIN_PICKED)) {
+ continue;
+ }
+
+ rl->flags |= LANPR_EDGE_FLAG_CHAIN_PICKED;
+
+ rlc = lanpr_create_render_line_chain(rb);
+
+ rlc->object_ref = rl->object_ref; /* can only be the same object in a chain. */
+ rlc->type = (rl->flags & LANPR_EDGE_FLAG_ALL_TYPE);
+
+ LANPR_RenderLine *new_rl = rl;
+ LANPR_RenderVert *new_rv;
+ float N[3] = {0};
+
+ if (rl->tl) {
+ N[0] += rl->tl->gn[0];
+ N[1] += rl->tl->gn[1];
+ N[2] += rl->tl->gn[2];
+ }
+ if (rl->tr) {
+ N[0] += rl->tr->gn[0];
+ N[1] += rl->tr->gn[1];
+ N[2] += rl->tr->gn[2];
+ }
+ if (rl->tl || rl->tr) {
+ normalize_v3(N);
+ }
+
+ /* step 1: grow left */
+ ba = ED_lanpr_get_point_bounding_area_deep(rb, rl->l->fbcoord[0], rl->l->fbcoord[1]);
+ new_rv = rl->l;
+ rls = rl->segments.first;
+ lanpr_push_render_line_chain_point(rb,
+ rlc,
+ new_rv->fbcoord[0],
+ new_rv->fbcoord[1],
+ new_rv->gloc[0],
+ new_rv->gloc[1],
+ new_rv->gloc[2],
+ N,
+ rl->flags,
+ rls->occlusion);
+ while (ba && (new_rl = lanpr_get_connected_render_line(ba, new_rv, &new_rv, rl->flags))) {
+ new_rl->flags |= LANPR_EDGE_FLAG_CHAIN_PICKED;
+
+ if (new_rl->tl || new_rl->tr) {
+ zero_v3(N);
+ if (new_rl->tl) {
+ N[0] += new_rl->tl->gn[0];
+ N[1] += new_rl->tl->gn[1];
+ N[2] += new_rl->tl->gn[2];
+ }
+ if (new_rl->tr) {
+ N[0] += new_rl->tr->gn[0];
+ N[1] += new_rl->tr->gn[1];
+ N[2] += new_rl->tr->gn[2];
+ }
+ normalize_v3(N);
+ }
+
+ if (new_rv == new_rl->l) {
+ for (rls = new_rl->segments.last; rls; rls = rls->prev) {
+ double gpos[3], lpos[3];
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, rls->at);
+ lanpr_push_render_line_chain_point(rb,
+ rlc,
+ lpos[0],
+ lpos[1],
+ gpos[0],
+ gpos[1],
+ gpos[2],
+ N,
+ new_rl->flags,
+ rls->occlusion);
+ last_occlusion = rls->occlusion;
+ }
+ }
+ else if (new_rv == new_rl->r) {
+ rls = new_rl->segments.first;
+ last_occlusion = rls->occlusion;
+ rls = rls->next;
+ for (; rls; rls = rls->next) {
+ double gpos[3], lpos[3];
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, rls->at);
+ lanpr_push_render_line_chain_point(rb,
+ rlc,
+ lpos[0],
+ lpos[1],
+ gpos[0],
+ gpos[1],
+ gpos[2],
+ N,
+ new_rl->flags,
+ last_occlusion);
+ last_occlusion = rls->occlusion;
+ }
+ lanpr_push_render_line_chain_point(rb,
+ rlc,
+ new_rl->r->fbcoord[0],
+ new_rl->r->fbcoord[1],
+ new_rl->r->gloc[0],
+ new_rl->r->gloc[1],
+ new_rl->r->gloc[2],
+ N,
+ new_rl->flags,
+ last_occlusion);
+ }
+ ba = ED_lanpr_get_point_bounding_area_deep(rb, new_rv->fbcoord[0], new_rv->fbcoord[1]);
+ }
+
+ /* Restore normal value */
+ if (rl->tl || rl->tr) {
+ zero_v3(N);
+ if (rl->tl) {
+ N[0] += rl->tl->gn[0];
+ N[1] += rl->tl->gn[1];
+ N[2] += rl->tl->gn[2];
+ }
+ if (rl->tr) {
+ N[0] += rl->tr->gn[0];
+ N[1] += rl->tr->gn[1];
+ N[2] += rl->tr->gn[2];
+ }
+ normalize_v3(N);
+ }
+ /* step 2: this line */
+ rls = rl->segments.first;
+ last_occlusion = ((LANPR_RenderLineSegment *)rls)->occlusion;
+ for (rls = rls->next; rls; rls = rls->next) {
+ double gpos[3], lpos[3];
+ interp_v3_v3v3_db(lpos, rl->l->fbcoord, rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, rl->l->gloc, rl->r->gloc, rls->at);
+ lanpr_append_render_line_chain_point(
+ rb, rlc, lpos[0], lpos[1], gpos[0], gpos[1], gpos[2], N, rl->flags, rls->occlusion);
+ last_occlusion = rls->occlusion;
+ }
+ lanpr_append_render_line_chain_point(rb,
+ rlc,
+ rl->r->fbcoord[0],
+ rl->r->fbcoord[1],
+ rl->r->gloc[0],
+ rl->r->gloc[1],
+ rl->r->gloc[2],
+ N,
+ rl->flags,
+ last_occlusion);
+
+ /* step 3: grow right */
+ ba = ED_lanpr_get_point_bounding_area_deep(rb, rl->r->fbcoord[0], rl->r->fbcoord[1]);
+ new_rv = rl->r;
+ /* below already done in step 2 */
+ /* lanpr_push_render_line_chain_point(rb,rlc,new_rv->fbcoord[0],new_rv->fbcoord[1],rl->flags,0);
+ */
+ while (ba && (new_rl = lanpr_get_connected_render_line(ba, new_rv, &new_rv, rl->flags))) {
+ new_rl->flags |= LANPR_EDGE_FLAG_CHAIN_PICKED;
+
+ if (new_rl->tl || new_rl->tr) {
+ zero_v3(N);
+ if (new_rl->tl) {
+ N[0] += new_rl->tl->gn[0];
+ N[1] += new_rl->tl->gn[1];
+ N[2] += new_rl->tl->gn[2];
+ }
+ if (new_rl->tr) {
+ N[0] += new_rl->tr->gn[0];
+ N[1] += new_rl->tr->gn[1];
+ N[2] += new_rl->tr->gn[2];
+ }
+ normalize_v3(N);
+ }
+
+ /* fix leading vertex type */
+ rlci = rlc->chain.last;
+ rlci->line_type = new_rl->flags & LANPR_EDGE_FLAG_ALL_TYPE;
+
+ if (new_rv == new_rl->l) {
+ rls = new_rl->segments.last;
+ last_occlusion = rls->occlusion;
+ rlci->occlusion = last_occlusion; /* fix leading vertex occlusion */
+ for (rls = new_rl->segments.last; rls; rls = rls->prev) {
+ double gpos[3], lpos[3];
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, rls->at);
+ last_occlusion = rls->prev ? rls->prev->occlusion : last_occlusion;
+ lanpr_append_render_line_chain_point(rb,
+ rlc,
+ lpos[0],
+ lpos[1],
+ gpos[0],
+ gpos[1],
+ gpos[2],
+ N,
+ new_rl->flags,
+ last_occlusion);
+ }
+ }
+ else if (new_rv == new_rl->r) {
+ rls = new_rl->segments.first;
+ last_occlusion = rls->occlusion;
+ rlci->occlusion = last_occlusion;
+ rls = rls->next;
+ for (; rls; rls = rls->next) {
+ double gpos[3], lpos[3];
+ interp_v3_v3v3_db(lpos, new_rl->l->fbcoord, new_rl->r->fbcoord, rls->at);
+ interp_v3_v3v3_db(gpos, new_rl->l->gloc, new_rl->r->gloc, rls->at);
+ lanpr_append_render_line_chain_point(rb,
+ rlc,
+ lpos[0],
+ lpos[1],
+ gpos[0],
+ gpos[1],
+ gpos[2],
+ N,
+ new_rl->flags,
+ rls->occlusion);
+ last_occlusion = rls->occlusion;
+ }
+ lanpr_append_render_line_chain_point(rb,
+ rlc,
+ new_rl->r->fbcoord[0],
+ new_rl->r->fbcoord[1],
+ new_rl->r->gloc[0],
+ new_rl->r->gloc[1],
+ new_rl->r->gloc[2],
+ N,
+ new_rl->flags,
+ last_occlusion);
+ }
+ ba = ED_lanpr_get_point_bounding_area_deep(rb, new_rv->fbcoord[0], new_rv->fbcoord[1]);
+ }
+ }
+}
+
+static LANPR_BoundingArea *lanpr_get_rlci_bounding_area_recursive(LANPR_RenderBuffer *rb,
+ LANPR_BoundingArea *root,
+ LANPR_RenderLineChainItem *rlci)
+{
+ if (!root->child) {
+ return root;
+ }
+ else {
+ LANPR_BoundingArea *ch = root->child;
+#define IN_BOUND(ba, rlci) \
+ ba.l <= rlci->pos[0] && ba.r >= rlci->pos[0] && ba.b <= rlci->pos[1] && ba.u >= rlci->pos[1]
+
+ if (IN_BOUND(ch[0], rlci)) {
+ return lanpr_get_rlci_bounding_area_recursive(rb, &ch[0], rlci);
+ }
+ else if (IN_BOUND(ch[1], rlci)) {
+ return lanpr_get_rlci_bounding_area_recursive(rb, &ch[1], rlci);
+ }
+ else if (IN_BOUND(ch[2], rlci)) {
+ return lanpr_get_rlci_bounding_area_recursive(rb, &ch[2], rlci);
+ }
+ else if (IN_BOUND(ch[3], rlci)) {
+ return lanpr_get_rlci_bounding_area_recursive(rb, &ch[3], rlci);
+ }
+#undef IN_BOUND
+ }
+ return NULL;
+}
+static LANPR_BoundingArea *lanpr_get_end_point_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_RenderLineChainItem *rlci)
+{
+ LANPR_BoundingArea *root = ED_lanpr_get_point_bounding_area(rb, rlci->pos[0], rlci->pos[1]);
+ if (!root) {
+ return NULL;
+ }
+ return lanpr_get_rlci_bounding_area_recursive(rb, root, rlci);
+}
+
+/* if reduction threshold is even larger than a small bounding area, */
+/* then 1) geometry is simply too dense. */
+/* 2) probably need to add it to root bounding area which has larger surface area then it
+ * will */
+/* cover typical threshold values. */
+static void lanpr_link_point_with_bounding_area_recursive(LANPR_RenderBuffer *rb,
+ LANPR_BoundingArea *root,
+ LANPR_RenderLineChain *rlc,
+ LANPR_RenderLineChainItem *rlci)
+{
+ if (!root->child) {
+ LANPR_ChainRegisterEntry *cre = list_append_pointer_static_sized(
+ &root->linked_chains, &rb->render_data_pool, rlc, sizeof(LANPR_ChainRegisterEntry));
+
+ cre->rlci = rlci;
+
+ if (rlci == rlc->chain.first) {
+ cre->is_left = 1;
+ }
+ }
+ else {
+ LANPR_BoundingArea *ch = root->child;
+
+#define IN_BOUND(ba, rlci) \
+ ba.l <= rlci->pos[0] && ba.r >= rlci->pos[0] && ba.b <= rlci->pos[1] && ba.u >= rlci->pos[1]
+
+ if (IN_BOUND(ch[0], rlci)) {
+ lanpr_link_point_with_bounding_area_recursive(rb, &ch[0], rlc, rlci);
+ }
+ else if (IN_BOUND(ch[1], rlci)) {
+ lanpr_link_point_with_bounding_area_recursive(rb, &ch[1], rlc, rlci);
+ }
+ else if (IN_BOUND(ch[2], rlci)) {
+ lanpr_link_point_with_bounding_area_recursive(rb, &ch[2], rlc, rlci);
+ }
+ else if (IN_BOUND(ch[3], rlci)) {
+ lanpr_link_point_with_bounding_area_recursive(rb, &ch[3], rlc, rlci);
+ }
+
+#undef IN_BOUND
+ }
+}
+
+static void lanpr_link_chain_with_bounding_areas(LANPR_RenderBuffer *rb,
+ LANPR_RenderLineChain *rlc)
+{
+ LANPR_RenderLineChainItem *pl = rlc->chain.first;
+ LANPR_RenderLineChainItem *pr = rlc->chain.last;
+ LANPR_BoundingArea *ba1 = ED_lanpr_get_point_bounding_area(rb, pl->pos[0], pl->pos[1]);
+ LANPR_BoundingArea *ba2 = ED_lanpr_get_point_bounding_area(rb, pr->pos[0], pr->pos[1]);
+
+ if (ba1) {
+ lanpr_link_point_with_bounding_area_recursive(rb, ba1, rlc, pl);
+ }
+ if (ba2) {
+ lanpr_link_point_with_bounding_area_recursive(rb, ba2, rlc, pr);
+ }
+}
+
+void ED_lanpr_split_chains_for_fixed_occlusion(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLineChain *rlc, *new_rlc;
+ LANPR_RenderLineChainItem *rlci, *next_rlci;
+ ListBase swap = {0};
+
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+
+ while ((rlc = BLI_pophead(&swap)) != NULL) {
+ rlc->next = rlc->prev = NULL;
+ BLI_addtail(&rb->chains, rlc);
+ LANPR_RenderLineChainItem *first_rlci = (LANPR_RenderLineChainItem *)rlc->chain.first;
+ int fixed_occ = first_rlci->occlusion;
+ rlc->level = fixed_occ;
+ for (rlci = first_rlci->next; rlci; rlci = next_rlci) {
+ next_rlci = rlci->next;
+ if (rlci->occlusion != fixed_occ) {
+ new_rlc = lanpr_create_render_line_chain(rb);
+ new_rlc->chain.first = rlci;
+ new_rlc->chain.last = rlc->chain.last;
+ rlc->chain.last = rlci->prev;
+ ((LANPR_RenderLineChainItem *)rlc->chain.last)->next = 0;
+ rlci->prev = 0;
+
+ /* end the previous one */
+ lanpr_append_render_line_chain_point(rb,
+ rlc,
+ rlci->pos[0],
+ rlci->pos[1],
+ rlci->gpos[0],
+ rlci->gpos[1],
+ rlci->gpos[2],
+ rlci->normal,
+ rlci->line_type,
+ fixed_occ);
+ new_rlc->object_ref = rlc->object_ref;
+ new_rlc->type = rlc->type;
+ rlc = new_rlc;
+ fixed_occ = rlci->occlusion;
+ rlc->level = fixed_occ;
+ }
+ }
+ }
+ for (rlc = rb->chains.first; rlc; rlc = rlc->next) {
+ lanpr_link_chain_with_bounding_areas(rb, rlc);
+ }
+}
+
+/* note: segment type (crease/material/contour...) is ambiguous after this. */
+static void lanpr_connect_two_chains(LANPR_RenderBuffer *UNUSED(rb),
+ LANPR_RenderLineChain *onto,
+ LANPR_RenderLineChain *sub,
+ int reverse_1,
+ int reverse_2)
+{
+ if (!reverse_1) { /* L--R L-R */
+ if (reverse_2) { /* L--R R-L */
+ BLI_listbase_reverse(&sub->chain);
+ }
+ ((LANPR_RenderLineChainItem *)onto->chain.last)->next = sub->chain.first;
+ ((LANPR_RenderLineChainItem *)sub->chain.first)->prev = onto->chain.last;
+ onto->chain.last = sub->chain.last;
+ }
+ else { /* L-R L--R */
+ if (!reverse_2) { /* R-L L--R */
+ BLI_listbase_reverse(&sub->chain);
+ }
+ ((LANPR_RenderLineChainItem *)sub->chain.last)->next = onto->chain.first;
+ ((LANPR_RenderLineChainItem *)onto->chain.first)->prev = sub->chain.last;
+ onto->chain.first = sub->chain.first;
+ }
+ /* ((LANPR_RenderLineChainItem*)sub->chain.first)->occlusion = */
+ /* ((LANPR_RenderLineChainItem*)onto->chain.first)->occlusion; */
+ /* ((LANPR_RenderLineChainItem*)onto->chain.last)->occlusion = */
+ /* ((LANPR_RenderLineChainItem*)onto->chain.first)->occlusion; */
+ /* ((LANPR_RenderLineChainItem*)sub->chain.last)->occlusion = */
+ /* ((LANPR_RenderLineChainItem*)onto->chain.first)->occlusion; */
+}
+
+/* this only does head-tail connection. */
+/* overlapping / tiny isolated segment / loop reduction not implemented here yet. */
+void ED_lanpr_connect_chains(LANPR_RenderBuffer *rb, int do_geometry_space)
+{
+ LANPR_RenderLineChain *rlc;
+ LANPR_RenderLineChainItem *rlci;
+ LANPR_BoundingArea *ba;
+ LANPR_ChainRegisterEntry *cre, *next_cre, *closest_cre;
+ float dist;
+ int occlusion;
+ ListBase swap = {0};
+
+ if ((!do_geometry_space && rb->scene->lanpr.chaining_image_threshold < 0.0001) ||
+ (do_geometry_space && rb->scene->lanpr.chaining_geometry_threshold < 0.0001)) {
+ return;
+ }
+
+ swap.first = rb->chains.first;
+ swap.last = rb->chains.last;
+
+ rb->chains.last = rb->chains.first = NULL;
+
+ while ((rlc = BLI_pophead(&swap)) != NULL) {
+ rlc->next = rlc->prev = NULL;
+ BLI_addtail(&rb->chains, rlc);
+ if (rlc->picked) {
+ continue;
+ }
+
+ rlc->picked = 1;
+
+ occlusion = ((LANPR_RenderLineChainItem *)rlc->chain.first)->occlusion;
+
+ rlci = rlc->chain.last;
+ while ((ba = lanpr_get_end_point_bounding_area(rb, rlci)) != NULL) {
+ dist = do_geometry_space ? rb->scene->lanpr.chaining_geometry_threshold :
+ rb->scene->lanpr.chaining_image_threshold;
+ closest_cre = NULL;
+ if (!ba->linked_chains.first) {
+ break;
+ }
+ for (cre = ba->linked_chains.first; cre; cre = next_cre) {
+ next_cre = cre->next;
+ if (cre->rlc->object_ref != rlc->object_ref) {
+ continue;
+ }
+ if (cre->rlc == rlc ||
+ ((LANPR_RenderLineChainItem *)cre->rlc->chain.first)->occlusion != occlusion ||
+ (cre->rlc->type != rlc->type)) {
+ continue;
+ }
+ if (cre->rlc->picked) {
+ BLI_remlink(&ba->linked_chains, cre);
+ continue;
+ }
+ float new_len = do_geometry_space ? len_v3v3(cre->rlci->gpos, rlci->gpos) :
+ len_v2v2(cre->rlci->pos, rlci->pos);
+ if (new_len < dist) {
+ closest_cre = cre;
+ dist = new_len;
+ }
+ }
+ if (closest_cre) {
+ closest_cre->picked = 1;
+ closest_cre->rlc->picked = 1;
+ BLI_remlink(&ba->linked_chains, cre);
+ if (closest_cre->is_left) {
+ lanpr_connect_two_chains(rb, rlc, closest_cre->rlc, 0, 0);
+ }
+ else {
+ lanpr_connect_two_chains(rb, rlc, closest_cre->rlc, 0, 1);
+ }
+ BLI_remlink(&swap, closest_cre->rlc);
+ }
+ else {
+ break;
+ }
+ rlci = rlc->chain.last;
+ }
+
+ rlci = rlc->chain.first;
+ while ((ba = lanpr_get_end_point_bounding_area(rb, rlci)) != NULL) {
+ dist = do_geometry_space ? rb->scene->lanpr.chaining_geometry_threshold :
+ rb->scene->lanpr.chaining_image_threshold;
+ closest_cre = NULL;
+ if (!ba->linked_chains.first) {
+ break;
+ }
+ for (cre = ba->linked_chains.first; cre; cre = next_cre) {
+ next_cre = cre->next;
+ if (cre->rlc->object_ref != rlc->object_ref) {
+ continue;
+ }
+ if (cre->rlc == rlc ||
+ ((LANPR_RenderLineChainItem *)cre->rlc->chain.first)->occlusion != occlusion ||
+ (cre->rlc->type != rlc->type)) {
+ continue;
+ }
+ if (cre->rlc->picked) {
+ BLI_remlink(&ba->linked_chains, cre);
+ continue;
+ }
+ float new_len = do_geometry_space ? len_v3v3(cre->rlci->gpos, rlci->gpos) :
+ len_v2v2(cre->rlci->pos, rlci->pos);
+ if (new_len < dist) {
+ closest_cre = cre;
+ dist = new_len;
+ }
+ }
+ if (closest_cre) {
+ closest_cre->picked = 1;
+ closest_cre->rlc->picked = 1;
+ BLI_remlink(&ba->linked_chains, cre);
+ if (closest_cre->is_left) {
+ lanpr_connect_two_chains(rb, rlc, closest_cre->rlc, 1, 0);
+ }
+ else {
+ lanpr_connect_two_chains(rb, rlc, closest_cre->rlc, 1, 1);
+ }
+ BLI_remlink(&swap, closest_cre->rlc);
+ }
+ else {
+ break;
+ }
+ rlci = rlc->chain.first;
+ }
+ }
+}
+
+/* length is in image space */
+float ED_lanpr_compute_chain_length(LANPR_RenderLineChain *rlc)
+{
+ LANPR_RenderLineChainItem *rlci;
+ float offset_accum = 0;
+ float dist;
+ float last_point[2];
+
+ rlci = rlc->chain.first;
+ copy_v2_v2(last_point, rlci->pos);
+ for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
+ dist = len_v2v2(rlci->pos, last_point);
+ offset_accum += dist;
+ copy_v2_v2(last_point, rlci->pos);
+ }
+ return offset_accum;
+}
+
+void ED_lanpr_discard_short_chains(LANPR_RenderBuffer *rb, float threshold)
+{
+ LANPR_RenderLineChain *rlc, *next_rlc;
+ for (rlc = rb->chains.first; rlc; rlc = next_rlc) {
+ next_rlc = rlc->next;
+ if (ED_lanpr_compute_chain_length(rlc) < threshold) {
+ BLI_remlink(&rb->chains, rlc);
+ }
+ }
+}
+
+int ED_lanpr_count_chain(LANPR_RenderLineChain *rlc)
+{
+ LANPR_RenderLineChainItem *rlci;
+ int Count = 0;
+ for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
+ Count++;
+ }
+ return Count;
+}
+
+void ED_lanpr_chain_clear_picked_flag(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLineChain *rlc;
+ if (!rb) {
+ return;
+ }
+ for (rlc = rb->chains.first; rlc; rlc = rlc->next) {
+ rlc->picked = 0;
+ }
+}
diff --git a/source/blender/editors/lanpr/lanpr_cpu.c b/source/blender/editors/lanpr/lanpr_cpu.c
new file mode 100644
index 00000000000..1563bbf29d2
--- /dev/null
+++ b/source/blender/editors/lanpr/lanpr_cpu.c
@@ -0,0 +1,4350 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include "ED_lanpr.h"
+
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math_matrix.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
+
+#include "BKE_object.h"
+#include "DNA_mesh_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_text_types.h"
+#include "DNA_lanpr_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "BKE_customdata.h"
+#include "DEG_depsgraph_query.h"
+#include "BKE_camera.h"
+#include "BKE_gpencil.h"
+#include "BKE_collection.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_text.h"
+#include "BKE_context.h"
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "BLI_math.h"
+#include "BLI_callbacks.h"
+#include "BLI_string_utils.h"
+
+#include "bmesh.h"
+#include "bmesh_class.h"
+#include "bmesh_tools.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "BKE_text.h"
+
+#include "lanpr_intern.h"
+
+extern LANPR_SharedResource lanpr_share;
+extern const char *RE_engine_id_BLENDER_LANPR;
+struct Object;
+
+/* Own functions */
+
+static LANPR_BoundingArea *lanpr_get_first_possible_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl);
+
+static void lanpr_link_line_with_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_BoundingArea *RootBoundingArea,
+ LANPR_RenderLine *rl);
+
+static LANPR_BoundingArea *lanpr_get_next_bounding_area(LANPR_BoundingArea *This,
+ LANPR_RenderLine *rl,
+ real x,
+ real y,
+ real k,
+ int PositiveX,
+ int PositiveY,
+ real *NextX,
+ real *NextY);
+static int lanpr_triangle_line_imagespace_intersection_v2(SpinLock *spl,
+ LANPR_RenderTriangle *rt,
+ LANPR_RenderLine *rl,
+ Object *cam,
+ double vp[4][4],
+ double *CameraDir,
+ double *From,
+ double *To);
+static int lanpr_get_line_bounding_areas(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl,
+ int *rowBegin,
+ int *rowEnd,
+ int *colBegin,
+ int *colEnd);
+
+/* Layer operations */
+
+static void lanpr_line_layer_unique_name(ListBase *list, LANPR_LineLayer *ll, const char *defname)
+{
+ BLI_uniquename(list, ll, defname, '.', offsetof(LANPR_LineLayer, name), sizeof(ll->name));
+}
+
+int ED_lanpr_max_occlusion_in_line_layers(SceneLANPR *lanpr)
+{
+ LANPR_LineLayer *lli;
+ int max_occ = -1, max;
+ for (lli = lanpr->line_layers.first; lli; lli = lli->next) {
+ if (lli->flags & LANPR_LINE_LAYER_USE_MULTIPLE_LEVELS) {
+ max = MAX2(lli->level_start, lli->level_end);
+ }
+ else {
+ max = lli->level_start;
+ }
+ max_occ = MAX2(max, max_occ);
+ }
+ return max_occ;
+}
+LANPR_LineLayer *ED_lanpr_new_line_layer(SceneLANPR *lanpr)
+{
+ LANPR_LineLayer *ll = MEM_callocN(sizeof(LANPR_LineLayer), "Line Layer");
+
+ lanpr_line_layer_unique_name(&lanpr->line_layers, ll, "Layer");
+
+ int max_occ = ED_lanpr_max_occlusion_in_line_layers(lanpr);
+
+ ll->level_start = ll->level_end = max_occ + 1;
+ ll->flags |= LANPR_LINE_LAYER_USE_SAME_STYLE;
+ ll->thickness = 1.0f;
+ copy_v3_fl(ll->color, 0.8);
+ ll->color[3] = 1.0f;
+ ll->contour.use = 1;
+ ll->crease.use = 1;
+ ll->material_separate.use = 1;
+ ll->edge_mark.use = 1;
+ ll->intersection.use = 1;
+
+ ll->normal_thickness_start = 0.2f;
+ ll->normal_thickness_end = 1.5f;
+ ll->normal_ramp_begin = 0.0f;
+ ll->normal_ramp_end = 1.0f;
+
+ ll->normal_mode = LANPR_NORMAL_DIRECTIONAL;
+
+ lanpr->active_layer = ll;
+ BLI_addtail(&lanpr->line_layers, ll);
+
+ return ll;
+}
+LANPR_LineLayerComponent *ED_lanpr_new_line_component(SceneLANPR *lanpr)
+{
+ if (!lanpr->active_layer) {
+ return 0;
+ }
+ LANPR_LineLayer *ll = lanpr->active_layer;
+
+ LANPR_LineLayerComponent *llc = MEM_callocN(sizeof(LANPR_LineLayerComponent), "Line Component");
+ BLI_addtail(&ll->components, llc);
+
+ return llc;
+}
+static int lanpr_add_line_layer_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ ED_lanpr_new_line_layer(lanpr);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_delete_line_layer_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ LANPR_LineLayer *ll = lanpr->active_layer;
+
+ if (!ll) {
+ return OPERATOR_FINISHED;
+ }
+
+ if (ll->prev) {
+ lanpr->active_layer = ll->prev;
+ }
+ else if (ll->next) {
+ lanpr->active_layer = ll->next;
+ }
+ else {
+ lanpr->active_layer = 0;
+ }
+
+ BLI_remlink(&scene->lanpr.line_layers, ll);
+
+ /* if (ll->batch) GPU_batch_discard(ll->batch); */
+
+ MEM_freeN(ll);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_move_line_layer_exec(struct bContext *C, struct wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ LANPR_LineLayer *ll = lanpr->active_layer;
+
+ if (!ll) {
+ return OPERATOR_FINISHED;
+ }
+
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (dir == 1 && ll->prev) {
+ BLI_remlink(&lanpr->line_layers, ll);
+ BLI_insertlinkbefore(&lanpr->line_layers, ll->prev, ll);
+ }
+ else if (dir == -1 && ll->next) {
+ BLI_remlink(&lanpr->line_layers, ll);
+ BLI_insertlinkafter(&lanpr->line_layers, ll->next, ll);
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_add_line_component_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ ED_lanpr_new_line_component(lanpr);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_delete_line_component_exec(struct bContext *C, struct wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+ LANPR_LineLayer *ll = lanpr->active_layer;
+ LANPR_LineLayerComponent *llc;
+ int i = 0;
+
+ if (!ll) {
+ return OPERATOR_FINISHED;
+ }
+
+ int index = RNA_int_get(op->ptr, "index");
+
+ for (llc = ll->components.first; llc; llc = llc->next) {
+ if (index == i) {
+ break;
+ }
+ i++;
+ }
+
+ if (llc) {
+ BLI_remlink(&ll->components, llc);
+ MEM_freeN(llc);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int ED_lanpr_rebuild_all_commands_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ ED_lanpr_rebuild_all_command(lanpr);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_enable_all_line_types_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+ LANPR_LineLayer *ll;
+
+ if (!(ll = lanpr->active_layer)) {
+ return OPERATOR_FINISHED;
+ }
+
+ ll->contour.use = 1;
+ ll->crease.use = 1;
+ ll->edge_mark.use = 1;
+ ll->material_separate.use = 1;
+ ll->intersection.use = 1;
+
+ copy_v3_v3(ll->contour.color, ll->color);
+ copy_v3_v3(ll->crease.color, ll->color);
+ copy_v3_v3(ll->edge_mark.color, ll->color);
+ copy_v3_v3(ll->material_separate.color, ll->color);
+ copy_v3_v3(ll->intersection.color, ll->color);
+
+ ll->contour.thickness = 1;
+ ll->crease.thickness = 1;
+ ll->material_separate.thickness = 1;
+ ll->edge_mark.thickness = 1;
+ ll->intersection.thickness = 1;
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_auto_create_line_layer_exec(struct bContext *C, struct wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+
+ LANPR_LineLayer *ll;
+
+ ll = ED_lanpr_new_line_layer(lanpr);
+ ll->thickness = 1.7;
+
+ lanpr_enable_all_line_types_exec(C, op);
+
+ ll = ED_lanpr_new_line_layer(lanpr);
+ ll->thickness = 0.9;
+ copy_v3_fl(ll->color, 0.6);
+
+ lanpr_enable_all_line_types_exec(C, op);
+
+ ll = ED_lanpr_new_line_layer(lanpr);
+ ll->thickness = 0.7;
+ copy_v3_fl(ll->color, 0.5);
+
+ lanpr_enable_all_line_types_exec(C, op);
+
+ ED_lanpr_rebuild_all_command(lanpr);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_lanpr_add_line_layer(struct wmOperatorType *ot)
+{
+
+ ot->name = "Add Line Layer";
+ ot->description = "Add a new line layer";
+ ot->idname = "SCENE_OT_lanpr_add_line_layer";
+
+ ot->exec = lanpr_add_line_layer_exec;
+}
+void SCENE_OT_lanpr_delete_line_layer(struct wmOperatorType *ot)
+{
+
+ ot->name = "Delete Line Layer";
+ ot->description = "Delete selected line layer";
+ ot->idname = "SCENE_OT_lanpr_delete_line_layer";
+
+ ot->exec = lanpr_delete_line_layer_exec;
+}
+void SCENE_OT_lanpr_rebuild_all_commands(struct wmOperatorType *ot)
+{
+
+ ot->name = "Refresh Drawing Commands";
+ ot->description = "Refresh LANPR line layer drawing commands";
+ ot->idname = "SCENE_OT_lanpr_rebuild_all_commands";
+
+ ot->exec = ED_lanpr_rebuild_all_commands_exec;
+}
+void SCENE_OT_lanpr_auto_create_line_layer(struct wmOperatorType *ot)
+{
+
+ ot->name = "Auto Create Line Layer";
+ ot->description = "Automatically create defalt line layer config";
+ ot->idname = "SCENE_OT_lanpr_auto_create_line_layer";
+
+ ot->exec = lanpr_auto_create_line_layer_exec;
+}
+void SCENE_OT_lanpr_move_line_layer(struct wmOperatorType *ot)
+{
+ static const EnumPropertyItem line_layer_move[] = {
+ {1, "UP", 0, "Up", ""}, {-1, "DOWN", 0, "Down", ""}, {0, NULL, 0, NULL, NULL}};
+
+ ot->name = "Move Line Layer";
+ ot->description = "Move LANPR line layer up and down";
+ ot->idname = "SCENE_OT_lanpr_move_line_layer";
+
+ /* this need property to assign up/down direction */
+
+ ot->exec = lanpr_move_line_layer_exec;
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ line_layer_move,
+ 0,
+ "Direction",
+ "Direction to move the active line layer towards");
+}
+void SCENE_OT_lanpr_enable_all_line_types(struct wmOperatorType *ot)
+{
+ ot->name = "Enable All Line Types";
+ ot->description = "Enable All Line Types In This Line Layer";
+ ot->idname = "SCENE_OT_lanpr_enable_all_line_types";
+
+ ot->exec = lanpr_enable_all_line_types_exec;
+}
+void SCENE_OT_lanpr_add_line_component(struct wmOperatorType *ot)
+{
+
+ ot->name = "Add Line Component";
+ ot->description = "Add a new line Component";
+ ot->idname = "SCENE_OT_lanpr_add_line_component";
+
+ ot->exec = lanpr_add_line_component_exec;
+}
+void SCENE_OT_lanpr_delete_line_component(struct wmOperatorType *ot)
+{
+
+ ot->name = "Delete Line Component";
+ ot->description = "Delete selected line component";
+ ot->idname = "SCENE_OT_lanpr_delete_line_component";
+
+ ot->exec = lanpr_delete_line_component_exec;
+
+ RNA_def_int(ot->srna, "index", 0, 0, 10000, "index", "index of this line component", 0, 10000);
+}
+
+/* Geometry */
+
+int use_smooth_contour_modifier_contour = 0; /* debug purpose */
+
+static void lanpr_cut_render_line(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl,
+ real Begin,
+ real End)
+{
+ LANPR_RenderLineSegment *rls = rl->segments.first, *irls;
+ LANPR_RenderLineSegment *begin_segment = 0, *end_segment = 0;
+ LANPR_RenderLineSegment *ns = 0, *ns2 = 0;
+ int untouched = 0;
+
+ if (TNS_DOUBLE_CLOSE_ENOUGH(Begin, End)) {
+ return;
+ }
+
+ if (Begin != Begin) {
+ Begin = 0;
+ }
+ if (End != End) {
+ End = 0;
+ }
+
+ if (Begin > End) {
+ real t = Begin;
+ Begin = End;
+ End = t;
+ }
+
+ for (rls = rl->segments.first; rls; rls = rls->next) {
+ if (TNS_DOUBLE_CLOSE_ENOUGH(rls->at, Begin)) {
+ begin_segment = rls;
+ ns = begin_segment;
+ break;
+ }
+ if (!rls->next) {
+ break;
+ }
+ irls = rls->next;
+ if (irls->at > Begin + 1e-09 && Begin > rls->at) {
+ begin_segment = irls;
+ ns = mem_static_aquire_thread(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ break;
+ }
+ }
+ if (!begin_segment && TNS_DOUBLE_CLOSE_ENOUGH(1, End)) {
+ untouched = 1;
+ }
+ for (rls = begin_segment; rls; rls = rls->next) {
+ if (TNS_DOUBLE_CLOSE_ENOUGH(rls->at, End)) {
+ end_segment = rls;
+ ns2 = end_segment;
+ break;
+ }
+ /* irls = rls->next; */
+ /* added this to prevent rls->at == 1.0 (we don't need an end point for this) */
+ if (!rls->next && TNS_DOUBLE_CLOSE_ENOUGH(1, End)) {
+ end_segment = rls;
+ ns2 = end_segment;
+ untouched = 1;
+ break;
+ }
+ else if (rls->at > End) {
+ end_segment = rls;
+ ns2 = mem_static_aquire_thread(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ break;
+ }
+ }
+
+ if (!ns) {
+ ns = mem_static_aquire_thread(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ }
+ if (!ns2) {
+ if (untouched) {
+ ns2 = ns;
+ end_segment = ns2;
+ }
+ else
+ ns2 = mem_static_aquire_thread(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ }
+
+ if (begin_segment) {
+ if (begin_segment != ns) {
+ ns->occlusion = begin_segment->prev ? (irls = begin_segment->prev)->occlusion : 0;
+ BLI_insertlinkbefore(&rl->segments, (void *)begin_segment, (void *)ns);
+ }
+ }
+ else {
+ ns->occlusion = (irls = rl->segments.last)->occlusion;
+ BLI_addtail(&rl->segments, ns);
+ }
+ if (end_segment) {
+ if (end_segment != ns2) {
+ ns2->occlusion = end_segment->prev ? (irls = end_segment->prev)->occlusion : 0;
+ BLI_insertlinkbefore(&rl->segments, (void *)end_segment, (void *)ns2);
+ }
+ }
+ else {
+ ns2->occlusion = (irls = rl->segments.last)->occlusion;
+ BLI_addtail(&rl->segments, ns2);
+ }
+
+ ns->at = Begin;
+ if (!untouched) {
+ ns2->at = End;
+ }
+ else {
+ ns2 = ns2->next;
+ }
+
+ for (rls = ns; rls && rls != ns2; rls = rls->next) {
+ rls->occlusion++;
+ }
+
+ char min_occ = 127;
+ for (rls = rl->segments.first; rls; rls = rls->next) {
+ min_occ = MIN2(min_occ, rls->occlusion);
+ }
+ rl->min_occ = min_occ;
+}
+static int lanpr_make_next_occlusion_task_info(LANPR_RenderBuffer *rb, LANPR_RenderTaskInfo *rti)
+{
+ LinkData *data;
+ int i;
+ int res = 0;
+
+ BLI_spin_lock(&rb->lock_task);
+
+ if (rb->contour_managed) {
+ data = rb->contour_managed;
+ rti->contour = (void *)data;
+ rti->contour_pointers.first = data;
+ for (i = 0; i < TNS_THREAD_LINE_COUNT && data; i++) {
+ data = data->next;
+ }
+ rb->contour_managed = data;
+ rti->contour_pointers.last = data ? data->prev : rb->contours.last;
+ res = 1;
+ }
+ else {
+ BLI_listbase_clear(&rti->contour_pointers);
+ rti->contour = 0;
+ }
+
+ if (rb->intersection_managed) {
+ data = rb->intersection_managed;
+ rti->intersection = (void *)data;
+ rti->intersection_pointers.first = data;
+ for (i = 0; i < TNS_THREAD_LINE_COUNT && data; i++) {
+ data = data->next;
+ }
+ rb->intersection_managed = data;
+ rti->intersection_pointers.last = data ? data->prev : rb->intersection_lines.last;
+ res = 1;
+ }
+ else {
+ BLI_listbase_clear(&rti->intersection_pointers);
+ rti->intersection = 0;
+ }
+
+ if (rb->crease_managed) {
+ data = rb->crease_managed;
+ rti->crease = (void *)data;
+ rti->crease_pointers.first = data;
+ for (i = 0; i < TNS_THREAD_LINE_COUNT && data; i++) {
+ data = data->next;
+ }
+ rb->crease_managed = data;
+ rti->crease_pointers.last = data ? data->prev : rb->crease_lines.last;
+ res = 1;
+ }
+ else {
+ BLI_listbase_clear(&rti->crease_pointers);
+ rti->crease = 0;
+ }
+
+ if (rb->material_managed) {
+ data = rb->material_managed;
+ rti->material = (void *)data;
+ rti->material_pointers.first = data;
+ for (i = 0; i < TNS_THREAD_LINE_COUNT && data; i++) {
+ data = data->next;
+ }
+ rb->material_managed = data;
+ rti->material_pointers.last = data ? data->prev : rb->material_lines.last;
+ res = 1;
+ }
+ else {
+ BLI_listbase_clear(&rti->material_pointers);
+ rti->material = 0;
+ }
+
+ if (rb->edge_mark_managed) {
+ data = rb->edge_mark_managed;
+ rti->edge_mark = (void *)data;
+ rti->edge_mark_pointers.first = data;
+ for (i = 0; i < TNS_THREAD_LINE_COUNT && data; i++) {
+ data = data->next;
+ }
+ rb->edge_mark_managed = data;
+ rti->edge_mark_pointers.last = data ? data->prev : rb->edge_marks.last;
+ res = 1;
+ }
+ else {
+ BLI_listbase_clear(&rti->edge_mark_pointers);
+ rti->edge_mark = 0;
+ }
+
+ BLI_spin_unlock(&rb->lock_task);
+
+ return res;
+}
+static void lanpr_calculate_single_line_occlusion(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl,
+ int thread_id)
+{
+ real x = rl->l->fbcoord[0], y = rl->l->fbcoord[1];
+ LANPR_BoundingArea *ba = lanpr_get_first_possible_bounding_area(rb, rl);
+ LANPR_BoundingArea *nba = ba;
+ LANPR_RenderTriangleThread *rt;
+ LinkData *lip;
+ Object *c = rb->scene->camera;
+ real l, r;
+ real k = (rl->r->fbcoord[1] - rl->l->fbcoord[1]) /
+ (rl->r->fbcoord[0] - rl->l->fbcoord[0] + 1e-30);
+ int PositiveX = (rl->r->fbcoord[0] - rl->l->fbcoord[0]) > 0 ?
+ 1 :
+ (rl->r->fbcoord[0] == rl->l->fbcoord[0] ? 0 : -1);
+ int PositiveY = (rl->r->fbcoord[1] - rl->l->fbcoord[1]) > 0 ?
+ 1 :
+ (rl->r->fbcoord[1] == rl->l->fbcoord[1] ? 0 : -1);
+
+ /* printf("PX %d %lf PY %d %lf\n", PositiveX, rl->r->fbcoord[0] - */
+ /* rl->l->fbcoord[0], PositiveY, rl->r->fbcoord[1] - */
+ /* rl->l->fbcoord[1]); */
+
+ while (nba) {
+
+ for (lip = nba->linked_triangles.first; lip; lip = lip->next) {
+ rt = lip->data;
+ if (rt->testing[thread_id] == rl || rl->l->intersecting_with == (void *)rt ||
+ rl->r->intersecting_with == (void *)rt) {
+ continue;
+ }
+ rt->testing[thread_id] = rl;
+ if (lanpr_triangle_line_imagespace_intersection_v2(
+ &rb->lock_task, (void *)rt, rl, c, rb->view_projection, rb->view_vector, &l, &r)) {
+ lanpr_cut_render_line(rb, rl, l, r);
+ if (rl->min_occ > rb->max_occlusion_level) {
+ return; /* No need to caluclate any longer. */
+ }
+ }
+ }
+
+ nba = lanpr_get_next_bounding_area(nba, rl, x, y, k, PositiveX, PositiveY, &x, &y);
+ }
+}
+static bool lanpr_calculation_is_canceled()
+{
+ bool is_canceled;
+ BLI_spin_lock(&lanpr_share.lock_render_status);
+ switch (lanpr_share.flag_render_status) {
+ case LANPR_RENDER_INCOMPELTE:
+ is_canceled = true;
+ default:
+ is_canceled = false;
+ }
+ BLI_spin_unlock(&lanpr_share.lock_render_status);
+ return is_canceled;
+}
+static void lanpr_calculate_line_occlusion_worker(TaskPool *__restrict UNUSED(pool),
+ LANPR_RenderTaskInfo *rti,
+ int UNUSED(threadid))
+{
+ LANPR_RenderBuffer *rb = lanpr_share.render_buffer_shared;
+ LinkData *lip;
+
+ while (lanpr_make_next_occlusion_task_info(rb, rti)) {
+
+ for (lip = (void *)rti->contour; lip && lip->prev != rti->contour_pointers.last;
+ lip = lip->next) {
+ lanpr_calculate_single_line_occlusion(rb, lip->data, rti->thread_id);
+ }
+
+ /* Monitoring cancelation flag every once a while. */
+ if (lanpr_calculation_is_canceled())
+ return;
+
+ for (lip = (void *)rti->crease; lip && lip->prev != rti->crease_pointers.last;
+ lip = lip->next) {
+ lanpr_calculate_single_line_occlusion(rb, lip->data, rti->thread_id);
+ }
+
+ if (lanpr_calculation_is_canceled())
+ return;
+
+ for (lip = (void *)rti->intersection; lip && lip->prev != rti->intersection_pointers.last;
+ lip = lip->next) {
+ lanpr_calculate_single_line_occlusion(rb, lip->data, rti->thread_id);
+ }
+
+ if (lanpr_calculation_is_canceled())
+ return;
+
+ for (lip = (void *)rti->material; lip && lip->prev != rti->material_pointers.last;
+ lip = lip->next) {
+ lanpr_calculate_single_line_occlusion(rb, lip->data, rti->thread_id);
+ }
+
+ if (lanpr_calculation_is_canceled())
+ return;
+
+ for (lip = (void *)rti->edge_mark; lip && lip->prev != rti->edge_mark_pointers.last;
+ lip = lip->next) {
+ lanpr_calculate_single_line_occlusion(rb, lip->data, rti->thread_id);
+ }
+
+ if (lanpr_calculation_is_canceled())
+ return;
+ }
+}
+static void lanpr_calculate_line_occlusion_begin(LANPR_RenderBuffer *rb)
+{
+ int thread_count = rb->thread_count;
+ LANPR_RenderTaskInfo *rti = MEM_callocN(sizeof(LANPR_RenderTaskInfo) * thread_count,
+ "Task Pool");
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ int i;
+
+ rb->contour_managed = rb->contours.first;
+ rb->crease_managed = rb->crease_lines.first;
+ rb->intersection_managed = rb->intersection_lines.first;
+ rb->material_managed = rb->material_lines.first;
+ rb->edge_mark_managed = rb->edge_marks.first;
+
+ TaskPool *tp = BLI_task_pool_create(scheduler, 0);
+
+ for (i = 0; i < thread_count; i++) {
+ rti[i].thread_id = i;
+ BLI_task_pool_push(tp,
+ (TaskRunFunction)lanpr_calculate_line_occlusion_worker,
+ &rti[i],
+ 0,
+ TASK_PRIORITY_HIGH);
+ }
+ BLI_task_pool_work_and_wait(tp);
+ BLI_task_pool_free(tp);
+
+ MEM_freeN(rti);
+}
+
+int ED_lanpr_point_inside_triangled(tnsVector2d v, tnsVector2d v0, tnsVector2d v1, tnsVector2d v2)
+{
+ double cl, c;
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ c = cl;
+
+ cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
+ if (c * cl <= 0) {
+ return 0;
+ }
+ else
+ c = cl;
+
+ cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
+ if (c * cl <= 0) {
+ return 0;
+ }
+ else
+ c = cl;
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ if (c * cl <= 0) {
+ return 0;
+ }
+
+ return 1;
+}
+static int lanpr_point_on_lined(tnsVector2d v, tnsVector2d v0, tnsVector2d v1)
+{
+ real c1, c2;
+
+ c1 = tMatGetLinearRatio(v0[0], v1[0], v[0]);
+ c2 = tMatGetLinearRatio(v0[1], v1[1], v[1]);
+
+ if (TNS_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
+ return 1;
+ }
+
+ return 0;
+}
+static int lanpr_point_triangle_relation(tnsVector2d v,
+ tnsVector2d v0,
+ tnsVector2d v1,
+ tnsVector2d v2)
+{
+ double cl, c;
+ real r;
+ if (lanpr_point_on_lined(v, v0, v1) || lanpr_point_on_lined(v, v1, v2) ||
+ lanpr_point_on_lined(v, v2, v0)) {
+ return 1;
+ }
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ c = cl;
+
+ cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
+ if ((r = c * cl) < 0) {
+ return 0;
+ }
+ /* else if(r == 0) return 1; // removed, point could still be on the extention line of some edge
+ */
+ else
+ c = cl;
+
+ cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
+ if ((r = c * cl) < 0) {
+ return 0;
+ }
+ /* else if(r == 0) return 1; */
+ else
+ c = cl;
+
+ cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
+ if ((r = c * cl) < 0) {
+ return 0;
+ }
+ else if (r == 0) {
+ return 1;
+ }
+
+ return 2;
+}
+static int lanpr_point_inside_triangle3de(tnsVector3d v,
+ tnsVector3d v0,
+ tnsVector3d v1,
+ tnsVector3d v2)
+{
+ tnsVector3d l, r;
+ tnsVector3d N1, N2;
+ real d;
+
+ sub_v3_v3v3_db(l, v1, v0);
+ sub_v3_v3v3_db(r, v, v1);
+ /* tmat_normalize_self_3d(l); */
+ /* tmat_normalize_self_3d(r); */
+ cross_v3_v3v3_db(N1, l, r);
+
+ sub_v3_v3v3_db(l, v2, v1);
+ sub_v3_v3v3_db(r, v, v2);
+ /* tmat_normalize_self_3d(l); */
+ /* tmat_normalize_self_3d(r); */
+ cross_v3_v3v3_db(N2, l, r);
+
+ if ((d = dot_v3v3_db(N1, N2)) < 0) {
+ return 0;
+ }
+ /* if (d<DBL_EPSILON) return -1; */
+
+ sub_v3_v3v3_db(l, v0, v2);
+ sub_v3_v3v3_db(r, v, v0);
+ /* tmat_normalize_self_3d(l); */
+ /* tmat_normalize_self_3d(r); */
+ cross_v3_v3v3_db(N1, l, r);
+
+ if ((d = dot_v3v3_db(N1, N2)) < 0) {
+ return 0;
+ }
+ /* if (d<DBL_EPSILON) return -1; */
+
+ sub_v3_v3v3_db(l, v1, v0);
+ sub_v3_v3v3_db(r, v, v1);
+ /* tmat_normalize_self_3d(l); */
+ /* tmat_normalize_self_3d(r); */
+ cross_v3_v3v3_db(N2, l, r);
+
+ if ((d = dot_v3v3_db(N1, N2)) < 0) {
+ return 0;
+ }
+ /* if (d<DBL_EPSILON) return -1; */
+
+ return 1;
+}
+
+static LANPR_RenderElementLinkNode *lanpr_new_cull_triangle_space64(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderElementLinkNode *reln;
+
+ LANPR_RenderTriangle *RenderTriangles = mem_static_aquire(
+ &rb->render_data_pool,
+ 64 * rb->triangle_size); /* CreateNewBuffer(LANPR_RenderTriangle, 64); */
+
+ reln = list_append_pointer_static_sized(&rb->triangle_buffer_pointers,
+ &rb->render_data_pool,
+ RenderTriangles,
+ sizeof(LANPR_RenderElementLinkNode));
+ reln->element_count = 64;
+ reln->additional = 1;
+
+ return reln;
+}
+static LANPR_RenderElementLinkNode *lanpr_new_cull_point_space64(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderElementLinkNode *reln;
+
+ LANPR_RenderVert *Rendervertices = mem_static_aquire(
+ &rb->render_data_pool,
+ sizeof(LANPR_RenderVert) * 64); /* CreateNewBuffer(LANPR_RenderVert, 64); */
+
+ reln = list_append_pointer_static_sized(&rb->vertex_buffer_pointers,
+ &rb->render_data_pool,
+ Rendervertices,
+ sizeof(LANPR_RenderElementLinkNode));
+ reln->element_count = 64;
+ reln->additional = 1;
+
+ return reln;
+}
+static void lanpr_assign_render_line_with_triangle(LANPR_RenderTriangle *rt)
+{
+ if (!rt->rl[0]->tl) {
+ rt->rl[0]->tl = rt;
+ }
+ else if (!rt->rl[0]->tr) {
+ rt->rl[0]->tr = rt;
+ }
+
+ if (!rt->rl[1]->tl) {
+ rt->rl[1]->tl = rt;
+ }
+ else if (!rt->rl[1]->tr) {
+ rt->rl[1]->tr = rt;
+ }
+
+ if (!rt->rl[2]->tl) {
+ rt->rl[2]->tl = rt;
+ }
+ else if (!rt->rl[2]->tr) {
+ rt->rl[2]->tr = rt;
+ }
+}
+static void lanpr_post_triangle(LANPR_RenderTriangle *rt, LANPR_RenderTriangle *orig)
+{
+ if (rt->v[0]) {
+ add_v3_v3_db(rt->gc, rt->v[0]->fbcoord);
+ }
+ if (rt->v[1]) {
+ add_v3_v3_db(rt->gc, rt->v[1]->fbcoord);
+ }
+ if (rt->v[2]) {
+ add_v3_v3_db(rt->gc, rt->v[2]->fbcoord);
+ }
+ mul_v3db_db(rt->gc, 1.0f / 3.0f);
+
+ copy_v3_v3_db(rt->gn, orig->gn);
+}
+
+#define RT_AT(head, rb, offset) ((unsigned char *)head + offset * rb->triangle_size)
+
+static void lanpr_cull_triangles(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLine *rl;
+ LANPR_RenderTriangle *rt, *rt1, *rt2;
+ LANPR_RenderVert *rv;
+ LANPR_RenderElementLinkNode *reln, *veln, *teln;
+ LANPR_RenderLineSegment *rls;
+ double **vp = rb->view_projection;
+ int i;
+ real a;
+ int v_count = 0, t_count = 0;
+ Object *o;
+
+ real cam_pos[3];
+ Object *cam = ((Object *)rb->scene->camera);
+ cam_pos[0] = cam->obmat[3][0];
+ cam_pos[1] = cam->obmat[3][1];
+ cam_pos[2] = cam->obmat[3][2];
+
+ real view_dir[3], clip_advance[3];
+ copy_v3_v3_db(view_dir, rb->view_vector);
+ copy_v3_v3_db(clip_advance, rb->view_vector);
+ mul_v3db_db(clip_advance, -((Camera *)cam->data)->clip_start);
+ add_v3_v3_db(cam_pos, clip_advance);
+
+ veln = lanpr_new_cull_point_space64(rb);
+ teln = lanpr_new_cull_triangle_space64(rb);
+ rv = &((LANPR_RenderVert *)veln->pointer)[v_count];
+ rt1 = (void *)(((unsigned char *)teln->pointer) + rb->triangle_size * t_count);
+
+ for (reln = rb->triangle_buffer_pointers.first; reln; reln = reln->next) {
+ if (reln->additional) {
+ continue;
+ }
+ o = reln->object_ref;
+ for (i = 0; i < reln->element_count; i++) {
+ int In1 = 0, In2 = 0, In3 = 0;
+ rt = (void *)(((unsigned char *)reln->pointer) + rb->triangle_size * i);
+ if (rt->v[0]->fbcoord[3] < ((Camera *)cam->data)->clip_start) {
+ In1 = 1;
+ }
+ if (rt->v[1]->fbcoord[3] < ((Camera *)cam->data)->clip_start) {
+ In2 = 1;
+ }
+ if (rt->v[2]->fbcoord[3] < ((Camera *)cam->data)->clip_start) {
+ In3 = 1;
+ }
+
+ if (v_count > 60) {
+ veln->element_count = v_count;
+ veln = lanpr_new_cull_point_space64(rb);
+ v_count = 0;
+ }
+
+ if (t_count > 60) {
+ teln->element_count = t_count;
+ teln = lanpr_new_cull_triangle_space64(rb);
+ t_count = 0;
+ }
+
+ /* if ((!rt->rl[0]->next && !rt->rl[0]->prev) || */
+ /* (!rt->rl[1]->next && !rt->rl[1]->prev) || */
+ /* (!rt->rl[2]->next && !rt->rl[2]->prev)) { */
+ /* printf("'"); // means this triangle is lonely???? */
+ /* } */
+
+ rv = &((LANPR_RenderVert *)veln->pointer)[v_count];
+ rt1 = (void *)(((unsigned char *)teln->pointer) + rb->triangle_size * t_count);
+ rt2 = (void *)(((unsigned char *)teln->pointer) + rb->triangle_size * (t_count + 1));
+
+ real vv1[3], vv2[3], dot1, dot2;
+
+ switch (In1 + In2 + In3) {
+ case 0:
+ continue;
+ case 3:
+ rt->cull_status = LANPR_CULL_DISCARD;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[0]);
+ rt->rl[0]->next = rt->rl[0]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[1]);
+ rt->rl[1]->next = rt->rl[1]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[2]);
+ rt->rl[2]->next = rt->rl[2]->prev = 0;
+ continue;
+ case 2:
+ rt->cull_status = LANPR_CULL_USED;
+ if (!In1) {
+ sub_v3_v3v3_db(vv1, rt->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[2]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[0]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+
+ sub_v3_v3v3_db(vv1, rt->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[1]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[0]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[0]);
+ rt->rl[0]->next = rt->rl[0]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[1]);
+ rt->rl[1]->next = rt->rl[1]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[2]);
+ rt->rl[2]->next = rt->rl[2]->prev = 0;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rt1->rl[1] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = rt->v[0];
+ rl->tl = rt->rl[0]->tl == rt ? rt1 : rt->rl[0]->tl;
+ rl->tr = rt->rl[0]->tr == rt ? rt1 : rt->rl[0]->tr;
+ rt1->rl[0] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[0];
+ rl->r = &rv[0];
+ rl->tl = rt->rl[2]->tl == rt ? rt1 : rt->rl[2]->tl;
+ rl->tr = rt->rl[2]->tr == rt ? rt1 : rt->rl[2]->tr;
+ rt1->rl[2] = rl;
+ rl->object_ref = o;
+
+ rt1->v[0] = rt->v[0];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ lanpr_post_triangle(rt1, rt);
+
+ v_count += 2;
+ t_count += 1;
+ continue;
+ }
+ else if (!In3) {
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[2]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[1]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[2]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[0]);
+ rt->rl[0]->next = rt->rl[0]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[1]);
+ rt->rl[1]->next = rt->rl[1]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[2]);
+ rt->rl[2]->next = rt->rl[2]->prev = 0;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[0];
+ rl->r = &rv[1];
+ rl->tl = rt1;
+ rt1->rl[0] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = rt->v[2];
+ rl->tl = rt->rl[1]->tl == rt ? rt1 : rt->rl[1]->tl;
+ rl->tr = rt->rl[1]->tr == rt ? rt1 : rt->rl[1]->tr;
+ rt1->rl[1] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[2];
+ rl->r = &rv[0];
+ rl->tl = rt->rl[2]->tl == rt ? rt1 : rt->rl[2]->tl;
+ rl->tr = rt->rl[2]->tr == rt ? rt1 : rt->rl[2]->tr;
+ rt1->rl[2] = rl;
+ rl->object_ref = o;
+
+ rt1->v[0] = &rv[1];
+ rt1->v[1] = rt->v[2];
+ rt1->v[2] = &rv[0];
+
+ lanpr_post_triangle(rt1, rt);
+
+ v_count += 2;
+ t_count += 1;
+ continue;
+ }
+ else if (!In2) {
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[2]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[1]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[1]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[0]);
+ rt->rl[0]->next = rt->rl[0]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[1]);
+ rt->rl[1]->next = rt->rl[1]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[2]);
+ rt->rl[2]->next = rt->rl[2]->prev = 0;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rt1->rl[2] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[0];
+ rl->r = rt->v[1];
+ rl->tl = rt->rl[0]->tl == rt ? rt1 : rt->rl[0]->tl;
+ rl->tr = rt->rl[0]->tr == rt ? rt1 : rt->rl[0]->tr;
+ rt1->rl[0] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[1];
+ rl->r = &rv[1];
+ rl->tl = rt->rl[1]->tl == rt ? rt1 : rt->rl[1]->tl;
+ rl->tr = rt->rl[1]->tr == rt ? rt1 : rt->rl[1]->tr;
+ rt1->rl[1] = rl;
+ rl->object_ref = o;
+
+ rt1->v[0] = rt->v[1];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ lanpr_post_triangle(rt1, rt);
+
+ v_count += 2;
+ t_count += 1;
+ continue;
+ }
+ break;
+ case 1:
+ rt->cull_status = LANPR_CULL_USED;
+ if (In1) {
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot2 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[0]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot2 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[0]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[0]);
+ rt->rl[0]->next = rt->rl[0]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[2]);
+ rt->rl[2]->next = rt->rl[2]->prev = 0;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rt1->rl[1] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[0];
+ rl->r = rt->v[1];
+ rl->tl = rt1;
+ rl->tr = rt->rl[0]->tr == rt ? rt->rl[0]->tl : rt->rl[0]->tr;
+ rt1->rl[2] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[1];
+ rl->r = &rv[1];
+ rl->tl = rt1;
+ rl->tr = rt2;
+ rt1->rl[0] = rl;
+ rt2->rl[0] = rl;
+ rl->object_ref = o;
+
+ rt1->v[0] = rt->v[1];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[2];
+ rl->r = &rv[1];
+ rl->tl = rt2;
+ rl->tr = rt->rl[2]->tr == rt ? rt->rl[2]->tl : rt->rl[2]->tr;
+ rt2->rl[2] = rl;
+ rt2->rl[1] = rt->rl[1];
+ rl->object_ref = o;
+
+ rt2->v[0] = &rv[1];
+ rt2->v[1] = rt->v[1];
+ rt2->v[2] = rt->v[2];
+
+ lanpr_post_triangle(rt1, rt);
+ lanpr_post_triangle(rt2, rt);
+
+ v_count += 2;
+ t_count += 2;
+ continue;
+ }
+ else if (In2) {
+
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[2]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[1]->gloc, rt->v[2]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+
+ sub_v3_v3v3_db(vv1, rt->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[1]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[0]);
+ rt->rl[0]->next = rt->rl[0]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[1]);
+ rt->rl[1]->next = rt->rl[1]->prev = 0;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rt1->rl[1] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[0];
+ rl->r = rt->v[2];
+ rl->tl = rt1;
+ rl->tr = rt->rl[1]->tl == rt ? rt->rl[1]->tr : rt->rl[1]->tl;
+ rt1->rl[2] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[2];
+ rl->r = &rv[1];
+ rl->tl = rt1;
+ rl->tr = rt2;
+ rt1->rl[0] = rl;
+ rt2->rl[0] = rl;
+ rl->object_ref = o;
+
+ rt1->v[0] = rt->v[2];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[0];
+ rl->r = &rv[1];
+ rl->tl = rt2;
+ rl->tr = rt->rl[0]->tr == rt ? rt->rl[0]->tl : rt->rl[0]->tr;
+ rt2->rl[2] = rl;
+ rt2->rl[1] = rt->rl[2];
+ rl->object_ref = o;
+
+ rt2->v[0] = &rv[1];
+ rt2->v[1] = rt->v[2];
+ rt2->v[2] = rt->v[0];
+
+ lanpr_post_triangle(rt1, rt);
+ lanpr_post_triangle(rt2, rt);
+
+ v_count += 2;
+ t_count += 2;
+ continue;
+ }
+ else if (In3) {
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[0]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[0].gloc, rt->v[2]->gloc, rt->v[0]->gloc, a);
+ mul_v4_m4v3_db(rv[0].fbcoord, vp, rv[0].gloc);
+
+ sub_v3_v3v3_db(vv1, rt->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(vv2, cam_pos, rt->v[1]->gloc);
+ dot1 = dot_v3v3_db(vv1, view_dir);
+ dot2 = dot_v3v3_db(vv2, view_dir);
+ a = dot1 / (dot1 + dot2);
+ interp_v3_v3v3_db(rv[1].gloc, rt->v[2]->gloc, rt->v[1]->gloc, a);
+ mul_v4_m4v3_db(rv[1].fbcoord, vp, rv[1].gloc);
+
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[1]);
+ rt->rl[1]->next = rt->rl[1]->prev = 0;
+ BLI_remlink(&rb->all_render_lines, (void *)rt->rl[2]);
+ rt->rl[2]->next = rt->rl[2]->prev = 0;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[1];
+ rl->r = &rv[0];
+ rl->tl = rt1;
+ rt1->rl[1] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = &rv[0];
+ rl->r = rt->v[0];
+ rl->tl = rt1;
+ rl->tr = rt->rl[2]->tl == rt ? rt->rl[2]->tr : rt->rl[2]->tl;
+ rt1->rl[2] = rl;
+ rl->object_ref = o;
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[0];
+ rl->r = &rv[1];
+ rl->tl = rt1;
+ rl->tr = rt2;
+ rt1->rl[0] = rl;
+ rt2->rl[0] = rl;
+ rl->object_ref = o;
+
+ rt1->v[0] = rt->v[0];
+ rt1->v[1] = &rv[1];
+ rt1->v[2] = &rv[0];
+
+ rl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ rls = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ BLI_addtail(&rb->all_render_lines, rl);
+ rl->l = rt->v[1];
+ rl->r = &rv[1];
+ rl->tl = rt2;
+ rl->tr = rt->rl[1]->tr == rt ? rt->rl[1]->tl : rt->rl[1]->tr;
+ rt2->rl[2] = rl;
+ rt2->rl[1] = rt->rl[0];
+ rl->object_ref = o;
+
+ rt2->v[0] = &rv[1];
+ rt2->v[1] = rt->v[0];
+ rt2->v[2] = rt->v[1];
+
+ lanpr_post_triangle(rt1, rt);
+ lanpr_post_triangle(rt2, rt);
+
+ v_count += 2;
+ t_count += 2;
+ continue;
+ }
+ break;
+ }
+ }
+ teln->element_count = t_count;
+ veln->element_count = v_count;
+ }
+}
+static void lanpr_perspective_division(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderVert *rv;
+ LANPR_RenderElementLinkNode *reln;
+ Camera *cam = rb->scene->camera->data;
+ int i;
+
+ if (cam->type != CAM_PERSP) {
+ return;
+ }
+
+ for (reln = rb->vertex_buffer_pointers.first; reln; reln = reln->next) {
+ rv = reln->pointer;
+ for (i = 0; i < reln->element_count; i++) {
+ /* if (rv->fbcoord[2] < -DBL_EPSILON) continue; */
+ mul_v3db_db(rv[i].fbcoord, 1 / rv[i].fbcoord[3]);
+ /* rv[i].fbcoord[2] = cam->clipsta * cam->clipend / (cam->clipend - */
+ /* fabs(rv[i].fbcoord[2]) * (cam->clipend - cam->clipsta)); */
+
+ rv[i].fbcoord[0] -= cam->shiftx * 2;
+ rv[i].fbcoord[1] -= cam->shifty * 2;
+ }
+ }
+}
+
+static void lanpr_transform_render_vert(BMVert *v,
+ int index,
+ LANPR_RenderVert *RvBuf,
+ double (*MvMat)[4],
+ double (*MvPMat)[4],
+ Camera *UNUSED(camera))
+{
+ double co[4];
+ LANPR_RenderVert *rv = &RvBuf[index];
+ copy_v3db_v3fl(co, v->co);
+ mul_v3_m4v3_db(rv->gloc, MvMat, co);
+ mul_v4_m4v3_db(rv->fbcoord, MvPMat, co);
+}
+
+static void lanpr_make_render_geometry_buffers_object(
+ Object *o, double (*MvMat)[4], double (*MvPMat)[4], LANPR_RenderBuffer *rb, int override_usage)
+{
+ BMesh *bm;
+ BMVert *v;
+ BMFace *f;
+ BMEdge *e;
+ BMLoop *loop;
+ LANPR_RenderLine *rl;
+ LANPR_RenderTriangle *rt;
+ double new_mvp[4][4], new_mv[4][4], Normal[4][4];
+ LANPR_RenderElementLinkNode *reln;
+ Object *cam_object = rb->scene->camera;
+ Camera *c = cam_object->data;
+ LANPR_RenderVert *orv;
+ LANPR_RenderLine *orl;
+ LANPR_RenderTriangle *ort;
+ LanprEdge *fe;
+ int CanFindFreestyle = 0;
+ int i;
+
+ int usage = override_usage ? override_usage : o->lanpr.usage;
+
+ if (usage == OBJECT_FEATURE_LINE_EXCLUDE) {
+ return;
+ }
+
+ if (o->type == OB_MESH) {
+
+ mul_m4db_m4db_m4fl_uniq(new_mvp, MvPMat, o->obmat);
+ mul_m4db_m4db_m4fl_uniq(new_mv, MvMat, o->obmat);
+
+ invert_m4_m4(o->imat, o->obmat);
+ transpose_m4(o->imat);
+ copy_m4d_m4(Normal, o->imat);
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(((Mesh *)(o->data)));
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+ BM_mesh_bm_from_me(bm,
+ o->data,
+ &((struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false);
+ BM_mesh_triangulate(
+ bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_BEAUTY, 4, false, NULL, NULL, NULL);
+ BM_mesh_normals_update(bm);
+ BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
+
+ if (CustomData_has_layer(&bm->edata, CD_LANPR_EDGE)) {
+ CanFindFreestyle = 1;
+ }
+
+ orv = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderVert) * bm->totvert);
+ ort = mem_static_aquire(&rb->render_data_pool, bm->totface * rb->triangle_size);
+ orl = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine) * bm->totedge);
+
+ reln = list_append_pointer_static_sized(&rb->vertex_buffer_pointers,
+ &rb->render_data_pool,
+ orv,
+ sizeof(LANPR_RenderElementLinkNode));
+ reln->element_count = bm->totvert;
+ reln->object_ref = o;
+
+ reln = list_append_pointer_static_sized(&rb->line_buffer_pointers,
+ &rb->render_data_pool,
+ orl,
+ sizeof(LANPR_RenderElementLinkNode));
+ reln->element_count = bm->totedge;
+ reln->object_ref = o;
+
+ reln = list_append_pointer_static_sized(&rb->triangle_buffer_pointers,
+ &rb->render_data_pool,
+ ort,
+ sizeof(LANPR_RenderElementLinkNode));
+ reln->element_count = bm->totface;
+ reln->object_ref = o;
+
+ for (i = 0; i < bm->totvert; i++) {
+ v = BM_vert_at_index(bm, i);
+ lanpr_transform_render_vert(v, i, orv, new_mv, new_mvp, c);
+ }
+
+ rl = orl;
+ for (i = 0; i < bm->totedge; i++) {
+ e = BM_edge_at_index(bm, i);
+ if (CanFindFreestyle) {
+ fe = CustomData_bmesh_get(&bm->edata, e->head.data, CD_LANPR_EDGE);
+ if (fe->flag & LANPR_EDGE_MARK) {
+ rl->flags |= LANPR_EDGE_FLAG_EDGE_MARK;
+ }
+ }
+ if (use_smooth_contour_modifier_contour) {
+ rl->edge_idx = i;
+ if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT)) {
+ rl->flags |= LANPR_EDGE_FLAG_CONTOUR;
+ }
+ }
+
+ rl->l = &orv[BM_elem_index_get(e->v1)];
+ rl->r = &orv[BM_elem_index_get(e->v2)];
+
+ rl->object_ref = o;
+
+ LANPR_RenderLineSegment *rls = mem_static_aquire(&rb->render_data_pool,
+ sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&rl->segments, rls);
+ if (usage == OBJECT_FEATURE_LINE_INHERENT) {
+ BLI_addtail(&rb->all_render_lines, rl);
+ }
+ rl++;
+ }
+
+ rt = ort;
+ for (i = 0; i < bm->totface; i++) {
+ f = BM_face_at_index(bm, i);
+
+ loop = f->l_first;
+ rt->v[0] = &orv[BM_elem_index_get(loop->v)];
+ rt->rl[0] = &orl[BM_elem_index_get(loop->e)];
+ loop = loop->next;
+ rt->v[1] = &orv[BM_elem_index_get(loop->v)];
+ rt->rl[1] = &orl[BM_elem_index_get(loop->e)];
+ loop = loop->next;
+ rt->v[2] = &orv[BM_elem_index_get(loop->v)];
+ rt->rl[2] = &orl[BM_elem_index_get(loop->e)];
+
+ rt->material_id = f->mat_nr;
+
+ add_v3_v3_db(rt->gc, rt->v[0]->fbcoord);
+ add_v3_v3_db(rt->gc, rt->v[1]->fbcoord);
+ add_v3_v3_db(rt->gc, rt->v[2]->fbcoord);
+ mul_v3db_db(rt->gc, 1.0f / 3.0f);
+
+ double gn[3];
+ copy_v3db_v3fl(gn, f->no);
+ mul_v3_mat3_m4v3_db(rt->gn, Normal, gn);
+ normalize_v3_d(rt->gn);
+ lanpr_assign_render_line_with_triangle(rt);
+ /* m = tnsGetIndexedMaterial(rb->scene, f->material_id); */
+ /* if(m) m->Previewv_count += (f->triangle_count*3); */
+
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ rt->material_id = 1;
+ }
+
+ rt = (LANPR_RenderTriangle *)(((unsigned char *)rt) + rb->triangle_size);
+ }
+
+ BM_mesh_free(bm);
+ }
+}
+
+static int lanpr_object_has_feature_line_modifier(Object *o)
+{
+ ModifierData *md;
+ for (md = o->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_FeatureLine) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int ED_lanpr_object_collection_usage_check(Collection *c, Object *o)
+{
+ CollectionChild *cc;
+ int object_is_used = (lanpr_object_has_feature_line_modifier(o) &&
+ o->lanpr.usage == OBJECT_FEATURE_LINE_INHERENT);
+
+ if (object_is_used && c->lanpr.force && c->lanpr.usage != COLLECTION_FEATURE_LINE_INCLUDE) {
+ if (BKE_collection_has_object_recursive(c, o)) {
+ if (c->lanpr.usage == COLLECTION_FEATURE_LINE_EXCLUDE) {
+ return OBJECT_FEATURE_LINE_EXCLUDE;
+ }
+ else if (c->lanpr.usage == COLLECTION_FEATURE_LINE_OCCLUSION_ONLY) {
+ return OBJECT_FEATURE_LINE_OCCLUSION_ONLY;
+ }
+ }
+ }
+
+ if (!c->children.first) {
+ if (BKE_collection_has_object(c, o)) {
+ if (o->lanpr.usage == OBJECT_FEATURE_LINE_INHERENT) {
+ if (c->lanpr.usage == COLLECTION_FEATURE_LINE_OCCLUSION_ONLY) {
+ return OBJECT_FEATURE_LINE_OCCLUSION_ONLY;
+ }
+ else if (c->lanpr.usage == COLLECTION_FEATURE_LINE_EXCLUDE) {
+ return OBJECT_FEATURE_LINE_EXCLUDE;
+ }
+ else {
+ return OBJECT_FEATURE_LINE_INHERENT;
+ }
+ }
+ else {
+ return o->lanpr.usage;
+ }
+ }
+ else {
+ return OBJECT_FEATURE_LINE_INHERENT;
+ }
+ }
+
+ for (cc = c->children.first; cc; cc = cc->next) {
+ int result = ED_lanpr_object_collection_usage_check(cc->collection, o);
+ if (result > OBJECT_FEATURE_LINE_INHERENT) {
+ return result;
+ }
+ }
+
+ return OBJECT_FEATURE_LINE_INHERENT;
+}
+
+static void lanpr_make_render_geometry_buffers(Depsgraph *depsgraph,
+ Scene *s,
+ Object *c /*camera*/,
+ LANPR_RenderBuffer *rb)
+{
+ double proj[4][4], view[4][4], result[4][4];
+ float inv[4][4];
+ Camera *cam = c->data;
+
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ real fov = focallength_to_fov(cam->lens, sensor);
+
+ memset(rb->material_pointers, 0, sizeof(void *) * 2048);
+
+ real asp = ((real)rb->w / (real)rb->h);
+
+ if (cam->type == CAM_PERSP) {
+ tmat_make_perspective_matrix_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
+ }
+ else if (cam->type == CAM_ORTHO) {
+ real w = cam->ortho_scale / 2;
+ tmat_make_ortho_matrix_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
+ }
+
+ unit_m4_db(view);
+
+ /* tObjApplyself_transformMatrix(c, 0); */
+ /* tObjApplyGlobalTransformMatrixReverted(c); */
+ invert_m4_m4(inv, c->obmat);
+ mul_m4db_m4db_m4fl_uniq(result, proj, inv);
+ copy_m4_m4_db(proj, result);
+ copy_m4_m4_db(rb->view_projection, proj);
+
+ BLI_listbase_clear(&rb->triangle_buffer_pointers);
+ BLI_listbase_clear(&rb->vertex_buffer_pointers);
+
+ DEG_OBJECT_ITER_BEGIN (depsgraph,
+ o,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) {
+ int usage = ED_lanpr_object_collection_usage_check(s->master_collection, o);
+
+ lanpr_make_render_geometry_buffers_object(o, view, proj, rb, usage);
+ }
+ DEG_OBJECT_ITER_END;
+
+ /* for (collection = s->master_collection.first; collection; collection = collection->ID.next) {
+ */
+ /* for (co = collection->gobject.first; co; co = co->next) { */
+ /* //tObjApplyGlobalTransformMatrixRecursive(o); */
+ /* lanpr_make_render_geometry_buffers_object(o, view, proj, rb); */
+ /* } */
+ /* } */
+}
+
+#define INTERSECT_SORT_MIN_TO_MAX_3(ia, ib, ic, lst) \
+ { \
+ lst[0] = TNS_MIN3_INDEX(ia, ib, ic); \
+ lst[1] = (((ia <= ib && ib <= ic) || (ic <= ib && ib <= ia)) ? \
+ 1 : \
+ (((ic <= ia && ia <= ib) || (ib < ia && ia <= ic)) ? 0 : 2)); \
+ lst[2] = TNS_MAX3_INDEX(ia, ib, ic); \
+ }
+
+/* ia ib ic are ordered */
+#define INTERSECT_JUST_GREATER(is, order, num, index) \
+ { \
+ index = (num < is[order[0]] ? \
+ order[0] : \
+ (num < is[order[1]] ? order[1] : (num < is[order[2]] ? order[2] : order[2]))); \
+ }
+
+/* ia ib ic are ordered */
+#define INTERSECT_JUST_SMALLER(is, order, num, index) \
+ { \
+ index = (num > is[order[2]] ? \
+ order[2] : \
+ (num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : order[0]))); \
+ }
+
+static LANPR_RenderLine *lanpr_another_edge(LANPR_RenderTriangle *rt, LANPR_RenderVert *rv)
+{
+ if (rt->v[0] == rv) {
+ return rt->rl[1];
+ }
+ else if (rt->v[1] == rv) {
+ return rt->rl[2];
+ }
+ else if (rt->v[2] == rv) {
+ return rt->rl[0];
+ }
+ return 0;
+}
+static int lanpr_share_edge_direct(LANPR_RenderTriangle *rt, LANPR_RenderLine *rl)
+{
+ if (rt->rl[0] == rl || rt->rl[1] == rl || rt->rl[2] == rl) {
+ return 1;
+ }
+ return 0;
+}
+
+static int lanpr_triangle_line_imagespace_intersection_v2(SpinLock *UNUSED(spl),
+ LANPR_RenderTriangle *rt,
+ LANPR_RenderLine *rl,
+ Object *cam,
+ double vp[4][4],
+ double *CameraDir,
+ double *From,
+ double *To)
+{
+ double is[3] = {0};
+ int order[3];
+ int LCross = -1, RCross = -1;
+ int a, b, c;
+ int StL = 0, StR = 0;
+
+ tnsVector3d Lv;
+ tnsVector3d Rv;
+ tnsVector4d vd4;
+ real Cv[3];
+ real DotL, DotR, DotLA, DotRA;
+ real DotF;
+ tnsVector4d gloc, Trans;
+ real Cut = -1;
+
+ double *LFBC = rl->l->fbcoord, *RFBC = rl->r->fbcoord, *FBC0 = rt->v[0]->fbcoord,
+ *FBC1 = rt->v[1]->fbcoord, *FBC2 = rt->v[2]->fbcoord;
+
+ /* printf("(%f %f)(%f %f)(%f %f) (%f %f)(%f %f)\n", FBC0[0], FBC0[1], FBC1[0], FBC1[1], */
+ /* FBC2[0], FBC2[1], LFBC[0], LFBC[1], RFBC[0], RFBC[1]); */
+
+ /* bound box. */
+ /* if (MIN3(FBC0[2], FBC1[2], FBC2[2]) > MAX2(LFBC[2], RFBC[2])) */
+ /* return 0; */
+ if ((MAX3(FBC0[0], FBC1[0], FBC2[0]) < MIN2(LFBC[0], RFBC[0])) ||
+ (MIN3(FBC0[0], FBC1[0], FBC2[0]) > MAX2(LFBC[0], RFBC[0])) ||
+ (MAX3(FBC0[1], FBC1[1], FBC2[1]) < MIN2(LFBC[1], RFBC[1])) ||
+ (MIN3(FBC0[1], FBC1[1], FBC2[1]) > MAX2(LFBC[1], RFBC[1]))) {
+ return 0;
+ }
+
+ if (lanpr_share_edge_direct(rt, rl)) {
+ return 0;
+ }
+
+ a = lanpr_LineIntersectTest2d(LFBC, RFBC, FBC0, FBC1, &is[0]);
+ b = lanpr_LineIntersectTest2d(LFBC, RFBC, FBC1, FBC2, &is[1]);
+ c = lanpr_LineIntersectTest2d(LFBC, RFBC, FBC2, FBC0, &is[2]);
+
+ /* printf("abc: %d %d %d\n", a,b,c); */
+
+ INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order);
+
+ sub_v3_v3v3_db(Lv, rl->l->gloc, rt->v[0]->gloc);
+ sub_v3_v3v3_db(Rv, rl->r->gloc, rt->v[0]->gloc);
+
+ copy_v3_v3_db(Cv, CameraDir);
+
+ copy_v4db_v4fl(vd4, cam->obmat[3]);
+ if (((Camera *)cam->data)->type == CAM_PERSP) {
+ sub_v3_v3v3_db(Cv, vd4, rt->v[0]->gloc);
+ }
+
+ DotL = dot_v3v3_db(Lv, rt->gn);
+ DotR = dot_v3v3_db(Rv, rt->gn);
+ DotF = dot_v3v3_db(Cv, rt->gn);
+
+ if (!DotF) {
+ return 0;
+ }
+
+ if (!a && !b && !c) {
+ if (!(StL = lanpr_point_triangle_relation(LFBC, FBC0, FBC1, FBC2)) &&
+ !(StR = lanpr_point_triangle_relation(RFBC, FBC0, FBC1, FBC2))) {
+ return 0; /* not occluding */
+ }
+ }
+
+ StL = lanpr_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
+ StR = lanpr_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
+
+ /* for (rv = rt->intersecting_verts.first; rv; rv = rv->next) { */
+ /* if (rv->intersecting_with == rt && rv->intersecting_line == rl) { */
+ /* Cut = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], */
+ /* rv->fbcoord[0]); break; */
+ /* } */
+ /* } */
+
+ DotLA = fabs(DotL);
+ if (DotLA < DBL_EPSILON) {
+ DotLA = 0;
+ DotL = 0;
+ }
+ DotRA = fabs(DotR);
+ if (DotRA < DBL_EPSILON) {
+ DotRA = 0;
+ DotR = 0;
+ }
+ if (DotL - DotR == 0) {
+ Cut = 100000;
+ }
+ else if (DotL * DotR <= 0) {
+ Cut = DotLA / fabs(DotL - DotR);
+ }
+ else {
+ Cut = fabs(DotR + DotL) / fabs(DotL - DotR);
+ Cut = DotRA > DotLA ? 1 - Cut : Cut;
+ }
+
+ if (((Camera *)cam->data)->type == CAM_PERSP) {
+ interp_v3_v3v3_db(gloc, rl->l->gloc, rl->r->gloc, Cut);
+ mul_v4_m4v3_db(Trans, vp, gloc);
+ mul_v3db_db(Trans, (1 / Trans[3]) /**HeightMultiply/2*/);
+ Camera *camera = cam->data;
+ Trans[0] -= camera->shiftx * 2;
+ Trans[1] -= camera->shifty * 2;
+ }
+ else {
+ interp_v3_v3v3_db(Trans, rl->l->fbcoord, rl->r->fbcoord, Cut);
+ /* mul_v4_m4v3_db(Trans, vp, gloc); */
+ }
+
+ /* Trans[2] = tmat_dist_3dv(gloc, cam->Base.gloc); */
+ /* Trans[2] = cam->clipsta*cam->clipend / (cam->clipend - fabs(Trans[2]) * (cam->clipend - */
+ /* cam->clipsta)); */
+
+ /* prevent vertical problem ? */
+ if (rl->l->fbcoord[0] != rl->r->fbcoord[0]) {
+ Cut = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], Trans[0]);
+ }
+ else {
+ Cut = tMatGetLinearRatio(rl->l->fbcoord[1], rl->r->fbcoord[1], Trans[1]);
+ }
+
+ /*
+ In = ED_lanpr_point_inside_triangled(
+ Trans, rt->v[0]->fbcoord, rt->v[1]->fbcoord, rt->v[2]->fbcoord);
+ */
+ if (StL == 2) {
+ if (StR == 2) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (StR == 1) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (StR == 0) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 0, RCross);
+ }
+ }
+ else if (StL == 1) {
+ if (StR == 2) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (StR == 1) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (StR == 0) {
+ INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross);
+ if (TNS_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ }
+ else {
+ INTERSECT_JUST_SMALLER(is, order, -DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, -DBL_TRIANGLE_LIM, RCross);
+ }
+ }
+ }
+ else if (StL == 0) {
+ if (StR == 2) {
+ INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else if (StR == 1) {
+ INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
+ if (TNS_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ }
+ else {
+ INTERSECT_JUST_SMALLER(is, order, 1 + DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(is, order, 1 + DBL_TRIANGLE_LIM, RCross);
+ }
+ }
+ else if (StR == 0) {
+ INTERSECT_JUST_GREATER(is, order, 0, LCross);
+ if (TNS_ABC(LCross) && is[LCross] > 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ else {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ }
+ }
+
+ real LF = DotL * DotF, RF = DotR * DotF;
+ /* int CrossCount = a + b + c; */
+ /* if (CrossCount == 2) { */
+ /* INTERSECT_JUST_GREATER(is, order, 0, LCross); */
+ /* if (!TNS_ABC(LCross)) INTERSECT_JUST_GREATER(is, order, is[LCross], LCross); */
+ /* INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); */
+ /* }else if(CrossCount == 1 || StL+StR==1) { */
+ /* if (StL) { */
+ /* INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross); */
+ /* INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross); */
+ /* }else if(StR) { */
+ /* INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross); */
+ /* INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); */
+ /* } */
+ /* }else if(CrossCount == 0) { */
+ /* INTERSECT_JUST_SMALLER(is, order, 0, LCross); */
+ /* INTERSECT_JUST_GREATER(is, order, 1, RCross); */
+ /* } */
+
+ if (LF <= 0 && RF <= 0 && (DotL || DotR)) {
+
+ *From = MAX2(0, is[LCross]);
+ *To = MIN2(1, is[RCross]);
+ if (*From >= *To) {
+ return 0;
+ }
+ /* printf("1 From %f to %f\n",*From, *To); */
+ return 1;
+ }
+ else if (LF >= 0 && RF <= 0 && (DotL || DotR)) {
+ *From = MAX2(Cut, is[LCross]);
+ *To = MIN2(1, is[RCross]);
+ if (*From >= *To) {
+ return 0;
+ }
+ /* printf("2 From %f to %f\n",*From, *To); */
+ return 1;
+ }
+ else if (LF <= 0 && RF >= 0 && (DotL || DotR)) {
+ *From = MAX2(0, is[LCross]);
+ *To = MIN2(Cut, is[RCross]);
+ if (*From >= *To) {
+ return 0;
+ }
+ /* printf("3 From %f to %f\n",*From, *To); */
+ return 1;
+ }
+ else
+ return 0;
+ return 1;
+}
+
+static LANPR_RenderLine *lanpr_triangle_share_edge(LANPR_RenderTriangle *l,
+ LANPR_RenderTriangle *r)
+{
+ if (l->rl[0] == r->rl[0]) {
+ return r->rl[0];
+ }
+ if (l->rl[0] == r->rl[1]) {
+ return r->rl[1];
+ }
+ if (l->rl[0] == r->rl[2]) {
+ return r->rl[2];
+ }
+ if (l->rl[1] == r->rl[0]) {
+ return r->rl[0];
+ }
+ if (l->rl[1] == r->rl[1]) {
+ return r->rl[1];
+ }
+ if (l->rl[1] == r->rl[2]) {
+ return r->rl[2];
+ }
+ if (l->rl[2] == r->rl[0]) {
+ return r->rl[0];
+ }
+ if (l->rl[2] == r->rl[1]) {
+ return r->rl[1];
+ }
+ if (l->rl[2] == r->rl[2]) {
+ return r->rl[2];
+ }
+ return 0;
+}
+static LANPR_RenderVert *lanpr_triangle_share_point(LANPR_RenderTriangle *l,
+ LANPR_RenderTriangle *r)
+{
+ if (l->v[0] == r->v[0]) {
+ return r->v[0];
+ }
+ if (l->v[0] == r->v[1]) {
+ return r->v[1];
+ }
+ if (l->v[0] == r->v[2]) {
+ return r->v[2];
+ }
+ if (l->v[1] == r->v[0]) {
+ return r->v[0];
+ }
+ if (l->v[1] == r->v[1]) {
+ return r->v[1];
+ }
+ if (l->v[1] == r->v[2]) {
+ return r->v[2];
+ }
+ if (l->v[2] == r->v[0]) {
+ return r->v[0];
+ }
+ if (l->v[2] == r->v[1]) {
+ return r->v[1];
+ }
+ if (l->v[2] == r->v[2]) {
+ return r->v[2];
+ }
+ return 0;
+}
+
+static LANPR_RenderVert *lanpr_triangle_line_intersection_test(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl,
+ LANPR_RenderTriangle *rt,
+ LANPR_RenderTriangle *testing,
+ LANPR_RenderVert *Last)
+{
+ tnsVector3d Lv;
+ tnsVector3d Rv;
+ real DotL, DotR;
+ LANPR_RenderVert *Result, *rv;
+ tnsVector3d gloc;
+ LANPR_RenderVert *l = rl->l, *r = rl->r;
+ int result;
+
+ for (rv = testing->intersecting_verts.first; rv; rv = rv->next) {
+ if (rv->intersecting_with == rt && rv->intersecting_line == rl) {
+ return rv;
+ }
+ }
+
+ sub_v3_v3v3_db(Lv, l->gloc, testing->v[0]->gloc);
+ sub_v3_v3v3_db(Rv, r->gloc, testing->v[0]->gloc);
+
+ DotL = dot_v3v3_db(Lv, testing->gn);
+ DotR = dot_v3v3_db(Rv, testing->gn);
+
+ if (DotL * DotR > 0 || (!DotL && !DotR)) {
+ return 0;
+ }
+
+ DotL = fabs(DotL);
+ DotR = fabs(DotR);
+
+ interp_v3_v3v3_db(gloc, l->gloc, r->gloc, DotL / (DotL + DotR));
+
+ if (Last && TNS_DOUBLE_CLOSE_ENOUGH(Last->gloc[0], gloc[0]) &&
+ TNS_DOUBLE_CLOSE_ENOUGH(Last->gloc[1], gloc[1]) &&
+ TNS_DOUBLE_CLOSE_ENOUGH(Last->gloc[2], gloc[2])) {
+
+ Last->intersecting_line2 = rl;
+ return 0;
+ }
+
+ if (!(result = lanpr_point_inside_triangle3de(
+ gloc, testing->v[0]->gloc, testing->v[1]->gloc, testing->v[2]->gloc))) {
+ return 0;
+ }
+ /*else if(result < 0) {
+ return 0;
+ }*/
+
+ Result = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderVert));
+
+ if (DotL > 0 || DotR < 0) {
+ Result->positive = 1;
+ }
+ else {
+ Result->positive = 0;
+ }
+
+ /* Result->IntersectingOnFace = testing; */
+ Result->edge_used = 1;
+ /* Result->IntersectL = l; */
+ Result->v = (void *)r; /* Caution! */
+ /* Result->intersecting_with = rt; */
+ copy_v3_v3_db(Result->gloc, gloc);
+
+ BLI_addtail(&testing->intersecting_verts, Result);
+
+ return Result;
+}
+static LANPR_RenderLine *lanpr_triangle_generate_intersection_line_only(
+ LANPR_RenderBuffer *rb, LANPR_RenderTriangle *rt, LANPR_RenderTriangle *testing)
+{
+ LANPR_RenderVert *l = 0, *r = 0;
+ LANPR_RenderVert **Next = &l;
+ LANPR_RenderLine *Result;
+ LANPR_RenderVert *E0T = 0;
+ LANPR_RenderVert *E1T = 0;
+ LANPR_RenderVert *E2T = 0;
+ LANPR_RenderVert *TE0 = 0;
+ LANPR_RenderVert *TE1 = 0;
+ LANPR_RenderVert *TE2 = 0;
+ tnsVector3d cl; /* rb->scene->ActiveCamera->gloc; */
+ real ZMax = ((Camera *)rb->scene->camera->data)->clip_end;
+ real ZMin = ((Camera *)rb->scene->camera->data)->clip_start;
+ LANPR_RenderVert *Share = lanpr_triangle_share_point(testing, rt);
+ Camera *cam = rb->scene->camera->data;
+
+ copy_v3db_v3fl(cl, rb->scene->camera->obmat[3]);
+
+ if (Share) {
+ LANPR_RenderVert *NewShare;
+ LANPR_RenderLine *rl = lanpr_another_edge(rt, Share);
+
+ l = NewShare = mem_static_aquire(&rb->render_data_pool, (sizeof(LANPR_RenderVert)));
+
+ NewShare->positive = 1;
+ NewShare->edge_used = 1;
+ /* NewShare->IntersectL = l; */
+ NewShare->v = (void *)r; /* Caution! */
+ /* Result->intersecting_with = rt; */
+ copy_v3_v3_db(NewShare->gloc, Share->gloc);
+
+ r = lanpr_triangle_line_intersection_test(rb, rl, rt, testing, 0);
+
+ if (!r) {
+ rl = lanpr_another_edge(testing, Share);
+ r = lanpr_triangle_line_intersection_test(rb, rl, testing, rt, 0);
+ if (!r) {
+ return 0;
+ }
+ BLI_addtail(&testing->intersecting_verts, NewShare);
+ }
+ else {
+ BLI_addtail(&rt->intersecting_verts, NewShare);
+ }
+ }
+ else {
+ if (!rt->rl[0] || !rt->rl[1] || !rt->rl[2]) {
+ return 0; /* shouldn't need this, there must be problems in culling. */
+ }
+ E0T = lanpr_triangle_line_intersection_test(rb, rt->rl[0], rt, testing, 0);
+ if (E0T && (!(*Next))) {
+ (*Next) = E0T;
+ (*Next)->intersecting_line = rt->rl[0];
+ Next = &r;
+ }
+ E1T = lanpr_triangle_line_intersection_test(rb, rt->rl[1], rt, testing, l);
+ if (E1T && (!(*Next))) {
+ (*Next) = E1T;
+ (*Next)->intersecting_line = rt->rl[1];
+ Next = &r;
+ }
+ if (!(*Next)) {
+ E2T = lanpr_triangle_line_intersection_test(rb, rt->rl[2], rt, testing, l);
+ }
+ if (E2T && (!(*Next))) {
+ (*Next) = E2T;
+ (*Next)->intersecting_line = rt->rl[2];
+ Next = &r;
+ }
+
+ if (!(*Next)) {
+ TE0 = lanpr_triangle_line_intersection_test(rb, testing->rl[0], testing, rt, l);
+ }
+ if (TE0 && (!(*Next))) {
+ (*Next) = TE0;
+ (*Next)->intersecting_line = testing->rl[0];
+ Next = &r;
+ }
+ if (!(*Next)) {
+ TE1 = lanpr_triangle_line_intersection_test(rb, testing->rl[1], testing, rt, l);
+ }
+ if (TE1 && (!(*Next))) {
+ (*Next) = TE1;
+ (*Next)->intersecting_line = testing->rl[1];
+ Next = &r;
+ }
+ if (!(*Next)) {
+ TE2 = lanpr_triangle_line_intersection_test(rb, testing->rl[2], testing, rt, l);
+ }
+ if (TE2 && (!(*Next))) {
+ (*Next) = TE2;
+ (*Next)->intersecting_line = testing->rl[2];
+ Next = &r;
+ }
+
+ if (!(*Next)) {
+ return 0;
+ }
+ }
+ mul_v4_m4v3_db(l->fbcoord, rb->view_projection, l->gloc);
+ mul_v4_m4v3_db(r->fbcoord, rb->view_projection, r->gloc);
+ mul_v3db_db(l->fbcoord, (1 / l->fbcoord[3]) /**HeightMultiply/2*/);
+ mul_v3db_db(r->fbcoord, (1 / r->fbcoord[3]) /**HeightMultiply/2*/);
+
+ l->fbcoord[0] -= cam->shiftx * 2;
+ l->fbcoord[1] -= cam->shifty * 2;
+ r->fbcoord[0] -= cam->shiftx * 2;
+ r->fbcoord[1] -= cam->shifty * 2;
+
+ l->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(l->fbcoord[2]) * (ZMax - ZMin));
+ r->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(r->fbcoord[2]) * (ZMax - ZMin));
+
+ l->intersecting_with = rt;
+ r->intersecting_with = testing;
+
+ /* ((1 / rl->l->fbcoord[3])*rb->FrameBuffer->H / 2) */
+
+ Result = mem_static_aquire(&rb->render_data_pool, sizeof(LANPR_RenderLine));
+ Result->l = l;
+ Result->r = r;
+ Result->tl = rt;
+ Result->tr = testing;
+ LANPR_RenderLineSegment *rls = mem_static_aquire(&rb->render_data_pool,
+ sizeof(LANPR_RenderLineSegment));
+ BLI_addtail(&Result->segments, rls);
+ BLI_addtail(&rb->all_render_lines, Result);
+ Result->flags |= LANPR_EDGE_FLAG_INTERSECTION;
+ list_append_pointer_static(&rb->intersection_lines, &rb->render_data_pool, Result);
+ int r1, r2, c1, c2, row, col;
+ if (lanpr_get_line_bounding_areas(rb, Result, &r1, &r2, &c1, &c2)) {
+ for (row = r1; row != r2 + 1; row++) {
+ for (col = c1; col != c2 + 1; col++) {
+ lanpr_link_line_with_bounding_area(rb, &rb->initial_bounding_areas[row * 4 + col], Result);
+ }
+ }
+ }
+
+ rb->intersection_count++;
+
+ return Result;
+}
+static void lanpr_triangle_calculate_intersections_in_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_RenderTriangle *rt,
+ LANPR_BoundingArea *ba)
+{
+ LANPR_RenderTriangle *TestingTriangle;
+ LinkData *lip, *next_lip;
+
+ real *FBC0 = rt->v[0]->fbcoord, *FBC1 = rt->v[1]->fbcoord, *FBC2 = rt->v[2]->fbcoord;
+
+ if (ba->child) {
+ lanpr_triangle_calculate_intersections_in_bounding_area(rb, rt, &ba->child[0]);
+ lanpr_triangle_calculate_intersections_in_bounding_area(rb, rt, &ba->child[1]);
+ lanpr_triangle_calculate_intersections_in_bounding_area(rb, rt, &ba->child[2]);
+ lanpr_triangle_calculate_intersections_in_bounding_area(rb, rt, &ba->child[3]);
+ return;
+ }
+
+ for (lip = ba->linked_triangles.first; lip; lip = next_lip) {
+ next_lip = lip->next;
+ TestingTriangle = lip->data;
+ if (TestingTriangle == rt || TestingTriangle->testing == rt ||
+ lanpr_triangle_share_edge(rt, TestingTriangle)) {
+
+ continue;
+ }
+
+ TestingTriangle->testing = rt;
+ real *RFBC0 = TestingTriangle->v[0]->fbcoord, *RFBC1 = TestingTriangle->v[1]->fbcoord,
+ *RFBC2 = TestingTriangle->v[2]->fbcoord;
+
+ if ((MIN3(FBC0[2], FBC1[2], FBC2[2]) > MAX3(RFBC0[2], RFBC1[2], RFBC2[2])) ||
+ (MAX3(FBC0[2], FBC1[2], FBC2[2]) < MIN3(RFBC0[2], RFBC1[2], RFBC2[2])) ||
+ (MIN3(FBC0[0], FBC1[0], FBC2[0]) > MAX3(RFBC0[0], RFBC1[0], RFBC2[0])) ||
+ (MAX3(FBC0[0], FBC1[0], FBC2[0]) < MIN3(RFBC0[0], RFBC1[0], RFBC2[0])) ||
+ (MIN3(FBC0[1], FBC1[1], FBC2[1]) > MAX3(RFBC0[1], RFBC1[1], RFBC2[1])) ||
+ (MAX3(FBC0[1], FBC1[1], FBC2[1]) < MIN3(RFBC0[1], RFBC1[1], RFBC2[1]))) {
+ continue;
+ }
+
+ lanpr_triangle_generate_intersection_line_only(rb, rt, TestingTriangle);
+ }
+}
+
+static void lanpr_compute_view_vector(LANPR_RenderBuffer *rb)
+{
+ float direction[3] = {0, 0, 1};
+ float trans[3];
+ float inv[4][4];
+
+ invert_m4_m4(inv, rb->scene->camera->obmat);
+ transpose_m4(inv);
+ mul_v3_mat3_m4v3(trans, inv, direction);
+ copy_v3db_v3fl(rb->view_vector, trans);
+}
+
+static void lanpr_compute_scene_contours(LANPR_RenderBuffer *rb, float threshold)
+{
+ real *view_vector = rb->view_vector;
+ real Dot1 = 0, Dot2 = 0;
+ real Result;
+ tnsVector3d cam_location;
+ int Add = 0;
+ Object *cam_obj = rb->scene->camera;
+ Camera *c = cam_obj->data;
+ LANPR_RenderLine *rl;
+ int contour_count = 0;
+ int crease_count = 0;
+ int MaterialCount = 0;
+
+ if (c->type == CAM_ORTHO) {
+ lanpr_compute_view_vector(rb);
+ }
+
+ for (rl = rb->all_render_lines.first; rl; rl = rl->next) {
+ /* if(rl->testing) */
+ /* if (!lanpr_line_crosses_frame(rl->l->fbcoord, rl->r->fbcoord)) */
+ /* continue; */
+
+ Add = 0;
+ Dot1 = 0;
+ Dot2 = 0;
+
+ if (c->type == CAM_PERSP) {
+ copy_v3db_v3fl(cam_location, cam_obj->obmat[3]);
+ sub_v3_v3v3_db(view_vector, rl->l->gloc, cam_location);
+ }
+
+ if (use_smooth_contour_modifier_contour) {
+ if (rl->flags & LANPR_EDGE_FLAG_CONTOUR) {
+ Add = 1;
+ }
+ }
+ else {
+ if (rl->tl) {
+ Dot1 = dot_v3v3_db(view_vector, rl->tl->gn);
+ }
+ else {
+ Add = 1;
+ }
+ if (rl->tr) {
+ Dot2 = dot_v3v3_db(view_vector, rl->tr->gn);
+ }
+ else {
+ Add = 1;
+ }
+ }
+
+ if (!Add) {
+ if ((Result = Dot1 * Dot2) <= 0 && (Dot1 + Dot2)) {
+ Add = 1;
+ }
+ else if (dot_v3v3_db(rl->tl->gn, rl->tr->gn) < threshold) {
+ Add = 2;
+ }
+ else if (rl->tl && rl->tr && rl->tl->material_id != rl->tr->material_id) {
+ Add = 3;
+ }
+ }
+
+ if (Add == 1) {
+ rl->flags |= LANPR_EDGE_FLAG_CONTOUR;
+ list_append_pointer_static(&rb->contours, &rb->render_data_pool, rl);
+ contour_count++;
+ }
+ else if (Add == 2) {
+ rl->flags |= LANPR_EDGE_FLAG_CREASE;
+ list_append_pointer_static(&rb->crease_lines, &rb->render_data_pool, rl);
+ crease_count++;
+ }
+ else if (Add == 3) {
+ rl->flags |= LANPR_EDGE_FLAG_MATERIAL;
+ list_append_pointer_static(&rb->material_lines, &rb->render_data_pool, rl);
+ MaterialCount++;
+ }
+ if (rl->flags & LANPR_EDGE_FLAG_EDGE_MARK) {
+ /* no need to mark again */
+ Add = 4;
+ list_append_pointer_static(&rb->edge_marks, &rb->render_data_pool, rl);
+ /* continue; */
+ }
+ if (Add) {
+ int r1, r2, c1, c2, row, col;
+ if (lanpr_get_line_bounding_areas(rb, rl, &r1, &r2, &c1, &c2)) {
+ for (row = r1; row != r2 + 1; row++) {
+ for (col = c1; col != c2 + 1; col++) {
+ lanpr_link_line_with_bounding_area(rb, &rb->initial_bounding_areas[row * 4 + col], rl);
+ }
+ }
+ }
+ }
+
+ /* line count reserved for feature such as progress feedback */
+ }
+}
+
+/* Buffer operations */
+
+void ED_lanpr_destroy_render_data(LANPR_RenderBuffer *rb)
+{
+ if (!rb) {
+ return;
+ }
+
+ rb->contour_count = 0;
+ rb->contour_managed = 0;
+ rb->intersection_count = 0;
+ rb->intersection_managed = 0;
+ rb->material_line_count = 0;
+ rb->material_managed = 0;
+ rb->crease_count = 0;
+ rb->crease_managed = 0;
+ rb->edge_mark_count = 0;
+ rb->edge_mark_managed = 0;
+
+ BLI_listbase_clear(&rb->contours);
+ BLI_listbase_clear(&rb->intersection_lines);
+ BLI_listbase_clear(&rb->crease_lines);
+ BLI_listbase_clear(&rb->material_lines);
+ BLI_listbase_clear(&rb->edge_marks);
+ BLI_listbase_clear(&rb->all_render_lines);
+ BLI_listbase_clear(&rb->chains);
+
+ BLI_listbase_clear(&rb->vertex_buffer_pointers);
+ BLI_listbase_clear(&rb->line_buffer_pointers);
+ BLI_listbase_clear(&rb->triangle_buffer_pointers);
+
+ BLI_spin_end(&rb->lock_task);
+ BLI_spin_end(&rb->render_data_pool.lock_mem);
+
+ BLI_spin_end(&lanpr_share.lock_render_status);
+
+ mem_static_destroy(&rb->render_data_pool);
+}
+LANPR_RenderBuffer *ED_lanpr_create_render_buffer(void)
+{
+ if (lanpr_share.render_buffer_shared) {
+ ED_lanpr_destroy_render_data(lanpr_share.render_buffer_shared);
+ return lanpr_share.render_buffer_shared;
+ }
+
+ LANPR_RenderBuffer *rb = MEM_callocN(sizeof(LANPR_RenderBuffer), "LANPR render buffer");
+
+ lanpr_share.render_buffer_shared = rb;
+
+ rb->cached_for_frame = -1;
+
+ BLI_spin_init(&rb->lock_task);
+ BLI_spin_init(&rb->render_data_pool.lock_mem);
+
+ BLI_spin_init(&lanpr_share.lock_render_status);
+
+ return rb;
+}
+
+void ED_lanpr_calculation_set_flag(LANPR_RenderStatus flag)
+{
+ BLI_spin_lock(&lanpr_share.lock_render_status);
+
+ if (flag == LANPR_RENDER_FINISHED && lanpr_share.flag_render_status == LANPR_RENDER_INCOMPELTE) {
+ ; /* Don't set the finished flag when it's canceled from any one of the thread.*/
+ }
+ else {
+ lanpr_share.flag_render_status = flag;
+ }
+
+ BLI_spin_unlock(&lanpr_share.lock_render_status);
+}
+
+bool ED_lanpr_calculation_flag_check(LANPR_RenderStatus flag)
+{
+ bool match;
+ BLI_spin_lock(&lanpr_share.lock_render_status);
+ match = (lanpr_share.flag_render_status == flag);
+ BLI_spin_unlock(&lanpr_share.lock_render_status);
+ return match;
+}
+
+static int lanpr_max_occlusion_in_collections(Collection *c)
+{
+ CollectionChild *cc;
+ int max_occ = 0;
+ int max;
+ if (c->lanpr.use_multiple_levels) {
+ max = MAX2(c->lanpr.level_start, c->lanpr.level_end);
+ }
+ else {
+ max = c->lanpr.level_start;
+ }
+ max_occ = MAX2(max, max_occ);
+
+ for (cc = c->children.first; cc; cc = cc->next) {
+ max = lanpr_max_occlusion_in_collections(cc->collection);
+ max_occ = MAX2(max, max_occ);
+ }
+
+ return max_occ;
+}
+static int lanpr_max_occlusion_in_targets(Depsgraph *depsgraph)
+{
+ int max_occ = 0;
+ int max;
+ Scene *s = DEG_get_evaluated_scene(depsgraph);
+
+ /* Objects */
+ DEG_OBJECT_ITER_BEGIN (depsgraph,
+ o,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) {
+ ModifierData *md;
+ for (md = o->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_FeatureLine) {
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+ if (flmd->target) {
+ if (flmd->use_multiple_levels) {
+ max = MAX2(flmd->level_start, flmd->level_end);
+ }
+ else {
+ max = flmd->level_start;
+ }
+ max_occ = MAX2(max, max_occ);
+ }
+ }
+ }
+ }
+ DEG_OBJECT_ITER_END;
+
+ /* Collections */
+ max = lanpr_max_occlusion_in_collections(s->master_collection);
+
+ max_occ = MAX2(max, max_occ);
+
+ return max_occ;
+}
+static int lanpr_get_max_occlusion_level(Depsgraph *dg)
+{
+ Scene *s = DEG_get_evaluated_scene(dg);
+ SceneLANPR *lanpr = &s->lanpr;
+ if (!strcmp(s->r.engine, RE_engine_id_BLENDER_LANPR)) {
+ /* Use the line layers in scene LANPR settings */
+ return ED_lanpr_max_occlusion_in_line_layers(lanpr);
+ }
+ else {
+ /* Other engines, use GPencil configurations */
+ return lanpr_max_occlusion_in_targets(dg);
+ }
+}
+
+static int lanpr_get_render_triangle_size(LANPR_RenderBuffer *rb)
+{
+ if (rb->thread_count == 0) {
+ rb->thread_count = BKE_render_num_threads(&rb->scene->r);
+ }
+ return sizeof(LANPR_RenderTriangle) + (sizeof(LANPR_RenderLine *) * rb->thread_count);
+}
+
+int lanpr_count_this_line(LANPR_RenderLine *rl, LANPR_LineLayer *ll)
+{
+ LANPR_LineLayerComponent *llc = ll->components.first;
+ int AndResult = 1, OrResult = 0;
+ if (!llc) {
+ return 1;
+ }
+ for (; llc; llc = llc->next) {
+ if (llc->component_mode == LANPR_COMPONENT_MODE_ALL) {
+ OrResult = 1;
+ }
+ else if (llc->component_mode == LANPR_COMPONENT_MODE_OBJECT && llc->object_select) {
+ if (rl->object_ref && rl->object_ref->id.orig_id == &llc->object_select->id) {
+ OrResult = 1;
+ }
+ else {
+ AndResult = 0;
+ }
+ }
+ else if (llc->component_mode == LANPR_COMPONENT_MODE_MATERIAL && llc->material_select) {
+ if ((rl->tl && rl->tl->material_id == llc->material_select->index) ||
+ (rl->tr && rl->tr->material_id == llc->material_select->index) ||
+ (!(rl->flags & LANPR_EDGE_FLAG_INTERSECTION))) {
+ OrResult = 1;
+ }
+ else {
+ AndResult = 0;
+ }
+ }
+ else if (llc->component_mode == LANPR_COMPONENT_MODE_COLLECTION && llc->collection_select) {
+ if (BKE_collection_has_object(llc->collection_select,
+ (Object *)rl->object_ref->id.orig_id)) {
+ OrResult = 1;
+ }
+ else {
+ AndResult = 0;
+ }
+ }
+ }
+ if (ll->logic_mode == LANPR_COMPONENT_LOGIG_OR) {
+ return OrResult;
+ }
+ else {
+ return AndResult;
+ }
+}
+int ED_lanpr_count_leveled_edge_segment_count(ListBase *LineList, LANPR_LineLayer *ll)
+{
+ LinkData *lip;
+ LANPR_RenderLine *rl;
+ LANPR_RenderLineSegment *rls;
+ int Count = 0;
+ for (lip = LineList->first; lip; lip = lip->next) {
+ rl = lip->data;
+ if (!lanpr_count_this_line(rl, ll)) {
+ continue;
+ }
+
+ for (rls = rl->segments.first; rls; rls = rls->next) {
+
+ if (!(ll->flags & LANPR_LINE_LAYER_USE_MULTIPLE_LEVELS)) {
+ if (rls->occlusion == ll->level_start) {
+ Count++;
+ }
+ }
+ else {
+ if (rls->occlusion >= ll->level_start && rls->occlusion <= ll->level_end) {
+ Count++;
+ }
+ }
+ }
+ }
+ return Count;
+}
+int lanpr_count_intersection_segment_count(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderLine *rl;
+ int Count = 0;
+ for (rl = rb->intersection_lines.first; rl; rl = rl->next) {
+ Count++;
+ }
+ return Count;
+}
+void *ED_lanpr_make_leveled_edge_vertex_array(LANPR_RenderBuffer *UNUSED(rb),
+ ListBase *LineList,
+ float *vertexArray,
+ float *NormalArray,
+ float **NextNormal,
+ LANPR_LineLayer *ll,
+ float componet_id)
+{
+ LinkData *lip;
+ LANPR_RenderLine *rl;
+ LANPR_RenderLineSegment *rls, *irls;
+ float *v = vertexArray;
+ float *N = NormalArray;
+ for (lip = LineList->first; lip; lip = lip->next) {
+ rl = lip->data;
+ if (!lanpr_count_this_line(rl, ll)) {
+ continue;
+ }
+
+ for (rls = rl->segments.first; rls; rls = rls->next) {
+ int use = 0;
+ if (!(ll->flags & LANPR_LINE_LAYER_USE_MULTIPLE_LEVELS)) {
+ if (rls->occlusion == ll->level_start) {
+ use = 1;
+ }
+ }
+ else {
+ if (rls->occlusion >= ll->level_start && rls->occlusion <= ll->level_end) {
+ use = 1;
+ }
+ }
+
+ if (!use)
+ continue;
+
+ if (rl->tl) {
+ N[0] += rl->tl->gn[0];
+ N[1] += rl->tl->gn[1];
+ N[2] += rl->tl->gn[2];
+ }
+ if (rl->tr) {
+ N[0] += rl->tr->gn[0];
+ N[1] += rl->tr->gn[1];
+ N[2] += rl->tr->gn[2];
+ }
+ if (rl->tl || rl->tr) {
+ normalize_v3(N);
+ copy_v3_v3(&N[3], N);
+ }
+ N += 6;
+
+ CLAMP(rls->at, 0, 1);
+ if ((irls = rls->next) != NULL) {
+ CLAMP(irls->at, 0, 1);
+ }
+
+ *v = interpf(rl->r->fbcoord[0], rl->l->fbcoord[0], rls->at);
+ v++;
+ *v = interpf(rl->r->fbcoord[1], rl->l->fbcoord[1], rls->at);
+ v++;
+ *v = componet_id;
+ v++;
+ *v = interpf(rl->r->fbcoord[0], rl->l->fbcoord[0], irls ? irls->at : 1);
+ v++;
+ *v = interpf(rl->r->fbcoord[1], rl->l->fbcoord[1], irls ? irls->at : 1);
+ v++;
+ *v = componet_id;
+ v++;
+ }
+ }
+ *NextNormal = N;
+ return v;
+}
+
+void lanpr_chain_generate_draw_command(LANPR_RenderBuffer *rb);
+
+#define TNS_BOUND_AREA_CROSSES(b1, b2) \
+ ((b1)[0] < (b2)[1] && (b1)[1] > (b2)[0] && (b1)[3] < (b2)[2] && (b1)[2] > (b2)[3])
+
+static void lanpr_make_initial_bounding_areas(LANPR_RenderBuffer *rb)
+{
+ int sp_w = 4; /* 20; */
+ int sp_h = 4; /* rb->H / (rb->W / sp_w); */
+ int row, col;
+ LANPR_BoundingArea *ba;
+ real span_w = (real)1 / sp_w * 2.0;
+ real span_h = (real)1 / sp_h * 2.0;
+
+ rb->tile_count_x = sp_w;
+ rb->tile_count_y = sp_h;
+ rb->width_per_tile = span_w;
+ rb->height_per_tile = span_h;
+
+ rb->bounding_area_count = sp_w * sp_h;
+ rb->initial_bounding_areas = mem_static_aquire(
+ &rb->render_data_pool, sizeof(LANPR_BoundingArea) * rb->bounding_area_count);
+
+ for (row = 0; row < sp_h; row++) {
+ for (col = 0; col < sp_w; col++) {
+ ba = &rb->initial_bounding_areas[row * 4 + col];
+
+ ba->l = span_w * col - 1.0;
+ ba->r = (col == sp_w - 1) ? 1.0 : (span_w * (col + 1) - 1.0);
+ ba->u = 1.0 - span_h * row;
+ ba->b = (row == sp_h - 1) ? -1.0 : (1.0 - span_h * (row + 1));
+
+ ba->cx = (ba->l + ba->r) / 2;
+ ba->cy = (ba->u + ba->b) / 2;
+
+ if (row) {
+ list_append_pointer_static(
+ &ba->up, &rb->render_data_pool, &rb->initial_bounding_areas[(row - 1) * 4 + col]);
+ }
+ if (col) {
+ list_append_pointer_static(
+ &ba->lp, &rb->render_data_pool, &rb->initial_bounding_areas[row * 4 + col - 1]);
+ }
+ if (row != sp_h - 1) {
+ list_append_pointer_static(
+ &ba->bp, &rb->render_data_pool, &rb->initial_bounding_areas[(row + 1) * 4 + col]);
+ }
+ if (col != sp_w - 1) {
+ list_append_pointer_static(
+ &ba->rp, &rb->render_data_pool, &rb->initial_bounding_areas[row * 4 + col + 1]);
+ }
+ }
+ }
+}
+static void lanpr_connect_new_bounding_areas(LANPR_RenderBuffer *rb, LANPR_BoundingArea *Root)
+{
+ LANPR_BoundingArea *ba = Root->child, *tba;
+ LinkData *lip, *lip2, *next_lip;
+ LANPR_StaticMemPool *mph = &rb->render_data_pool;
+
+ list_append_pointer_static_pool(mph, &ba[1].rp, &ba[0]);
+ list_append_pointer_static_pool(mph, &ba[0].lp, &ba[1]);
+ list_append_pointer_static_pool(mph, &ba[1].bp, &ba[2]);
+ list_append_pointer_static_pool(mph, &ba[2].up, &ba[1]);
+ list_append_pointer_static_pool(mph, &ba[2].rp, &ba[3]);
+ list_append_pointer_static_pool(mph, &ba[3].lp, &ba[2]);
+ list_append_pointer_static_pool(mph, &ba[3].up, &ba[0]);
+ list_append_pointer_static_pool(mph, &ba[0].bp, &ba[3]);
+
+ for (lip = Root->lp.first; lip; lip = lip->next) {
+ tba = lip->data;
+ if (ba[1].u > tba->b && ba[1].b < tba->u) {
+ list_append_pointer_static_pool(mph, &ba[1].lp, tba);
+ list_append_pointer_static_pool(mph, &tba->rp, &ba[1]);
+ }
+ if (ba[2].u > tba->b && ba[2].b < tba->u) {
+ list_append_pointer_static_pool(mph, &ba[2].lp, tba);
+ list_append_pointer_static_pool(mph, &tba->rp, &ba[2]);
+ }
+ }
+ for (lip = Root->rp.first; lip; lip = lip->next) {
+ tba = lip->data;
+ if (ba[0].u > tba->b && ba[0].b < tba->u) {
+ list_append_pointer_static_pool(mph, &ba[0].rp, tba);
+ list_append_pointer_static_pool(mph, &tba->lp, &ba[0]);
+ }
+ if (ba[3].u > tba->b && ba[3].b < tba->u) {
+ list_append_pointer_static_pool(mph, &ba[3].rp, tba);
+ list_append_pointer_static_pool(mph, &tba->lp, &ba[3]);
+ }
+ }
+ for (lip = Root->up.first; lip; lip = lip->next) {
+ tba = lip->data;
+ if (ba[0].r > tba->l && ba[0].l < tba->r) {
+ list_append_pointer_static_pool(mph, &ba[0].up, tba);
+ list_append_pointer_static_pool(mph, &tba->bp, &ba[0]);
+ }
+ if (ba[1].r > tba->l && ba[1].l < tba->r) {
+ list_append_pointer_static_pool(mph, &ba[1].up, tba);
+ list_append_pointer_static_pool(mph, &tba->bp, &ba[1]);
+ }
+ }
+ for (lip = Root->bp.first; lip; lip = lip->next) {
+ tba = lip->data;
+ if (ba[2].r > tba->l && ba[2].l < tba->r) {
+ list_append_pointer_static_pool(mph, &ba[2].bp, tba);
+ list_append_pointer_static_pool(mph, &tba->up, &ba[2]);
+ }
+ if (ba[3].r > tba->l && ba[3].l < tba->r) {
+ list_append_pointer_static_pool(mph, &ba[3].bp, tba);
+ list_append_pointer_static_pool(mph, &tba->up, &ba[3]);
+ }
+ }
+ for (lip = Root->lp.first; lip; lip = lip->next) {
+ for (lip2 = ((LANPR_BoundingArea *)lip->data)->rp.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == Root) {
+ list_remove_pointer_item_no_free(&((LANPR_BoundingArea *)lip->data)->rp, lip2);
+ if (ba[1].u > tba->b && ba[1].b < tba->u) {
+ list_append_pointer_static_pool(mph, &tba->rp, &ba[1]);
+ }
+ if (ba[2].u > tba->b && ba[2].b < tba->u) {
+ list_append_pointer_static_pool(mph, &tba->rp, &ba[2]);
+ }
+ }
+ }
+ }
+ for (lip = Root->rp.first; lip; lip = lip->next) {
+ for (lip2 = ((LANPR_BoundingArea *)lip->data)->lp.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == Root) {
+ list_remove_pointer_item_no_free(&((LANPR_BoundingArea *)lip->data)->lp, lip2);
+ if (ba[0].u > tba->b && ba[0].b < tba->u) {
+ list_append_pointer_static_pool(mph, &tba->lp, &ba[0]);
+ }
+ if (ba[3].u > tba->b && ba[3].b < tba->u) {
+ list_append_pointer_static_pool(mph, &tba->lp, &ba[3]);
+ }
+ }
+ }
+ }
+ for (lip = Root->up.first; lip; lip = lip->next) {
+ for (lip2 = ((LANPR_BoundingArea *)lip->data)->bp.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == Root) {
+ list_remove_pointer_item_no_free(&((LANPR_BoundingArea *)lip->data)->bp, lip2);
+ if (ba[0].r > tba->l && ba[0].l < tba->r) {
+ list_append_pointer_static_pool(mph, &tba->up, &ba[0]);
+ }
+ if (ba[1].r > tba->l && ba[1].l < tba->r) {
+ list_append_pointer_static_pool(mph, &tba->up, &ba[1]);
+ }
+ }
+ }
+ }
+ for (lip = Root->bp.first; lip; lip = lip->next) {
+ for (lip2 = ((LANPR_BoundingArea *)lip->data)->up.first; lip2; lip2 = next_lip) {
+ next_lip = lip2->next;
+ tba = lip2->data;
+ if (tba == Root) {
+ list_remove_pointer_item_no_free(&((LANPR_BoundingArea *)lip->data)->up, lip2);
+ if (ba[2].r > tba->l && ba[2].l < tba->r) {
+ list_append_pointer_static_pool(mph, &tba->bp, &ba[2]);
+ }
+ if (ba[3].r > tba->l && ba[3].l < tba->r) {
+ list_append_pointer_static_pool(mph, &tba->bp, &ba[3]);
+ }
+ }
+ }
+ }
+ while (list_pop_pointer_no_free(&Root->lp))
+ ;
+ while (list_pop_pointer_no_free(&Root->rp))
+ ;
+ while (list_pop_pointer_no_free(&Root->up))
+ ;
+ while (list_pop_pointer_no_free(&Root->bp))
+ ;
+}
+static void lanpr_link_triangle_with_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_BoundingArea *RootBoundingArea,
+ LANPR_RenderTriangle *rt,
+ real *LRUB,
+ int Recursive);
+static void lanpr_split_bounding_area(LANPR_RenderBuffer *rb, LANPR_BoundingArea *Root)
+{
+ LANPR_BoundingArea *ba = mem_static_aquire(&rb->render_data_pool,
+ sizeof(LANPR_BoundingArea) * 4);
+ LANPR_RenderTriangle *rt;
+ LANPR_RenderLine *rl;
+
+ ba[0].l = Root->cx;
+ ba[0].r = Root->r;
+ ba[0].u = Root->u;
+ ba[0].b = Root->cy;
+ ba[0].cx = (ba[0].l + ba[0].r) / 2;
+ ba[0].cy = (ba[0].u + ba[0].b) / 2;
+
+ ba[1].l = Root->l;
+ ba[1].r = Root->cx;
+ ba[1].u = Root->u;
+ ba[1].b = Root->cy;
+ ba[1].cx = (ba[1].l + ba[1].r) / 2;
+ ba[1].cy = (ba[1].u + ba[1].b) / 2;
+
+ ba[2].l = Root->l;
+ ba[2].r = Root->cx;
+ ba[2].u = Root->cy;
+ ba[2].b = Root->b;
+ ba[2].cx = (ba[2].l + ba[2].r) / 2;
+ ba[2].cy = (ba[2].u + ba[2].b) / 2;
+
+ ba[3].l = Root->cx;
+ ba[3].r = Root->r;
+ ba[3].u = Root->cy;
+ ba[3].b = Root->b;
+ ba[3].cx = (ba[3].l + ba[3].r) / 2;
+ ba[3].cy = (ba[3].u + ba[3].b) / 2;
+
+ Root->child = ba;
+
+ lanpr_connect_new_bounding_areas(rb, Root);
+
+ while ((rt = list_pop_pointer_no_free(&Root->linked_triangles)) != NULL) {
+ LANPR_BoundingArea *cba = Root->child;
+ real b[4];
+ b[0] = MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[1] = MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[2] = MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ b[3] = MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ if (TNS_BOUND_AREA_CROSSES(b, &cba[0].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &cba[0], rt, b, 0);
+ }
+ if (TNS_BOUND_AREA_CROSSES(b, &cba[1].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &cba[1], rt, b, 0);
+ }
+ if (TNS_BOUND_AREA_CROSSES(b, &cba[2].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &cba[2], rt, b, 0);
+ }
+ if (TNS_BOUND_AREA_CROSSES(b, &cba[3].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &cba[3], rt, b, 0);
+ }
+ }
+
+ while ((rl = list_pop_pointer_no_free(&Root->linked_lines)) != NULL) {
+ lanpr_link_line_with_bounding_area(rb, Root, rl);
+ }
+
+ rb->bounding_area_count += 3;
+}
+static int lanpr_line_crosses_bounding_area(LANPR_RenderBuffer *UNUSED(fb),
+ tnsVector2d l,
+ tnsVector2d r,
+ LANPR_BoundingArea *ba)
+{
+ real vx, vy;
+ tnsVector4d converted;
+ real c1, c;
+
+ if (((converted[0] = (real)ba->l) > MAX2(l[0], r[0])) ||
+ ((converted[1] = (real)ba->r) < MIN2(l[0], r[0])) ||
+ ((converted[2] = (real)ba->b) > MAX2(l[1], r[1])) ||
+ ((converted[3] = (real)ba->u) < MIN2(l[1], r[1]))) {
+ return 0;
+ }
+
+ vx = l[0] - r[0];
+ vy = l[1] - r[1];
+
+ c1 = vx * (converted[2] - l[1]) - vy * (converted[0] - l[0]);
+ c = c1;
+
+ c1 = vx * (converted[2] - l[1]) - vy * (converted[1] - l[0]);
+ if (c1 * c <= 0) {
+ return 1;
+ }
+ else {
+ c = c1;
+ }
+
+ c1 = vx * (converted[3] - l[1]) - vy * (converted[0] - l[0]);
+ if (c1 * c <= 0) {
+ return 1;
+ }
+ else {
+ c = c1;
+ }
+
+ c1 = vx * (converted[3] - l[1]) - vy * (converted[1] - l[0]);
+ if (c1 * c <= 0) {
+ return 1;
+ }
+ else {
+ c = c1;
+ }
+
+ return 0;
+}
+static int lanpr_triangle_covers_bounding_area(LANPR_RenderBuffer *fb,
+ LANPR_RenderTriangle *rt,
+ LANPR_BoundingArea *ba)
+{
+ tnsVector2d p1, p2, p3, p4;
+ real *FBC1 = rt->v[0]->fbcoord, *FBC2 = rt->v[1]->fbcoord, *FBC3 = rt->v[2]->fbcoord;
+
+ p3[0] = p1[0] = (real)ba->l;
+ p2[1] = p1[1] = (real)ba->b;
+ p2[0] = p4[0] = (real)ba->r;
+ p3[1] = p4[1] = (real)ba->u;
+
+ if ((FBC1[0] >= p1[0] && FBC1[0] <= p2[0] && FBC1[1] >= p1[1] && FBC1[1] <= p3[1]) ||
+ (FBC2[0] >= p1[0] && FBC2[0] <= p2[0] && FBC2[1] >= p1[1] && FBC2[1] <= p3[1]) ||
+ (FBC3[0] >= p1[0] && FBC3[0] <= p2[0] && FBC3[1] >= p1[1] && FBC3[1] <= p3[1])) {
+ return 1;
+ }
+
+ if (ED_lanpr_point_inside_triangled(p1, FBC1, FBC2, FBC3) ||
+ ED_lanpr_point_inside_triangled(p2, FBC1, FBC2, FBC3) ||
+ ED_lanpr_point_inside_triangled(p3, FBC1, FBC2, FBC3) ||
+ ED_lanpr_point_inside_triangled(p4, FBC1, FBC2, FBC3)) {
+ return 1;
+ }
+
+ if ((lanpr_line_crosses_bounding_area(fb, FBC1, FBC2, ba)) ||
+ (lanpr_line_crosses_bounding_area(fb, FBC2, FBC3, ba)) ||
+ (lanpr_line_crosses_bounding_area(fb, FBC3, FBC1, ba))) {
+ return 1;
+ }
+
+ return 0;
+}
+static void lanpr_link_triangle_with_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_BoundingArea *RootBoundingArea,
+ LANPR_RenderTriangle *rt,
+ real *LRUB,
+ int Recursive)
+{
+ if (!lanpr_triangle_covers_bounding_area(rb, rt, RootBoundingArea)) {
+ return;
+ }
+ if (!RootBoundingArea->child) {
+ list_append_pointer_static_pool(
+ &rb->render_data_pool, &RootBoundingArea->linked_triangles, rt);
+ RootBoundingArea->triangle_count++;
+ if (RootBoundingArea->triangle_count > 200 && Recursive) {
+ lanpr_split_bounding_area(rb, RootBoundingArea);
+ }
+ if (Recursive && rb->use_intersections) {
+ lanpr_triangle_calculate_intersections_in_bounding_area(rb, rt, RootBoundingArea);
+ }
+ }
+ else {
+ LANPR_BoundingArea *ba = RootBoundingArea->child;
+ real *B1 = LRUB;
+ real b[4];
+ if (!LRUB) {
+ b[0] = MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[1] = MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[2] = MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ b[3] = MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ B1 = b;
+ }
+ if (TNS_BOUND_AREA_CROSSES(B1, &ba[0].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &ba[0], rt, B1, Recursive);
+ }
+ if (TNS_BOUND_AREA_CROSSES(B1, &ba[1].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &ba[1], rt, B1, Recursive);
+ }
+ if (TNS_BOUND_AREA_CROSSES(B1, &ba[2].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &ba[2], rt, B1, Recursive);
+ }
+ if (TNS_BOUND_AREA_CROSSES(B1, &ba[3].l)) {
+ lanpr_link_triangle_with_bounding_area(rb, &ba[3], rt, B1, Recursive);
+ }
+ }
+}
+static void lanpr_link_line_with_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_BoundingArea *RootBoundingArea,
+ LANPR_RenderLine *rl)
+{
+ if (!RootBoundingArea->child) {
+ list_append_pointer_static_pool(&rb->render_data_pool, &RootBoundingArea->linked_lines, rl);
+ }
+ else {
+ if (lanpr_line_crosses_bounding_area(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &RootBoundingArea->child[0])) {
+ lanpr_link_line_with_bounding_area(rb, &RootBoundingArea->child[0], rl);
+ }
+ else if (lanpr_line_crosses_bounding_area(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &RootBoundingArea->child[1])) {
+ lanpr_link_line_with_bounding_area(rb, &RootBoundingArea->child[1], rl);
+ }
+ else if (lanpr_line_crosses_bounding_area(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &RootBoundingArea->child[2])) {
+ lanpr_link_line_with_bounding_area(rb, &RootBoundingArea->child[2], rl);
+ }
+ else if (lanpr_line_crosses_bounding_area(
+ rb, rl->l->fbcoord, rl->r->fbcoord, &RootBoundingArea->child[3])) {
+ lanpr_link_line_with_bounding_area(rb, &RootBoundingArea->child[3], rl);
+ }
+ }
+}
+static int lanpr_get_triangle_bounding_areas(LANPR_RenderBuffer *rb,
+ LANPR_RenderTriangle *rt,
+ int *rowBegin,
+ int *rowEnd,
+ int *colBegin,
+ int *colEnd)
+{
+ real sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ real b[4];
+
+ if (!rt->v[0] || !rt->v[1] || !rt->v[2]) {
+ return 0;
+ }
+
+ b[0] = MIN3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[1] = MAX3(rt->v[0]->fbcoord[0], rt->v[1]->fbcoord[0], rt->v[2]->fbcoord[0]);
+ b[2] = MIN3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+ b[3] = MAX3(rt->v[0]->fbcoord[1], rt->v[1]->fbcoord[1], rt->v[2]->fbcoord[1]);
+
+ if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) {
+ return 0;
+ }
+
+ (*colBegin) = (int)((b[0] + 1.0) / sp_w);
+ (*colEnd) = (int)((b[1] + 1.0) / sp_w);
+ (*rowEnd) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowBegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+
+ if ((*colEnd) >= rb->tile_count_x) {
+ (*colEnd) = rb->tile_count_x - 1;
+ }
+ if ((*rowEnd) >= rb->tile_count_y) {
+ (*rowEnd) = rb->tile_count_y - 1;
+ }
+ if ((*colBegin) < 0) {
+ (*colBegin) = 0;
+ }
+ if ((*rowBegin) < 0) {
+ (*rowBegin) = 0;
+ }
+
+ return 1;
+}
+static int lanpr_get_line_bounding_areas(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl,
+ int *rowBegin,
+ int *rowEnd,
+ int *colBegin,
+ int *colEnd)
+{
+ real sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ real b[4];
+
+ if (!rl->l || !rl->r) {
+ return 0;
+ }
+
+ if (rl->l->fbcoord[0] != rl->l->fbcoord[0] || rl->r->fbcoord[0] != rl->r->fbcoord[0]) {
+ return 0;
+ }
+
+ b[0] = MIN2(rl->l->fbcoord[0], rl->r->fbcoord[0]);
+ b[1] = MAX2(rl->l->fbcoord[0], rl->r->fbcoord[0]);
+ b[2] = MIN2(rl->l->fbcoord[1], rl->r->fbcoord[1]);
+ b[3] = MAX2(rl->l->fbcoord[1], rl->r->fbcoord[1]);
+
+ if (b[0] > 1 || b[1] < -1 || b[2] > 1 || b[3] < -1) {
+ return 0;
+ }
+
+ (*colBegin) = (int)((b[0] + 1.0) / sp_w);
+ (*colEnd) = (int)((b[1] + 1.0) / sp_w);
+ (*rowEnd) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowBegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+
+ if ((*colEnd) >= rb->tile_count_x) {
+ (*colEnd) = rb->tile_count_x - 1;
+ }
+ if ((*rowEnd) >= rb->tile_count_y) {
+ (*rowEnd) = rb->tile_count_y - 1;
+ }
+ if ((*colBegin) < 0) {
+ (*colBegin) = 0;
+ }
+ if ((*rowBegin) < 0) {
+ (*rowBegin) = 0;
+ }
+
+ return 1;
+}
+LANPR_BoundingArea *ED_lanpr_get_point_bounding_area(LANPR_RenderBuffer *rb, real x, real y)
+{
+ real sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ int col, row;
+
+ if (x > 1 || x < -1 || y > 1 || y < -1) {
+ return 0;
+ }
+
+ col = (int)((x + 1.0) / sp_w);
+ row = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+
+ if (col >= rb->tile_count_x) {
+ col = rb->tile_count_x - 1;
+ }
+ if (row >= rb->tile_count_y) {
+ row = rb->tile_count_y - 1;
+ }
+ if (col < 0) {
+ col = 0;
+ }
+ if (row < 0) {
+ row = 0;
+ }
+
+ return &rb->initial_bounding_areas[row * 4 + col];
+}
+static LANPR_BoundingArea *lanpr_get_point_bounding_area_recursive(LANPR_BoundingArea *ba,
+ real x,
+ real y)
+{
+ if (!ba->child) {
+ return ba;
+ }
+ else {
+#define IN_BOUND(i, x, y) \
+ ba->child[i].l <= x && ba->child[i].r >= x && ba->child[i].b <= y && ba->child[i].u >= y
+
+ if (IN_BOUND(0, x, y)) {
+ return lanpr_get_point_bounding_area_recursive(&ba->child[0], x, y);
+ }
+ else if (IN_BOUND(1, x, y)) {
+ return lanpr_get_point_bounding_area_recursive(&ba->child[1], x, y);
+ }
+ else if (IN_BOUND(2, x, y)) {
+ return lanpr_get_point_bounding_area_recursive(&ba->child[2], x, y);
+ }
+ else if (IN_BOUND(3, x, y)) {
+ return lanpr_get_point_bounding_area_recursive(&ba->child[3], x, y);
+ }
+ }
+ return NULL;
+}
+LANPR_BoundingArea *ED_lanpr_get_point_bounding_area_deep(LANPR_RenderBuffer *rb, real x, real y)
+{
+ LANPR_BoundingArea *ba;
+ if ((ba = ED_lanpr_get_point_bounding_area(rb, x, y)) != NULL) {
+ return lanpr_get_point_bounding_area_recursive(ba, x, y);
+ }
+ return NULL;
+}
+
+static void lanpr_add_triangles(LANPR_RenderBuffer *rb)
+{
+ LANPR_RenderElementLinkNode *reln;
+ LANPR_RenderTriangle *rt;
+ int i, lim;
+ int x1, x2, y1, y2;
+ int r, co;
+
+ for (reln = rb->triangle_buffer_pointers.first; reln; reln = reln->next) {
+ rt = reln->pointer;
+ lim = reln->element_count;
+ for (i = 0; i < lim; i++) {
+ if (rt->cull_status) {
+ rt = (void *)(((unsigned char *)rt) + rb->triangle_size);
+ continue;
+ }
+ if (lanpr_get_triangle_bounding_areas(rb, rt, &y1, &y2, &x1, &x2)) {
+ for (co = x1; co <= x2; co++) {
+ for (r = y1; r <= y2; r++) {
+ lanpr_link_triangle_with_bounding_area(
+ rb, &rb->initial_bounding_areas[r * 4 + co], rt, 0, 1);
+ }
+ }
+ }
+ else {
+ ; /* throw away. */
+ }
+ rt = (void *)(((unsigned char *)rt) + rb->triangle_size);
+ /* if (tnsglobal_TriangleIntersectionCount >= 2000) { */
+ /* tnsset_PlusRenderIntersectionCount(rb, tnsglobal_TriangleIntersectionCount); */
+ /* tnsglobal_TriangleIntersectionCount = 0; */
+ /* } */
+ }
+ }
+ /* tnsset_PlusRenderIntersectionCount(rb, tnsglobal_TriangleIntersectionCount); */
+}
+static LANPR_BoundingArea *lanpr_get_next_bounding_area(LANPR_BoundingArea *This,
+ LANPR_RenderLine *rl,
+ real x,
+ real y,
+ real k,
+ int PositiveX,
+ int PositiveY,
+ real *NextX,
+ real *NextY)
+{
+ real rx, ry, ux, uy, lx, ly, bx, by;
+ real r1, r2;
+ LANPR_BoundingArea *ba;
+ LinkData *lip;
+ if (PositiveX > 0) {
+ rx = This->r;
+ ry = y + k * (rx - x);
+ if (PositiveY > 0) {
+ uy = This->u;
+ ux = x + (uy - y) / k;
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], rx);
+ r2 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], ux);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ for (lip = This->rp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->u >= ry && ba->b < ry) {
+ *NextX = rx;
+ *NextY = ry;
+ return ba;
+ }
+ }
+ }
+ else {
+ for (lip = This->up.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->r >= ux && ba->l < ux) {
+ *NextX = ux;
+ *NextY = uy;
+ return ba;
+ }
+ }
+ }
+ }
+ else if (PositiveY < 0) {
+ by = This->b;
+ bx = x + (by - y) / k;
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], rx);
+ r2 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], bx);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ for (lip = This->rp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->u >= ry && ba->b < ry) {
+ *NextX = rx;
+ *NextY = ry;
+ return ba;
+ }
+ }
+ }
+ else {
+ for (lip = This->bp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->r >= bx && ba->l < bx) {
+ *NextX = bx;
+ *NextY = by;
+ return ba;
+ }
+ }
+ }
+ }
+ else { /* Y diffence == 0 */
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], This->r);
+ if (r1 > 1) {
+ return 0;
+ }
+ for (lip = This->rp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->u >= y && ba->b < y) {
+ *NextX = This->r;
+ *NextY = y;
+ return ba;
+ }
+ }
+ }
+ }
+ else if (PositiveX < 0) { /* X diffence < 0 */
+ lx = This->l;
+ ly = y + k * (lx - x);
+ if (PositiveY > 0) {
+ uy = This->u;
+ ux = x + (uy - y) / k;
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], lx);
+ r2 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], ux);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ for (lip = This->lp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->u >= ly && ba->b < ly) {
+ *NextX = lx;
+ *NextY = ly;
+ return ba;
+ }
+ }
+ }
+ else {
+ for (lip = This->up.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->r >= ux && ba->l < ux) {
+ *NextX = ux;
+ *NextY = uy;
+ return ba;
+ }
+ }
+ }
+ }
+ else if (PositiveY < 0) {
+ by = This->b;
+ bx = x + (by - y) / k;
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], lx);
+ r2 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], bx);
+ if (MIN2(r1, r2) > 1) {
+ return 0;
+ }
+ if (r1 <= r2) {
+ for (lip = This->lp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->u >= ly && ba->b < ly) {
+ *NextX = lx;
+ *NextY = ly;
+ return ba;
+ }
+ }
+ }
+ else {
+ for (lip = This->bp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->r >= bx && ba->l < bx) {
+ *NextX = bx;
+ *NextY = by;
+ return ba;
+ }
+ }
+ }
+ }
+ else { /* Y diffence == 0 */
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[0], rl->r->fbcoord[0], This->l);
+ if (r1 > 1) {
+ return 0;
+ }
+ for (lip = This->lp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->u >= y && ba->b < y) {
+ *NextX = This->l;
+ *NextY = y;
+ return ba;
+ }
+ }
+ }
+ }
+ else { /* X difference == 0; */
+ if (PositiveY > 0) {
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[1], rl->r->fbcoord[1], This->u);
+ if (r1 > 1) {
+ return 0;
+ }
+ for (lip = This->up.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->r > x && ba->l <= x) {
+ *NextX = x;
+ *NextY = This->u;
+ return ba;
+ }
+ }
+ }
+ else if (PositiveY < 0) {
+ r1 = tMatGetLinearRatio(rl->l->fbcoord[1], rl->r->fbcoord[1], This->b);
+ if (r1 > 1) {
+ return 0;
+ }
+ for (lip = This->bp.first; lip; lip = lip->next) {
+ ba = lip->data;
+ if (ba->r > x && ba->l <= x) {
+ *NextX = x;
+ *NextY = This->b;
+ return ba;
+ }
+ }
+ }
+ else
+ return 0; /* segment has no length */
+ }
+ return 0;
+}
+
+static LANPR_BoundingArea *lanpr_get_bounding_area(LANPR_RenderBuffer *rb, real x, real y)
+{
+ LANPR_BoundingArea *iba;
+ real sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ int c = (int)((x + 1.0) / sp_w);
+ int r = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ if (r < 0) {
+ r = 0;
+ }
+ if (c < 0) {
+ c = 0;
+ }
+ if (r >= rb->tile_count_y) {
+ r = rb->tile_count_y - 1;
+ }
+ if (c >= rb->tile_count_x) {
+ c = rb->tile_count_x - 1;
+ }
+
+ iba = &rb->initial_bounding_areas[r * 4 + c];
+ while (iba->child) {
+ if (x > iba->cx) {
+ if (y > iba->cy) {
+ iba = &iba->child[0];
+ }
+ else {
+ iba = &iba->child[3];
+ }
+ }
+ else {
+ if (y > iba->cy) {
+ iba = &iba->child[1];
+ }
+ else {
+ iba = &iba->child[2];
+ }
+ }
+ }
+ return iba;
+}
+static LANPR_BoundingArea *lanpr_get_first_possible_bounding_area(LANPR_RenderBuffer *rb,
+ LANPR_RenderLine *rl)
+{
+ LANPR_BoundingArea *iba;
+ real data[2] = {rl->l->fbcoord[0], rl->l->fbcoord[1]};
+ tnsVector2d LU = {-1, 1}, RU = {1, 1}, LB = {-1, -1}, RB = {1, -1};
+ real r = 1, sr = 1;
+
+ if (data[0] > -1 && data[0] < 1 && data[1] > -1 && data[1] < 1) {
+ return lanpr_get_bounding_area(rb, data[0], data[1]);
+ }
+ else {
+ if ((lanpr_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, LU, RU, &sr) && sr < r &&
+ sr > 0) ||
+ (lanpr_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, LB, RB, &sr) && sr < r &&
+ sr > 0) ||
+ (lanpr_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, LB, LU, &sr) && sr < r &&
+ sr > 0) ||
+ (lanpr_LineIntersectTest2d(rl->l->fbcoord, rl->r->fbcoord, RB, RU, &sr) && sr < r &&
+ sr > 0)) {
+ r = sr;
+ }
+ interp_v2_v2v2_db(data, rl->l->fbcoord, rl->r->fbcoord, r);
+
+ return lanpr_get_bounding_area(rb, data[0], data[1]);
+ }
+
+ return iba;
+}
+
+/* Calculations */
+
+int ED_lanpr_compute_feature_lines_internal(Depsgraph *depsgraph, int intersectons_only)
+{
+ LANPR_RenderBuffer *rb;
+ Scene *s = DEG_get_evaluated_scene(depsgraph);
+ SceneLANPR *lanpr = &s->lanpr;
+ int is_lanpr_engine = !strcmp(s->r.engine, RE_engine_id_BLENDER_LANPR);
+
+ if (!is_lanpr_engine && (lanpr->flags & LANPR_ENABLED) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ rb = ED_lanpr_create_render_buffer();
+
+ lanpr_share.render_buffer_shared = rb;
+
+ rb->scene = s;
+ rb->w = s->r.xsch;
+ rb->h = s->r.ysch;
+ rb->use_intersections = (lanpr->flags & LANPR_USE_INTERSECTIONS);
+
+ rb->triangle_size = lanpr_get_render_triangle_size(rb);
+
+ rb->max_occlusion_level = lanpr_get_max_occlusion_level(depsgraph);
+
+ ED_lanpr_update_render_progress("LANPR: Loading geometries.");
+
+ lanpr_make_render_geometry_buffers(depsgraph, rb->scene, rb->scene->camera, rb);
+
+ lanpr_compute_view_vector(rb);
+ lanpr_cull_triangles(rb);
+
+ lanpr_perspective_division(rb);
+
+ lanpr_make_initial_bounding_areas(rb);
+
+ if (!intersectons_only) {
+ lanpr_compute_scene_contours(rb, lanpr->crease_threshold);
+ }
+
+ ED_lanpr_update_render_progress("LANPR: Computing intersections.");
+
+ lanpr_add_triangles(rb);
+
+ ED_lanpr_update_render_progress("LANPR: Computing line occlusion.");
+
+ if (!intersectons_only) {
+ lanpr_calculate_line_occlusion_begin(rb);
+ }
+
+ ED_lanpr_update_render_progress("LANPR: Chaining.");
+
+ /* When not using LANPR engine, chaining is forced in order to generate data for GPencil. */
+ if (((lanpr->flags & LANPR_USE_CHAINING) || !is_lanpr_engine) && (!intersectons_only)) {
+ float t_image = rb->scene->lanpr.chaining_image_threshold;
+ float t_geom = rb->scene->lanpr.chaining_geometry_threshold;
+
+ ED_lanpr_NO_THREAD_chain_feature_lines(rb);
+
+ if (is_lanpr_engine) {
+ /* Enough with it. We can provide an option after we have LANPR internal smoothing */
+ ED_lanpr_calculation_set_flag(LANPR_RENDER_FINISHED);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Below are simply for better GPencil experience. */
+
+ ED_lanpr_split_chains_for_fixed_occlusion(rb);
+
+ if (t_image < FLT_EPSILON && t_geom < FLT_EPSILON) {
+ t_geom = 0.0f;
+ t_image = 0.01f;
+ }
+
+ ED_lanpr_connect_chains(rb, 1);
+ ED_lanpr_connect_chains(rb, 0);
+
+ /* This configuration ensures there won't be accidental lost of short segments */
+ ED_lanpr_discard_short_chains(rb, MIN3(t_image, t_geom, 0.01f) - FLT_EPSILON);
+ }
+
+ rb->cached_for_frame = rb->scene->r.cfra;
+
+ ED_lanpr_calculation_set_flag(LANPR_RENDER_FINISHED);
+
+ return OPERATOR_FINISHED;
+}
+
+typedef struct LANPR_FeatureLineWorker {
+ Depsgraph *dg;
+ int intersection_only;
+} LANPR_FeatureLineWorker;
+
+static void lanpr_compute_feature_lines_worker(TaskPool *__restrict UNUSED(pool),
+ LANPR_FeatureLineWorker *worker_data,
+ int UNUSED(threadid))
+{
+ ED_lanpr_compute_feature_lines_internal(worker_data->dg, worker_data->intersection_only);
+}
+
+void ED_lanpr_compute_feature_lines_background(Depsgraph *dg, int intersection_only)
+{
+ /* If the calculation is already started then bypass it. */
+ if (!ED_lanpr_calculation_flag_check(LANPR_RENDER_IDLE)) {
+ return;
+ }
+
+ ED_lanpr_calculation_set_flag(LANPR_RENDER_RUNNING);
+
+ LANPR_FeatureLineWorker *flw = MEM_callocN(sizeof(LANPR_FeatureLineWorker), "Task Pool");
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+
+ flw->dg = dg;
+ flw->intersection_only = intersection_only;
+
+ TaskPool *tp = BLI_task_pool_create_background(scheduler, flw);
+
+ BLI_task_pool_push(tp, lanpr_compute_feature_lines_worker, flw, true, TASK_PRIORITY_HIGH);
+}
+
+static bool lanpr_camera_exists(struct bContext *c)
+{
+ Scene *s = CTX_data_scene(c);
+ return s->camera ? true : false;
+}
+static int lanpr_compute_feature_lines_exec(struct bContext *C, struct wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneLANPR *lanpr = &scene->lanpr;
+ int result;
+ int is_lanpr_engine = !strcmp(scene->r.engine, RE_engine_id_BLENDER_LANPR);
+
+ if (!is_lanpr_engine && (lanpr->flags & LANPR_ENABLED) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!scene->camera) {
+ BKE_report(op->reports, RPT_ERROR, "There is no active camera in this scene!");
+ printf("LANPR Warning: There is no active camera in this scene!\n");
+ return OPERATOR_FINISHED;
+ }
+
+ int intersections_only = (is_lanpr_engine && lanpr->master_mode != LANPR_MASTER_MODE_SOFTWARE);
+
+ result = ED_lanpr_compute_feature_lines_internal(CTX_data_depsgraph_pointer(C),
+ intersections_only);
+
+ ED_lanpr_rebuild_all_command(lanpr);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return result;
+}
+static void lanpr_compute_feature_lines_cancel(struct bContext *UNUSED(C),
+ struct wmOperator *UNUSED(op))
+{
+ return;
+}
+
+void SCENE_OT_lanpr_calculate_feature_lines(struct wmOperatorType *ot)
+{
+
+ /* identifiers */
+ ot->name = "Calculate Feature Lines";
+ ot->description = "LANPR calculates feature line in current scene";
+ ot->idname = "SCENE_OT_lanpr_calculate";
+
+ ot->poll = lanpr_camera_exists;
+ ot->cancel = lanpr_compute_feature_lines_cancel;
+ ot->exec = lanpr_compute_feature_lines_exec;
+}
+
+static bool lanpr_render_buffer_found(struct bContext *UNUSED(C))
+{
+ if (lanpr_share.render_buffer_shared) {
+ return true;
+ }
+ return false;
+}
+
+/* Access */
+bool ED_lanpr_dpix_shader_error()
+{
+ return lanpr_share.dpix_shader_error;
+}
+
+/* GPencil bindings */
+
+static void lanpr_generate_gpencil_from_chain(Depsgraph *depsgraph,
+ Object *ob,
+ bGPDlayer *UNUSED(gpl),
+ bGPDframe *gpf,
+ int level_start,
+ int level_end,
+ int material_nr,
+ Collection *col,
+ int types)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ LANPR_RenderBuffer *rb = lanpr_share.render_buffer_shared;
+
+ if (rb == NULL) {
+ printf("NULL LANPR rb!\n");
+ return;
+ }
+ if (scene->lanpr.master_mode != LANPR_MASTER_MODE_SOFTWARE) {
+ return;
+ }
+
+ int color_idx = 0;
+ short thickness = 100;
+
+ float mat[4][4];
+
+ unit_m4(mat);
+
+ LANPR_RenderLineChain *rlc;
+ LANPR_RenderLineChainItem *rlci;
+ for (rlc = rb->chains.first; rlc; rlc = rlc->next) {
+
+ if (rlc->picked) {
+ continue;
+ }
+ if (ob && !rlc->object_ref) {
+ continue; /* intersection lines are all in the first collection running into here */
+ }
+ if (!(rlc->type & types)) {
+ continue;
+ }
+ if (rlc->level > level_end || rlc->level < level_start) {
+ continue;
+ }
+ if (ob && &ob->id != rlc->object_ref->id.orig_id) {
+ continue;
+ }
+ if (col && rlc->object_ref) {
+ if (!BKE_collection_has_object_recursive(col, (Object *)rlc->object_ref->id.orig_id)) {
+ continue;
+ }
+ }
+
+ rlc->picked = 1;
+
+ int array_idx = 0;
+ int count = ED_lanpr_count_chain(rlc);
+ bGPDstroke *gps = BKE_gpencil_add_stroke(gpf, color_idx, count, thickness);
+
+ float *stroke_data = BLI_array_alloca(stroke_data, count * GP_PRIM_DATABUF_SIZE);
+
+ for (rlci = rlc->chain.first; rlci; rlci = rlci->next) {
+ float opatity = 1.0f; /* rlci->occlusion ? 0.0f : 1.0f; */
+ stroke_data[array_idx] = rlci->gpos[0];
+ stroke_data[array_idx + 1] = rlci->gpos[1];
+ stroke_data[array_idx + 2] = rlci->gpos[2];
+ stroke_data[array_idx + 3] = 1; /* thickness */
+ stroke_data[array_idx + 4] = opatity; /* hardness? */
+ array_idx += 5;
+ }
+
+ BKE_gpencil_stroke_add_points(gps, stroke_data, count, mat);
+ gps->mat_nr = material_nr;
+ }
+}
+static void lanpr_clear_gp_lanpr_flags(Depsgraph *dg, int frame)
+{
+ DEG_OBJECT_ITER_BEGIN (dg,
+ o,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) {
+ if (o->type == OB_GPENCIL) {
+ bGPdata *gpd = ((Object *)o->id.orig_id)->data;
+ bGPDlayer *gpl;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, frame);
+ if (!gpf) {
+ continue;
+ }
+ gpf->flag &= ~GP_FRAME_LANPR_CLEARED;
+ }
+ }
+ }
+ DEG_OBJECT_ITER_END;
+}
+static void lanpr_update_gp_strokes_recursive(
+ Depsgraph *dg, struct Collection *col, int frame, Object *source_only, Object *target_only)
+{
+ Object *ob;
+ Object *gpobj;
+ ModifierData *md;
+ bGPdata *gpd;
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ CollectionObject *co;
+ CollectionChild *cc;
+
+ for (co = col->gobject.first; co || source_only; co = co->next) {
+ ob = source_only ? source_only : co->ob;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_FeatureLine) {
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+ if (flmd->target && flmd->target->type == OB_GPENCIL) {
+ gpobj = flmd->target;
+
+ if (target_only && target_only != gpobj) {
+ continue;
+ }
+
+ gpd = gpobj->data;
+ gpl = BKE_gpencil_layer_get_index(gpd, flmd->layer, 1);
+ if (!gpl) {
+ gpl = BKE_gpencil_layer_addnew(gpd, "lanpr_layer", true);
+ }
+ gpf = BKE_gpencil_layer_getframe(gpl, frame, GP_GETFRAME_ADD_NEW);
+
+ if (gpf->strokes.first &&
+ !(lanpr_share.render_buffer_shared->scene->lanpr.flags & LANPR_GPENCIL_OVERWRITE)) {
+ continue;
+ }
+
+ if (!(gpf->flag & GP_FRAME_LANPR_CLEARED)) {
+ BKE_gpencil_free_strokes(gpf);
+ gpf->flag |= GP_FRAME_LANPR_CLEARED;
+ }
+
+ lanpr_generate_gpencil_from_chain(dg,
+ ob,
+ gpl,
+ gpf,
+ flmd->level_start,
+ flmd->use_multiple_levels ? flmd->level_end :
+ flmd->level_start,
+ flmd->material,
+ NULL,
+ flmd->types);
+ DEG_id_tag_update(&gpd->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ }
+ if (source_only) {
+ return;
+ }
+ }
+ for (cc = col->children.first; cc; cc = cc->next) {
+ lanpr_update_gp_strokes_recursive(dg, cc->collection, frame, source_only, target_only);
+ }
+}
+static void lanpr_update_gp_strokes_collection(
+ Depsgraph *dg, struct Collection *col, int frame, int this_only, Object *target_only)
+{
+ Object *gpobj;
+ bGPdata *gpd;
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ CollectionChild *cc;
+
+ /* depth first */
+ if (!this_only) {
+ for (cc = col->children.first; cc; cc = cc->next) {
+ lanpr_update_gp_strokes_collection(dg, cc->collection, frame, this_only, target_only);
+ }
+ }
+
+ if (col->lanpr.usage != COLLECTION_LANPR_INCLUDE || !col->lanpr.target) {
+ return;
+ }
+
+ gpobj = col->lanpr.target;
+
+ if (target_only && target_only != gpobj) {
+ return;
+ }
+
+ gpd = gpobj->data;
+ gpl = BKE_gpencil_layer_get_index(gpd, col->lanpr.layer, 1);
+ if (!gpl) {
+ gpl = BKE_gpencil_layer_addnew(gpd, "lanpr_layer", true);
+ }
+ gpf = BKE_gpencil_layer_getframe(gpl, frame, GP_GETFRAME_ADD_NEW);
+
+ if (gpf->strokes.first &&
+ !(lanpr_share.render_buffer_shared->scene->lanpr.flags & LANPR_GPENCIL_OVERWRITE)) {
+ return;
+ }
+
+ if (!(gpf->flag & GP_FRAME_LANPR_CLEARED)) {
+ BKE_gpencil_free_strokes(gpf);
+ gpf->flag |= GP_FRAME_LANPR_CLEARED;
+ }
+
+ lanpr_generate_gpencil_from_chain(dg,
+ NULL,
+ gpl,
+ gpf,
+ col->lanpr.level_start,
+ col->lanpr.use_multiple_levels ? col->lanpr.level_end :
+ col->lanpr.level_start,
+ col->lanpr.material,
+ col,
+ col->lanpr.types);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
+static void lanpr_update_gp_strokes_actual(Scene *scene, Depsgraph *dg)
+{
+ int frame = scene->r.cfra;
+
+ if (!lanpr_share.render_buffer_shared ||
+ lanpr_share.render_buffer_shared->cached_for_frame != frame) {
+ ED_lanpr_compute_feature_lines_internal(dg, 0);
+ }
+
+ ED_lanpr_chain_clear_picked_flag(lanpr_share.render_buffer_shared);
+
+ lanpr_update_gp_strokes_recursive(dg, scene->master_collection, frame, NULL, NULL);
+
+ lanpr_update_gp_strokes_collection(dg, scene->master_collection, frame, 0, NULL);
+
+ lanpr_clear_gp_lanpr_flags(dg, frame);
+}
+static int lanpr_update_gp_strokes_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *dg = CTX_data_depsgraph_pointer(C);
+
+ lanpr_update_gp_strokes_actual(scene, dg);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_bake_gp_strokes_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *dg = CTX_data_depsgraph_pointer(C);
+ int frame;
+ int frame_begin = scene->r.sfra;
+ int frame_end = scene->r.efra;
+
+ for (frame = frame_begin; frame <= frame_end; frame++) {
+ // BKE_scene_frame_set(scene,frame);
+ DEG_evaluate_on_framechange(CTX_data_main(C), dg, frame);
+
+ ED_lanpr_compute_feature_lines_internal(dg, 0);
+
+ ED_lanpr_chain_clear_picked_flag(lanpr_share.render_buffer_shared);
+
+ lanpr_update_gp_strokes_recursive(dg, scene->master_collection, frame, NULL, NULL);
+
+ lanpr_update_gp_strokes_collection(dg, scene->master_collection, frame, 0, NULL);
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_update_gp_target_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *dg = CTX_data_depsgraph_pointer(C);
+ Object *gpo = CTX_data_active_object(C);
+
+ int frame = scene->r.cfra;
+
+ if (!lanpr_share.render_buffer_shared ||
+ lanpr_share.render_buffer_shared->cached_for_frame != frame) {
+ ED_lanpr_compute_feature_lines_internal(dg, 0);
+ }
+
+ ED_lanpr_chain_clear_picked_flag(lanpr_share.render_buffer_shared);
+
+ lanpr_update_gp_strokes_recursive(dg, scene->master_collection, frame, NULL, gpo);
+
+ lanpr_update_gp_strokes_collection(dg, scene->master_collection, frame, 0, gpo);
+
+ lanpr_clear_gp_lanpr_flags(dg, frame);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
+}
+static int lanpr_update_gp_source_exec(struct bContext *C, struct wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *dg = CTX_data_depsgraph_pointer(C);
+ Object *source_obj = CTX_data_active_object(C);
+
+ int frame = scene->r.cfra;
+
+ if (!lanpr_share.render_buffer_shared ||
+ lanpr_share.render_buffer_shared->cached_for_frame != frame) {
+ ED_lanpr_compute_feature_lines_internal(dg, 0);
+ }
+
+ ED_lanpr_chain_clear_picked_flag(lanpr_share.render_buffer_shared);
+
+ lanpr_update_gp_strokes_recursive(dg, scene->master_collection, frame, source_obj, NULL);
+
+ lanpr_update_gp_strokes_collection(dg, scene->master_collection, frame, 0, NULL);
+
+ lanpr_clear_gp_lanpr_flags(dg, frame);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool lanpr_active_is_gpencil_object(bContext *C)
+{
+ Object *o = CTX_data_active_object(C);
+ return o->type == OB_GPENCIL;
+}
+static bool lanpr_active_is_source_object(bContext *C)
+{
+ Object *o = CTX_data_active_object(C);
+ if (o->type != OB_MESH) {
+ return false;
+ }
+ else {
+ ModifierData *md;
+ for (md = o->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_FeatureLine) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void SCENE_OT_lanpr_update_gp_strokes(struct wmOperatorType *ot)
+{
+ ot->name = "Update LANPR Strokes";
+ ot->description = "Update strokes for LANPR grease pencil targets";
+ ot->idname = "SCENE_OT_lanpr_update_gp_strokes";
+
+ ot->exec = lanpr_update_gp_strokes_exec;
+}
+void SCENE_OT_lanpr_bake_gp_strokes(struct wmOperatorType *ot)
+{
+ ot->name = "Bake LANPR Strokes";
+ ot->description = "Bake strokes for LANPR grease pencil targets in all frames";
+ ot->idname = "SCENE_OT_lanpr_bake_gp_strokes";
+
+ ot->exec = lanpr_bake_gp_strokes_exec;
+}
+void OBJECT_OT_lanpr_update_gp_target(struct wmOperatorType *ot)
+{
+ ot->name = "Update Strokes";
+ ot->description = "Update LANPR strokes for selected GPencil object";
+ ot->idname = "OBJECT_OT_lanpr_update_gp_target";
+
+ ot->poll = lanpr_active_is_gpencil_object;
+ ot->exec = lanpr_update_gp_target_exec;
+}
+/* Not working due to lack of GP flags for the object */
+void OBJECT_OT_lanpr_update_gp_source(struct wmOperatorType *ot)
+{
+ ot->name = "Update Strokes";
+ ot->description = "Update LANPR strokes for selected Mesh object.";
+ ot->idname = "OBJECT_OT_lanpr_update_gp_source";
+
+ ot->poll = lanpr_active_is_source_object;
+ ot->exec = lanpr_update_gp_source_exec;
+}
+
+/* Post-frame updater */
+
+void ED_lanpr_post_frame_update_external(Scene *s, Depsgraph *dg)
+{
+ if ((s->lanpr.flags & LANPR_ENABLED) == 0 || !(s->lanpr.flags & LANPR_AUTO_UPDATE)) {
+ return;
+ }
+ if (strcmp(s->r.engine, RE_engine_id_BLENDER_LANPR)) {
+ /* Not LANPR engine, do GPencil updates. */
+ /* LANPR engine will automatically update when drawing the viewport. */
+ if (!lanpr_share.render_buffer_shared ||
+ lanpr_share.render_buffer_shared->cached_for_frame != s->r.cfra) {
+ ED_lanpr_compute_feature_lines_internal(dg, 0);
+ lanpr_update_gp_strokes_actual(s, dg);
+ }
+ }
+}
diff --git a/source/blender/editors/lanpr/lanpr_intern.h b/source/blender/editors/lanpr/lanpr_intern.h
new file mode 100644
index 00000000000..1b34b9d889d
--- /dev/null
+++ b/source/blender/editors/lanpr/lanpr_intern.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#ifndef __LANPR_INTERN_H__
+#define __LANPR_INTERN_H__
+
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "DNA_lanpr_types.h"
+
+#include <math.h>
+#include <string.h>
+
+struct LANPR_StaticMemPoolNode;
+struct LANPR_RenderLine;
+struct LANPR_RenderBuffer;
+
+void *list_append_pointer_static(ListBase *h, struct LANPR_StaticMemPool *smp, void *p);
+void *list_append_pointer_static_sized(ListBase *h, struct LANPR_StaticMemPool *smp, void *p, int size);
+void *list_push_pointer_static(ListBase *h, struct LANPR_StaticMemPool *smp, void *p);
+void *list_push_pointer_static_sized(ListBase *h, struct LANPR_StaticMemPool *smp, void *p, int size);
+
+void *list_append_pointer_static_pool(struct LANPR_StaticMemPool *mph, ListBase *h, void *p);
+void *list_pop_pointer_no_free(ListBase *h);
+void list_remove_pointer_item_no_free(ListBase *h, LinkData *lip);
+
+LANPR_StaticMemPoolNode *mem_new_static_pool(struct LANPR_StaticMemPool *smp);
+void *mem_static_aquire(struct LANPR_StaticMemPool *smp, int size);
+void *mem_static_aquire_thread(struct LANPR_StaticMemPool *smp, int size);
+void *mem_static_destroy(LANPR_StaticMemPool *smp);
+
+void tmat_make_ortho_matrix_44d(
+ double (*mProjection)[4], double xMin, double xMax, double yMin, double yMax, double zMin, double zMax);
+void tmat_make_perspective_matrix_44d(
+ double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax);
+
+int lanpr_count_this_line(struct LANPR_RenderLine *rl, struct LANPR_LineLayer *ll);
+int lanpr_count_intersection_segment_count(struct LANPR_RenderBuffer *rb);
+
+
+#endif
diff --git a/source/blender/editors/lanpr/lanpr_ops.c b/source/blender/editors/lanpr/lanpr_ops.c
new file mode 100644
index 00000000000..f5b23022c5b
--- /dev/null
+++ b/source/blender/editors/lanpr/lanpr_ops.c
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+
+#include "ED_lanpr.h"
+
+void ED_operatortypes_lanpr(void)
+{
+ /* lanpr: */
+ WM_operatortype_append(SCENE_OT_lanpr_calculate_feature_lines);
+ WM_operatortype_append(SCENE_OT_lanpr_add_line_layer);
+ WM_operatortype_append(SCENE_OT_lanpr_delete_line_layer);
+ WM_operatortype_append(SCENE_OT_lanpr_rebuild_all_commands);
+ WM_operatortype_append(SCENE_OT_lanpr_auto_create_line_layer);
+ WM_operatortype_append(SCENE_OT_lanpr_move_line_layer);
+ WM_operatortype_append(SCENE_OT_lanpr_add_line_component);
+ WM_operatortype_append(SCENE_OT_lanpr_delete_line_component);
+ WM_operatortype_append(SCENE_OT_lanpr_enable_all_line_types);
+ WM_operatortype_append(SCENE_OT_lanpr_update_gp_strokes);
+ WM_operatortype_append(SCENE_OT_lanpr_bake_gp_strokes);
+
+ WM_operatortype_append(OBJECT_OT_lanpr_update_gp_target);
+ /* Not working */
+ /* WM_operatortype_append(OBJECT_OT_lanpr_update_gp_source); */
+}
diff --git a/source/blender/editors/lanpr/lanpr_util.c b/source/blender/editors/lanpr/lanpr_util.c
new file mode 100644
index 00000000000..6f9934087fd
--- /dev/null
+++ b/source/blender/editors/lanpr/lanpr_util.c
@@ -0,0 +1,197 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+/* #include <time.h> */
+#include "ED_lanpr.h"
+#include "MEM_guardedalloc.h"
+#include <math.h>
+
+#include "lanpr_intern.h"
+
+/* ===================================================================[slt] */
+
+void *list_append_pointer_static(ListBase *h, LANPR_StaticMemPool *smp, void *data)
+{
+ LinkData *lip;
+ if (!h) {
+ return 0;
+ }
+ lip = mem_static_aquire(smp, sizeof(LinkData));
+ lip->data = data;
+ BLI_addtail(h, lip);
+ return lip;
+}
+void *list_append_pointer_static_sized(ListBase *h, LANPR_StaticMemPool *smp, void *data, int size)
+{
+ LinkData *lip;
+ if (!h) {
+ return 0;
+ }
+ lip = mem_static_aquire(smp, size);
+ lip->data = data;
+ BLI_addtail(h, lip);
+ return lip;
+}
+
+void *list_append_pointer_static_pool(LANPR_StaticMemPool *mph, ListBase *h, void *data)
+{
+ LinkData *lip;
+ if (!h) {
+ return 0;
+ }
+ lip = mem_static_aquire(mph, sizeof(LinkData));
+ lip->data = data;
+ BLI_addtail(h, lip);
+ return lip;
+}
+void *list_pop_pointer_no_free(ListBase *h)
+{
+ LinkData *lip;
+ void *rev = 0;
+ if (!h) {
+ return 0;
+ }
+ lip = BLI_pophead(h);
+ rev = lip ? lip->data : 0;
+ return rev;
+}
+void list_remove_pointer_item_no_free(ListBase *h, LinkData *lip)
+{
+ BLI_remlink(h, (void *)lip);
+}
+
+LANPR_StaticMemPoolNode *mem_new_static_pool(LANPR_StaticMemPool *smp)
+{
+ LANPR_StaticMemPoolNode *smpn = MEM_callocN(LANPR_MEMORY_POOL_128MB, "mempool");
+ smpn->used_byte = sizeof(LANPR_StaticMemPoolNode);
+ BLI_addhead(&smp->pools, smpn);
+ return smpn;
+}
+void *mem_static_aquire(LANPR_StaticMemPool *smp, int size)
+{
+ LANPR_StaticMemPoolNode *smpn = smp->pools.first;
+ void *ret;
+
+ if (!smpn || (smpn->used_byte + size) > LANPR_MEMORY_POOL_128MB) {
+ smpn = mem_new_static_pool(smp);
+ }
+
+ ret = ((unsigned char *)smpn) + smpn->used_byte;
+
+ smpn->used_byte += size;
+
+ return ret;
+}
+void *mem_static_aquire_thread(LANPR_StaticMemPool *smp, int size)
+{
+ LANPR_StaticMemPoolNode *smpn = smp->pools.first;
+ void *ret;
+
+ BLI_spin_lock(&smp->lock_mem);
+
+ if (!smpn || (smpn->used_byte + size) > LANPR_MEMORY_POOL_128MB) {
+ smpn = mem_new_static_pool(smp);
+ }
+
+ ret = ((unsigned char *)smpn) + smpn->used_byte;
+
+ smpn->used_byte += size;
+
+ BLI_spin_unlock(&smp->lock_mem);
+
+ return ret;
+}
+void *mem_static_destroy(LANPR_StaticMemPool *smp)
+{
+ LANPR_StaticMemPoolNode *smpn;
+ void *ret = 0;
+
+ while ((smpn = BLI_pophead(&smp->pools)) != NULL) {
+ MEM_freeN(smpn);
+ }
+
+ smp->each_size = 0;
+
+ return ret;
+}
+
+/* =======================================================================[str] */
+
+real tmat_length_3d(tnsVector3d l)
+{
+ return (sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]));
+}
+real tmat_vector_cross_3d(tnsVector3d result, tnsVector3d l, tnsVector3d r)
+{
+ result[0] = l[1] * r[2] - l[2] * r[1];
+ result[1] = l[2] * r[0] - l[0] * r[2];
+ result[2] = l[0] * r[1] - l[1] * r[0];
+ return tmat_length_3d(result);
+}
+void tmat_make_perspective_matrix_44d(
+ double (*mProjection)[4], real fFov_rad, real fAspect, real zMin, real zMax)
+{
+ real yMax;
+ real yMin;
+ real xMin;
+ real xMax;
+
+ if (fAspect < 1) {
+ yMax = zMin * tan(fFov_rad * 0.5f);
+ yMin = -yMax;
+ xMin = yMin * fAspect;
+ xMax = -xMin;
+ }
+ else {
+ xMax = zMin * tan(fFov_rad * 0.5f);
+ xMin = -xMax;
+ yMin = xMin / fAspect;
+ yMax = -yMin;
+ }
+
+ unit_m4_db(mProjection);
+
+ mProjection[0][0] = (2.0f * zMin) / (xMax - xMin);
+ mProjection[1][1] = (2.0f * zMin) / (yMax - yMin);
+ mProjection[2][0] = (xMax + xMin) / (xMax - xMin);
+ mProjection[2][1] = (yMax + yMin) / (yMax - yMin);
+ mProjection[2][2] = -((zMax + zMin) / (zMax - zMin));
+ mProjection[2][3] = -1.0f;
+ mProjection[3][2] = -((2.0f * (zMax * zMin)) / (zMax - zMin));
+ mProjection[3][3] = 0.0f;
+}
+void tmat_make_ortho_matrix_44d(
+ double (*mProjection)[4], real xMin, real xMax, real yMin, real yMax, real zMin, real zMax)
+{
+ unit_m4_db(mProjection);
+
+ mProjection[0][0] = 2.0f / (xMax - xMin);
+ mProjection[1][1] = 2.0f / (yMax - yMin);
+ mProjection[2][2] = -2.0f / (zMax - zMin);
+ mProjection[3][0] = -((xMax + xMin) / (xMax - xMin));
+ mProjection[3][1] = -((yMax + yMin) / (yMax - yMin));
+ mProjection[3][2] = -((zMax + zMin) / (zMax - zMin));
+ mProjection[3][3] = 1.0f;
+}
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 06c41b78c37..42f722dcdaa 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -28,9 +28,8 @@
#include "DNA_mesh_types.h"
#include "DNA_windowmanager_types.h"
-#ifdef WITH_FREESTYLE
-# include "DNA_meshdata_types.h"
-#endif
+// for freestyle edge mark.
+#include "DNA_meshdata_types.h"
#include "BLI_math.h"
#include "BLI_linklist.h"
@@ -301,12 +300,10 @@ static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false;
case EDGE_MODE_TAG_BEVEL:
return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false;
-#ifdef WITH_FREESTYLE
case EDGE_MODE_TAG_FREESTYLE: {
- FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
- return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false;
+ LanprEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_LANPR_EDGE);
+ return (!fed) ? false : (fed->flag & LANPR_EDGE_MARK) ? true : false;
}
-#endif
}
return 0;
}
@@ -332,19 +329,17 @@ static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
case EDGE_MODE_TAG_BEVEL:
BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
break;
-#ifdef WITH_FREESTYLE
case EDGE_MODE_TAG_FREESTYLE: {
- FreestyleEdge *fed;
- fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
+ LanprEdge *fed;
+ fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_LANPR_EDGE);
if (!val) {
- fed->flag &= ~FREESTYLE_EDGE_MARK;
+ fed->flag &= ~LANPR_EDGE_MARK;
}
else {
- fed->flag |= FREESTYLE_EDGE_MARK;
+ fed->flag |= LANPR_EDGE_MARK;
}
break;
}
-#endif
}
}
@@ -359,13 +354,11 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
case EDGE_MODE_TAG_BEVEL:
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
break;
-#ifdef WITH_FREESTYLE
case EDGE_MODE_TAG_FREESTYLE:
- if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
- BM_data_layer_add(bm, &bm->edata, CD_FREESTYLE_EDGE);
+ if (!CustomData_has_layer(&bm->edata, CD_LANPR_EDGE)) {
+ BM_data_layer_add(bm, &bm->edata, CD_LANPR_EDGE);
}
break;
-#endif
default:
break;
}
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index 2782cc92aca..02ec903dcdf 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -233,7 +233,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
break;
}
case SIMFACE_FREESTYLE: {
- if (!CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
+ if (!CustomData_has_layer(&bm->pdata, CD_LANPR_FACE)) {
face_data_value |= SIMFACE_DATA_FALSE;
continue;
}
@@ -297,9 +297,9 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
break;
}
case SIMFACE_FREESTYLE: {
- FreestyleFace *fface;
- fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE);
- if ((fface == NULL) || ((fface->flag & FREESTYLE_FACE_MARK) == 0)) {
+ LanprFace *fface;
+ fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_LANPR_FACE);
+ if ((fface == NULL) || ((fface->flag & LANPR_FACE_MARK) == 0)) {
face_data_value |= SIMFACE_DATA_FALSE;
}
else {
@@ -357,7 +357,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
break;
}
case SIMFACE_FREESTYLE: {
- has_custom_data_layer = CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE);
+ has_custom_data_layer = CustomData_has_layer(&bm->pdata, CD_LANPR_FACE);
if ((face_data_value == SIMFACE_DATA_TRUE) && !has_custom_data_layer) {
continue;
}
@@ -459,7 +459,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
}
break;
case SIMFACE_FREESTYLE: {
- FreestyleFace *fface;
+ LanprFace *fface;
if (!has_custom_data_layer) {
BLI_assert(face_data_value == SIMFACE_DATA_FALSE);
@@ -467,8 +467,8 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
break;
}
- fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE);
- if (((fface != NULL) && (fface->flag & FREESTYLE_FACE_MARK)) ==
+ fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_LANPR_FACE);
+ if (((fface != NULL) && (fface->flag & LANPR_FACE_MARK)) ==
((face_data_value & SIMFACE_DATA_TRUE) != 0)) {
select = true;
}
@@ -687,7 +687,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
switch (type) {
case SIMEDGE_FREESTYLE: {
- if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
+ if (!CustomData_has_layer(&bm->edata, CD_LANPR_EDGE)) {
edge_data_value |= SIMEDGE_DATA_FALSE;
continue;
}
@@ -745,9 +745,9 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
}
break;
case SIMEDGE_FREESTYLE: {
- FreestyleEdge *fedge;
- fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE);
- if ((fedge == NULL) || ((fedge->flag & FREESTYLE_EDGE_MARK) == 0)) {
+ LanprEdge *fedge;
+ fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_LANPR_EDGE);
+ if ((fedge == NULL) || ((fedge->flag & LANPR_EDGE_MARK) == 0)) {
edge_data_value |= SIMEDGE_DATA_FALSE;
}
else {
@@ -790,7 +790,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
bool has_custom_data_layer = false;
switch (type) {
case SIMEDGE_FREESTYLE: {
- has_custom_data_layer = CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE);
+ has_custom_data_layer = CustomData_has_layer(&bm->edata, CD_LANPR_EDGE);
if ((edge_data_value == SIMEDGE_DATA_TRUE) && !has_custom_data_layer) {
continue;
}
@@ -877,7 +877,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
}
break;
case SIMEDGE_FREESTYLE: {
- FreestyleEdge *fedge;
+ LanprEdge *fedge;
if (!has_custom_data_layer) {
BLI_assert(edge_data_value == SIMEDGE_DATA_FALSE);
@@ -885,8 +885,8 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
break;
}
- fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE);
- if (((fedge != NULL) && (fedge->flag & FREESTYLE_EDGE_MARK)) ==
+ fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_LANPR_EDGE);
+ if (((fedge != NULL) && (fedge->flag & LANPR_EDGE_MARK)) ==
((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) {
select = true;
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index e5023068100..0c4db012786 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -7413,17 +7413,18 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
/** \} */
-#ifdef WITH_FREESTYLE
+/* preserve the edge marking capability */
+//#ifdef WITH_FREESTYLE
/* -------------------------------------------------------------------- */
/** \name Mark Edge (Freestyle) Operator
* \{ */
-static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
+static int edbm_mark_lanpr_edge_exec(bContext *C, wmOperator *op)
{
BMEdge *eed;
BMIter iter;
- FreestyleEdge *fed;
+ LanprEdge *fed;
const bool clear = RNA_boolean_get(op->ptr, "clear");
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -7444,23 +7445,23 @@ static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
continue;
}
- if (!CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
- BM_data_layer_add(em->bm, &em->bm->edata, CD_FREESTYLE_EDGE);
+ if (!CustomData_has_layer(&em->bm->edata, CD_LANPR_EDGE)) {
+ BM_data_layer_add(em->bm, &em->bm->edata, CD_LANPR_EDGE);
}
if (clear) {
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
- fed->flag &= ~FREESTYLE_EDGE_MARK;
+ fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_LANPR_EDGE);
+ fed->flag &= ~LANPR_EDGE_MARK;
}
}
}
else {
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
- fed->flag |= FREESTYLE_EDGE_MARK;
+ fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_LANPR_EDGE);
+ fed->flag |= LANPR_EDGE_MARK;
}
}
}
@@ -7473,17 +7474,17 @@ static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
+void MESH_OT_mark_lanpr_edge(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
- ot->name = "Mark Freestyle Edge";
- ot->description = "(Un)mark selected edges as Freestyle feature edges";
- ot->idname = "MESH_OT_mark_freestyle_edge";
+ ot->name = "Mark LANPR Edge";
+ ot->description = "(Un)mark selected edges as LANPR feature edges";
+ ot->idname = "MESH_OT_mark_lanpr_edge";
/* api callbacks */
- ot->exec = edbm_mark_freestyle_edge_exec;
+ ot->exec = edbm_mark_lanpr_edge_exec;
ot->poll = ED_operator_editmesh;
/* flags */
@@ -7499,11 +7500,11 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
/** \name Mark Face (Freestyle) Operator
* \{ */
-static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
+static int edbm_mark_lanpr_face_exec(bContext *C, wmOperator *op)
{
BMFace *efa;
BMIter iter;
- FreestyleFace *ffa;
+ LanprFace *ffa;
const bool clear = RNA_boolean_get(op->ptr, "clear");
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -7522,23 +7523,23 @@ static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
continue;
}
- if (!CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) {
- BM_data_layer_add(em->bm, &em->bm->pdata, CD_FREESTYLE_FACE);
+ if (!CustomData_has_layer(&em->bm->pdata, CD_LANPR_FACE)) {
+ BM_data_layer_add(em->bm, &em->bm->pdata, CD_LANPR_FACE);
}
if (clear) {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
- ffa->flag &= ~FREESTYLE_FACE_MARK;
+ ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_LANPR_FACE);
+ ffa->flag &= ~LANPR_FACE_MARK;
}
}
}
else {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
- ffa->flag |= FREESTYLE_FACE_MARK;
+ ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_LANPR_FACE);
+ ffa->flag |= LANPR_FACE_MARK;
}
}
}
@@ -7551,17 +7552,17 @@ static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
+void MESH_OT_mark_lanpr_face(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
- ot->name = "Mark Freestyle Face";
- ot->description = "(Un)mark selected faces for exclusion from Freestyle feature edge detection";
- ot->idname = "MESH_OT_mark_freestyle_face";
+ ot->name = "Mark LANPR Face";
+ ot->description = "(Un)mark selected faces for exclusion from LANPR feature edge detection";
+ ot->idname = "MESH_OT_mark_lanpr_face";
/* api callbacks */
- ot->exec = edbm_mark_freestyle_face_exec;
+ ot->exec = edbm_mark_lanpr_face_exec;
ot->poll = ED_operator_editmesh;
/* flags */
@@ -7573,7 +7574,7 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
/** \} */
-#endif /* WITH_FREESTYLE */
+//#endif /* WITH_FREESTYLE */
/* -------------------------------------------------------------------- */
/** \name Loop Normals Editing Tools Modal Map
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 8332cb71f95..3558a07c6fb 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -248,10 +248,8 @@ void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
-#ifdef WITH_FREESTYLE
-void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
-void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
-#endif
+void MESH_OT_mark_lanpr_edge(struct wmOperatorType *ot);
+void MESH_OT_mark_lanpr_face(struct wmOperatorType *ot);
/* *** mesh_data.c *** */
void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 28c55afbf2e..9b6e991a9f5 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -114,9 +114,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_faces_shade_smooth);
WM_operatortype_append(MESH_OT_faces_shade_flat);
WM_operatortype_append(MESH_OT_sort_elements);
-#ifdef WITH_FREESTYLE
- WM_operatortype_append(MESH_OT_mark_freestyle_face);
-#endif
+ WM_operatortype_append(MESH_OT_mark_lanpr_face);
WM_operatortype_append(MESH_OT_delete);
WM_operatortype_append(MESH_OT_delete_loose);
@@ -133,9 +131,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_loop_multi_select);
WM_operatortype_append(MESH_OT_mark_seam);
WM_operatortype_append(MESH_OT_mark_sharp);
-#ifdef WITH_FREESTYLE
- WM_operatortype_append(MESH_OT_mark_freestyle_edge);
-#endif
+ WM_operatortype_append(MESH_OT_mark_lanpr_edge);
+
WM_operatortype_append(MESH_OT_vertices_smooth);
WM_operatortype_append(MESH_OT_vertices_smooth_laplacian);
WM_operatortype_append(MESH_OT_flip_normals);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 82e4d577777..3254b8d9f8a 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -59,6 +59,8 @@
#include "ED_render.h"
#include "ED_view3d.h"
+#include "ED_lanpr.h"
+
#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -95,6 +97,9 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
return;
}
+ /* Temporary solution for updating LANPR GPencil targets. */
+ ED_lanpr_post_frame_update_external(scene, update_ctx->depsgraph);
+
recursive_check = true;
C = CTX_create();
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 95775f80b50..a2f4ca37c08 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -64,6 +64,8 @@
#include "ED_gizmo_library.h"
#include "ED_transform.h"
+#include "ED_lanpr.h"
+
#include "io_ops.h"
/* only call once on startup, storage is global in BKE kernel listbase */
@@ -123,6 +125,8 @@ void ED_spacetypes_init(void)
ED_operatortypes_view2d();
ED_operatortypes_ui();
+ ED_operatortypes_lanpr();
+
ED_screen_user_menu_register();
/* gizmo types */
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index a6584966643..5b57f14133d 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -164,6 +164,31 @@ static int buttons_context_path_world(ButsContextPath *path)
return 0;
}
+static int buttons_context_path_collection(ButsContextPath *path, wmWindow *window)
+{
+ Scene *scene;
+ World *world;
+ PointerRNA *ptr = &path->ptr[path->len - 1];
+
+ /* if we already have a (pinned) collection, we're done */
+ if (RNA_struct_is_a(ptr->type, &RNA_Collection)) {
+ return 1;
+ }
+ /* if we have a view layer, use the view layer's active collection */
+ else if (buttons_context_path_view_layer(path, window)) {
+ ViewLayer *view_layer = path->ptr[path->len - 1].data;
+ Collection *c = view_layer->active_collection->collection;
+ if (c) {
+ RNA_id_pointer_create(&c->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
+ }
+
+ /* no path to a collection possible */
+ return 0;
+}
+
static int buttons_context_path_linestyle(ButsContextPath *path, wmWindow *window)
{
FreestyleLineStyle *linestyle;
@@ -575,6 +600,18 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
case BCONTEXT_WORLD:
found = buttons_context_path_world(path);
break;
+ case BCONTEXT_COLLECTION:
+ found = buttons_context_path_collection(path, window);
+ break;
+ case BCONTEXT_LANPR:
+ if (scene &&
+ ((scene->lanpr.flags & LANPR_ENABLED) || !strcmp(scene->r.engine, "BLENDER_LANPR"))) {
+ found = buttons_context_path_object(path);
+ }
+ else {
+ found = 0;
+ }
+ break;
case BCONTEXT_TOOL:
found = true;
break;
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 23c224f5ae0..6008d06e376 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -160,6 +160,12 @@ static void buttons_main_region_layout_properties(const bContext *C,
case BCONTEXT_WORLD:
contexts[0] = "world";
break;
+ case BCONTEXT_COLLECTION:
+ contexts[0] = "collection";
+ break;
+ case BCONTEXT_LANPR:
+ contexts[0] = "lanpr";
+ break;
case BCONTEXT_OBJECT:
contexts[0] = "object";
break;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 5974100b534..8c4f2f62602 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1043,6 +1043,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
}
WM_msg_subscribe_rna_anon_type(mbus, SceneEEVEE, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_type(mbus, SceneLANPR, &msg_sub_value_region_tag_redraw);
WM_msg_subscribe_rna_anon_type(mbus, SceneDisplay, &msg_sub_value_region_tag_redraw);
WM_msg_subscribe_rna_anon_type(mbus, ObjectDisplay, &msg_sub_value_region_tag_redraw);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 8bd4fda8e23..d20da1ca377 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -392,7 +392,7 @@ int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3
return 0;
}
-static bool testEdgeMark(Mesh *me, FreestyleEdge *fed, const MLoopTri *lt, int i)
+static bool testEdgeMark(Mesh *me, LanprEdge *fed, const MLoopTri *lt, int i)
{
MLoop *mloop = &me->mloop[lt->tri[i]];
MLoop *mloop_next = &me->mloop[lt->tri[(i + 1) % 3]];
@@ -403,7 +403,7 @@ static bool testEdgeMark(Mesh *me, FreestyleEdge *fed, const MLoopTri *lt, int i
return false;
}
- return (fed[mloop->e].flag & FREESTYLE_EDGE_MARK) != 0;
+ return (fed[mloop->e].flag & LANPR_EDGE_MARK) != 0;
}
void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
@@ -427,8 +427,8 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
MVert *mvert = me->mvert;
MLoop *mloop = me->mloop;
MPoly *mpoly = me->mpoly;
- FreestyleEdge *fed = (FreestyleEdge *)CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
- FreestyleFace *ffa = (FreestyleFace *)CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
+ LanprEdge *fed = (LanprEdge *)CustomData_get_layer(&me->edata, CD_LANPR_EDGE);
+ LanprFace *ffa = (LanprFace *)CustomData_get_layer(&me->pdata, CD_LANPR_FACE);
// Compute view matrix
Object *ob_camera_eval = DEG_get_evaluated_object(_depsgraph, RE_GetCamera(_re));
@@ -559,7 +559,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
continue;
}
- bool fm = (ffa) ? (ffa[lt->poly].flag & FREESTYLE_FACE_MARK) != 0 : false;
+ bool fm = (ffa) ? (ffa[lt->poly].flag & LANPR_FACE_MARK) != 0 : false;
bool em1 = false, em2 = false, em3 = false;
if (fed) {
diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h
index af543864536..4b1a86cd7b1 100644
--- a/source/blender/makesdna/DNA_collection_types.h
+++ b/source/blender/makesdna/DNA_collection_types.h
@@ -43,6 +43,49 @@ typedef struct CollectionChild {
struct Collection *collection;
} CollectionChild;
+enum CollectionFeatureLine_Usage {
+ COLLECTION_FEATURE_LINE_INCLUDE = 0,
+ COLLECTION_FEATURE_LINE_OCCLUSION_ONLY = (1 << 0),
+ COLLECTION_FEATURE_LINE_EXCLUDE = (1 << 1),
+};
+
+typedef struct CollectionLANPR {
+ short usage;
+ short force; /* force objects with LANPR modifier follow the rule */
+
+ int types;
+
+ struct Object *target;
+ int replace;
+ int layer;
+ int material;
+ int use_multiple_levels;
+ int level_start;
+ int level_end;
+} CollectionLANPR;
+
+/* CollectionLANPR->types */
+enum CollectionFeatureLine_TypeFlag {
+ COLLECTION_FEATURE_LINE_NONE = (1 << 0),
+ COLLECTION_FEATURE_LINE_CONTOUR = (1 << 1),
+ COLLECTION_FEATURE_LINE_CREASE = (1 << 2),
+ COLLECTION_FEATURE_LINE_MARK = (1 << 3),
+ COLLECTION_FEATURE_LINE_MATERIAL = (1 << 4),
+ COLLECTION_FEATURE_LINE_INTERSECTION = (1 << 5),
+};
+
+#define COLLECTION_FEATURE_LINE_ALL \
+ (COLLECTION_FEATURE_LINE_CONTOUR | COLLECTION_FEATURE_LINE_CREASE | \
+ COLLECTION_FEATURE_LINE_MARK | COLLECTION_FEATURE_LINE_MATERIAL | \
+ COLLECTION_FEATURE_LINE_INTERSECTION)
+
+/* CollectionLANPR->mode */
+enum {
+ COLLECTION_LANPR_INCLUDE = 0,
+ COLLECTION_LANPR_OCCLUSION_ONLY = 1,
+ COLLECTION_LANPR_EXCLUDE = 2,
+};
+
typedef struct Collection {
ID id;
@@ -61,6 +104,9 @@ typedef struct Collection {
short tag;
char _pad[4];
+ /** LANPR engine specific */
+ CollectionLANPR lanpr;
+
/* Runtime. Cache of objects in this collection and all its
* children. This is created on demand when e.g. some physics
* simulation needs it, we don't want to have it for every
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 9799489982d..415eb03e26d 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -139,8 +139,8 @@ typedef enum CustomDataType {
CD_PAINT_MASK = 34,
CD_GRID_PAINT_MASK = 35,
CD_MVERT_SKIN = 36,
- CD_FREESTYLE_EDGE = 37,
- CD_FREESTYLE_FACE = 38,
+ CD_LANPR_EDGE = 37,
+ CD_LANPR_FACE = 38,
CD_MLOOPTANGENT = 39,
CD_TESSLOOPNORMAL = 40,
CD_CUSTOMLOOPNORMAL = 41,
@@ -188,8 +188,8 @@ typedef enum CustomDataType {
#define CD_MASK_PAINT_MASK (1LL << CD_PAINT_MASK)
#define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK)
#define CD_MASK_MVERT_SKIN (1LL << CD_MVERT_SKIN)
-#define CD_MASK_FREESTYLE_EDGE (1LL << CD_FREESTYLE_EDGE)
-#define CD_MASK_FREESTYLE_FACE (1LL << CD_FREESTYLE_FACE)
+#define CD_MASK_FREESTYLE_EDGE (1LL << CD_LANPR_EDGE)
+#define CD_MASK_FREESTYLE_FACE (1LL << CD_LANPR_FACE)
#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT)
#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL)
#define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL)
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 2dffdf82688..9f058051c00 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -294,6 +294,8 @@ typedef enum eGPDframe_Flag {
GP_FRAME_PAINT = (1 << 0),
/* for editing in Action Editor */
GP_FRAME_SELECT = (1 << 1),
+ /* LANPR generation */
+ GP_FRAME_LANPR_CLEARED = (1 << 2),
} eGPDframe_Flag;
/* ***************************************** */
diff --git a/source/blender/makesdna/DNA_lanpr_types.h b/source/blender/makesdna/DNA_lanpr_types.h
new file mode 100644
index 00000000000..2ba468ba56c
--- /dev/null
+++ b/source/blender/makesdna/DNA_lanpr_types.h
@@ -0,0 +1,138 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DNA_LANPR_TYPES_H__
+#define __DNA_LANPR_TYPES_H__
+
+/** \file DNA_lanpr_types.h
+ * \ingroup DNA
+ */
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+
+struct Object;
+struct Material;
+struct Collection;
+
+typedef enum LANPR_TaperSettings {
+ LANPR_USE_DIFFERENT_TAPER = 0,
+ LANPR_USE_SAME_TAPER = 1,
+} LANPR_TaperSettings;
+
+typedef enum LANPR_NomalEffect {
+ /* Shouldn't have access to zero value. */
+ /* Enable/disable is another flag. */
+ LANPR_NORMAL_DIRECTIONAL = 1,
+ LANPR_NORMAL_POINT = 2,
+} LANPR_NomalEffect;
+
+typedef enum LANPR_ComponentMode {
+ LANPR_COMPONENT_MODE_ALL = 0,
+ LANPR_COMPONENT_MODE_OBJECT = 1,
+ LANPR_COMPONENT_MODE_MATERIAL = 2,
+ LANPR_COMPONENT_MODE_COLLECTION = 3,
+} LANPR_ComponentMode;
+
+typedef enum LANPR_ComponentUsage {
+ LANPR_COMPONENT_INCLUSIVE = 0,
+ LANPR_COMPONENT_EXCLUSIVE = 1,
+} LANPR_ComponentUsage;
+
+typedef enum LANPR_ComponentLogic {
+ LANPR_COMPONENT_LOGIG_OR = 0,
+ LANPR_COMPONENT_LOGIC_AND = 1,
+} LANPR_ComponentLogic;
+
+struct DRWShadingGroup;
+
+typedef struct LANPR_LineLayerComponent {
+ struct LANPR_LineLayerComponent *next, *prev;
+
+ struct Object *object_select;
+ struct Material *material_select;
+ struct Collection *collection_select;
+
+ int component_mode;
+ int what;
+
+} LANPR_LineLayerComponent;
+
+typedef struct LANPR_LineType {
+ int use;
+ float thickness;
+ float color[4];
+} LANPR_LineType;
+
+typedef enum LANPR_LineLayerFlags {
+ LANPR_LINE_LAYER_USE_SAME_STYLE = (1 << 0),
+ LANPR_LINE_LAYER_USE_MULTIPLE_LEVELS = (1 << 1),
+ LANPR_LINE_LAYER_NORMAL_ENABLED = (1 << 2),
+ LANPR_LINE_LAYER_NORMAL_INVERSE = (1 << 3),
+} LANPR_LineLayerFlags;
+
+typedef struct LANPR_LineLayer {
+ struct LANPR_LineLayer *next, *prev;
+
+ int flags;
+ int _pad1;
+ int level_start;
+ int level_end;
+
+ /** To be displayed on the list */
+ char name[64];
+
+ LANPR_LineType contour;
+ LANPR_LineType crease;
+ LANPR_LineType edge_mark;
+ LANPR_LineType material_separate;
+ LANPR_LineType intersection;
+
+ float thickness;
+
+ float color[4];
+
+ int normal_mode;
+ float normal_ramp_begin;
+ float normal_ramp_end;
+ float normal_thickness_start;
+ float normal_thickness_end;
+ struct Object *normal_control_object;
+
+ /** For component evaluation */
+ int logic_mode;
+ int _pad3;
+
+ ListBase components;
+
+ struct DRWShadingGroup *shgrp;
+ struct GPUBatch *batch;
+
+} LANPR_LineLayer;
+
+#endif
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 1d1ccef8846..3d309f3c22f 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -27,6 +27,7 @@
#include "DNA_defs.h"
#include "DNA_ID.h"
#include "DNA_listBase.h"
+#include "DNA_lanpr_types.h"
#ifndef MAX_MTEX
# define MAX_MTEX 18
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index f6a7a8a5f5b..50402bbdc87 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -363,24 +363,24 @@ typedef struct MVertSkin {
int flag;
} MVertSkin;
-typedef struct FreestyleEdge {
+typedef struct LanprEdge {
char flag;
char _pad[3];
-} FreestyleEdge;
+} LanprEdge;
-/* FreestyleEdge->flag */
+/* LanprEdge->flag */
enum {
- FREESTYLE_EDGE_MARK = 1,
+ LANPR_EDGE_MARK = 1,
};
-typedef struct FreestyleFace {
+typedef struct LanprFace {
char flag;
char _pad[3];
-} FreestyleFace;
+} LanprFace;
-/* FreestyleFace->flag */
+/* LanprFace->flag */
enum {
- FREESTYLE_FACE_MARK = 1,
+ LANPR_FACE_MARK = 1,
};
/* mvert->flag */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 5243dc1aecd..86d01fd7f54 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -86,6 +86,7 @@ typedef enum ModifierType {
eModifierType_MeshSequenceCache = 52,
eModifierType_SurfaceDeform = 53,
eModifierType_WeightedNormal = 54,
+ eModifierType_FeatureLine = 55,
NUM_MODIFIER_TYPES,
} ModifierType;
@@ -1944,4 +1945,47 @@ enum {
#define MOD_MESHSEQ_READ_ALL \
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
+enum {
+ MOD_MYBMESH_TRIANG = (1 << 0),
+ MOD_MYBMESH_FF_SPLIT = (1 << 1),
+ MOD_MYBMESH_CUSP_D = (1 << 2),
+ MOD_MYBMESH_CUSP_I = (1 << 3),
+ MOD_MYBMESH_FB_SPLIT = (1 << 4),
+ MOD_MYBMESH_RAD_I = (1 << 5),
+ MOD_MYBMESH_RAD_FLIP = (1 << 6),
+ MOD_MYBMESH_OPTI = (1 << 7),
+ MOD_MYBMESH_SEL = (1 << 8),
+};
+
+typedef struct FeatureLineModifierData {
+ ModifierData modifier;
+
+ char _pad[4];
+ int types; // eFeatureLine_TypeFlag
+
+ struct Object *target;
+ int replace;
+ int layer;
+ int material;
+
+ int use_multiple_levels;
+ int level_start;
+ int level_end;
+
+} FeatureLineModifierData;
+
+enum eFeatureLine_TypeFlag {
+ MOD_FEATURE_LINE_NONE = (1 << 0),
+ MOD_FEATURE_LINE_CONTOUR = (1 << 1),
+ MOD_FEATURE_LINE_CREASE = (1 << 2),
+ MOD_FEATURE_LINE_MARK = (1 << 3),
+ MOD_FEATURE_LINE_MATERIAL = (1 << 4),
+ MOD_FEATURE_LINE_INTERSECTION = (1 << 5),
+ MOD_FEATURE_LINE_MODIFIER_MARK = (1 << 6)
+};
+
+#define MOD_FEATURE_LINE_ALL \
+ (MOD_FEATURE_LINE_CONTOUR | MOD_FEATURE_LINE_CREASE | MOD_FEATURE_LINE_MARK | \
+ MOD_FEATURE_LINE_MATERIAL | MOD_FEATURE_LINE_MODIFIER_MARK | MOD_FEATURE_LINE_INTERSECTION)
+
#endif /* __DNA_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index b4d65aa7ea9..f307fc8fc2d 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -186,6 +186,17 @@ typedef struct Object_Runtime {
void *_pad2; /* Padding is here for win32s unconventional struct alignment rules. */
} Object_Runtime;
+typedef struct ObjectLANPR {
+ int usage;
+ char _pad[4];
+} ObjectLANPR;
+
+enum ObjectFeatureLine_Usage {
+ OBJECT_FEATURE_LINE_INHERENT = 0,
+ OBJECT_FEATURE_LINE_OCCLUSION_ONLY = (1 << 0),
+ OBJECT_FEATURE_LINE_EXCLUDE = (1 << 1),
+};
+
typedef struct Object {
ID id;
/** Animation data (must be immediately after id for utilities to use it). */
@@ -396,6 +407,8 @@ typedef struct Object {
struct PreviewImage *preview;
+ ObjectLANPR lanpr;
+
/** Runtime evaluation data (keep last). */
Object_Runtime runtime;
} Object;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 5e96759bc90..89555458f8f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1648,6 +1648,79 @@ typedef struct SceneEEVEE {
float light_threshold;
} SceneEEVEE;
+/* LANPR Global Config */
+
+struct LANPR_RenderBuffer;
+struct LANPR_LineLayer;
+
+typedef enum LANPR_MasterMode {
+ LANPR_MASTER_MODE_SOFTWARE = 0,
+ LANPR_MASTER_MODE_DPIX = 1,
+ LANPR_MASTER_MODE_SNAKE = 2,
+} LANPR_MasterMode;
+
+typedef enum LANPR_PostProcessingStatus {
+ LANPR_POST_PROCESSING_DISABLED = 0,
+ LANPR_POST_PROCESSING_ENABLED = 1,
+} LANPR_PostProcessingStatus;
+
+typedef enum LANPR_MainFlags {
+ LANPR_ENABLED = 0,
+ /* For LANPR->GP and viewport to update automatically. */
+ LANPR_AUTO_UPDATE = (1 << 0),
+ LANPR_SAME_TAPER = (1 << 2),
+ /* Edge split modifier will cause problems in LANPR. */
+ LANPR_DISABLE_EDGE_SPLITS = (1 << 3),
+ LANPR_USE_CHAINING = (1 << 4),
+ LANPR_USE_INTERSECTIONS = (1 << 5),
+ /* Overwrite existing strokes in this frame. */
+ LANPR_GPENCIL_OVERWRITE = (1 << 6),
+} LANPR_MainFlags;
+
+typedef struct SceneLANPR {
+
+ int flags;
+
+ int master_mode; /* LANPR_MasterMode */
+
+ float taper_left_distance;
+ float taper_left_strength;
+ float taper_right_distance;
+ float taper_right_strength;
+
+ /* shared */
+
+ float contour_fade; /* for dpix contour fading,reserved for future usage */
+ float crease_threshold; /* 0-1 range for cosine angle */
+ float crease_fade_threshold; /* for dpix crease fading */
+
+ float line_color[4];
+
+ float depth_width_influence;
+ float depth_width_curve;
+ float depth_alpha_influence;
+ float depth_alpha_curve;
+
+ int gpu_cache_size; /* enum! */
+ int _pad;
+
+ int enable_chain_connection;
+
+ /* offline render */
+ ListBase line_layers;
+ struct LANPR_LineLayer *active_layer;
+
+ float chaining_geometry_threshold;
+ float chaining_image_threshold;
+} SceneLANPR;
+
+enum {
+ LANPR_GPU_CACHE_SIZE_512 = 0,
+ LANPR_GPU_CACHE_SIZE_1K = 1, /* default */
+ LANPR_GPU_CACHE_SIZE_2K = 2,
+ LANPR_GPU_CACHE_SIZE_4K = 3,
+};
+
/* *************************************************************** */
/* Scene ID-Block */
@@ -1778,6 +1851,9 @@ typedef struct Scene {
struct SceneDisplay display;
struct SceneEEVEE eevee;
+
+ /* LANPR stuff */
+ struct SceneLANPR lanpr;
} Scene;
/* **************** RENDERDATA ********************* */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index f212346f547..2740d27e1af 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -195,6 +195,8 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_TOOL = 14,
BCONTEXT_SHADERFX = 15,
BCONTEXT_OUTPUT = 16,
+ BCONTEXT_COLLECTION = 17,
+ BCONTEXT_LANPR = 18,
/* always as last... */
BCONTEXT_TOT,
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 80d37d89f14..c688699cc76 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -84,6 +84,7 @@ static const char *includefiles[] = {
"DNA_mesh_types.h",
"DNA_meshdata_types.h",
"DNA_modifier_types.h",
+ "DNA_lanpr_types.h",
"DNA_lattice_types.h",
"DNA_object_types.h",
"DNA_object_force_types.h",
@@ -1543,6 +1544,7 @@ int main(int argc, char **argv)
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_lanpr_types.h"
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f9f05348c5c..85c841d84db 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -109,6 +109,7 @@ extern StructRNA RNA_CloudsTexture;
extern StructRNA RNA_Collection;
extern StructRNA RNA_CollectionEngineSettings;
extern StructRNA RNA_CollectionProperty;
+extern StructRNA RNA_CollectionLANPR;
extern StructRNA RNA_CollisionModifier;
extern StructRNA RNA_CollisionSensor;
extern StructRNA RNA_CollisionSettings;
@@ -451,6 +452,7 @@ extern StructRNA RNA_NormalEditModifier;
extern StructRNA RNA_Object;
extern StructRNA RNA_ObjectBase;
extern StructRNA RNA_ObjectDisplay;
+extern StructRNA RNA_ObjectLANPR;
extern StructRNA RNA_ObstacleFluidSettings;
extern StructRNA RNA_OceanModifier;
extern StructRNA RNA_OceanTexData;
@@ -523,6 +525,7 @@ extern StructRNA RNA_SPHFluidSettings;
extern StructRNA RNA_Scene;
extern StructRNA RNA_SceneDisplay;
extern StructRNA RNA_SceneEEVEE;
+extern StructRNA RNA_SceneLANPR;
extern StructRNA RNA_SceneObjects;
extern StructRNA RNA_SceneRenderLayer;
extern StructRNA RNA_SceneSequence;
@@ -635,6 +638,7 @@ extern StructRNA RNA_SunLight;
extern StructRNA RNA_SurfaceCurve;
extern StructRNA RNA_SurfaceDeformModifier;
extern StructRNA RNA_SurfaceModifier;
+extern StructRNA RNA_FeatureLineModifier;
extern StructRNA RNA_TexMapping;
extern StructRNA RNA_Text;
extern StructRNA RNA_TextBox;
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 2745cfa9740..89fa80e6dd6 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -53,6 +53,7 @@ set(DEFSRC
rna_light.c
rna_lightprobe.c
rna_linestyle.c
+ rna_lanpr.c
rna_main.c
rna_mask.c
rna_material.c
@@ -384,6 +385,7 @@ set(LIB
bf_editor_object
bf_editor_physics
bf_editor_render
+ bf_editor_lanpr
bf_editor_scene
bf_editor_sculpt_paint
bf_editor_space_clip
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 5aaddc30e07..1617d85b6c2 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4226,6 +4226,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_lattice.c", "rna_lattice_api.c", RNA_def_lattice},
{"rna_layer.c", NULL, RNA_def_view_layer},
{"rna_linestyle.c", NULL, RNA_def_linestyle},
+ {"rna_lanpr.c", NULL, RNA_def_lanpr},
{"rna_main.c", "rna_main_api.c", RNA_def_main},
{"rna_material.c", "rna_material_api.c", RNA_def_material},
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
index fb366422f34..e438cf1f491 100644
--- a/source/blender/makesrna/intern/rna_collection.c
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -365,6 +365,90 @@ static void rna_def_collection_children(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
+static void rna_def_collection_lanpr(BlenderRNA *brna, StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem rna_collection_lanpr_usage[] = {
+ {COLLECTION_LANPR_INCLUDE, "INCLUDE", 0, "Include", "Collection will produce feature lines"},
+ {COLLECTION_LANPR_OCCLUSION_ONLY,
+ "OCCLUSION_ONLY",
+ 0,
+ "Occlusion Only",
+ "Only use the collection to produce occlusion"},
+ {COLLECTION_LANPR_EXCLUDE, "EXCLUDE", 0, "Exclude", "Don't use this collection in LANPR"},
+ {0, NULL, 0, NULL, NULL}};
+
+ srna = RNA_def_struct(brna, "CollectionLANPR", NULL);
+ RNA_def_struct_sdna(srna, "CollectionLANPR");
+ RNA_def_struct_ui_text(srna, "Collection LANPR Usage", "LANPR usage for this collection");
+
+ prop = RNA_def_property(srna, "usage", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_collection_lanpr_usage);
+ RNA_def_property_enum_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Usage", "How to use this collection in LANPR");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", COLLECTION_FEATURE_LINE_CONTOUR);
+ RNA_def_property_ui_text(prop, "Contour", "Contour lines");
+
+ prop = RNA_def_property(srna, "use_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", COLLECTION_FEATURE_LINE_CREASE);
+ RNA_def_property_ui_text(prop, "Crease", "Crease lines");
+
+ prop = RNA_def_property(srna, "enable_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", COLLECTION_FEATURE_LINE_MARK);
+ RNA_def_property_ui_text(prop, "Mark", "Marked NPR edges");
+
+ prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", COLLECTION_FEATURE_LINE_MATERIAL);
+ RNA_def_property_ui_text(prop, "Material", "Material lines");
+
+ prop = RNA_def_property(srna, "use_intersection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", COLLECTION_FEATURE_LINE_INTERSECTION);
+ RNA_def_property_ui_text(prop, "Intersection", "Intersection lines");
+
+ prop = RNA_def_property(srna, "force", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(
+ prop, "Force", "Force object that has LANPR modifiers to follow collection usage flag");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_ui_text(prop, "Target", "Grease Pencil object to put the stroke result");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+
+ prop = RNA_def_property(srna, "replace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Replace", "Replace existing GP frames");
+
+ prop = RNA_def_property(srna, "layer", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 1, -1);
+ RNA_def_property_ui_text(prop, "Layer", "Grease Pencil layer to put the results into");
+
+ prop = RNA_def_property(srna, "material", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 1, -1);
+ RNA_def_property_ui_text(
+ prop, "Material", "Grease Pencil material to use to generate the results");
+
+ prop = RNA_def_property(srna, "use_multiple_levels", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_multiple_levels", 0);
+ RNA_def_property_ui_text(prop, "Multiple Levels", "Use multiple occlusion levels");
+
+ prop = RNA_def_property(srna, "level_start", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_range(prop, 0, 255, 1, -1);
+ RNA_def_property_ui_text(prop, "Level Start", "Occlusion level start");
+
+ prop = RNA_def_property(srna, "level_end", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_range(prop, 0, 255, 1, -1);
+ RNA_def_property_ui_text(prop, "Level End", "Occlusion level end");
+}
+
void RNA_def_collections(BlenderRNA *brna)
{
StructRNA *srna;
@@ -458,6 +542,11 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1);
RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
+
+ rna_def_collection_lanpr(brna, srna);
+ prop = RNA_def_property(srna, "lanpr", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CollectionLANPR");
+ RNA_def_property_ui_text(prop, "LANPR", "LANPR settings for the collection");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index fa13c56e4fa..e5058626180 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -160,6 +160,7 @@ void RNA_def_key(struct BlenderRNA *brna);
void RNA_def_light(struct BlenderRNA *brna);
void RNA_def_lattice(struct BlenderRNA *brna);
void RNA_def_linestyle(struct BlenderRNA *brna);
+void RNA_def_lanpr(struct BlenderRNA *brna);
void RNA_def_main(struct BlenderRNA *brna);
void RNA_def_material(struct BlenderRNA *brna);
void RNA_def_mesh(struct BlenderRNA *brna);
diff --git a/source/blender/makesrna/intern/rna_lanpr.c b/source/blender/makesrna/intern/rna_lanpr.c
new file mode 100644
index 00000000000..1a4ef2aefd8
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_lanpr.c
@@ -0,0 +1,235 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation (2008).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_lanpr.c
+ * \ingroup RNA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "DNA_lanpr_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#ifdef RNA_RUNTIME
+
+#else
+
+static void rna_def_lanpr_line_layer(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem rna_enum_lanpr_normal_mode[] = {
+ {LANPR_NORMAL_DIRECTIONAL,
+ "DIRECTIONAL",
+ 0,
+ "Directional",
+ "Use directional vector to control line width"},
+ /* Seems working... */
+ {LANPR_NORMAL_POINT, "POINT", 0, "Point", "Use Point Light Style"},
+ {0, NULL, 0, NULL, NULL}};
+
+ srna = RNA_def_struct(brna, "LANPR_LineLayer", NULL);
+ RNA_def_struct_sdna(srna, "LANPR_LineLayer");
+ RNA_def_struct_ui_text(srna, "Line Layer", "LANPR_LineLayer");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Name of this layer");
+
+ prop = RNA_def_property(srna, "normal_enabled", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_LINE_LAYER_NORMAL_ENABLED);
+ RNA_def_property_ui_text(prop, "Enabled", "Enable normal controlled line weight");
+
+ prop = RNA_def_property(srna, "normal_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_lanpr_normal_mode);
+ RNA_def_property_ui_text(prop, "Normal", "Normal controlled line weight");
+
+ prop = RNA_def_property(srna, "normal_effect_inverse", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_LINE_LAYER_NORMAL_INVERSE);
+ RNA_def_property_ui_text(prop, "Inverse", "Inverse normal effect");
+
+ prop = RNA_def_property(
+ srna, "normal_ramp_begin", PROP_FLOAT, PROP_FACTOR); /* begin is least strength */
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Ramp Begin", "Normal ramp begin value");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2);
+
+ prop = RNA_def_property(srna, "normal_ramp_end", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Ramp End", "Normal ramp end value");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2);
+
+ prop = RNA_def_property(
+ srna, "normal_thickness_start", PROP_FLOAT, PROP_NONE); /* begin is least strength */
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_ui_text(prop, "Thickness Begin", "Normal thickness begin value");
+ RNA_def_property_ui_range(prop, 0.0f, 5.0f, 0.05, 2);
+
+ prop = RNA_def_property(srna, "normal_thickness_end", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 1.5f);
+ RNA_def_property_ui_text(prop, "Thickness End", "Normal thickness end value");
+ RNA_def_property_ui_range(prop, 0.0f, 5.0f, 0.05, 2);
+
+ prop = RNA_def_property(srna, "normal_control_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Normal style control object");
+
+ prop = RNA_def_property(srna, "use_same_style", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_LINE_LAYER_USE_SAME_STYLE);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Same Style", "Use same styles for multiple line types.");
+
+ prop = RNA_def_property(srna, "use_multiple_levels", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_LINE_LAYER_USE_MULTIPLE_LEVELS);
+ RNA_def_property_ui_text(
+ prop, "Use Multiple Levels", "Select lines from multiple occlusion levels");
+
+ /* types */
+ prop = RNA_def_property(srna, "contour", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LANPR_LineType");
+ RNA_def_property_ui_text(prop, "Contour", "Contour line type");
+
+ prop = RNA_def_property(srna, "crease", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LANPR_LineType");
+ RNA_def_property_ui_text(prop, "Crease", "Creaseline type");
+
+ prop = RNA_def_property(srna, "edge_mark", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LANPR_LineType");
+ RNA_def_property_ui_text(prop, "Edge Mark", "Edge mark line type");
+
+ prop = RNA_def_property(srna, "material_separate", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LANPR_LineType");
+ RNA_def_property_ui_text(prop, "Material Separate", "Material separate line type");
+
+ prop = RNA_def_property(srna, "intersection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LANPR_LineType");
+ RNA_def_property_ui_text(prop, "Intersection", "Intersection line type");
+
+ prop = RNA_def_property(srna, "level_start", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Level Start", "Occlusion level start");
+ RNA_def_property_range(prop, 0, 128);
+
+ prop = RNA_def_property(srna, "level_end", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Level End", "Occlusion level end");
+ RNA_def_property_range(prop, 0, 128);
+
+ prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Thickness", "Master Thickness");
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 2);
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Master Color");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 2);
+
+ prop = RNA_def_property(srna, "components", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "components", NULL);
+ RNA_def_property_struct_type(prop, "LANPR_LineLayerComponent");
+ RNA_def_property_ui_text(prop, "Components", "Line Layer Components");
+}
+
+static void rna_def_lanpr_line_type(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LANPR_LineType", NULL);
+ RNA_def_struct_sdna(srna, "LANPR_LineType");
+ RNA_def_struct_ui_text(srna, "Line Type", "LANPR_LineType");
+
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Use", "This line type is enabled");
+
+ prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Thickness", "Relative thickness to master");
+ RNA_def_property_ui_range(prop, 0.0f, 2.0f, 0.01, 2);
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Color of this line type");
+}
+
+static void rna_def_lanpr_line_component(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem lanpr_line_component_modes[] = {
+ {0, "ALL", 0, "All", "Show all lines, lines are already selected are not affected"},
+ {1, "OBJECT", 0, "Object", "Filter lines for selected object"},
+ {2, "MATERIAL", 0, "Material", "Filter lines that touches specific material"},
+ {3, "COLLECTION", 0, "Collection", "Filter lines in specific collections"},
+ {0, NULL, 0, NULL, NULL}};
+
+ srna = RNA_def_struct(brna, "LANPR_LineLayerComponent", NULL);
+ RNA_def_struct_sdna(srna, "LANPR_LineLayerComponent");
+ RNA_def_struct_ui_text(srna, "Line Layer Component", "LANPR_LineLayerComponent");
+
+ prop = RNA_def_property(srna, "component_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, lanpr_line_component_modes);
+ RNA_def_property_enum_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Mode", "Limit the range of displayed lines");
+
+ prop = RNA_def_property(srna, "object_select", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Display lines for selected object");
+
+ prop = RNA_def_property(srna, "material_select", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Material", "Display lines that touches specific material");
+
+ prop = RNA_def_property(srna, "collection_select", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Collection", "Display lines in specific collections");
+}
+
+void RNA_def_lanpr(BlenderRNA *brna)
+{
+ rna_def_lanpr_line_component(brna);
+ rna_def_lanpr_line_type(brna);
+ rna_def_lanpr_line_layer(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index f7e0990aa88..704bb11fc8a 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -603,25 +603,25 @@ static bool rna_MEdge_freestyle_edge_mark_get(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
MEdge *medge = (MEdge *)ptr->data;
- FreestyleEdge *fed = CustomData_get(&me->edata, (int)(medge - me->medge), CD_FREESTYLE_EDGE);
+ LanprEdge *fed = CustomData_get(&me->edata, (int)(medge - me->medge), CD_LANPR_EDGE);
- return fed && (fed->flag & FREESTYLE_EDGE_MARK) != 0;
+ return fed && (fed->flag & LANPR_EDGE_MARK) != 0;
}
static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value)
{
Mesh *me = rna_mesh(ptr);
MEdge *medge = (MEdge *)ptr->data;
- FreestyleEdge *fed = CustomData_get(&me->edata, (int)(medge - me->medge), CD_FREESTYLE_EDGE);
+ LanprEdge *fed = CustomData_get(&me->edata, (int)(medge - me->medge), CD_LANPR_EDGE);
if (!fed) {
- fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_CALLOC, NULL, me->totedge);
+ fed = CustomData_add_layer(&me->edata, CD_LANPR_EDGE, CD_CALLOC, NULL, me->totedge);
}
if (value) {
- fed->flag |= FREESTYLE_EDGE_MARK;
+ fed->flag |= LANPR_EDGE_MARK;
}
else {
- fed->flag &= ~FREESTYLE_EDGE_MARK;
+ fed->flag &= ~LANPR_EDGE_MARK;
}
}
@@ -629,25 +629,25 @@ static bool rna_MPoly_freestyle_face_mark_get(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
MPoly *mpoly = (MPoly *)ptr->data;
- FreestyleFace *ffa = CustomData_get(&me->pdata, (int)(mpoly - me->mpoly), CD_FREESTYLE_FACE);
+ LanprFace *ffa = CustomData_get(&me->pdata, (int)(mpoly - me->mpoly), CD_LANPR_FACE);
- return ffa && (ffa->flag & FREESTYLE_FACE_MARK) != 0;
+ return ffa && (ffa->flag & LANPR_FACE_MARK) != 0;
}
static void rna_MPoly_freestyle_face_mark_set(PointerRNA *ptr, int value)
{
Mesh *me = rna_mesh(ptr);
MPoly *mpoly = (MPoly *)ptr->data;
- FreestyleFace *ffa = CustomData_get(&me->pdata, (int)(mpoly - me->mpoly), CD_FREESTYLE_FACE);
+ LanprFace *ffa = CustomData_get(&me->pdata, (int)(mpoly - me->mpoly), CD_LANPR_FACE);
if (!ffa) {
- ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_CALLOC, NULL, me->totpoly);
+ ffa = CustomData_add_layer(&me->pdata, CD_LANPR_FACE, CD_CALLOC, NULL, me->totpoly);
}
if (value) {
- ffa->flag |= FREESTYLE_FACE_MARK;
+ ffa->flag |= LANPR_FACE_MARK;
}
else {
- ffa->flag &= ~FREESTYLE_FACE_MARK;
+ ffa->flag &= ~LANPR_FACE_MARK;
}
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 712fe2a9984..8473d48269a 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -104,6 +104,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WIREFRAME,
"Wireframe",
"Generate a wireframe on the edges of a mesh"},
+ {eModifierType_FeatureLine,
+ "FEATURE_LINE",
+ ICON_MOD_WIREFRAME,
+ "Feature Line",
+ "Extract feature lines into an GPencil object target"},
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
@@ -573,6 +578,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_SurfaceDeformModifier;
case eModifierType_WeightedNormal:
return &RNA_WeightedNormalModifier;
+ case eModifierType_FeatureLine:
+ return &RNA_FeatureLineModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -5990,6 +5997,89 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_featureline(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "FeatureLineModifier", "Modifier");
+ RNA_def_struct_ui_text(
+ srna, "Feature Line Modifier", "To extract feature lines from a mesh using LANPR");
+ RNA_def_struct_sdna(srna, "FeatureLineModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_WIREFRAME);
+
+ prop = RNA_def_property(srna, "use_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", MOD_FEATURE_LINE_CONTOUR);
+ RNA_def_property_ui_text(prop, "Contour", "Contour lines");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", MOD_FEATURE_LINE_CREASE);
+ RNA_def_property_ui_text(prop, "Crease", "Crease lines");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "enable_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", MOD_FEATURE_LINE_MARK);
+ RNA_def_property_ui_text(prop, "Mark", "Marked NPR edges");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", MOD_FEATURE_LINE_MATERIAL);
+ RNA_def_property_ui_text(prop, "Material", "Material lines");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_intersection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", MOD_FEATURE_LINE_INTERSECTION);
+ RNA_def_property_ui_text(prop, "Intersection", "Intersection lines");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "enable_modifier_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "types", MOD_FEATURE_LINE_MODIFIER_MARK);
+ RNA_def_property_ui_text(prop, "Modifier Mark", "Modifier mark lines");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_ui_text(prop, "Target", "GPencil object to put the stroke result");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "replace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Replace", "Replace existing GP frames");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 1, -1);
+ RNA_def_property_ui_text(prop, "Layer", "Grease Pencil layer to put the results into");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 1, -1);
+ RNA_def_property_ui_text(
+ prop, "Material", "Grease Pencil material to use to generate the results");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_multiple_levels", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_multiple_levels", 0);
+ RNA_def_property_ui_text(prop, "Multiple Levels", "Use multiple occlusion levels");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "level_start", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_range(prop, 0, 255, 1, -1);
+ RNA_def_property_ui_text(prop, "Level Start", "Occlusion level start");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "level_end", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_range(prop, 0, 255, 1, -1);
+ RNA_def_property_ui_text(prop, "Level End", "Occlusion level end");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6115,6 +6205,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_meshseqcache(brna);
rna_def_modifier_surfacedeform(brna);
rna_def_modifier_weightednormal(brna);
+ rna_def_modifier_featureline(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 6dd75100e71..8289183ed09 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2372,6 +2372,39 @@ static void rna_def_object_display(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
}
+static void rna_def_object_lanpr(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_feature_line_usage_items[] = {
+ {OBJECT_FEATURE_LINE_INHERENT,
+ "INHEREIT",
+ 0,
+ "Inhereit",
+ "Follow settings from the parent collection"},
+ {OBJECT_FEATURE_LINE_OCCLUSION_ONLY,
+ "OCCLUSION_ONLY",
+ 0,
+ "Occlusion Only",
+ "Don't produce lines, only used as occlusion object"},
+ {OBJECT_FEATURE_LINE_EXCLUDE,
+ "EXCLUDE",
+ 0,
+ "Exclude",
+ "Don't use this object for LANPR rendering"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "ObjectLANPR", NULL);
+ RNA_def_struct_ui_text(srna, "Object LANPR", "Object lanpr settings");
+ RNA_def_struct_sdna(srna, "ObjectLANPR");
+
+ prop = RNA_def_property(srna, "usage", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_feature_line_usage_items);
+ RNA_def_property_ui_text(prop, "Usage", "How to use this object");
+}
+
static void rna_def_object(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3120,6 +3153,11 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_Object_display_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Object Display", "Object display settings for 3d viewport");
+ /* LANPR */
+ prop = RNA_def_property(srna, "lanpr", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ObjectLANPR");
+ RNA_def_property_ui_text(prop, "LANPR", "LANPR settings for the object");
+
RNA_api_object(srna);
}
@@ -3132,6 +3170,7 @@ void RNA_def_object(BlenderRNA *brna)
rna_def_face_map(brna);
rna_def_material_slot(brna);
rna_def_object_display(brna);
+ rna_def_object_lanpr(brna);
RNA_define_animate_sdna(true);
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index f37ee5ff817..066a45072da 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -33,6 +33,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h" /* TransformOrientation */
+#include "DNA_lanpr_types.h"
#include "IMB_imbuf_types.h"
@@ -2507,6 +2508,64 @@ static char *rna_UnitSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("unit_settings");
}
+/* lanpr */
+
+void rna_lanpr_active_line_layer_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ SceneLANPR *lanpr = (SceneLANPR *)ptr->data;
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&lanpr->line_layers) - 1);
+}
+
+int rna_lanpr_active_line_layer_index_get(PointerRNA *ptr)
+{
+ SceneLANPR *lanpr = (SceneLANPR *)ptr->data;
+ LANPR_LineLayer *ls;
+ int i = 0;
+ for (ls = lanpr->line_layers.first; ls; ls = ls->next) {
+ if (ls == lanpr->active_layer)
+ return i;
+ i++;
+ }
+ return 0;
+}
+
+void rna_lanpr_active_line_layer_index_set(PointerRNA *ptr, int value)
+{
+ SceneLANPR *lanpr = (SceneLANPR *)ptr->data;
+ LANPR_LineLayer *ls;
+ int i = 0;
+ for (ls = lanpr->line_layers.first; ls; ls = ls->next) {
+ if (i == value) {
+ lanpr->active_layer = ls;
+ return;
+ }
+ i++;
+ }
+ lanpr->active_layer = 0;
+}
+
+PointerRNA rna_lanpr_active_line_layer_get(PointerRNA *ptr)
+{
+ SceneLANPR *lanpr = (SceneLANPR *)ptr->data;
+ LANPR_LineLayer *ls = lanpr->active_layer;
+ return rna_pointer_inherit_refine(ptr, &RNA_LANPR_LineLayer, ls);
+}
+
+void rna_lanpr_active_line_layer_set(PointerRNA *ptr, PointerRNA value)
+{
+ SceneLANPR *lanpr = (SceneLANPR *)ptr->data;
+ lanpr->active_layer = value.data;
+}
+
+extern bool ED_lanpr_dpix_shader_error(void);
+
+static bool rna_lanpr_shader_error_get(PointerRNA *UNUSED(ptr))
+{
+ return ED_lanpr_dpix_shader_error();
+}
+
#else
/* Grease Pencil Interpolation tool settings */
@@ -7197,6 +7256,225 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
}
+static void rna_def_scene_lanpr(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem rna_enum_lanpr_master_mode[] = {
+ {LANPR_MASTER_MODE_SOFTWARE, "SOFTWARE", 0, "CPU", "Software edge calculation"},
+ {LANPR_MASTER_MODE_DPIX, "DPIX", 0, "GPU", "DPIX GPU edge extraction"},
+ /* Temporally remove image filter mode. */
+ /* {LANPR_MASTER_MODE_SNAKE, "SNAKE", 0, "Edge Detection", "Edge detection filter and
+ tracing"}, */
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem rna_enum_lanpr_use_same_taper[] = {
+ {LANPR_USE_DIFFERENT_TAPER, "DISABLED", 0, "Different", "Use different taper value"},
+ {LANPR_USE_SAME_TAPER,
+ "ENABLED",
+ 0,
+ "Same",
+ "Use same taper value for both sides of the line"},
+ {0, NULL, 0, NULL, NULL}};
+ static const EnumPropertyItem rna_enum_lanpr_gpu_cache_size[] = {
+ {LANPR_GPU_CACHE_SIZE_512, "S512", 0, "512", "512px texture as cache"},
+ {LANPR_GPU_CACHE_SIZE_1K, "S1K", 0, "1K", "1K px texture as cache"},
+ {LANPR_GPU_CACHE_SIZE_2K, "S2K", 0, "2K", "2K px texture as cache"},
+ {LANPR_GPU_CACHE_SIZE_4K, "S4K", 0, "4K", "4K px texture as cache"},
+ {0, NULL, 0, NULL, NULL}};
+
+ srna = RNA_def_struct(brna, "SceneLANPR", NULL);
+ RNA_def_struct_sdna(srna, "SceneLANPR");
+ RNA_def_struct_ui_text(srna, "Scene LANPR Config", "LANPR global config");
+
+ prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_ENABLED);
+ RNA_def_property_ui_text(prop, "Enabled", "Is LANPR enabled");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "auto_update", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_AUTO_UPDATE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(
+ prop, "Auto Update", "Automatically update LANPR cache when frame changes");
+
+ prop = RNA_def_property(srna, "gpencil_overwrite", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_GPENCIL_OVERWRITE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop,
+ "GPencil Overwrite",
+ "Overwrite existing strokes in the current frame of target GP objects");
+
+ prop = RNA_def_property(srna, "master_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_lanpr_master_mode);
+ RNA_def_property_enum_default(prop, LANPR_MASTER_MODE_DPIX);
+ RNA_def_property_ui_text(prop, "Master Mode", "Choose calculation mode for NPR Line");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "gpu_cache_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_lanpr_gpu_cache_size);
+ RNA_def_property_enum_default(prop, LANPR_GPU_CACHE_SIZE_512);
+ RNA_def_property_ui_text(prop, "GPU Cache Size", "Texture cache size for DPIX algorithm");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "depth_width_influence", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_float_default(prop, 0.3f);
+ RNA_def_property_ui_text(prop, "Width Influence", "Use camera distance to control line width.");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "depth_width_curve", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.3f);
+ RNA_def_property_ui_text(prop, "Width Curve", "Width curve");
+ RNA_def_property_ui_range(prop, -5.0f, 0.90f, 0.1, 1);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "depth_alpha_influence", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_float_default(prop, 0.3f);
+ RNA_def_property_ui_text(prop, "Alpha Influence", "Use camera distance to control line alpha.");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "depth_alpha_curve", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.3f);
+ RNA_def_property_ui_text(prop, "Alpha Curve", "alpha curve");
+ RNA_def_property_ui_range(prop, -5.0f, 0.90f, 0.1, 1);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "taper_left_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 20.0f);
+ RNA_def_property_ui_text(prop, "Left Distance", "Left side taper distance");
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "taper_right_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 20.0f);
+ RNA_def_property_ui_text(prop, "Right Distance", "Right side taper distance");
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "taper_left_strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Left Strength", "Left side taper strength");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "taper_right_strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Right Strength", "Right side taper strength");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_same_taper", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_SAME_TAPER);
+ RNA_def_property_ui_text(prop, "Same Taper", "Same/Different taper value");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "line_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Line Color", "Drawing lines using this color");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "crease_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Crease Threshold", "cosine value of face angle");
+ RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.01, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "crease_fade_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Crease Fade", "cosine value of face angle");
+ RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.01, 2);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_intersections", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_USE_INTERSECTIONS);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Calculate Intersections", "Calculate Intersections or not");
+
+ prop = RNA_def_property(srna, "enable_chaining", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LANPR_USE_CHAINING);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Enable Chaining", "Chain Feature Lines After Occlusion Test");
+
+ prop = RNA_def_property(srna, "enable_chain_connection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop,
+ "Enable Chain Connection",
+ "Connect short chains in the image space into one longer chain");
+
+ /* should be read-only */
+ prop = RNA_def_property(srna, "shader_error", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_funcs(prop, "rna_lanpr_shader_error_get", "");
+ RNA_def_property_ui_text(
+ prop, "DPIX Shader Error", "Can't compile DPIX transform shader on your GPU.");
+
+ prop = RNA_def_property(srna, "chaining_geometry_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_ui_text(prop,
+ "Geometry Threshold",
+ "Segments where their geometric distance between them lower than this "
+ "will be chained together");
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+
+ prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.01f);
+ RNA_def_property_ui_text(
+ prop,
+ "Image Threshold",
+ "Segments where their image distance between them lower than this will be chained together");
+ RNA_def_property_ui_range(prop, 0.0f, 0.3f, 0.001, 4);
+ RNA_def_property_range(prop, 0.0f, 0.3f);
+
+ /* here's the collection stuff.... */
+
+ prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "line_layers", NULL);
+ RNA_def_property_struct_type(prop, "LANPR_LineLayer");
+ RNA_def_property_ui_text(prop, "Line Layers", "LANPR Line Layers");
+
+ /* this part I refered to gpencil's and freestyle's and it seems that there's no difference */
+ RNA_def_property_srna(prop, "LineLayers");
+ srna = RNA_def_struct(brna, "LineLayers", NULL);
+ RNA_def_struct_sdna(srna, "SceneLANPR");
+ RNA_def_struct_ui_text(srna, "LANPR Line Layers", "");
+
+ prop = RNA_def_property(srna, "active_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LANPR_LineLayer");
+ RNA_def_property_pointer_funcs(
+ prop, "rna_lanpr_active_line_layer_get", "rna_lanpr_active_line_layer_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Line Layer", "Active line layer being displayed");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "active_layer_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop,
+ "rna_lanpr_active_line_layer_index_get",
+ "rna_lanpr_active_line_layer_index_set",
+ "rna_lanpr_active_line_layer_index_range");
+ RNA_def_property_ui_text(prop, "Active Line Layer Index", "Index of active line layer slot");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
void RNA_def_scene(BlenderRNA *brna)
{
StructRNA *srna;
@@ -7672,6 +7950,11 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "SceneEEVEE");
RNA_def_property_ui_text(prop, "EEVEE", "EEVEE settings for the scene");
+ /* LANPR */
+ prop = RNA_def_property(srna, "lanpr", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneLANPR");
+ RNA_def_property_ui_text(prop, "LANPR", "LANPR settings for the scene");
+
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -7689,6 +7972,7 @@ void RNA_def_scene(BlenderRNA *brna)
rna_def_display_safe_areas(brna);
rna_def_scene_display(brna);
rna_def_scene_eevee(brna);
+ rna_def_scene_lanpr(brna);
RNA_define_animate_sdna(true);
/* *** Animated *** */
rna_def_scene_render_data(brna);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 727745e69dd..86df9b5f3af 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -384,20 +384,18 @@ const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
* but helps for context-less access (e.g. doc, i18n...). */
static const EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_TOOL, "TOOL", ICON_TOOL_SETTINGS, "Tool", "Active Tool and Workspace settings"},
- {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene Properties"},
- {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render Properties"},
- {BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output Properties"},
- {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer Properties"},
- {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World Properties"},
- {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object Properties"},
- {BCONTEXT_CONSTRAINT,
- "CONSTRAINT",
- ICON_CONSTRAINT,
- "Constraints",
- "Object Constraint Properties"},
- {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifier Properties"},
- {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data Properties"},
- {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone Properties"},
+ {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene"},
+ {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render"},
+ {BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output"},
+ {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer"},
+ {BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"},
+ {BCONTEXT_COLLECTION, "COLLECTION", ICON_GROUP, "Collection", "Collection"},
+ {BCONTEXT_LANPR, "LANPR", ICON_SHADING_RENDERED, "LANPR", "LANPR Data"},
+ {BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"},
+ {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Object Constraints"},
+ {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifiers"},
+ {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data"},
+ {BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone"},
{BCONTEXT_BONE_CONSTRAINT,
"BONE_CONSTRAINT",
ICON_CONSTRAINT_BONE,
@@ -1642,6 +1640,18 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSE
RNA_enum_item_add_separator(&item, &totitem);
}
+ if (sbuts->pathflag & (1 << BCONTEXT_COLLECTION)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_COLLECTION);
+ }
+
+ if (sbuts->pathflag & (1 << BCONTEXT_LANPR)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_LANPR);
+ }
+
+ if (totitem) {
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_OBJECT)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_OBJECT);
}
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 1ae1f891e6f..f236604d491 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
intern/MOD_explode.c
intern/MOD_fluidsim.c
intern/MOD_fluidsim_util.c
+ intern/MOD_featureline.c
intern/MOD_hook.c
intern/MOD_laplaciandeform.c
intern/MOD_laplaciansmooth.c
@@ -100,7 +101,7 @@ set(SRC
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
intern/MOD_wireframe.c
-
+
MOD_modifiertypes.h
intern/MOD_fluidsim_util.h
intern/MOD_meshcache_util.h
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 96622bf7763..9f42fa3abc7 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -81,6 +81,7 @@ extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
extern ModifierTypeInfo modifierType_WeightedNormal;
+extern ModifierTypeInfo modifierType_FeatureLine;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_featureline.c b/source/blender/modifiers/intern/MOD_featureline.c
new file mode 100644
index 00000000000..0d2e3c7ae6b
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_featureline.c
@@ -0,0 +1,124 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include "BLI_utildefines.h"
+
+#include "BLI_edgehash.h"
+#include "BLI_kdtree.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_deform.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+#include "BKE_library_query.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_modifiertypes.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(ModifierData *md)
+{
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+ flmd->types = MOD_FEATURE_LINE_ALL;
+}
+static void freeData(ModifierData *md)
+{
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+}
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
+{
+ FeatureLineModifierData *tflmd = (FeatureLineModifierData *)target;
+
+ modifier_copyData_generic(md, target, flag);
+}
+static bool dependsOnTime(ModifierData *UNUSED(md))
+{
+ return true; /* ?? */
+}
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+ return mesh;
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
+{
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+
+ walk(userData, ob, &flmd->target, IDWALK_NOP);
+}
+
+static bool isDisabled(const struct Scene *scene, struct ModifierData *md, bool userRenderParams)
+{
+ FeatureLineModifierData *flmd = (FeatureLineModifierData *)md;
+ if (!flmd->target) {
+ return true;
+ }
+ return false;
+}
+
+ModifierTypeInfo modifierType_FeatureLine = {
+ /* name */ "Feature Line",
+ /* structName */ "FeatureLineModifierData",
+ /* structSize */ sizeof(FeatureLineModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_Single,
+ /* copyData */ copyData,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* freeRuntimeData */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index e7acbd3e32e..bb5d644defc 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -307,5 +307,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
INIT_TYPE(WeightedNormal);
+ INIT_TYPE(FeatureLine);
#undef INIT_TYPE
}
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index a7f4e30b494..c97fa246df3 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -252,7 +252,7 @@ static PyGetSetDef bpy_bmlayeraccess_edge_getseters[] = {
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
(char *)bpy_bmlayeraccess_collection__freestyle_edge_doc,
- (void *)CD_FREESTYLE_EDGE},
+ (void *)CD_LANPR_EDGE},
#endif
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
@@ -285,7 +285,7 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
(getter)bpy_bmlayeraccess_collection_get,
(setter)NULL,
(char *)bpy_bmlayeraccess_collection__freestyle_face_doc,
- (void *)CD_FREESTYLE_FACE},
+ (void *)CD_LANPR_FACE},
#endif
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */