diff options
Diffstat (limited to 'source/blender')
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 */ |