From 3fc178b19e4c11ac384731c4088b2bd3fa809794 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Thu, 26 Nov 2020 14:19:05 -0700 Subject: Outliner: Highlight icons on cursor hover The icons for collapsed children already draw highlighted when hovered. Because the item icons are now select targets (for outliner to properties editor tab switching) this adds highlights on hover for all outliner element icons. --- source/blender/editors/space_outliner/outliner_dragdrop.c | 6 ++++-- source/blender/editors/space_outliner/outliner_draw.c | 12 +++++++++--- source/blender/editors/space_outliner/outliner_edit.c | 14 +++++++++++--- source/blender/editors/space_outliner/space_outliner.c | 2 +- source/blender/makesdna/DNA_outliner_types.h | 2 ++ 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 865e06bf0b6..d3da7b80765 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -854,7 +854,8 @@ static bool datastack_drop_poll(bContext *C, SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); ARegion *region = CTX_wm_region(C); - bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + bool changed = outliner_flag_set( + &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); StackDropData *drop_data = drag->poin; if (!drop_data) { @@ -1173,7 +1174,8 @@ static bool collection_drop_poll(bContext *C, { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); ARegion *region = CTX_wm_region(C); - bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + bool changed = outliner_flag_set( + &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); CollectionDrop data; if (!event->shift && collection_drop_init(C, drag, event, &data)) { diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index ea2e3ce2565..6364fbc0a87 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2782,7 +2782,7 @@ static void outliner_draw_iconrow_doit(uiBlock *block, icon_border); } - if (tselem->flag & TSE_HIGHLIGHTED) { + if (tselem->flag & TSE_HIGHLIGHTED_ICON) { alpha_fac += 0.5; } tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, alpha_fac, false); @@ -3078,8 +3078,14 @@ static void outliner_draw_tree_element(bContext *C, /* datatype icon */ if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) { - tselem_draw_icon( - block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true); + tselem_draw_icon(block, + xmax, + (float)startx + offsx, + (float)*starty, + tselem, + te, + (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac, + true); offsx += UI_UNIT_X + 4 * ufac; } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index bf94e9e04a4..6c0759b9842 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -117,19 +117,27 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const TreeElement *hovered_te = outliner_find_item_at_y( space_outliner, &space_outliner->tree, view_mval[1]); + TreeElement *icon_te = NULL; bool is_over_icon; if (hovered_te) { - hovered_te = outliner_find_item_at_x_in_row( + icon_te = outliner_find_item_at_x_in_row( space_outliner, hovered_te, view_mval[0], NULL, &is_over_icon); } + bool changed = false; - if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) { - changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + if (!hovered_te || !is_over_icon || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED) || + !(icon_te->store_elem->flag & TSE_HIGHLIGHTED_ICON)) { + /* Clear highlights when nothing is hovered or when a new item is hovered. */ + changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); if (hovered_te) { hovered_te->store_elem->flag |= TSE_HIGHLIGHTED; changed = true; } + if (is_over_icon) { + icon_te->store_elem->flag |= TSE_HIGHLIGHTED_ICON; + changed = true; + } } if (changed) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 5ec55eee7fb..cd8e8a0be98 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -426,7 +426,7 @@ static void outliner_deactivate(struct ScrArea *area) { /* Remove hover highlights */ SpaceOutliner *space_outliner = area->spacedata.first; - outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED, false); + outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false); ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index cc376c0cebf..d561b489ae4 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -66,7 +66,9 @@ enum { /* Needed because outliner-only elements can be active */ TSE_ACTIVE = (1 << 9), /* TSE_ACTIVE_WALK = (1 << 10), */ /* Unused */ + TSE_HIGHLIGHTED_ICON = (1 << 11), TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER), + TSE_HIGHLIGHTED_ANY = (TSE_HIGHLIGHTED | TSE_HIGHLIGHTED_ICON), }; /* TreeStoreElem->types */ -- cgit v1.2.3 From cba5137f32f925d8216288ef6708707e98f5aef0 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Wed, 2 Dec 2020 09:25:45 -0700 Subject: Fix crash in outliner on cursor hover The previous commit surfaced a bug introduced in rBab4654cdfe8f in which a boolean wasn't initialized to false. --- source/blender/editors/space_outliner/outliner_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 6c0759b9842..a1ff6193cd0 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -118,7 +118,7 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const space_outliner, &space_outliner->tree, view_mval[1]); TreeElement *icon_te = NULL; - bool is_over_icon; + bool is_over_icon = false; if (hovered_te) { icon_te = outliner_find_item_at_x_in_row( space_outliner, hovered_te, view_mval[0], NULL, &is_over_icon); -- cgit v1.2.3 From dc4feed59dda2b2b346136d369ce70e1756e87c3 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 2 Dec 2020 18:16:04 -0500 Subject: Cleanup: view-port --> 2D/3D Viewport --- release/scripts/startup/bl_operators/clip.py | 4 ++-- release/scripts/startup/bl_operators/image.py | 2 +- source/blender/blenkernel/intern/layer.c | 2 +- source/blender/editors/mesh/editmesh_select.c | 2 +- source/blender/editors/space_text/text_draw.c | 2 +- source/blender/editors/space_view3d/view3d_draw.c | 2 +- source/blender/editors/space_view3d/view3d_edit.c | 2 +- source/blender/editors/space_view3d/view3d_intern.h | 2 +- source/blender/editors/space_view3d/view3d_utils.c | 10 +++++----- source/blender/makesdna/DNA_meshdata_types.h | 2 +- source/blender/makesdna/DNA_vfont_types.h | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py index a3c54a7b069..51a9695e44a 100644 --- a/release/scripts/startup/bl_operators/clip.py +++ b/release/scripts/startup/bl_operators/clip.py @@ -414,8 +414,8 @@ class CLIP_OT_delete_proxy(Operator): class CLIP_OT_set_viewport_background(Operator): - """Set current movie clip as a camera background in 3D view-port """ \ - """(works only when a 3D view-port is visible)""" + """Set current movie clip as a camera background in 3D Viewport """ \ + """(works only when a 3D Viewport is visible)""" bl_idname = "clip.set_viewport_background" bl_label = "Set as Background" diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index 8d543daeac7..f2cd0ad7478 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -116,7 +116,7 @@ class EditExternally(Operator): class ProjectEdit(Operator): - """Edit a snapshot of the view-port in an external image editor""" + """Edit a snapshot of the 3D Viewport in an external image editor""" bl_idname = "image.project_edit" bl_label = "Project Edit" bl_options = {'REGISTER'} diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 0757cf791b7..73b330bc0de 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -1261,7 +1261,7 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, const View3D *v3d) } /** - * Sync the local collection for all the view-ports. + * Sync the local collection for all the 3D Viewports. */ void BKE_layer_collection_local_sync_all(const Main *bmain) { diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 4dd543e71a9..a2fe949b6c5 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -3574,7 +3574,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE /* To support redo. */ { - /* Note that the `base_index` can't be used as the index depends on the view-port + /* Note that the `base_index` can't be used as the index depends on the 3D Viewport * which might not be available on redo. */ BM_mesh_elem_index_ensure(bm, ele->head.htype); int object_index; diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 2c9ea1d6afa..849766851aa 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -886,7 +886,7 @@ static void calc_text_rcts(SpaceText *st, ARegion *region, rcti *scroll, rcti *b scroll->ymin = pix_top_margin; scroll->ymax = pix_available; - /* when re-sizing a view-port with the bar at the bottom to a greater height + /* when re-sizing a 2D Viewport with the bar at the bottom to a greater height * more blank lines will be added */ if (ltexth + blank_lines < st->top + st->runtime.viewlines) { blank_lines = st->top + st->runtime.viewlines - ltexth; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 3b5dc3f57b9..797c7d73df3 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -848,7 +848,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *region, View3D *v3d, bo /* get surface depth without bias */ rv3d->rflag |= RV3D_ZOFFSET_DISABLED; - /* Needed in cases the view-port isn't already setup. */ + /* Needed in cases the 3D Viewport isn't already setup. */ WM_draw_region_viewport_ensure(region, SPACE_VIEW3D); WM_draw_region_viewport_bind(region); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index f9de462813f..9429da342a6 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -222,7 +222,7 @@ typedef struct ViewOpsData { /** Current state. */ struct { /** Working copy of #RegionView3D.viewquat, needed for rotation calculation - * so we can apply snap to the view-port while keeping the unsnapped rotation + * so we can apply snap to the 3D Viewport while keeping the unsnapped rotation * here to use when snap is disabled and for continued calculation. */ float viewquat[4]; } curr; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 0815850d694..118ec2425fc 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -171,7 +171,7 @@ bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb); /** - * Parameters for setting the new view-port state. + * Parameters for setting the new 3D Viewport state. * * Each of the struct members may be NULL to signify they aren't to be adjusted. */ diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index a70e74665c5..1be9bd27c7a 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -574,11 +574,11 @@ bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *re /* -------------------------------------------------------------------- */ /** \name Camera Lock API * - * Lock the camera to the view-port, allowing view manipulation to transform the camera. + * Lock the camera to the 3D Viewport, allowing view manipulation to transform the camera. * \{ */ /** - * \return true when the view-port is locked to its camera. + * \return true when the 3D Viewport is locked to its camera. */ bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) { @@ -587,8 +587,8 @@ bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) } /** - * Apply the camera object transformation to the view-port. - * (needed so we can use regular view-port manipulation operators, that sync back to the camera). + * Apply the camera object transformation to the 3D Viewport. + * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera). */ void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, View3D *v3d, @@ -612,7 +612,7 @@ void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionV } /** - * Apply the view-port transformation back to the camera object. + * Apply the 3D Viewport transformation back to the camera object. * * \return true if the camera is moved. */ diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index b2f8d845815..780115a31be 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -340,7 +340,7 @@ enum { }; /** - * \note While alpha is currently is not in the view-port, + * \note While alpha is not currently in the 3D Viewport, * this may eventually be added back, keep this value set to 255. */ typedef struct MLoopCol { diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h index 6f0820ff62c..bc1a71102da 100644 --- a/source/blender/makesdna/DNA_vfont_types.h +++ b/source/blender/makesdna/DNA_vfont_types.h @@ -20,7 +20,7 @@ /** \file * \ingroup DNA * - * Vector Fonts used for text in the 3D view-port + * Vector Fonts used for text in the 3D Viewport * (unrelated to text used to render the GUI). */ -- cgit v1.2.3 From fc05e2c0e0763b47641414f718351799a18a9e24 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 2 Dec 2020 22:01:00 -0500 Subject: Bmesh: Improve documentation of op parameters These comments are used to generate Py API docs. Most of the comments are just copies of the mesh operator counterparts. More improvements can be made here in the future. Thanks to Jon Denning on twitter: https://twitter.com/gfxcoder/status/1334178566993555459 --- source/blender/bmesh/intern/bmesh_opdefines.c | 191 +++++++++++++------------- 1 file changed, 92 insertions(+), 99 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 05b84ba21e2..a9d99466709 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -182,7 +182,7 @@ static BMOpDefine bmo_smooth_laplacian_vert_def = { static BMOpDefine bmo_recalc_face_normals_def = { "recalc_face_normals", /* slots_in */ - {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -485,8 +485,7 @@ static BMOpDefine bmo_collapse_uvs_def = { static BMOpDefine bmo_weld_verts_def = { "weld_verts", /* slots_in */ - /* maps welded vertices to verts they should weld to */ - {{"targetmap", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {{"targetmap", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, /* maps welded vertices to verts they should weld to */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -527,11 +526,11 @@ static BMOpDefine bmo_join_triangles_def = { "join_triangles", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input geometry. */ - {"cmp_seam", BMO_OP_SLOT_BOOL}, - {"cmp_sharp", BMO_OP_SLOT_BOOL}, - {"cmp_uvs", BMO_OP_SLOT_BOOL}, - {"cmp_vcols", BMO_OP_SLOT_BOOL}, - {"cmp_materials", BMO_OP_SLOT_BOOL}, + {"cmp_seam", BMO_OP_SLOT_BOOL}, /* Compare seam */ + {"cmp_sharp", BMO_OP_SLOT_BOOL}, /* Compare sharp */ + {"cmp_uvs", BMO_OP_SLOT_BOOL}, /* Compare UVs */ + {"cmp_vcols", BMO_OP_SLOT_BOOL}, /* compare VCols */ + {"cmp_materials", BMO_OP_SLOT_BOOL}, /* compare materials */ {"angle_face_threshold", BMO_OP_SLOT_FLT}, {"angle_shape_threshold", BMO_OP_SLOT_FLT}, {{'\0'}}, @@ -587,9 +586,9 @@ static BMOpDefine bmo_bridge_loops_def = { {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ {"use_pairs", BMO_OP_SLOT_BOOL}, {"use_cyclic", BMO_OP_SLOT_BOOL}, - {"use_merge", BMO_OP_SLOT_BOOL}, - {"merge_factor", BMO_OP_SLOT_FLT}, - {"twist_offset", BMO_OP_SLOT_INT}, + {"use_merge", BMO_OP_SLOT_BOOL}, /* merge rather than creating faces */ + {"merge_factor", BMO_OP_SLOT_FLT}, /* merge factor */ + {"twist_offset", BMO_OP_SLOT_INT}, /* twist offset for closed loops */ {{'\0'}}, }, /* slots_out */ @@ -831,8 +830,8 @@ static BMOpDefine bmo_transform_def = { static BMOpDefine bmo_object_load_bmesh_def = { "object_load_bmesh", /* slots_in */ - {{"scene", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_SCENE}}, - {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, + {{"scene", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_SCENE}}, /* pointer to an scene structure */ + {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, /* pointer to an object structure */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -850,10 +849,8 @@ static BMOpDefine bmo_bmesh_to_mesh_def = { "bmesh_to_mesh", /* slots_in */ { - /* pointer to a mesh structure to fill in */ - {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, - /* pointer to an object structure */ - {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, + {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, /* pointer to a mesh structure to fill in */ + {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, /* pointer to an object structure */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -871,10 +868,8 @@ static BMOpDefine bmo_mesh_to_bmesh_def = { "mesh_to_bmesh", /* slots_in */ { - /* pointer to a Mesh structure */ - {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, - /* pointer to an Object structure */ - {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, + {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}}, /* pointer to a Mesh structure */ + {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}}, /* pointer to an Object structure */ {"use_shapekey", BMO_OP_SLOT_BOOL}, /* load active shapekey coordinates into verts */ {{'\0'}}, }, @@ -955,8 +950,8 @@ static BMOpDefine bmo_extrude_vert_indiv_def = { static BMOpDefine bmo_connect_verts_def = { "connect_verts", /* slots_in */ - {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, - {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ + {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces to explicitly exclude from connecting */ {"check_degenerate", BMO_OP_SLOT_BOOL}, /* prevent splits with overlaps & intersections */ {{'\0'}}, }, @@ -978,7 +973,7 @@ static BMOpDefine bmo_connect_verts_def = { static BMOpDefine bmo_connect_verts_concave_def = { "connect_verts_concave", /* slots_in */ - {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {{'\0'}}, }, /* slots_out */ @@ -1001,7 +996,7 @@ static BMOpDefine bmo_connect_verts_nonplanar_def = { "connect_verts_nonplanar", /* slots_in */ {{"angle_limit", BMO_OP_SLOT_FLT}, /* total rotation angle (radians) */ - {"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {{'\0'}}, }, /* slots_out */ @@ -1023,9 +1018,9 @@ static BMOpDefine bmo_connect_verts_nonplanar_def = { static BMOpDefine bmo_connect_vert_pair_def = { "connect_vert_pair", /* slots_in */ - {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, - {"verts_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, - {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ + {"verts_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices to explicitly exclude from connecting */ + {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces to explicitly exclude from connecting */ {{'\0'}}, }, /* slots_out */ @@ -1048,7 +1043,7 @@ static BMOpDefine bmo_extrude_face_region_def = { "extrude_face_region", /* slots_in */ {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */ - {"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}}, + {"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}}, /* input edges to explicitly exclude from extrusion */ {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */ {"use_normal_flip", BMO_OP_SLOT_BOOL}, /* Create faces with reversed direction. */ {"use_normal_from_adjacent", BMO_OP_SLOT_BOOL}, /* Use winding from surrounding faces instead of this region. */ @@ -1070,9 +1065,9 @@ static BMOpDefine bmo_extrude_face_region_def = { static BMOpDefine bmo_dissolve_verts_def = { "dissolve_verts", /* slots_in */ - {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, - {"use_face_split", BMO_OP_SLOT_BOOL}, - {"use_boundary_tear", BMO_OP_SLOT_BOOL}, + {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ + {"use_face_split", BMO_OP_SLOT_BOOL}, /* split off face corners to maintain surrounding geometry */ + {"use_boundary_tear", BMO_OP_SLOT_BOOL}, /* split off face corners instead of merging faces */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -1089,9 +1084,9 @@ static BMOpDefine bmo_dissolve_verts_def = { static BMOpDefine bmo_dissolve_edges_def = { "dissolve_edges", /* slots_in */ - {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, + {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ {"use_verts", BMO_OP_SLOT_BOOL}, /* dissolve verts left between only 2 edges. */ - {"use_face_split", BMO_OP_SLOT_BOOL}, + {"use_face_split", BMO_OP_SLOT_BOOL}, /* split off face corners to maintain surrounding geometry */ {{'\0'}}, }, /* slots_out */ @@ -1111,7 +1106,7 @@ static BMOpDefine bmo_dissolve_edges_def = { static BMOpDefine bmo_dissolve_faces_def = { "dissolve_faces", /* slots_in */ - {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {"use_verts", BMO_OP_SLOT_BOOL}, /* dissolve verts left between only 2 edges. */ {{'\0'}}, }, @@ -1144,10 +1139,10 @@ static BMOpDefine bmo_dissolve_limit_def = { "dissolve_limit", /* slots_in */ {{"angle_limit", BMO_OP_SLOT_FLT}, /* total rotation angle (radians) */ - {"use_dissolve_boundaries", BMO_OP_SLOT_BOOL}, - {"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, - {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, - {"delimit", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_FLAG}, bmo_enum_dissolve_limit_flags}, + {"use_dissolve_boundaries", BMO_OP_SLOT_BOOL}, /* dissolve all vertices in between face boundaries */ + {"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ + {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ + {"delimit", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_FLAG}, bmo_enum_dissolve_limit_flags}, /* delimit dissolve operation */ {{'\0'}}, }, /* slots_out */ @@ -1169,11 +1164,11 @@ static BMOpDefine bmo_dissolve_degenerate_def = { "dissolve_degenerate", /* slots_in */ {{"dist", BMO_OP_SLOT_FLT}, /* maximum distance to consider degenerate */ - {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, + {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ {{'\0'}}, }, /* slots_out */ - {{{'\0'}}}, + {{{'\0'}}},dissolve_degenerate bmo_dissolve_degenerate_exec, (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | @@ -1201,9 +1196,9 @@ static BMO_FlagSet bmo_enum_triangulate_ngon_method[] = { static BMOpDefine bmo_triangulate_def = { "triangulate", /* slots_in */ - {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, - {"quad_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_triangulate_quad_method}, - {"ngon_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_triangulate_ngon_method}, + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ + {"quad_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_triangulate_quad_method}, /* method for splitting the quads into triangles */ + {"ngon_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_triangulate_ngon_method}, /* method for splitting the polygons into triangles */ {{'\0'}}, }, /* slots_out */ @@ -1228,7 +1223,7 @@ static BMOpDefine bmo_unsubdivide_def = { "unsubdivide", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ - {"iterations", BMO_OP_SLOT_INT}, + {"iterations", BMO_OP_SLOT_INT}, /* number of times to unsubdivide */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ @@ -1256,13 +1251,13 @@ static BMO_FlagSet bmo_enum_subdivide_edges_quad_corner_type[] = { static BMOpDefine bmo_subdivide_edges_def = { "subdivide_edges", /* slots_in */ - {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, - {"smooth", BMO_OP_SLOT_FLT}, + {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ + {"smooth", BMO_OP_SLOT_FLT}, /* smoothness factor */ {"smooth_falloff", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_falloff_type}, /* smooth falloff type */ - {"fractal", BMO_OP_SLOT_FLT}, - {"along_normal", BMO_OP_SLOT_FLT}, - {"cuts", BMO_OP_SLOT_INT}, - {"seed", BMO_OP_SLOT_INT}, + {"fractal", BMO_OP_SLOT_FLT}, /* fractal randomness factor */ + {"along_normal", BMO_OP_SLOT_FLT}, /* apply fractal displacement along normal only */ + {"cuts", BMO_OP_SLOT_INT}, /* number of cuts */ + {"seed", BMO_OP_SLOT_INT}, /* seed for the random number generator */ {"custom_patterns", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* uses custom pointers */ {"edge_percents", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_FLT}}, {"quad_corner_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_subdivide_edges_quad_corner_type}, /* quad corner type */ @@ -1304,10 +1299,10 @@ static BMOpDefine bmo_subdivide_edgering_def = { /* slots_in */ {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input vertices */ {"interp_mode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_subdivide_edgering_interp_mode}, /* interpolation method */ - {"smooth", BMO_OP_SLOT_FLT}, - {"cuts", BMO_OP_SLOT_INT}, + {"smooth", BMO_OP_SLOT_FLT}, /* smoothness factor */ + {"cuts", BMO_OP_SLOT_INT}, /* number of cuts */ {"profile_shape", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_falloff_type}, /* profile shape type */ - {"profile_shape_factor", BMO_OP_SLOT_FLT}, + {"profile_shape_factor", BMO_OP_SLOT_FLT}, /* how much intermediary new edges are shrunk/expanded */ {{'\0'}}, }, {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ @@ -1327,7 +1322,7 @@ static BMOpDefine bmo_subdivide_edgering_def = { static BMOpDefine bmo_bisect_plane_def = { "bisect_plane", /* slots_in */ - {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ {"dist", BMO_OP_SLOT_FLT}, /* minimum distance when testing if a vert is exactly on the plane */ {"plane_co", BMO_OP_SLOT_VEC}, /* point on the plane */ {"plane_no", BMO_OP_SLOT_VEC}, /* direction of the plane */ @@ -1365,7 +1360,7 @@ static BMO_FlagSet bmo_enum_delete_context[] = { static BMOpDefine bmo_delete_def = { "delete", /* slots_in */ - {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ {"context", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_delete_context}, /* geometry types to delete */ {{'\0'}}, }, @@ -1385,9 +1380,8 @@ static BMOpDefine bmo_delete_def = { static BMOpDefine bmo_duplicate_def = { "duplicate", /* slots_in */ - {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - /* destination bmesh, if NULL will use current on */ - {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ + {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, /* destination bmesh, if NULL will use current on */ {"use_select_history", BMO_OP_SLOT_BOOL}, {"use_edge_flip_from_face", BMO_OP_SLOT_BOOL}, {{'\0'}}, @@ -1418,9 +1412,8 @@ static BMOpDefine bmo_duplicate_def = { static BMOpDefine bmo_split_def = { "split", /* slots_in */ - {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - /* destination bmesh, if NULL will use current one */ - {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ + {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, /* destination bmesh, if NULL will use current one */ {"use_only_faces", BMO_OP_SLOT_BOOL}, /* when enabled. don't duplicate loose verts/edges */ {{'\0'}}, }, @@ -1444,7 +1437,7 @@ static BMOpDefine bmo_split_def = { static BMOpDefine bmo_spin_def = { "spin", /* slots_in */ - {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ {"cent", BMO_OP_SLOT_VEC}, /* rotation center */ {"axis", BMO_OP_SLOT_VEC}, /* rotation axis */ {"dvec", BMO_OP_SLOT_VEC}, /* translation delta per step */ @@ -1657,7 +1650,7 @@ static BMOpDefine bmo_create_cone_def = { /* slots_in */ {{"cap_ends", BMO_OP_SLOT_BOOL}, /* whether or not to fill in the ends with faces */ {"cap_tris", BMO_OP_SLOT_BOOL}, /* fill ends with triangles instead of ngons */ - {"segments", BMO_OP_SLOT_INT}, + {"segments", BMO_OP_SLOT_INT}, /* number of vertices in the base circle */ {"diameter1", BMO_OP_SLOT_FLT}, /* diameter of one end */ {"diameter2", BMO_OP_SLOT_FLT}, /* diameter of the opposite */ {"depth", BMO_OP_SLOT_FLT}, /* distance between ends */ @@ -1682,7 +1675,7 @@ static BMOpDefine bmo_create_circle_def = { /* slots_in */ {{"cap_ends", BMO_OP_SLOT_BOOL}, /* whether or not to fill in the ends with faces */ {"cap_tris", BMO_OP_SLOT_BOOL}, /* fill ends with triangles instead of ngons */ - {"segments", BMO_OP_SLOT_INT}, + {"segments", BMO_OP_SLOT_INT}, /* number of vertices in the circle */ {"radius", BMO_OP_SLOT_FLT}, /* Radius of the circle. */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ @@ -1794,7 +1787,7 @@ static BMOpDefine bmo_bevel_def = { {"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"smoothresh", BMO_OP_SLOT_FLT}, /* for passing mesh's smoothresh, used in hardening */ {"custom_profile", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_STRUCT}}, /* CurveProfile */ - {"vmesh_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, + {"vmesh_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, /* the method to use to create meshes at intersections */ bmo_enum_bevel_vmesh_method}, {{'\0'}}, }, @@ -1852,7 +1845,7 @@ static BMOpDefine bmo_beautify_fill_def = { static BMOpDefine bmo_triangle_fill_def = { "triangle_fill", /* slots_in */ - {{"use_beauty", BMO_OP_SLOT_BOOL}, + {{"use_beauty", BMO_OP_SLOT_BOOL}, /* use best triangulation division */ {"use_dissolve", BMO_OP_SLOT_BOOL}, /* dissolve resulting faces */ {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ {"normal", BMO_OP_SLOT_VEC}, /* optionally pass the fill normal to use */ @@ -1876,8 +1869,8 @@ static BMOpDefine bmo_triangle_fill_def = { static BMOpDefine bmo_solidify_def = { "solidify", /* slots_in */ - {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - {"thickness", BMO_OP_SLOT_FLT}, + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ + {"thickness", BMO_OP_SLOT_FLT}, /* thickness */ {{'\0'}}, }, /* slots_out */ @@ -1898,11 +1891,11 @@ static BMOpDefine bmo_inset_individual_def = { "inset_individual", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ - {"thickness", BMO_OP_SLOT_FLT}, - {"depth", BMO_OP_SLOT_FLT}, - {"use_even_offset", BMO_OP_SLOT_BOOL}, - {"use_interpolate", BMO_OP_SLOT_BOOL}, - {"use_relative_offset", BMO_OP_SLOT_BOOL}, + {"thickness", BMO_OP_SLOT_FLT}, /* thickness */ + {"depth", BMO_OP_SLOT_FLT}, /* depth */ + {"use_even_offset", BMO_OP_SLOT_BOOL}, /* scale the offset to give more even thickness */ + {"use_interpolate", BMO_OP_SLOT_BOOL}, /* blend face data across the inset */ + {"use_relative_offset", BMO_OP_SLOT_BOOL}, /* scale the offset by surrounding geometry */ {{'\0'}}, }, /* slots_out */ @@ -1923,15 +1916,15 @@ static BMOpDefine bmo_inset_region_def = { "inset_region", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ - {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, - {"use_boundary", BMO_OP_SLOT_BOOL}, - {"use_even_offset", BMO_OP_SLOT_BOOL}, - {"use_interpolate", BMO_OP_SLOT_BOOL}, - {"use_relative_offset", BMO_OP_SLOT_BOOL}, - {"use_edge_rail", BMO_OP_SLOT_BOOL}, - {"thickness", BMO_OP_SLOT_FLT}, - {"depth", BMO_OP_SLOT_FLT}, - {"use_outset", BMO_OP_SLOT_BOOL}, + {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces to explicitly exclude from inset */ + {"use_boundary", BMO_OP_SLOT_BOOL}, /* inset face boundaries */ + {"use_even_offset", BMO_OP_SLOT_BOOL}, /* scale the offset to give more even thickness */ + {"use_interpolate", BMO_OP_SLOT_BOOL}, /* blend face data across the inset */ + {"use_relative_offset", BMO_OP_SLOT_BOOL}, /* scale the offset by surrounding geometry */ + {"use_edge_rail", BMO_OP_SLOT_BOOL}, /* inset the region along existing edges */ + {"thickness", BMO_OP_SLOT_FLT}, /* thickness */ + {"depth", BMO_OP_SLOT_FLT}, /* depth */ + {"use_outset", BMO_OP_SLOT_BOOL}, /* outset rather than inset */ {{'\0'}}, }, /* slots_out */ @@ -1951,12 +1944,12 @@ static BMOpDefine bmo_inset_region_def = { static BMOpDefine bmo_offset_edgeloops_def = { "offset_edgeloops", /* slots_in */ - {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input faces */ - {"use_cap_endpoint", BMO_OP_SLOT_BOOL}, + {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ + {"use_cap_endpoint", BMO_OP_SLOT_BOOL}, /* extend loop around end-points */ {{'\0'}}, }, /* slots_out */ - {{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output faces */ + {{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */ {{'\0'}}, }, bmo_offset_edgeloops_exec, @@ -1973,15 +1966,15 @@ static BMOpDefine bmo_wireframe_def = { "wireframe", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ - {"thickness", BMO_OP_SLOT_FLT}, - {"offset", BMO_OP_SLOT_FLT}, - {"use_replace", BMO_OP_SLOT_BOOL}, - {"use_boundary", BMO_OP_SLOT_BOOL}, - {"use_even_offset", BMO_OP_SLOT_BOOL}, - {"use_crease", BMO_OP_SLOT_BOOL}, - {"crease_weight", BMO_OP_SLOT_FLT}, - {"use_relative_offset", BMO_OP_SLOT_BOOL}, - {"material_offset", BMO_OP_SLOT_INT}, + {"thickness", BMO_OP_SLOT_FLT}, /* thickness */ + {"offset", BMO_OP_SLOT_FLT}, /* offset the thickness from the center */ + {"use_replace", BMO_OP_SLOT_BOOL}, /* remove original geometry */ + {"use_boundary", BMO_OP_SLOT_BOOL}, /* inset face boundaries */ + {"use_even_offset", BMO_OP_SLOT_BOOL}, /* scale the offset to give more even thickness */ + {"use_crease", BMO_OP_SLOT_BOOL}, /* crease hub edges for improved subdivision surface */ + {"crease_weight", BMO_OP_SLOT_FLT}, /* the mean crease weight for resulting edges */ + {"use_relative_offset", BMO_OP_SLOT_BOOL}, /* scale the offset by surrounding geometry */ + {"material_offset", BMO_OP_SLOT_INT}, /* offset material index of generated faces */ {{'\0'}}, }, /* slots_out */ @@ -2045,15 +2038,15 @@ static BMOpDefine bmo_poke_def = { static BMOpDefine bmo_convex_hull_def = { "convex_hull", /* slots_in */ - {{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - {"use_existing_faces", BMO_OP_SLOT_BOOL}, + {{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ + {"use_existing_faces", BMO_OP_SLOT_BOOL}, /* skip hull triangles that are covered by a pre-existing face */ {{'\0'}}, }, /* slots_out */ {{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, {"geom_interior.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, {"geom_unused.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - {"geom_holes.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, + {"geom_holes.out", BMO_OP_SLOT_ELEMENT_BUF,convex_hull {BM_VERT | BM_EDGE | BM_FACE}}, {{'\0'}}, }, bmo_convex_hull_exec, @@ -2076,7 +2069,7 @@ static BMOpDefine bmo_convex_hull_def = { static BMOpDefine bmo_symmetrize_def = { "symmetrize", /* slots_in */ - {{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, + {{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */ {"direction", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_axis_neg_xyz_and_xyz}, /* axis to use */ {"dist", BMO_OP_SLOT_FLT}, /* minimum distance */ {{'\0'}}, -- cgit v1.2.3 From acaee97c2f8fe00142416ce7f96df409fdc67f91 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 2 Dec 2020 22:26:14 -0500 Subject: Fix accendental copy/paste errors after last commit --- source/blender/bmesh/intern/bmesh_opdefines.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index a9d99466709..cf58dfc684e 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1168,7 +1168,7 @@ static BMOpDefine bmo_dissolve_degenerate_def = { {{'\0'}}, }, /* slots_out */ - {{{'\0'}}},dissolve_degenerate + {{{'\0'}}}, bmo_dissolve_degenerate_exec, (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | @@ -2046,7 +2046,7 @@ static BMOpDefine bmo_convex_hull_def = { {{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, {"geom_interior.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, {"geom_unused.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, - {"geom_holes.out", BMO_OP_SLOT_ELEMENT_BUF,convex_hull {BM_VERT | BM_EDGE | BM_FACE}}, + {"geom_holes.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, {{'\0'}}, }, bmo_convex_hull_exec, -- cgit v1.2.3 From 899dcc5f60667a54d9628fcb5656f7e9db642068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 3 Dec 2020 11:07:06 +0100 Subject: Fix linker errors when building without Cycles Fix linker errors by explicitly linking PugiXML when OpenImageIO is used. PugiXML has been separated from OpenImageIO (D8628). This means that any time OpenImageIO libraries are linked, the PugiXML libraries have to be linked as well. This was set up correctly for Cycles, but not for imbuf. Because of this, building without Cycles but with OIIO would produce linker errors. --- source/blender/imbuf/intern/oiio/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt index 211b6a0b40e..ee5848dec36 100644 --- a/source/blender/imbuf/intern/oiio/CMakeLists.txt +++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt @@ -49,6 +49,7 @@ if(WITH_OPENIMAGEIO) ) list(APPEND LIB ${OPENIMAGEIO_LIBRARIES} + ${PUGIXML_LIBRARIES} ) if(WITH_IMAGE_OPENEXR) list(APPEND INC_SYS -- cgit v1.2.3 From a6c4e39876d8a0765290312f6d8c0175274114cd Mon Sep 17 00:00:00 2001 From: Henrik Dick Date: Thu, 3 Dec 2020 10:42:29 +0100 Subject: Add Custom Object Space to Constraints Add Custom Space to the list of space conversions for constraints. Constraints can use World Space, Local Space, Pose Space, Local with Parent, and now also Custom Space with a custom object to define the evaluation space. The Custom Space option uses the Local Space of an other object/bone/vertex group. If selected on owner or target it will show a box for object selection. If an armature is selected, then it will also show a box for bone selection. If a mesh object is selected it will show the option for using the local space of a vertex group. Reviewed By: #animation_rigging, sybren, Severin, angavrilov Differential Revision: https://developer.blender.org/D7437 --- .../scripts/startup/bl_ui/properties_constraint.py | 23 +- source/blender/blenkernel/BKE_constraint.h | 4 + source/blender/blenkernel/intern/constraint.c | 304 +++++++++++++++------ source/blender/blenkernel/intern/fcurve_driver.c | 8 +- source/blender/editors/armature/armature_add.c | 17 +- source/blender/makesdna/DNA_constraint_types.h | 13 +- source/blender/makesrna/intern/rna_constraint.c | 29 ++ source/blender/makesrna/intern/rna_object_api.c | 21 +- tests/python/bl_constraints.py | 74 +++++ 9 files changed, 398 insertions(+), 95 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index f46e9f9727f..71a7b056d07 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -85,14 +85,23 @@ class ConstraintButtonsPanel(Panel): row.operator("constraint.disable_keep_transform", text="", icon='CANCEL') @staticmethod - def space_template(layout, con, target=True, owner=True): + def space_template(layout, con, target=True, owner=True, separator=True): if target or owner: - layout.separator() + if separator: + layout.separator() if target: layout.prop(con, "target_space", text="Target") if owner: layout.prop(con, "owner_space", text="Owner") + if con.target_space == 'CUSTOM' or con.owner_space == 'CUSTOM': + col = layout.column() + col.prop(con, "space_object") + if con.space_object and con.space_object.type == 'ARMATURE': + col.prop_search(con, "space_subtarget", con.space_object.data, "bones", text="Bone") + elif con.space_object and con.space_object.type in {'MESH', 'LATTICE'}: + col.prop_search(con, "space_subtarget", con.space_object, "vertex_groups", text="Vertex Group") + @staticmethod def target_template(layout, con, subtargets=True): col = layout.column() @@ -237,7 +246,7 @@ class ConstraintButtonsPanel(Panel): row.label(icon="BLANK1") layout.prop(con, "use_transform_limit") - layout.prop(con, "owner_space") + self.space_template(layout, con, target=False, owner=True) self.draw_influence(layout, con) @@ -306,7 +315,7 @@ class ConstraintButtonsPanel(Panel): row.prop_decorator(con, "max_z") layout.prop(con, "use_transform_limit") - layout.prop(con, "owner_space") + self.space_template(layout, con, target=False, owner=True) self.draw_influence(layout, con) @@ -375,7 +384,7 @@ class ConstraintButtonsPanel(Panel): row.prop_decorator(con, "max_z") layout.prop(con, "use_transform_limit") - layout.prop(con, "owner_space") + self.space_template(layout, con, target=False, owner=True) self.draw_influence(layout, con) @@ -483,7 +492,7 @@ class ConstraintButtonsPanel(Panel): layout.prop(con, "volume") - layout.prop(con, "owner_space") + self.space_template(layout, con, target=False, owner=True) self.draw_influence(layout, con) @@ -1117,7 +1126,7 @@ class ConstraintButtonsSubPanel(Panel): col = layout.column() col.active = not con.use_eval_time col.prop(con, "transform_channel", text="Channel") - col.prop(con, "target_space") + ConstraintButtonsPanel.space_template(col, con, target=True, owner=False, separator=False) sub = col.column(align=True) sub.prop(con, "min", text="Range Min") diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index e5c4535560d..4b9f480e091 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -56,6 +56,8 @@ typedef struct bConstraintOb { float matrix[4][4]; /** original matrix (before constraint solving) */ float startmat[4][4]; + /** space matrix for custom object space */ + float space_obj_world_matrix[4][4]; /** type of owner */ short type; @@ -203,6 +205,7 @@ void BKE_constraints_clear_evalob(struct bConstraintOb *cob); void BKE_constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, + struct bConstraintOb *cob, float mat[4][4], short from, short to, @@ -221,6 +224,7 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, struct bConstraintOb *ob, struct ListBase *targets, float ctime); +void BKE_constraint_custom_object_space_get(float r_mat[4][4], struct bConstraint *con); void BKE_constraints_solve(struct Depsgraph *depsgraph, struct ListBase *conlist, struct bConstraintOb *cob, diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 5497065bb34..1a16f1d3c6e 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -261,8 +261,13 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob) * of a matrix from one space to another for constraint evaluation. * For now, this is only implemented for Objects and PoseChannels. */ -void BKE_constraint_mat_convertspace( - Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale) +void BKE_constraint_mat_convertspace(Object *ob, + bPoseChannel *pchan, + bConstraintOb *cob, + float mat[4][4], + short from, + short to, + const bool keep_scale) { float diff_mat[4][4]; float imat[4][4]; @@ -282,25 +287,30 @@ void BKE_constraint_mat_convertspace( switch (from) { case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */ { - /* world to pose */ - invert_m4_m4(imat, ob->obmat); - mul_m4_m4m4(mat, imat, mat); - - /* use pose-space as stepping stone for other spaces... */ - if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { - /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + if (to == CONSTRAINT_SPACE_CUSTOM) { + /* World to custom. */ + BLI_assert(cob); + invert_m4_m4(imat, cob->space_obj_world_matrix); + mul_m4_m4m4(mat, imat, mat); + } + else { + /* World to pose. */ + invert_m4_m4(imat, ob->obmat); + mul_m4_m4m4(mat, imat, mat); + + /* Use pose-space as stepping stone for other spaces. */ + if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { + /* Call self with slightly different values. */ + BKE_constraint_mat_convertspace( + ob, pchan, cob, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + } } break; } case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */ { - /* pose to world */ - if (to == CONSTRAINT_SPACE_WORLD) { - mul_m4_m4m4(mat, ob->obmat, mat); - } /* pose to local */ - else if (to == CONSTRAINT_SPACE_LOCAL) { + if (to == CONSTRAINT_SPACE_LOCAL) { if (pchan->bone) { BKE_armature_mat_pose_to_bone(pchan, mat, mat); } @@ -312,6 +322,16 @@ void BKE_constraint_mat_convertspace( mul_m4_m4m4(mat, imat, mat); } } + else { + /* Pose to world. */ + mul_m4_m4m4(mat, ob->obmat, mat); + /* Use world-space as stepping stone for other spaces. */ + if (to != CONSTRAINT_SPACE_WORLD) { + /* Call self with slightly different values. */ + BKE_constraint_mat_convertspace( + ob, pchan, cob, mat, CONSTRAINT_SPACE_WORLD, to, keep_scale); + } + } break; } case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */ @@ -323,9 +343,10 @@ void BKE_constraint_mat_convertspace( } /* use pose-space as stepping stone for other spaces */ - if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { + if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_CUSTOM)) { /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + BKE_constraint_mat_convertspace( + ob, pchan, cob, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); } break; } @@ -337,9 +358,24 @@ void BKE_constraint_mat_convertspace( } /* use pose-space as stepping stone for other spaces */ - if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { + if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_CUSTOM)) { /* call self with slightly different values */ - BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + BKE_constraint_mat_convertspace( + ob, pchan, cob, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); + } + break; + } + case CONSTRAINT_SPACE_CUSTOM: /* -------------- FROM CUSTOM SPACE ---------- */ + { + /* Custom to world. */ + BLI_assert(cob); + mul_m4_m4m4(mat, cob->space_obj_world_matrix, mat); + + /* Use world-space as stepping stone for other spaces. */ + if (to != CONSTRAINT_SPACE_WORLD) { + /* Call self with slightly different values. */ + BKE_constraint_mat_convertspace( + ob, pchan, cob, mat, CONSTRAINT_SPACE_WORLD, to, keep_scale); } break; } @@ -347,37 +383,44 @@ void BKE_constraint_mat_convertspace( } else { /* objects */ - if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) { - /* check if object has a parent */ - if (ob->parent) { - /* 'subtract' parent's effects from owner */ - mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); - invert_m4_m4_safe(imat, diff_mat); - mul_m4_m4m4(mat, imat, mat); - } - else { - /* Local space in this case will have to be defined as local to the owner's - * transform-property-rotated axes. So subtract this rotation component. - */ - /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as - * global space! - * Think what we want actually here is some kind of 'Final Space', i.e - * . once transformations are applied - users are often confused about this too, - * this is not consistent with bones - * local space either... Meh :| - * --mont29 - */ - BKE_object_to_mat4(ob, diff_mat); - if (!keep_scale) { - normalize_m4(diff_mat); + if (from == CONSTRAINT_SPACE_WORLD) { + if (to == CONSTRAINT_SPACE_LOCAL) { + /* Check if object has a parent. */ + if (ob->parent) { + /* 'subtract' parent's effects from owner. */ + mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv); + invert_m4_m4_safe(imat, diff_mat); + mul_m4_m4m4(mat, imat, mat); } - zero_v3(diff_mat[3]); + else { + /* Local space in this case will have to be defined as local to the owner's + * transform-property-rotated axes. So subtract this rotation component. + */ + /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same + * as global space! Think what we want actually here is some kind of 'Final Space', i.e + * . once transformations are applied - users are often confused about this too, + * this is not consistent with bones + * local space either... Meh :| + * --mont29 + */ + BKE_object_to_mat4(ob, diff_mat); + if (!keep_scale) { + normalize_m4(diff_mat); + } + zero_v3(diff_mat[3]); - invert_m4_m4_safe(imat, diff_mat); + invert_m4_m4_safe(imat, diff_mat); + mul_m4_m4m4(mat, imat, mat); + } + } + else if (to == CONSTRAINT_SPACE_CUSTOM) { + /* 'subtract' custom objects's effects from owner. */ + BLI_assert(cob); + invert_m4_m4_safe(imat, cob->space_obj_world_matrix); mul_m4_m4m4(mat, imat, mat); } } - else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) { + else if (from == CONSTRAINT_SPACE_LOCAL) { /* check that object has a parent - otherwise this won't work */ if (ob->parent) { /* 'add' parent's effect back to owner */ @@ -397,6 +440,24 @@ void BKE_constraint_mat_convertspace( mul_m4_m4m4(mat, diff_mat, mat); } + if (to == CONSTRAINT_SPACE_CUSTOM) { + /* 'subtract' objects's effects from owner. */ + BLI_assert(cob); + invert_m4_m4_safe(imat, cob->space_obj_world_matrix); + mul_m4_m4m4(mat, imat, mat); + } + } + else if (from == CONSTRAINT_SPACE_CUSTOM) { + /* Custom to world. */ + BLI_assert(cob); + mul_m4_m4m4(mat, cob->space_obj_world_matrix, mat); + + /* Use world-space as stepping stone for other spaces. */ + if (to != CONSTRAINT_SPACE_WORLD) { + /* Call self with slightly different values. */ + BKE_constraint_mat_convertspace( + ob, pchan, cob, mat, CONSTRAINT_SPACE_WORLD, to, keep_scale); + } } } } @@ -573,6 +634,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m /* The cases where the target can be object data have not been implemented */ static void constraint_target_to_mat4(Object *ob, const char *substring, + bConstraintOb *cob, float mat[4][4], short from, short to, @@ -582,7 +644,7 @@ static void constraint_target_to_mat4(Object *ob, /* Case OBJECT */ if (substring[0] == '\0') { copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); + BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false); } /* Case VERTEXGROUP */ /* Current method just takes the average location of all the points in the @@ -595,11 +657,11 @@ static void constraint_target_to_mat4(Object *ob, */ else if (ob->type == OB_MESH) { contarget_get_mesh_mat(ob, substring, mat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); + BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false); } else if (ob->type == OB_LATTICE) { contarget_get_lattice_mat(ob, substring, mat); - BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); + BKE_constraint_mat_convertspace(ob, NULL, cob, mat, from, to, false); } /* Case BONE */ else { @@ -662,7 +724,7 @@ static void constraint_target_to_mat4(Object *ob, } /* convert matrix space as required */ - BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false); + BKE_constraint_mat_convertspace(ob, pchan, cob, mat, from, to, false); } } @@ -705,13 +767,14 @@ static bConstraintTypeInfo CTI_CONSTRNAME = { */ static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, - bConstraintOb *UNUSED(cob), + bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { if (VALID_CONS_TARGET(ct)) { constraint_target_to_mat4(ct->tar, ct->subtarget, + cob, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, @@ -727,13 +790,14 @@ static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), */ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, - bConstraintOb *UNUSED(cob), + bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { if (VALID_CONS_TARGET(ct)) { constraint_target_to_mat4(ct->tar, ct->subtarget, + cob, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, @@ -844,6 +908,32 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), } \ (void)0 +static void custom_space_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) +{ + func(con, (ID **)&con->space_object, false, userdata); +} + +static int get_space_tar(bConstraint *con, ListBase *list) +{ + if (!con || !list || + (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) { + return 0; + } + bConstraintTarget *ct; + SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, list); + return 1; +} + +static void flush_space_tar(bConstraint *con, ListBase *list, bool no_copy) +{ + if (!con || !list || + (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) { + return; + } + bConstraintTarget *ct = (bConstraintTarget *)list->last; + SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, list, no_copy); +} + /* --------- ChildOf Constraint ------------ */ static void childof_new_data(void *cdata) @@ -1030,6 +1120,8 @@ static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *use /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int trackto_get_tars(bConstraint *con, ListBase *list) @@ -1041,7 +1133,7 @@ static int trackto_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -1055,6 +1147,7 @@ static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -1262,6 +1355,7 @@ static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), if (VALID_CONS_TARGET(ct)) { constraint_target_to_mat4(ct->tar, ct->subtarget, + cob, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, @@ -1533,11 +1627,11 @@ static bConstraintTypeInfo CTI_LOCLIMIT = { "Limit Location", /* name */ "bLocLimitConstraint", /* struct name */ NULL, /* free data */ - NULL, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ NULL, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ + get_space_tar, /* get constraint targets */ + flush_space_tar, /* flush constraint targets */ NULL, /* get target matrix */ loclimit_evaluate, /* evaluate */ }; @@ -1596,11 +1690,11 @@ static bConstraintTypeInfo CTI_ROTLIMIT = { "Limit Rotation", /* name */ "bRotLimitConstraint", /* struct name */ NULL, /* free data */ - NULL, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ NULL, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ + get_space_tar, /* get constraint targets */ + flush_space_tar, /* flush constraint targets */ NULL, /* get target matrix */ rotlimit_evaluate, /* evaluate */ }; @@ -1663,11 +1757,11 @@ static bConstraintTypeInfo CTI_SIZELIMIT = { "Limit Scale", /* name */ "bSizeLimitConstraint", /* struct name */ NULL, /* free data */ - NULL, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ NULL, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ + get_space_tar, /* get constraint targets */ + flush_space_tar, /* flush constraint targets */ NULL, /* get target matrix */ sizelimit_evaluate, /* evaluate */ }; @@ -1687,6 +1781,8 @@ static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int loclike_get_tars(bConstraint *con, ListBase *list) @@ -1698,7 +1794,7 @@ static int loclike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -1712,6 +1808,7 @@ static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -1784,6 +1881,8 @@ static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int rotlike_get_tars(bConstraint *con, ListBase *list) @@ -1795,7 +1894,7 @@ static int rotlike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -1809,6 +1908,7 @@ static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -1962,6 +2062,8 @@ static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *us /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int sizelike_get_tars(bConstraint *con, ListBase *list) @@ -1973,7 +2075,7 @@ static int sizelike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -1987,6 +2089,7 @@ static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -2084,6 +2187,8 @@ static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *u /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int translike_get_tars(bConstraint *con, ListBase *list) @@ -2095,7 +2200,7 @@ static int translike_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -2109,6 +2214,7 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -2212,11 +2318,11 @@ static bConstraintTypeInfo CTI_SAMEVOL = { "Maintain Volume", /* name */ "bSameVolumeConstraint", /* struct name */ NULL, /* free data */ - NULL, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ samevolume_new_data, /* new data */ - NULL, /* get constraint targets */ - NULL, /* flush constraint targets */ + get_space_tar, /* get constraint targets */ + flush_space_tar, /* flush constraint targets */ NULL, /* get target matrix */ samevolume_evaluate, /* evaluate */ }; @@ -2282,7 +2388,7 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd /* Whether this approach is maintained remains to be seen (aligorith) */ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, - bConstraintOb *UNUSED(cob), + bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { @@ -2301,6 +2407,7 @@ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), */ constraint_target_to_mat4(ct->tar, ct->subtarget, + cob, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, @@ -2608,6 +2715,8 @@ static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *user /* action */ func(con, (ID **)&data->act, true, userdata); + + custom_space_id_looper(con, func, userdata); } static int actcon_get_tars(bConstraint *con, ListBase *list) @@ -2619,7 +2728,7 @@ static int actcon_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -2633,6 +2742,7 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -2660,6 +2770,7 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph, /* get the transform matrix of the target */ constraint_target_to_mat4(ct->tar, ct->subtarget, + cob, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, @@ -3117,6 +3228,8 @@ static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *u /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int distlimit_get_tars(bConstraint *con, ListBase *list) @@ -3128,7 +3241,7 @@ static int distlimit_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -3142,6 +3255,7 @@ static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -3470,6 +3584,8 @@ static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *user /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int minmax_get_tars(bConstraint *con, ListBase *list) @@ -3481,7 +3597,7 @@ static int minmax_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -3495,6 +3611,7 @@ static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -3789,6 +3906,8 @@ static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *u /* target only */ func(con, (ID **)&data->tar, false, userdata); + + custom_space_id_looper(con, func, userdata); } static int transform_get_tars(bConstraint *con, ListBase *list) @@ -3800,7 +3919,7 @@ static int transform_get_tars(bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list); - return 1; + return 1 + get_space_tar(con, list); } return 0; @@ -3814,6 +3933,7 @@ static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy); + flush_space_tar(con, list, no_copy); } } @@ -4122,7 +4242,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), * See T42447. */ unit_m4(mat); BKE_constraint_mat_convertspace( - cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); + cob->ob, cob->pchan, cob, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); invert_m4(mat); mul_mat3_m4_v3(mat, no); @@ -6000,6 +6120,35 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, } } +void BKE_constraint_custom_object_space_get(float r_mat[4][4], bConstraint *con) +{ + if (!con || + (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) { + return; + } + bConstraintTarget *ct; + ListBase target = {NULL, NULL}; + SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, &target); + + /* Basically default_get_tarmat but without the unused parameters. */ + if (VALID_CONS_TARGET(ct)) { + constraint_target_to_mat4(ct->tar, + ct->subtarget, + NULL, + ct->matrix, + CONSTRAINT_SPACE_WORLD, + CONSTRAINT_SPACE_WORLD, + 0, + 0); + copy_m4_m4(r_mat, ct->matrix); + } + else { + unit_m4(r_mat); + } + + SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, &target, true); +} + /* ---------- Evaluation ----------- */ /* This function is called whenever constraints need to be evaluated. Currently, all @@ -6048,12 +6197,15 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph, */ enf = con->enforce; + /* Get custom space matrix. */ + BKE_constraint_custom_object_space_get(cob->space_obj_world_matrix, con); + /* make copy of world-space matrix pre-constraint for use with blending later */ copy_m4_m4(oldmat, cob->matrix); /* move owner matrix into right space */ BKE_constraint_mat_convertspace( - cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); + cob->ob, cob->pchan, cob, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); /* prepare targets for constraint solving */ BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); @@ -6072,7 +6224,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph, /* move owner back into world-space for next constraint/other business */ if ((con->flag & CONSTRAINT_SPACEONCE) == 0) { BKE_constraint_mat_convertspace( - cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); + cob->ob, cob->pchan, cob, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); } /* Interpolate the enforcement, to blend result of constraint into final owner transform diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index b11a3cb9457..1bce9ad8e35 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -411,7 +411,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* Extract transform just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); BKE_constraint_mat_convertspace( - ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); + ob, pchan, NULL, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); /* ... and from that, we get our transform. */ copy_v3_v3(tmp_loc, mat[3]); @@ -437,7 +437,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* Extract transform just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); BKE_constraint_mat_convertspace( - ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); + ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); /* ... and from that, we get our transform. */ copy_v3_v3(tmp_loc, mat[3]); @@ -514,7 +514,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) /* Just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); BKE_constraint_mat_convertspace( - ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); + ob, pchan, NULL, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); } else { /* Specially calculate local matrix, since chan_mat is not valid @@ -541,7 +541,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) /* Just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); BKE_constraint_mat_convertspace( - ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); + ob, NULL, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); } else { /* Transforms to matrix. */ diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index fde062b8454..af323bf91e4 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -453,10 +453,13 @@ static void updateDuplicateActionConstraintSettings(EditBone *dup_bone, float mat[4][4]; + bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = NULL}; + BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon); + unit_m4(mat); bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget); BKE_constraint_mat_convertspace( - ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); + ob, target_pchan, &cob, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); float max_axis_val = 0; int max_axis = 0; @@ -605,8 +608,11 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob, unit_m4(local_mat); + bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan}; + BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon); + BKE_constraint_mat_convertspace( - ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); + ob, pchan, &cob, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) { /* Zero out any location translation */ @@ -657,9 +663,12 @@ static void updateDuplicateTransformConstraintSettings(Object *ob, float target_mat[4][4], own_mat[4][4], imat[4][4]; + bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan}; + BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon); + unit_m4(own_mat); BKE_constraint_mat_convertspace( - ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); + ob, pchan, &cob, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); /* ###Source map mirroring### */ float old_min, old_max; @@ -717,7 +726,7 @@ static void updateDuplicateTransformConstraintSettings(Object *ob, bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget); unit_m4(target_mat); BKE_constraint_mat_convertspace( - ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); + ob, target_pchan, &cob, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); invert_m4_m4(imat, target_mat); /* convert values into local object space */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 70d33d9ff94..ddc1b3bd9d7 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -61,12 +61,17 @@ typedef struct bConstraint { /** Space that target should be evaluated in (only used if 1 target). */ char tarspace; - /** Constraint name, MAX_NAME. */ - char name[64]; - /* An "expand" bit for each of the constraint's (sub)panels (uiPanelDataExpansion). */ short ui_expand_flag; + /** Object to use as target for Custom Space of owner. */ + struct Object *space_object; + /** Subtarget for Custom Space of owner - pchan or vgroup name, MAX_ID_NAME-2. */ + char space_subtarget[64]; + + /** Constraint name, MAX_NAME. */ + char name[64]; + /** Amount of influence exherted by constraint (0.0-1.0). */ float enforce; /** Point along subtarget bone where the actual target is. 0=head (default for all), 1=tail. */ @@ -722,6 +727,8 @@ typedef enum eBConstraint_Flags { typedef enum eBConstraint_SpaceTypes { /** Default for all - worldspace. */ CONSTRAINT_SPACE_WORLD = 0, + /** For all - custom space. */ + CONSTRAINT_SPACE_CUSTOM = 5, /** * For objects (relative to parent/without parent influence), * for bones (along normals of bone, without parent/rest-positions). diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 1c84be5907b..170de68a038 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -200,6 +200,12 @@ static const EnumPropertyItem target_space_pchan_items[] = { "World Space", "The transformation of the target is evaluated relative to the world " "coordinate system"}, + {CONSTRAINT_SPACE_CUSTOM, + "CUSTOM", + 0, + "Custom Space", + "The transformation of the target is evaluated relative to a custom object/bone/vertex " + "group"}, {CONSTRAINT_SPACE_POSE, "POSE", 0, @@ -227,6 +233,11 @@ static const EnumPropertyItem owner_space_pchan_items[] = { 0, "World Space", "The constraint is applied relative to the world coordinate system"}, + {CONSTRAINT_SPACE_CUSTOM, + "CUSTOM", + 0, + "Custom Space", + "The constraint is applied in local space of a custom object/bone/vertex group"}, {CONSTRAINT_SPACE_POSE, "POSE", 0, @@ -275,6 +286,12 @@ static const EnumPropertyItem space_object_items[] = { 0, "World Space", "The transformation of the target is evaluated relative to the world coordinate system"}, + {CONSTRAINT_SPACE_CUSTOM, + "CUSTOM", + 0, + "Custom Space", + "The transformation of the target is evaluated relative to a custom object/bone/vertex " + "group"}, {CONSTRAINT_SPACE_LOCAL, "LOCAL", 0, @@ -3398,6 +3415,18 @@ void RNA_def_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Target Space", "Space that target is evaluated in"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "space_object", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "space_object"); + RNA_def_property_ui_text(prop, "Object", "Object for Custom Space"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + prop = RNA_def_property(srna, "space_subtarget", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "space_subtarget"); + RNA_def_property_ui_text(prop, "Sub-Target", "Armature bone, mesh or lattice vertex group, ..."); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); + /* flags */ prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index a04ad28f9c3..9fb883568c9 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -324,8 +324,27 @@ static void rna_Object_mat_convert_space(Object *ob, return; } } + /* These checks are extra security, they should never occur. */ + if (from == CONSTRAINT_SPACE_CUSTOM) { + const char *identifier = NULL; + RNA_enum_identifier(space_items, from, &identifier); + BKE_reportf(reports, + RPT_ERROR, + "'from_space' '%s' is invalid when no custom space is given!", + identifier); + return; + } + if (to == CONSTRAINT_SPACE_CUSTOM) { + const char *identifier = NULL; + RNA_enum_identifier(space_items, to, &identifier); + BKE_reportf(reports, + RPT_ERROR, + "'to_space' '%s' is invalid when no custom space is given!", + identifier); + return; + } - BKE_constraint_mat_convertspace(ob, pchan, (float(*)[4])mat_ret, from, to, false); + BKE_constraint_mat_convertspace(ob, pchan, NULL, (float(*)[4])mat_ret, from, to, false); } static void rna_Object_calc_matrix_camera(Object *ob, diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py index 4deabc5f541..279c896c6af 100644 --- a/tests/python/bl_constraints.py +++ b/tests/python/bl_constraints.py @@ -301,6 +301,80 @@ class ObjectSolverTest(AbstractConstraintTests): self.matrix_test('Object Solver.owner', initial_matrix) +class CustomSpaceTest(AbstractConstraintTests): + layer_collection = 'Custom Space' + + def test_loc_like_object(self): + """Custom Space: basic custom space evaluation for objects""" + loc_like_constraint = bpy.data.objects["Custom Space.object.owner"].constraints["Copy Location"] + loc_like_constraint.use_x = True + loc_like_constraint.use_y = True + loc_like_constraint.use_z = True + self.matrix_test('Custom Space.object.owner', Matrix(( + (1.0, 0.0, -2.9802322387695312e-08, -0.01753106713294983), + (0.0, 1.0, 0.0, -0.08039519190788269), + (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, 0.1584688425064087), + (0.0, 0.0, 0.0, 1.0), + ))) + loc_like_constraint.use_x = False + self.matrix_test('Custom Space.object.owner', Matrix(( + (1.0, 0.0, -2.9802322387695312e-08, 0.18370598554611206), + (0.0, 1.0, 0.0, 0.47120195627212524), + (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, -0.16521614789962769), + (0.0, 0.0, 0.0, 1.0), + ))) + loc_like_constraint.use_y = False + self.matrix_test('Custom Space.object.owner', Matrix(( + (1.0, 0.0, -2.9802322387695312e-08, -0.46946945786476135), + (0.0, 1.0, 0.0, 0.423120379447937), + (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, -0.6532361507415771), + (0.0, 0.0, 0.0, 1.0), + ))) + loc_like_constraint.use_z = False + loc_like_constraint.use_y = True + self.matrix_test('Custom Space.object.owner', Matrix(( + (1.0, 0.0, -2.9802322387695312e-08, -0.346824586391449), + (0.0, 1.0, 0.0, 1.0480815172195435), + (-2.9802322387695312e-08, 5.960464477539063e-08, 1.0, 0.48802000284194946), + (0.0, 0.0, 0.0, 1.0), + ))) + + def test_loc_like_armature(self): + """Custom Space: basic custom space evaluation for bones""" + loc_like_constraint = bpy.data.objects["Custom Space.armature.owner"].pose.bones["Bone"].constraints["Copy Location"] + loc_like_constraint.use_x = True + loc_like_constraint.use_y = True + loc_like_constraint.use_z = True + self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix(( + (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -0.01753103733062744), + (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.08039522171020508), + (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.1584688425064087), + (0.0, 0.0, 0.0, 1.0), + ))) + loc_like_constraint.use_x = False + self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix(( + (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -0.310153603553772), + (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.8824828863143921), + (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.629145085811615), + (0.0, 0.0, 0.0, 1.0), + ))) + loc_like_constraint.use_y = False + self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix(( + (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -1.0574829578399658), + (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.937495231628418), + (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.07077804207801819), + (0.0, 0.0, 0.0, 1.0), + ))) + loc_like_constraint.use_z = False + loc_like_constraint.use_y = True + self.bone_matrix_test('Custom Space.armature.owner', 'Bone', Matrix(( + (0.4556015729904175, -0.03673229366540909, -0.8894257545471191, -0.25267064571380615), + (-0.45956411957740784, -0.8654094934463501, -0.19966775178909302, -0.9449876546859741), + (-0.762383222579956, 0.49971696734428406, -0.4111628830432892, 0.5583670735359192), + (0.0, 0.0, 0.0, 1.0), + ))) + + def main(): global args import argparse -- cgit v1.2.3 From 5d1308262218db60e22088bd7f16587cf28148e0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Dec 2020 14:32:57 +0100 Subject: Tracking: Improve multithreading of tracking many markers This change solves a bottleneck which was caused by attempt to cache postprocessed search areas used for tracking. It was a single cache used by all threads, which required to have some synchronization mechanism. This synchronization turned out to be making all threads to idle while one thread is accessing the cache. The access was not cheap, so the multi-threading did not provide expected speedup. Current solution is to remove the cache of search areas. This avoids any threading synchronization overhead because there is no need for it anymore. The downside is that for certain configurations tracking became slower when comparing to master branch. There is no expected slowdown compared to 2.91 release. The slowdown is mainly experienced when using big search area and keyframe matching strategy. Other cases should still be within a ballpark of performance of single-threaded code prior to this change. The reason why is it so is because while this change makes it so the image accessors needs to process images multiple times the complexity of this process is almost the same as all the overhead for the cache lookup and maintenance. Here are Some numbers gained on different configurations. CPU: Intel Xeom CPU E5-2699 v4 OS: Linux Footage: Old_Factory MVI_4005.mov from the first part of Track Match Blend training which can be found on the Blender Cloud. Tracking 443 markers across 250 frames. The unit is seconds. File: F9433209 2.91: 401.520874 before: 358.650055 after: 14.966302 Tracking single marker across 250 frames. The unit is seconds. File: F9433211 2.91 before after Big keyframe 1.307203 1.005324 1.227300 Big previous frame 1.144055 0.881139 0.944044 Small keyframe 0.434015 0.197760 0.224982 Small previous frame 0.463207 0.218058 0.234172 All at once 2.338268 1.481220 1.518060 --- source/blender/blenkernel/intern/tracking_auto.c | 2 + source/blender/blenkernel/intern/tracking_util.c | 114 +---------------------- source/blender/blenkernel/tracking_private.h | 2 - 3 files changed, 4 insertions(+), 114 deletions(-) diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 05d1e427c14..7351372b6c4 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -34,7 +34,9 @@ #include "BLI_task.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "PIL_time.h" +#include "BKE_global.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index eb57c28de09..ad2713b9977 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -615,88 +615,6 @@ MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track, /*********************** Frame accessr *************************/ -typedef struct AccessCacheKey { - int clip_index; - int frame; - int downscale; - libmv_InputMode input_mode; - bool has_region; - float region_min[2], region_max[2]; - int64_t transform_key; -} AccessCacheKey; - -static unsigned int accesscache_hashhash(const void *key_v) -{ - const AccessCacheKey *key = (const AccessCacheKey *)key_v; - /* TODP(sergey): Need better hashing here for faster frame access. */ - return key->clip_index << 16 | key->frame; -} - -static bool accesscache_hashcmp(const void *a_v, const void *b_v) -{ - const AccessCacheKey *a = (const AccessCacheKey *)a_v; - const AccessCacheKey *b = (const AccessCacheKey *)b_v; - if (a->clip_index != b->clip_index || a->frame != b->frame || a->downscale != b->downscale || - a->input_mode != b->input_mode || a->has_region != b->has_region || - a->transform_key != b->transform_key) { - return true; - } - /* If there is region applied, compare it. */ - if (a->has_region) { - if (!equals_v2v2(a->region_min, b->region_min) || !equals_v2v2(a->region_max, b->region_max)) { - return true; - } - } - return false; -} - -static void accesscache_construct_key(AccessCacheKey *key, - int clip_index, - int frame, - libmv_InputMode input_mode, - int downscale, - const libmv_Region *region, - int64_t transform_key) -{ - key->clip_index = clip_index; - key->frame = frame; - key->input_mode = input_mode; - key->downscale = downscale; - key->has_region = (region != NULL); - if (key->has_region) { - copy_v2_v2(key->region_min, region->min); - copy_v2_v2(key->region_max, region->max); - } - key->transform_key = transform_key; -} - -static void accesscache_put(TrackingImageAccessor *accessor, - int clip_index, - int frame, - libmv_InputMode input_mode, - int downscale, - const libmv_Region *region, - int64_t transform_key, - ImBuf *ibuf) -{ - AccessCacheKey key; - accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, region, transform_key); - IMB_moviecache_put(accessor->cache, &key, ibuf); -} - -static ImBuf *accesscache_get(TrackingImageAccessor *accessor, - int clip_index, - int frame, - libmv_InputMode input_mode, - int downscale, - const libmv_Region *region, - int64_t transform_key) -{ - AccessCacheKey key; - accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, region, transform_key); - return IMB_moviecache_get(accessor->cache, &key); -} - static ImBuf *accessor_get_preprocessed_ibuf(TrackingImageAccessor *accessor, int clip_index, int frame) @@ -776,33 +694,14 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, const libmv_Region *region, const libmv_FrameTransform *transform) { - ImBuf *ibuf, *orig_ibuf, *final_ibuf; - int64_t transform_key = 0; - if (transform != NULL) { - transform_key = libmv_frameAccessorgetTransformKey(transform); - } /* First try to get fully processed image from the cache. */ - BLI_spin_lock(&accessor->cache_lock); - ibuf = accesscache_get( - accessor, clip_index, frame, input_mode, downscale, region, transform_key); - BLI_spin_unlock(&accessor->cache_lock); - if (ibuf != NULL) { - CACHE_PRINTF("Used cached buffer for frame %d\n", frame); - /* This is a little heuristic here: if we re-used image once, this is - * a high probability of the image to be related to a keyframe matched - * reference image. Those images we don't want to be thrown away because - * if we toss them out we'll be re-calculating them at the next - * iteration. - */ - ibuf->userflags |= IB_PERSISTENT; - return ibuf; - } CACHE_PRINTF("Calculate new buffer for frame %d\n", frame); /* And now we do postprocessing of the original frame. */ - orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame); + ImBuf *orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame); if (orig_ibuf == NULL) { return NULL; } + ImBuf *final_ibuf; /* Cut a region if requested. */ if (region != NULL) { int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1]; @@ -902,11 +801,6 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor, final_ibuf = IMB_dupImBuf(orig_ibuf); } IMB_freeImBuf(orig_ibuf); - BLI_spin_lock(&accessor->cache_lock); - /* Put final buffer to cache. */ - accesscache_put( - accessor, clip_index, frame, input_mode, downscale, region, transform_key, final_ibuf); - BLI_spin_unlock(&accessor->cache_lock); return final_ibuf; } @@ -1016,9 +910,6 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR BLI_assert(num_clips <= MAX_ACCESSOR_CLIP); - accessor->cache = IMB_moviecache_create( - "frame access cache", sizeof(AccessCacheKey), accesscache_hashhash, accesscache_hashcmp); - memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *)); accessor->num_clips = num_clips; @@ -1040,7 +931,6 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR void tracking_image_accessor_destroy(TrackingImageAccessor *accessor) { - IMB_moviecache_free(accessor->cache); libmv_FrameAccessorDestroy(accessor->libmv_accessor); BLI_spin_end(&accessor->cache_lock); MEM_freeN(accessor->tracks); diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h index 64db84d5ac3..c8e7fea6601 100644 --- a/source/blender/blenkernel/tracking_private.h +++ b/source/blender/blenkernel/tracking_private.h @@ -131,8 +131,6 @@ struct libmv_FrameAccessor; #define MAX_ACCESSOR_CLIP 64 typedef struct TrackingImageAccessor { - struct MovieCache *cache; - struct MovieClip *clips[MAX_ACCESSOR_CLIP]; int num_clips; -- cgit v1.2.3 From a3c40912153235508aaccbd310f247073029becb Mon Sep 17 00:00:00 2001 From: Patrick Mours Date: Thu, 3 Dec 2020 15:20:50 +0100 Subject: Fix Cycles device kernels containing debug assertation code NanoVDB includes "assert.h" and makes use of "assert" in several places and since the compile pipeline for CUDA/OptiX kernels does not define "NDEBUG" for release builds, those debug checks were always added. This is not intended, so this patch disables "assert" for CUDA/OptiX by defining "NDEBUG" before including NanoVDB headers. This also fixes a warning about unknown pragmas in NanoVDB thrown by the CUDA compiler. --- intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h | 1 + intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index 44c658d4cab..59b96c86c50 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -18,6 +18,7 @@ #define __KERNEL_CPU_IMAGE_H__ #ifdef WITH_NANOVDB +# define NANOVDB_USE_INTRINSICS # include # include #endif diff --git a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h index 001bc652810..82ad9225fc3 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h +++ b/intern/cycles/kernel/kernels/cuda/kernel_cuda_image.h @@ -15,6 +15,8 @@ */ #ifdef WITH_NANOVDB +# define NDEBUG /* Disable "assert" in device code */ +# define NANOVDB_USE_INTRINSICS # include "nanovdb/NanoVDB.h" # include "nanovdb/util/SampleFromVoxels.h" #endif -- cgit v1.2.3 From 675d84826e596d09b6ddba06915c949da61f087f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 3 Dec 2020 15:02:56 +0100 Subject: Fix T83315: Crash showing animation channel context menu after baking sound Fix a crash when right-clicking in the Graph Editor animation channel list. The code for getting selected keyframes was not checking for baked curves. --- source/blender/editors/screen/screen_context.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index af09100b8e6..244ebea5bbe 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -1004,6 +1004,11 @@ static eContextResult screen_ctx_selected_editable_keyframes(const bContext *C, } fcurve = (FCurve *)ale->data; + if (fcurve->bezt == NULL) { + /* Skip baked FCurves. */ + continue; + } + for (i = 0, bezt = fcurve->bezt; i < fcurve->totvert; i++, bezt++) { if ((bezt->f2 & SELECT) == 0) { continue; -- cgit v1.2.3 From 2c181521ec0c4e0fca579fb512801410570800fb Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 3 Dec 2020 16:20:09 +0100 Subject: Geometry Nodes: add custom data type getter for attribute accessor This is just an utility method, that avoids that the caller has to do the conversion every time it is necessary. --- source/blender/blenkernel/BKE_attribute_access.hh | 25 +++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index e58fba36342..f5ee2cf2bf5 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -31,6 +31,9 @@ namespace blender::bke { using fn::CPPType; +const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); +CustomDataType cpp_type_to_custom_data_type(const CPPType &type); + /** * This class offers an indirection for reading an attribute. * This is useful for the following reasons: @@ -47,6 +50,7 @@ class ReadAttribute { protected: const AttributeDomain domain_; const CPPType &cpp_type_; + const CustomDataType custom_data_type_; const int64_t size_; /* Protects the span below, so that no two threads initialize it at the same time. */ @@ -59,7 +63,10 @@ class ReadAttribute { public: ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size) - : domain_(domain), cpp_type_(cpp_type), size_(size) + : domain_(domain), + cpp_type_(cpp_type), + custom_data_type_(cpp_type_to_custom_data_type(cpp_type)), + size_(size) { } @@ -75,6 +82,11 @@ class ReadAttribute { return cpp_type_; } + CustomDataType custom_data_type() const + { + return custom_data_type_; + } + int64_t size() const { return size_; @@ -104,6 +116,7 @@ class WriteAttribute { protected: const AttributeDomain domain_; const CPPType &cpp_type_; + const CustomDataType custom_data_type_; const int64_t size_; /* When not null, this points either to the attribute array or to a temporary array. */ @@ -115,7 +128,10 @@ class WriteAttribute { public: WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size) - : domain_(domain), cpp_type_(cpp_type), size_(size) + : domain_(domain), + cpp_type_(cpp_type), + custom_data_type_(cpp_type_to_custom_data_type(cpp_type)), + size_(size) { } @@ -131,6 +147,11 @@ class WriteAttribute { return cpp_type_; } + CustomDataType custom_data_type() const + { + return custom_data_type_; + } + int64_t size() const { return size_; -- cgit v1.2.3 From 107231eb956a953c89a2ab134371988ebe338c59 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 3 Dec 2020 16:25:48 +0100 Subject: Geometry Nodes: improve support for Color attributes * Add typed attribute accessors for color attributes. * Support implicit conversions between colors and floats. --- source/blender/blenkernel/BKE_attribute_access.hh | 6 +++--- source/blender/nodes/NOD_geometry_exec.hh | 2 ++ source/blender/nodes/intern/node_tree_multi_function.cc | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index f5ee2cf2bf5..c4a704ef385 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -23,6 +23,7 @@ #include "BKE_attribute.h" +#include "BLI_color.hh" #include "BLI_float3.hh" struct Mesh; @@ -267,10 +268,9 @@ template class TypedWriteAttribute { using FloatReadAttribute = TypedReadAttribute; using Float3ReadAttribute = TypedReadAttribute; +using Color4fReadAttribute = TypedReadAttribute; using FloatWriteAttribute = TypedWriteAttribute; using Float3WriteAttribute = TypedWriteAttribute; - -const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); -CustomDataType cpp_type_to_custom_data_type(const CPPType &type); +using Color4fWriteAttribute = TypedWriteAttribute; } // namespace blender::bke diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 2b95f76d06b..fde576d7429 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -26,6 +26,8 @@ namespace blender::nodes { +using bke::Color4fReadAttribute; +using bke::Color4fWriteAttribute; using bke::Float3ReadAttribute; using bke::Float3WriteAttribute; using bke::FloatReadAttribute; diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index 8440e996651..ec5527a2970 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -204,6 +204,10 @@ static DataTypeConversions create_implicit_conversions() conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); }); add_implicit_conversion( conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); }); + add_implicit_conversion( + conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); + add_implicit_conversion( + conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); return conversions; } -- cgit v1.2.3 From 570a16da180a917021db77e7ec2c034793e4c3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 3 Dec 2020 16:32:55 +0100 Subject: Fix: remove `show_group_colors` from graph editor menu The `show_group_colors` option was moved to the user preferences in ad85256e71, but accidentally remained in the graph editor menu. --- release/scripts/startup/bl_ui/space_graph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 3fee0ae9d47..0c37b58a583 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -119,7 +119,6 @@ class GRAPH_MT_view(Menu): layout.prop(st, "use_realtime_update") layout.prop(st, "show_cursor") layout.prop(st, "show_sliders") - layout.prop(st, "show_group_colors") layout.prop(st, "use_auto_merge_keyframes") if st.mode != 'DRIVERS': -- cgit v1.2.3 From 986955a2d53a5fd94be38f22e0eb954333763aff Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 3 Dec 2020 16:46:16 +0100 Subject: GPencil: Add Vertex Paint operators to Paint menu These operators existed since 2.83, but the menu was hidden by error. Also the operators have been cleanup and make multiframe compatible. Reviewed By: mendio Differential Revision: https://developer.blender.org/D9671 --- release/scripts/startup/bl_ui/space_view3d.py | 23 +- source/blender/editors/gpencil/gpencil_edit.c | 155 ------ .../blender/editors/gpencil/gpencil_vertex_ops.c | 576 +++++++++++++++------ 3 files changed, 428 insertions(+), 326 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 5af88e15111..10c9f25b92a 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1828,7 +1828,13 @@ class VIEW3D_MT_paint_gpencil(Menu): def draw(self, context): layout = self.layout + layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors") layout.operator("gpencil.stroke_reset_vertex_color") + layout.separator() + layout.operator("gpencil.vertex_color_invert", text="Invert") + layout.operator("gpencil.vertex_color_levels", text="Levels") + layout.operator("gpencil.vertex_color_hsv", text="Hue Saturation Value") + layout.operator("gpencil.vertex_color_brightness_contrast", text="Bright/Contrast") class VIEW3D_MT_select_gpencil(Menu): @@ -5044,22 +5050,6 @@ class VIEW3D_MT_weight_gpencil(Menu): layout.menu("VIEW3D_MT_gpencil_autoweights") -class VIEW3D_MT_vertex_gpencil(Menu): - bl_label = "Paint" - - def draw(self, _context): - layout = self.layout - layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors") - layout.separator() - layout.operator("gpencil.vertex_color_invert", text="Invert") - layout.operator("gpencil.vertex_color_levels", text="Levels") - layout.operator("gpencil.vertex_color_hsv", text="Hue Saturation Value") - layout.operator("gpencil.vertex_color_brightness_contrast", text="Bright/Contrast") - - layout.separator() - layout.menu("VIEW3D_MT_join_palette") - - class VIEW3D_MT_gpencil_animation(Menu): bl_label = "Animation" @@ -7606,7 +7596,6 @@ classes = ( VIEW3D_MT_edit_gpencil_delete, VIEW3D_MT_edit_gpencil_showhide, VIEW3D_MT_weight_gpencil, - VIEW3D_MT_vertex_gpencil, VIEW3D_MT_gpencil_animation, VIEW3D_MT_gpencil_simplify, VIEW3D_MT_gpencil_copy_layer, diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 15162f491d5..a183c34fd9d 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -5206,158 +5206,3 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Reset Stroke Vertex Color Operator - * \{ */ - -static void gpencil_reset_vertex(bGPDstroke *gps, eGp_Vertex_Mode mode) -{ - if (mode != GPPAINT_MODE_STROKE) { - zero_v4(gps->vert_color_fill); - } - - if (mode != GPPAINT_MODE_FILL) { - bGPDspoint *pt; - for (int i = 0; i < gps->totpoints; i++) { - pt = &gps->points[i]; - zero_v4(pt->vert_color); - } - } -} - -static int gpencil_stroke_reset_vertex_color_exec(bContext *C, wmOperator *op) -{ - Object *obact = CTX_data_active_object(C); - bGPdata *gpd = (bGPdata *)obact->data; - const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - bGPDstroke *gps = NULL; - - if (gpd == NULL) { - BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); - return OPERATOR_CANCELLED; - } - eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); - - /* First need to check if there are something selected. If not, apply to all strokes. */ - bool all_strokes = true; - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { - if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { - if (gpf == NULL) { - continue; - } - for (gps = gpf->strokes.first; gps; gps = gps->next) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - - if (is_curve_edit) { - if (gps->editcurve == NULL) { - continue; - } - bGPDcurve *gpc = gps->editcurve; - if (gpc->flag & GP_CURVE_SELECT) { - all_strokes = false; - break; - } - } - else { - if (gps->flag & GP_STROKE_SELECT) { - all_strokes = false; - break; - } - } - } - /* if not multiedit, exit loop*/ - if (!is_multiedit) { - break; - } - } - } - } - CTX_DATA_END; - - /* Reset Vertex colors. */ - bool changed = false; - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - - for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { - if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { - if (gpf == NULL) { - continue; - } - - for (gps = gpf->strokes.first; gps; gps = gps->next) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - - if (is_curve_edit) { - if (gps->editcurve == NULL) { - continue; - } - bGPDcurve *gpc = gps->editcurve; - if ((all_strokes) || (gpc->flag & GP_CURVE_SELECT)) { - gpencil_reset_vertex(gps, mode); - } - } - else { - if ((all_strokes) || (gps->flag & GP_STROKE_SELECT)) { - gpencil_reset_vertex(gps, mode); - } - } - - changed = true; - } - /* if not multiedit, exit loop*/ - if (!is_multiedit) { - break; - } - } - } - } - CTX_DATA_END; - - if (changed) { - /* updates */ - DEG_id_tag_update(&gpd->id, - ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); - DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - } - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot) -{ - static EnumPropertyItem mode_types_items[] = { - {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"}, - {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Reset Vertex Color"; - ot->idname = "GPENCIL_OT_stroke_reset_vertex_color"; - ot->description = "Reset vertex color for all or selected strokes"; - - /* callbacks */ - ot->exec = gpencil_stroke_reset_vertex_color_exec; - ot->poll = gpencil_stroke_edit_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "mode", mode_types_items, GPPAINT_MODE_BOTH, "Mode", ""); -} - -/** \} */ diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 69e50beb66e..c3fd8d10b64 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -60,23 +60,69 @@ #include "gpencil_intern.h" -enum { - GP_PAINT_VERTEX_STROKE = 0, - GP_PAINT_VERTEX_FILL = 1, - GP_PAINT_VERTEX_BOTH = 2, -}; - static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = { - {GP_PAINT_VERTEX_STROKE, "STROKE", 0, "Stroke", ""}, - {GP_PAINT_VERTEX_FILL, "FILL", 0, "Fill", ""}, - {GP_PAINT_VERTEX_BOTH, "BOTH", 0, "Both", ""}, + {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", ""}, + {GPPAINT_MODE_FILL, "FILL", 0, "Fill", ""}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", ""}, {0, NULL, 0, NULL, NULL}, }; +/* Helper: Check if any stroke is selected. */ +static bool is_any_stroke_selected(bContext *C, const bool is_multiedit, const bool is_curve_edit) +{ + bool is_selected = false; + + /* If not enabled any mask mode, the strokes are considered as not selected. */ + ToolSettings *ts = CTX_data_tool_settings(C); + if (!GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)) { + return false; + } + + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + + if (is_curve_edit) { + if (gps->editcurve == NULL) { + continue; + } + bGPDcurve *gpc = gps->editcurve; + if (gpc->flag & GP_CURVE_SELECT) { + is_selected = true; + break; + } + } + else { + if (gps->flag & GP_STROKE_SELECT) { + is_selected = true; + break; + } + } + } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } + } + } + } + CTX_DATA_END; + + return is_selected; +} + /* Poll callback for stroke vertex paint operator. */ static bool gpencil_vertexpaint_mode_poll(bContext *C) { - ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { return false; @@ -84,10 +130,6 @@ static bool gpencil_vertexpaint_mode_poll(bContext *C) bGPdata *gpd = (bGPdata *)ob->data; if (GPENCIL_VERTEX_MODE(gpd)) { - if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) { - return false; - } - /* Any data to use. */ if (gpd->layers.first) { return true; @@ -101,10 +143,9 @@ static int gpencil_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; - bool changed = false; - int i; - bGPDspoint *pt; - const int mode = RNA_enum_get(op->ptr, "mode"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); + const bool any_selected = is_any_stroke_selected(C, is_multiedit, false); float gain, offset; { @@ -130,34 +171,56 @@ static int gpencil_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator } /* Loop all selected strokes. */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - /* Fill color. */ - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->vert_color_fill[3] > 0.0f) { - for (int i2 = 0; i2 < 3; i2++) { - gps->vert_color_fill[i2] = gain * gps->vert_color_fill[i2] + offset; - } - } + bool changed = false; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; } - } - /* Stroke points. */ - if (mode != GP_PAINT_VERTEX_FILL) { - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { - for (int i2 = 0; i2 < 3; i2++) { - pt->vert_color[i2] = gain * pt->vert_color[i2] + offset; + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + + if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) { + /* Fill color. */ + if (mode != GPPAINT_MODE_STROKE) { + if (gps->vert_color_fill[3] > 0.0f) { + changed = true; + for (int i2 = 0; i2 < 3; i2++) { + gps->vert_color_fill[i2] = gain * gps->vert_color_fill[i2] + offset; + } + } + } + /* Stroke points. */ + if (mode != GPPAINT_MODE_FILL) { + changed = true; + int i; + bGPDspoint *pt; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) && + (pt->vert_color[3] > 0.0f)) { + for (int i2 = 0; i2 < 3; i2++) { + pt->vert_color[i2] = gain * pt->vert_color[i2] + offset; + } + } + } } } } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } } } } - GP_EDITABLE_STROKES_END(gpstroke_iter); + CTX_DATA_END; /* notifiers */ if (changed) { @@ -185,7 +248,8 @@ void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* params */ - ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", ""); + ot->prop = RNA_def_enum( + ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", ""); const float min = -100, max = +100; prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); @@ -197,64 +261,88 @@ static int gpencil_vertexpaint_hsv_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; - bool changed = false; - int i; - bGPDspoint *pt; - float hsv[3]; - - const int mode = RNA_enum_get(op->ptr, "mode"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); + const bool any_selected = is_any_stroke_selected(C, is_multiedit, false); float hue = RNA_float_get(op->ptr, "h"); float sat = RNA_float_get(op->ptr, "s"); float val = RNA_float_get(op->ptr, "v"); - /* Loop all selected strokes. */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - - /* Fill color. */ - if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->vert_color_fill[3] > 0.0f) { + bool changed = false; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - rgb_to_hsv_v(gps->vert_color_fill, hsv); + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } - hsv[0] += (hue - 0.5f); - if (hsv[0] > 1.0f) { - hsv[0] -= 1.0f; - } - else if (hsv[0] < 0.0f) { - hsv[0] += 1.0f; + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; } - hsv[1] *= sat; - hsv[2] *= val; - hsv_to_rgb_v(hsv, gps->vert_color_fill); - } - } + if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) { + float hsv[3]; - /* Stroke points. */ - if (mode != GP_PAINT_VERTEX_FILL) { - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { - rgb_to_hsv_v(pt->vert_color, hsv); + /* Fill color. */ + if (mode != GPPAINT_MODE_STROKE) { + if (gps->vert_color_fill[3] > 0.0f) { + changed = true; - hsv[0] += (hue - 0.5f); - if (hsv[0] > 1.0f) { - hsv[0] -= 1.0f; - } - else if (hsv[0] < 0.0f) { - hsv[0] += 1.0f; + rgb_to_hsv_v(gps->vert_color_fill, hsv); + + hsv[0] += (hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= sat; + hsv[2] *= val; + + hsv_to_rgb_v(hsv, gps->vert_color_fill); + } } - hsv[1] *= sat; - hsv[2] *= val; - hsv_to_rgb_v(hsv, pt->vert_color); + /* Stroke points. */ + if (mode != GPPAINT_MODE_FILL) { + changed = true; + int i; + bGPDspoint *pt; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) && + (pt->vert_color[3] > 0.0f)) { + rgb_to_hsv_v(pt->vert_color, hsv); + + hsv[0] += (hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= sat; + hsv[2] *= val; + + hsv_to_rgb_v(hsv, pt->vert_color); + } + } + } } } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } } } } - GP_EDITABLE_STROKES_END(gpstroke_iter); + + CTX_DATA_END; /* notifiers */ if (changed) { @@ -280,7 +368,8 @@ void GPENCIL_OT_vertex_color_hsv(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* params */ - ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", ""); + ot->prop = RNA_def_enum( + ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", ""); RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); @@ -291,41 +380,62 @@ static int gpencil_vertexpaint_invert_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); + const bool any_selected = is_any_stroke_selected(C, is_multiedit, false); + bool changed = false; - int i; - bGPDspoint *pt; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - const int mode = RNA_enum_get(op->ptr, "mode"); + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } - /* Loop all selected strokes. */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - /* Fill color. */ - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->vert_color_fill[3] > 0.0f) { - for (int i2 = 0; i2 < 3; i2++) { - gps->vert_color_fill[i2] = 1.0f - gps->vert_color_fill[i2]; - } + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; } - } - } - /* Stroke points. */ - if (mode != GP_PAINT_VERTEX_FILL) { - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { - for (int i2 = 0; i2 < 3; i2++) { - pt->vert_color[i2] = 1.0f - pt->vert_color[i2]; + if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) { + /* Fill color. */ + if (mode != GPPAINT_MODE_STROKE) { + if (gps->vert_color_fill[3] > 0.0f) { + changed = true; + for (int i2 = 0; i2 < 3; i2++) { + gps->vert_color_fill[i2] = 1.0f - gps->vert_color_fill[i2]; + } + } + } + + /* Stroke points. */ + if (mode != GPPAINT_MODE_FILL) { + changed = true; + int i; + bGPDspoint *pt; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) && + (pt->vert_color[3] > 0.0f)) { + for (int i2 = 0; i2 < 3; i2++) { + pt->vert_color[i2] = 1.0f - pt->vert_color[i2]; + } + } + } } } } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } } } } - GP_EDITABLE_STROKES_END(gpstroke_iter); + CTX_DATA_END; /* notifiers */ if (changed) { @@ -351,7 +461,8 @@ void GPENCIL_OT_vertex_color_invert(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* params */ - ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", ""); + ot->prop = RNA_def_enum( + ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", ""); } static int gpencil_vertexpaint_levels_exec(bContext *C, wmOperator *op) @@ -359,41 +470,63 @@ static int gpencil_vertexpaint_levels_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; - bool changed = false; - bGPDspoint *pt; - - const int mode = RNA_enum_get(op->ptr, "mode"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); + const bool any_selected = is_any_stroke_selected(C, is_multiedit, false); float gain = RNA_float_get(op->ptr, "gain"); float offset = RNA_float_get(op->ptr, "offset"); - /* Loop all selected strokes. */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { + bool changed = false; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - /* Fill color. */ - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->vert_color_fill[3] > 0.0f) { - for (int i2 = 0; i2 < 3; i2++) { - gps->vert_color_fill[i2] = gain * (gps->vert_color_fill[i2] + offset); - } + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; } - } - } - /* Stroke points. */ - if (mode != GP_PAINT_VERTEX_FILL) { - int i; - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { - for (int i2 = 0; i2 < 3; i2++) { - pt->vert_color[i2] = gain * (pt->vert_color[i2] + offset); + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; } + + if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) { + /* Fill color. */ + if (mode != GPPAINT_MODE_STROKE) { + if (gps->vert_color_fill[3] > 0.0f) { + changed = true; + for (int i2 = 0; i2 < 3; i2++) { + gps->vert_color_fill[i2] = gain * (gps->vert_color_fill[i2] + offset); + } + } + } + /* Stroke points. */ + if (mode != GPPAINT_MODE_FILL) { + changed = true; + int i; + bGPDspoint *pt; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) && + (pt->vert_color[3] > 0.0f)) { + for (int i2 = 0; i2 < 3; i2++) { + pt->vert_color[i2] = gain * (pt->vert_color[i2] + offset); + } + } + } + } + } + } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; } } } } - GP_EDITABLE_STROKES_END(gpstroke_iter); + CTX_DATA_END; /* notifiers */ if (changed) { @@ -420,7 +553,8 @@ void GPENCIL_OT_vertex_color_levels(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* params */ - ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", ""); + ot->prop = RNA_def_enum( + ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", ""); RNA_def_float( ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); @@ -436,36 +570,58 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op) Paint *paint = &ts->gp_vertexpaint->paint; Brush *brush = paint->brush; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); + const bool any_selected = is_any_stroke_selected(C, is_multiedit, false); + float factor = RNA_float_get(op->ptr, "factor"); + bool changed = false; - int i; - bGPDspoint *pt; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - const int mode = RNA_enum_get(op->ptr, "mode"); - float factor = RNA_float_get(op->ptr, "factor"); + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } - /* Loop all selected strokes. */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - - /* Fill color. */ - if (gps->flag & GP_STROKE_SELECT) { - changed = true; - if (mode != GP_PAINT_VERTEX_STROKE) { - copy_v3_v3(gps->vert_color_fill, brush->rgb); - gps->vert_color_fill[3] = factor; - } - } + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } - /* Stroke points. */ - if (mode != GP_PAINT_VERTEX_FILL) { - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->flag & GP_SPOINT_SELECT) { - copy_v3_v3(pt->vert_color, brush->rgb); - pt->vert_color[3] = factor; + if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) { + /* Fill color. */ + if (mode != GPPAINT_MODE_STROKE) { + changed = true; + copy_v3_v3(gps->vert_color_fill, brush->rgb); + gps->vert_color_fill[3] = factor; + } + + /* Stroke points. */ + if (mode != GPPAINT_MODE_FILL) { + changed = true; + int i; + bGPDspoint *pt; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) { + copy_v3_v3(pt->vert_color, brush->rgb); + pt->vert_color[3] = factor; + } + } + } + } + } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; } } } } - GP_EDITABLE_STROKES_END(gpstroke_iter); + CTX_DATA_END; /* notifiers */ if (changed) { @@ -492,7 +648,8 @@ void GPENCIL_OT_vertex_color_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* params */ - ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", ""); + ot->prop = RNA_def_enum( + ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", ""); RNA_def_float(ot->srna, "factor", 1.0f, 0.001f, 1.0f, "Factor", "Mix Factor", 0.001f, 1.0f); } @@ -900,3 +1057,114 @@ void GPENCIL_OT_extract_palette_vertex(wmOperatorType *ot) ot->srna, "selected", false, "Only Selected", "Convert only selected strokes"); RNA_def_int(ot->srna, "threshold", 1, 1, 4, "Threshold", "", 1, 4); } + +/* -------------------------------------------------------------------- */ +/** \name Reset Stroke Vertex Color Operator + * \{ */ + +static void gpencil_reset_vertex(bGPDstroke *gps, eGp_Vertex_Mode mode) +{ + if (mode != GPPAINT_MODE_STROKE) { + zero_v4(gps->vert_color_fill); + } + + if (mode != GPPAINT_MODE_FILL) { + bGPDspoint *pt; + for (int i = 0; i < gps->totpoints; i++) { + pt = &gps->points[i]; + zero_v4(pt->vert_color); + } + } +} + +static int gpencil_stroke_reset_vertex_color_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + bGPdata *gpd = (bGPdata *)obact->data; + const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode"); + + /* First need to check if there are something selected. If not, apply to all strokes. */ + const bool any_selected = is_any_stroke_selected(C, is_multiedit, is_curve_edit); + + /* Reset Vertex colors. */ + bool changed = false; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + + if (is_curve_edit) { + if (gps->editcurve == NULL) { + continue; + } + bGPDcurve *gpc = gps->editcurve; + if ((!any_selected) || (gpc->flag & GP_CURVE_SELECT)) { + gpencil_reset_vertex(gps, mode); + } + } + else { + if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) { + gpencil_reset_vertex(gps, mode); + } + } + + changed = true; + } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } + } + } + } + CTX_DATA_END; + + if (changed) { + /* updates */ + DEG_id_tag_update(&gpd->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot) +{ + static EnumPropertyItem mode_types_items[] = { + {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"}, + {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Reset Vertex Color"; + ot->idname = "GPENCIL_OT_stroke_reset_vertex_color"; + ot->description = "Reset vertex color for all or selected strokes"; + + /* callbacks */ + ot->exec = gpencil_stroke_reset_vertex_color_exec; + ot->poll = gpencil_vertexpaint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "mode", mode_types_items, GPPAINT_MODE_BOTH, "Mode", ""); +} + +/** \} */ -- cgit v1.2.3 From c821aa8ca76b219e51bbc1f6b840efd6152c045e Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 3 Dec 2020 17:18:01 +0100 Subject: GPencil: Fix unreported refresh of stroke after using Arrange operator When change the order of the stroke using the arrange operator, the arrange was done, but the viewport did not display the result until you refresh the viewport. --- source/blender/editors/gpencil/gpencil_data.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index a963632a01b..33a1469beab 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1586,6 +1586,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op) gps = link->data; BLI_remlink(&gpf->strokes, gps); BLI_addtail(&gpf->strokes, gps); + changed = true; } break; /* Bring Forward */ @@ -1593,6 +1594,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op) LISTBASE_FOREACH_BACKWARD (LinkData *, link, &selected) { gps = link->data; BLI_listbase_link_move(&gpf->strokes, gps, 1); + changed = true; } break; /* Send Backward */ @@ -1600,6 +1602,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op) LISTBASE_FOREACH (LinkData *, link, &selected) { gps = link->data; BLI_listbase_link_move(&gpf->strokes, gps, -1); + changed = true; } break; /* Send to Back */ @@ -1608,12 +1611,12 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op) gps = link->data; BLI_remlink(&gpf->strokes, gps); BLI_addhead(&gpf->strokes, gps); + changed = true; } break; default: BLI_assert(0); break; - changed = true; } } BLI_freelistN(&selected); -- cgit v1.2.3 From 769818f7f44341511f17925f41535a06f2224558 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 3 Dec 2020 17:42:12 +0100 Subject: GPencil: Reduce UI range for Simplify Adaptive factor The old range was too big, so now the soft limit is between 0 and 5 --- source/blender/makesrna/intern/rna_gpencil_modifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 19264aeebd7..e30ee2e9ee7 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -781,7 +781,7 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna) prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "factor"); RNA_def_property_range(prop, 0, 100.0); - RNA_def_property_ui_range(prop, 0, 100.0, 1.0f, 3); + RNA_def_property_ui_range(prop, 0, 5.0f, 1.0f, 3); RNA_def_property_ui_text(prop, "Factor", "Factor of Simplify"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); -- cgit v1.2.3 From f637b47064237683343f00190a1438638058e92e Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Thu, 3 Dec 2020 11:00:58 -0700 Subject: MSVC: Enable clang-tidy analyser This enables the use of clang-tidy in the VS IDE. To use it: 1 - Enable WITH_CLANG_TIDY in your cmake configuration 2 - From the Analyse pull down menu select Run Code Analysis on... The analyser is currently not enabled by default on build given it is quite slow and there are quite a few problems it reports that we still need to deal with. --- CMakeLists.txt | 4 ++-- build_files/cmake/platform/platform_win32.cmake | 17 ++++++++++++++++- source/CMakeLists.txt | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81fe4739da4..0d7cf4e325c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -427,8 +427,8 @@ mark_as_advanced(WITH_CXX_GUARDEDALLOC) option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" ON) mark_as_advanced(WITH_ASSERT_ABORT) -if(UNIX AND NOT APPLE) - option(WITH_CLANG_TIDY "Use Clang Tidy to analyze the source code (only enable for development on Linux using Clang)" OFF) +if((UNIX AND NOT APPLE) OR (CMAKE_GENERATOR MATCHES "^Visual Studio.+")) + option(WITH_CLANG_TIDY "Use Clang Tidy to analyze the source code (only enable for development on Linux using Clang, or Windows using the Visual Studio IDE)" OFF) mark_as_advanced(WITH_CLANG_TIDY) endif() diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 3954a5f143c..dd8b286c689 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -239,9 +239,24 @@ if(NOT EXISTS "${LIBDIR}/") message(FATAL_ERROR "\n\nWindows requires pre-compiled libs at: '${LIBDIR}'. Please run `make update` in the blender source folder to obtain them.") endif() +if(CMAKE_GENERATOR MATCHES "^Visual Studio.+" AND # Only supported in the VS IDE + MSVC_VERSION GREATER_EQUAL 1924 AND # Supported for 16.4+ + WITH_CLANG_TIDY # And Clang Tidy needs to be on + ) + set(CMAKE_VS_GLOBALS + "RunCodeAnalysis=false" + "EnableMicrosoftCodeAnalysis=false" + "EnableClangTidyCodeAnalysis=true" + ) + set(VS_CLANG_TIDY On) +endif() + # Mark libdir as system headers with a lower warn level, to resolve some warnings # that we have very little control over -if(MSVC_VERSION GREATER_EQUAL 1914 AND NOT MSVC_CLANG AND NOT WITH_WINDOWS_SCCACHE) +if(MSVC_VERSION GREATER_EQUAL 1914 AND # Available with 15.7+ + NOT MSVC_CLANG AND # But not for clang + NOT WITH_WINDOWS_SCCACHE AND # And not when sccache is enabled + NOT VS_CLANG_TIDY) # Clang-tidy does not like these options add_compile_options(/experimental:external /external:templates- /external:I "${LIBDIR}" /external:W0) endif() diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 88c19355960..0ce2341fc2e 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -22,7 +22,7 @@ if(WITH_LEGACY_OPENGL) add_definitions(-DWITH_LEGACY_OPENGL) endif() -if(WITH_CLANG_TIDY) +if(WITH_CLANG_TIDY AND NOT MSVC) if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang") message(WARNING "Currently Clang-Tidy might fail with GCC toolchain, switch to Clang toolchain if that happens") endif() -- cgit v1.2.3 From f3b08af24c9f00f437e57e8fc762235c6cff9286 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Thu, 3 Dec 2020 15:29:23 -0300 Subject: Fix T83352: Move with constraint showing an incorrect value in the header The displayed value was always that of the x axis. --- .../editors/transform/transform_mode_translate.c | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index a54de102966..90c1f241338 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -60,13 +60,18 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ char autoik[NUM_STR_REP_LEN]; float dist; + UnitSettings *unit = NULL; + if (!(t->flag & T_2D_EDIT)) { + unit = &t->scene->unit; + } + if (hasNumInput(&t->num)) { outputNumInput(&(t->num), tvec, &t->scene->unit); dist = len_v3(t->num.val); } else { float dvec[3]; - if (!(t->flag & T_2D_EDIT) && t->con.mode & CON_APPLY) { + if (t->con.mode & CON_APPLY) { int i = 0; zero_v3(dvec); if (t->con.mode & CON_AXIS0) { @@ -81,18 +86,22 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } else { copy_v3_v3(dvec, vec); + } + + if (t->flag & T_2D_EDIT) { applyAspectRatio(t, dvec); } - dist = len_v3(vec); - if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { + dist = len_v3(dvec); + + if (unit) { for (int i = 0; i < 3; i++) { BKE_unit_value_as_string(&tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, - dvec[i] * t->scene->unit.scale_length, + dvec[i] * unit->scale_length, 4, B_UNIT_LENGTH, - &t->scene->unit, + unit, true); } } @@ -103,14 +112,9 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ } } - if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { - BKE_unit_value_as_string(distvec, - sizeof(distvec), - dist * t->scene->unit.scale_length, - 4, - B_UNIT_LENGTH, - &t->scene->unit, - false); + if (unit) { + BKE_unit_value_as_string( + distvec, sizeof(distvec), dist * unit->scale_length, 4, B_UNIT_LENGTH, unit, false); } else if (dist > 1e10f || dist < -1e10f) { /* prevent string buffer overflow */ -- cgit v1.2.3 From 82e401031fd12962cdf61e5334197aa013f65ec9 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Thu, 3 Dec 2020 20:21:09 +0100 Subject: UI: Fix Node Groups color in Geometry Nodes Node Groups didn't have a category assigned so they looked like inputs (red) instead of the Node Group theme color (green by default). --- source/blender/nodes/geometry/nodes/node_geo_common.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc index 8adc3962698..441ad6bdc13 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_common.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc @@ -26,7 +26,7 @@ void register_node_type_geo_group(void) { static bNodeType ntype; - node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", 0, 0); + node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP, 0); ntype.type = NODE_GROUP; ntype.poll = geo_node_poll_default; ntype.poll_instance = node_group_poll_instance; -- cgit v1.2.3 From 92e44ce67cadff6f9e39bf9e3e20da81935f2f54 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Tue, 1 Dec 2020 22:22:13 +0100 Subject: UI: Add sculpt stats to statusbar This was missing from D9623. Now the same sculpt scene stats are also displayed in the status bar. Reviewed By: sergey Differential Revision: https://developer.blender.org/D9700 --- source/blender/editors/space_info/info_stats.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 890bb8a64bc..ffac5c982d6 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -559,12 +559,23 @@ static void get_stats_string( stats_fmt->totgpstroke, stats_fmt->totgppoint); } - else if (stats_is_object_dynamic_topology_sculpt(ob)) { - *ofs += BLI_snprintf(info + *ofs, - len - *ofs, - TIP_("Verts:%s | Tris:%s"), - stats_fmt->totvert, - stats_fmt->tottri); + else if (ob && (object_mode & OB_MODE_SCULPT)) { + if (stats_is_object_dynamic_topology_sculpt(ob)) { + *ofs += BLI_snprintf(info + *ofs, + len - *ofs, + TIP_("Verts:%s | Tris:%s"), + stats_fmt->totvert, + stats_fmt->tottri); + } + else { + *ofs += BLI_snprintf(info + *ofs, + len - *ofs, + TIP_("Verts:%s/%s | Faces:%s/%s"), + stats_fmt->totvertsculpt, + stats_fmt->totvert, + stats_fmt->totfacesculpt, + stats_fmt->totface); + } } else { *ofs += BLI_snprintf(info + *ofs, -- cgit v1.2.3 From 1bc75dfa4a9863016002800b27d6f5addbc3ed7d Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Tue, 1 Dec 2020 00:15:15 +0100 Subject: Sculpt: Allow inverting the Erase Displacement mesh filter When inverting erase displacement the filter can increase the displacement over the limit surface. After using apply base, this can be used as an alternative intensify details as it usually gives better results. This is the same concept as smoothing inverting to intensify details. Reviewed By: sergey Differential Revision: https://developer.blender.org/D9679 --- source/blender/editors/sculpt_paint/sculpt_filter_mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 11af63c6e47..02d4be20e1b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -448,7 +448,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, mul_v3_v3fl(disp, ss->filter_cache->detail_directions[vd.index], -fabsf(fade)); } break; case MESH_FILTER_ERASE_DISPLACEMENT: { - fade = clamp_f(fade, 0.0f, 1.0f); + fade = clamp_f(fade, -1.0f, 1.0f); sub_v3_v3v3(disp, ss->filter_cache->limit_surface_co[vd.index], orig_co); mul_v3_fl(disp, fade); break; -- cgit v1.2.3 From 9234a6a619fdb7530ad7e2e005a6c389e3e6f886 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Fri, 20 Nov 2020 18:26:18 +0100 Subject: Fix T82872: Add design task link for tilt support Reviewed By: sergey, Blendify Maniphest Tasks: T82872 Differential Revision: https://developer.blender.org/D9615 --- release/scripts/startup/bl_ui/space_userpref.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 53c1a136dec..e90c9fb27e7 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2187,7 +2187,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel): context, ( ({"property": "use_sculpt_vertex_colors"}, "T71947"), ({"property": "use_switch_object_operator"}, "T80402"), - ({"property": "use_sculpt_tools_tilt"}, "T00000"), + ({"property": "use_sculpt_tools_tilt"}, "T82877"), ({"property": "use_object_add_tool"}, "T57210"), ), ) -- cgit v1.2.3 From cc6ec71b1934b5489caa538c13d290b45d2b1aa5 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Tue, 17 Nov 2020 22:33:09 +0100 Subject: Sculpt: Wet paint area radius This adds a new property to the sculpt vertex color paint brush to limit the area of the brush that is going to be used to sample the wet paint color. This is exactly the same concept as normal radius and area radius that exist for sculpting brushes for sampling the surface depth and orientation. When working near color hard edges, this allows to prevent the color from the other side of the edge to blend into the wet paint. With 1.0 (the previous default) wet paint radius, as soon as the brush touches one vertex of the other color, the wet paint mix color changes, making it impossible to maintain the border between the two colors. Reviewed By: sergey, dbystedt, JulienKaspar Differential Revision: https://developer.blender.org/D9587 --- release/scripts/startup/bl_ui/properties_paint_common.py | 3 +++ source/blender/blenkernel/intern/brush.c | 1 + source/blender/blenloader/intern/versioning_290.c | 7 +++++++ source/blender/editors/sculpt_paint/sculpt_paint_color.c | 3 +++ source/blender/makesdna/DNA_brush_defaults.h | 1 + source/blender/makesdna/DNA_brush_types.h | 3 ++- source/blender/makesrna/intern/rna_brush.c | 10 ++++++++++ 7 files changed, 27 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 63ccbd2ae05..3075d76d6fa 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -716,6 +716,9 @@ def brush_settings(layout, context, brush, popover=False): row.prop(brush, "invert_wet_persistence_pressure", text="") row.prop(brush, "use_wet_persistence_pressure", text="") + row = layout.row(align=True) + row.prop(brush, "wet_paint_radius_factor") + row = layout.row(align=True) row.prop(brush, "density") row.prop(brush, "invert_density_pressure", text="") diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 1b77989c2b8..96791aed2c3 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -446,6 +446,7 @@ static void brush_defaults(Brush *brush) FROM_DEFAULT(topology_rake_factor); FROM_DEFAULT(crease_pinch_factor); FROM_DEFAULT(normal_radius_factor); + FROM_DEFAULT(wet_paint_radius_factor); FROM_DEFAULT(area_radius_factor); FROM_DEFAULT(disconnected_distance_max); FROM_DEFAULT(sculpt_plane); diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 9278ff51b8d..cebeef1fc46 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -483,6 +483,13 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) } } } + + /* Wet Paint Radius Factor */ + for (Brush *br = bmain->brushes.first; br; br = br->id.next) { + if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) { + br->wet_paint_radius_factor = 1.0f; + } + } } static void panels_remove_x_closed_flag_recursive(Panel *panel) diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index f0047448a8d..39320f3f558 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -220,6 +220,9 @@ static void do_sample_wet_paint_task_cb(void *__restrict userdata, SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + test.radius *= data->brush->wet_paint_radius_factor; + test.radius_squared = test.radius * test.radius; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h index b0a35ac783e..fb726e24929 100644 --- a/source/blender/makesdna/DNA_brush_defaults.h +++ b/source/blender/makesdna/DNA_brush_defaults.h @@ -45,6 +45,7 @@ .topology_rake_factor = 0.0f, \ .crease_pinch_factor = 0.5f, \ .normal_radius_factor = 0.5f, \ + .wet_paint_radius_factor = 0.5f, \ .area_radius_factor = 0.5f, \ .disconnected_distance_max = 0.1f, \ .sculpt_plane = SCULPT_DISP_DIR_AREA, \ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 756f21321f4..50aac69da19 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -573,7 +573,7 @@ typedef struct Brush { char gpencil_sculpt_tool; /** Active grease pencil weight tool. */ char gpencil_weight_tool; - char _pad1[6]; + char _pad1[2]; float autosmooth_factor; @@ -585,6 +585,7 @@ typedef struct Brush { float normal_radius_factor; float area_radius_factor; + float wet_paint_radius_factor; float plane_trim; /** Affectable height of brush (layer height for layer tool, i.e.). */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 1e5309e5869..cf36c1a3742 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -2854,6 +2854,16 @@ static void rna_def_brush(BlenderRNA *brna) "used to sample the area center"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "wet_paint_radius_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "wet_paint_radius_factor"); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_range(prop, 0.0f, 2.0f, 0.001, 3); + RNA_def_property_ui_text(prop, + "Wet Paint Radius", + "Ratio between the brush radius and the radius that is going to be " + "used to sample the color to blend in wet paint"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "stencil_pos", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "stencil_pos"); RNA_def_property_array(prop, 2); -- cgit v1.2.3 From a88e6261db97dd742865d9814aaecefc1c9c1098 Mon Sep 17 00:00:00 2001 From: Yevgeny Makarov Date: Thu, 3 Dec 2020 17:23:13 -0800 Subject: UI: Remove Decorators from Keymap Preferences Improvements to the layout of the Keymaps section of Preferences by removing unneeded Decorator columns. Differential Revision: https://developer.blender.org/D9726 Reviewed by Hans Goudey --- release/scripts/presets/keyconfig/blender.py | 1 + release/scripts/presets/keyconfig/blender_27x.py | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/release/scripts/presets/keyconfig/blender.py b/release/scripts/presets/keyconfig/blender.py index d24735ba8b7..113e99fed42 100644 --- a/release/scripts/presets/keyconfig/blender.py +++ b/release/scripts/presets/keyconfig/blender.py @@ -168,6 +168,7 @@ class Prefs(bpy.types.KeyConfigPreferences): def draw(self, layout): layout.use_property_split = True + layout.use_property_decorate = False is_select_left = (self.select_mouse == 'LEFT') diff --git a/release/scripts/presets/keyconfig/blender_27x.py b/release/scripts/presets/keyconfig/blender_27x.py index a02ac895efb..efb013b9216 100644 --- a/release/scripts/presets/keyconfig/blender_27x.py +++ b/release/scripts/presets/keyconfig/blender_27x.py @@ -33,11 +33,11 @@ class Prefs(bpy.types.KeyConfigPreferences): ) def draw(self, layout): - split = layout.split() - col = split.column() - col.label(text="Select With:") - col.row().prop(self, "select_mouse", expand=True) - split.column() + layout.use_property_split = True + layout.use_property_decorate = False + + col = layout.column() + col.row().prop(self, "select_mouse", text="Select with Mouse Button", expand=True) blender_default = bpy.utils.execfile(os.path.join(DIRNAME, "keymap_data", "blender_default.py")) -- cgit v1.2.3 From 2bd0263fbf2175c672d46c9df9eff7fd3ceecbce Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 3 Dec 2020 23:37:16 -0600 Subject: Fix T83346: Scrolling doesn't work with mouse over panel header Just a misplaced assignment to the return value from the panel handler in rB600fb28b6295. --- source/blender/editors/interface/interface_panel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index b60fa40f39a..e96c0a25d6d 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -2452,11 +2452,12 @@ int ui_handler_panel_region(bContext *C, if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { /* All mouse clicks inside panel headers should return in break. */ - retval = WM_UI_HANDLER_BREAK; if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, LEFTMOUSE)) { + retval = WM_UI_HANDLER_BREAK; ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); } else if (event->type == RIGHTMOUSE) { + retval = WM_UI_HANDLER_BREAK; ui_popup_context_menu_for_panel(C, region, block->panel); } break; -- cgit v1.2.3 From 2bae11d5c08a9095f2c8ec5e465e73ada9840ed1 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 4 Dec 2020 08:13:54 +0100 Subject: EEVEE: Arbitrary Output Variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for AOVs in EEVEE. AOV Outputs can be defined in the render pass tab and used in shader materials. Both Object and World based shaders are supported. The AOV can be previewed in the viewport using the renderpass selector in the shading popover. AOV names that conflict with other AOVs are automatically corrected. AOV conflicts with render passes get a warning icon. The reason behind this is that changing render engines/passes can change the conflict, but you might not notice it. Changing this automatically would also make the materials incorrect, so best to leave this to the user. **Implementation** The patch adds a copies the AOV structures of Cycles into Blender. The goal is that the Cycles will use Blenders AOV defintions. In the Blender kernel (`layer.c`) the logic of these structures are implemented. The GLSL shader of any GPUMaterial can hold multiple outputs (the main output and the AOV outputs) based on the renderPassUBO the right output is selected. This selection uses an hash that encodes the AOV structure. The full AOV needed to be encoded when actually drawing the material pass as the AOV type changes the behavior of the AOV. This isn't known yet when the GLSL is compiled. **Future Developments** * The AOV definitions in the render layer panel isn't shared with Cycles. Cycles should be migrated to use the same viewlayer aovs. During a previous attempt this failed as the AOV validation in cycles and in Blender have implementation differences what made it crash when an aov name was invalid. This could be fixed by extending the external render engine API. * Add support to Cycles to render AOVs in the 3d viewport. * Use a drop down list for selecting AOVs in the AOV Output node. * Give user feedback when multiple AOV output nodes with the same AOV name exists in the same shader. * Fix viewing single channel images in the image editor [T83314] * Reduce viewport render time by only render needed draw passes. [T83316] Reviewed By: Brecht van Lommel, Clément Foucault Differential Revision: https://developer.blender.org/D7010 --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- .../scripts/startup/bl_ui/properties_view_layer.py | 50 +++++- release/scripts/startup/nodeitems_builtins.py | 7 +- source/blender/blenkernel/BKE_appdir.h | 1 + source/blender/blenkernel/BKE_layer.h | 10 ++ source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/appdir.c | 8 + source/blender/blenkernel/intern/layer.c | 162 +++++++++++++++++++ source/blender/blenkernel/intern/layer_test.cc | 177 +++++++++++++++++++++ .../tests/blendfile_loading_base_test.cc | 2 +- source/blender/draw/engines/eevee/eevee_data.c | 3 + .../blender/draw/engines/eevee/eevee_materials.c | 119 ++++++++++++-- source/blender/draw/engines/eevee/eevee_private.h | 19 ++- source/blender/draw/engines/eevee/eevee_render.c | 60 ++++++- .../draw/engines/eevee/eevee_renderpasses.c | 53 ++++-- .../draw/engines/eevee/shaders/renderpass_lib.glsl | 13 ++ .../eevee/shaders/renderpass_postprocess_frag.glsl | 37 +++-- source/blender/editors/render/render_intern.h | 2 + source/blender/editors/render/render_ops.c | 2 + source/blender/editors/render/render_shading.c | 88 ++++++++++ source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/GPU_material.h | 1 + source/blender/gpu/intern/gpu_codegen.c | 37 ++++- source/blender/gpu/intern/gpu_material.c | 8 + source/blender/gpu/intern/gpu_material_library.c | 7 + source/blender/gpu/intern/gpu_node_graph.c | 4 + source/blender/gpu/intern/gpu_node_graph.h | 10 +- .../material/gpu_shader_material_output_aov.glsl | 13 ++ source/blender/makesdna/DNA_layer_types.h | 29 +++- source/blender/makesdna/DNA_view3d_types.h | 1 + source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_internal.h | 4 + source/blender/makesrna/intern/rna_layer.c | 13 +- source/blender/makesrna/intern/rna_scene.c | 95 +++++++++++ source/blender/makesrna/intern/rna_space.c | 96 ++++++++++- source/blender/nodes/shader/node_shader_tree.c | 15 ++ .../nodes/shader/nodes/node_shader_output_aov.c | 19 +++ source/blender/windowmanager/WM_api.h | 3 + source/blender/windowmanager/intern/wm_init_exit.c | 1 + source/blender/windowmanager/intern/wm_window.c | 11 ++ source/tools | 2 +- 42 files changed, 1109 insertions(+), 80 deletions(-) create mode 100644 source/blender/blenkernel/intern/layer_test.cc create mode 100644 source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl diff --git a/release/datafiles/locale b/release/datafiles/locale index ae7e6c215c9..1c0e9c29fd3 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit ae7e6c215c9fc715cdedbc1c1e33e946fc90b496 +Subproject commit 1c0e9c29fd33963ff42ff9252a64016abda8d2a7 diff --git a/release/scripts/addons b/release/scripts/addons index ca741974401..672cfe9c85e 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit ca74197440127e56c9f6f2a277c30957f34fd07c +Subproject commit 672cfe9c85e2ac71b97b5331d9034d23c9723d71 diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index afa00bb50c2..35cd7ae5ab9 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -17,7 +17,16 @@ # ##### END GPL LICENSE BLOCK ##### # -from bpy.types import Panel +from bpy.types import Panel, UIList + + +class VIEWLAYER_UL_aov(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + row = layout.row() + split = row.split(factor=0.65) + icon = 'NONE' if item.is_valid else 'ERROR' + split.row().prop(item, "name", text="", icon=icon, emboss=False) + split.row().prop(item, "type", text="", emboss=False) class ViewLayerButtonsPanel: @@ -49,7 +58,7 @@ class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel): col.prop(rd, "use_single_layer", text="Render Single Layer") -class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel): +class VIEWLAYER_PT_layer_passes(ViewLayerButtonsPanel, Panel): bl_label = "Passes" COMPAT_ENGINES = {'BLENDER_EEVEE'} @@ -59,7 +68,7 @@ class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel): class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel): bl_label = "Data" - bl_parent_id = "VIEWLAYER_PT_eevee_layer_passes" + bl_parent_id = "VIEWLAYER_PT_layer_passes" COMPAT_ENGINES = {'BLENDER_EEVEE'} @@ -81,7 +90,7 @@ class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel): class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel): bl_label = "Light" - bl_parent_id = "VIEWLAYER_PT_eevee_layer_passes" + bl_parent_id = "VIEWLAYER_PT_layer_passes" COMPAT_ENGINES = {'BLENDER_EEVEE'} def draw(self, context): @@ -116,7 +125,7 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel): class VIEWLAYER_PT_eevee_layer_passes_effects(ViewLayerButtonsPanel, Panel): bl_label = "Effects" - bl_parent_id = "VIEWLAYER_PT_eevee_layer_passes" + bl_parent_id = "VIEWLAYER_PT_layer_passes" COMPAT_ENGINES = {'BLENDER_EEVEE'} def draw(self, context): @@ -135,12 +144,41 @@ class VIEWLAYER_PT_eevee_layer_passes_effects(ViewLayerButtonsPanel, Panel): col.active = scene_eevee.use_bloom +class VIEWLAYER_PT_layer_passes_aov(ViewLayerButtonsPanel, Panel): + bl_label = "Shader AOV" + bl_parent_id = "VIEWLAYER_PT_layer_passes" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + + layout.use_property_split = True + layout.use_property_decorate = False + + view_layer = context.view_layer + + row = layout.row() + col = row.column() + col.template_list("VIEWLAYER_UL_aov", "aovs", view_layer, "aovs", view_layer, "active_aov_index", rows=2) + + col = row.column() + sub = col.column(align=True) + sub.operator("scene.view_layer_add_aov", icon='ADD', text="") + sub.operator("scene.view_layer_remove_aov", icon='REMOVE', text="") + + aov = view_layer.active_aov + if aov and not aov.is_valid: + layout.label(text="Conflicts with another render pass with the same name", icon='ERROR') + + classes = ( VIEWLAYER_PT_layer, - VIEWLAYER_PT_eevee_layer_passes, + VIEWLAYER_PT_layer_passes, VIEWLAYER_PT_eevee_layer_passes_data, VIEWLAYER_PT_eevee_layer_passes_light, VIEWLAYER_PT_eevee_layer_passes_effects, + VIEWLAYER_PT_layer_passes_aov, + VIEWLAYER_UL_aov, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index b1789776728..abab50b95a2 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -165,11 +165,6 @@ def object_cycles_shader_nodes_poll(context): cycles_shader_nodes_poll(context)) -def cycles_aov_node_poll(context): - return (object_cycles_shader_nodes_poll(context) or - world_shader_nodes_poll(context)) - - def object_eevee_shader_nodes_poll(context): return (object_shader_nodes_poll(context) and eevee_shader_nodes_poll(context)) @@ -210,7 +205,7 @@ shader_node_categories = [ ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[ NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll), - NodeItem("ShaderNodeOutputAOV", poll=cycles_aov_node_poll), + NodeItem("ShaderNodeOutputAOV"), NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll), NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll), NodeItem("NodeGroupOutput", poll=group_input_output_item_poll), diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index 3e52d7f3301..6da6079ea2a 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -26,6 +26,7 @@ extern "C" { struct ListBase; void BKE_appdir_init(void); +void BKE_appdir_exit(void); /* note on naming: typical _get() suffix is omitted here, * since its the main purpose of the API. */ diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 7091a060243..e5fab35891c 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -42,6 +42,7 @@ struct Depsgraph; struct LayerCollection; struct Main; struct Object; +struct RenderEngine; struct Scene; struct View3D; struct ViewLayer; @@ -444,6 +445,15 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_dat BKE_view_layer_array_from_objects_in_mode( \ view_layer, v3d, r_len, {.object_mode = mode, .no_dup_data = true}) +struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer); +void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov); +void BKE_view_layer_set_active_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov); +void BKE_view_layer_verify_aov(struct RenderEngine *engine, + struct Scene *scene, + struct ViewLayer *view_layer); +bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer); +ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *view_layer_aov); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1a90d6fadd3..a328c600eac 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -726,6 +726,7 @@ if(WITH_GTESTS) intern/fcurve_test.cc intern/lattice_deform_test.cc intern/tracking_test.cc + intern/layer_test.cc ) set(TEST_INC ../editors/include diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 2038079744d..b1462167edd 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -114,6 +114,14 @@ void BKE_appdir_init(void) #endif } +void BKE_appdir_exit(void) +{ +#ifndef NDEBUG + BLI_assert(is_appdir_init == true); + is_appdir_init = false; +#endif +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 73b330bc0de..6b346d7a337 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -57,6 +57,8 @@ #include "DRW_engine.h" +#include "RE_engine.h" + #include "MEM_guardedalloc.h" #include "BLO_read_write.h" @@ -279,6 +281,8 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) } } BLI_freelistN(&view_layer->drawdata); + BLI_freelistN(&view_layer->aovs); + view_layer->active_aov = NULL; MEM_SAFE_FREE(view_layer->stats); @@ -412,6 +416,28 @@ void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Bas } /**************************** Copy View Layer and Layer Collections ***********************/ +static void layer_aov_copy_data(ViewLayer *view_layer_dst, + const ViewLayer *view_layer_src, + ListBase *aovs_dst, + const ListBase *aovs_src) +{ + if (aovs_src != NULL) { + BLI_duplicatelist(aovs_dst, aovs_src); + } + + ViewLayerAOV *aov_dst = aovs_dst->first; + const ViewLayerAOV *aov_src = aovs_src->first; + + while (aov_dst != NULL) { + BLI_assert(aov_src); + if (aov_src == view_layer_src->active_aov) { + view_layer_dst->active_aov = aov_dst; + } + + aov_dst = aov_dst->next; + aov_src = aov_src->next; + } +} static void layer_collections_copy_data(ViewLayer *view_layer_dst, const ViewLayer *view_layer_src, @@ -482,6 +508,10 @@ void BKE_view_layer_copy_data(Scene *scene_dst, LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first; lc_scene_dst->collection = scene_dst->master_collection; + BLI_listbase_clear(&view_layer_dst->aovs); + layer_aov_copy_data( + view_layer_dst, view_layer_src, &view_layer_dst->aovs, &view_layer_src->aovs); + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)view_layer_dst->mat_override); } @@ -1864,6 +1894,9 @@ void BKE_view_layer_blend_write(BlendWriter *writer, ViewLayer *view_layer) LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { BLO_write_struct(writer, FreestyleLineSet, fls); } + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + BLO_write_struct(writer, ViewLayerAOV, aov); + } write_layer_collections(writer, &view_layer->layer_collections); } @@ -1899,6 +1932,9 @@ void BKE_view_layer_blend_read_data(BlendDataReader *reader, ViewLayer *view_lay BLO_read_list(reader, &(view_layer->freestyle_config.modules)); BLO_read_list(reader, &(view_layer->freestyle_config.linesets)); + BLO_read_list(reader, &view_layer->aovs); + BLO_read_data_address(reader, &view_layer->active_aov); + BLI_listbase_clear(&view_layer->drawdata); view_layer->object_bases_array = NULL; view_layer->object_bases_hash = NULL; @@ -1952,3 +1988,129 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay IDP_BlendReadLib(reader, view_layer->id_properties); } + +/* -------------------------------------------------------------------- */ +/** \name Shader AOV + * \{ */ + +static void viewlayer_aov_make_name_unique(ViewLayer *view_layer) +{ + ViewLayerAOV *aov = view_layer->active_aov; + if (aov == NULL) { + return; + } + BLI_uniquename( + &view_layer->aovs, aov, DATA_("AOV"), '.', offsetof(ViewLayerAOV, name), sizeof(aov->name)); +} + +static void viewlayer_aov_active_set(ViewLayer *view_layer, ViewLayerAOV *aov) +{ + if (aov != NULL) { + BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1); + view_layer->active_aov = aov; + } + else { + view_layer->active_aov = NULL; + } +} + +struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer) +{ + ViewLayerAOV *aov; + aov = MEM_callocN(sizeof(ViewLayerAOV), __func__); + aov->type = AOV_TYPE_COLOR; + BLI_strncpy(aov->name, DATA_("AOV"), sizeof(aov->name)); + BLI_addtail(&view_layer->aovs, aov); + viewlayer_aov_active_set(view_layer, aov); + viewlayer_aov_make_name_unique(view_layer); + return aov; +} + +void BKE_view_layer_remove_aov(ViewLayer *view_layer, ViewLayerAOV *aov) +{ + BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1); + BLI_assert(aov != NULL); + if (view_layer->active_aov == aov) { + if (aov->next) { + viewlayer_aov_active_set(view_layer, aov->next); + } + else { + viewlayer_aov_active_set(view_layer, aov->prev); + } + } + BLI_freelinkN(&view_layer->aovs, aov); +} + +void BKE_view_layer_set_active_aov(ViewLayer *view_layer, ViewLayerAOV *aov) +{ + viewlayer_aov_active_set(view_layer, aov); +} + +static void bke_view_layer_verify_aov_cb(void *userdata, + Scene *UNUSED(scene), + ViewLayer *UNUSED(view_layer), + const char *name, + int UNUSED(channels), + const char *UNUSED(chanid), + int UNUSED(type)) +{ + GHash *name_count = userdata; + void **value_p; + void *key = BLI_strdup(name); + + if (!BLI_ghash_ensure_p(name_count, key, &value_p)) { + *value_p = POINTER_FROM_INT(1); + } + else { + int value = POINTER_AS_INT(*value_p); + value++; + *value_p = POINTER_FROM_INT(value); + MEM_freeN(key); + } +} + +/* Update the naming and conflicts of the AOVs. + * + * Name must be unique between all AOVs. + * Conflicts with render passes will show a conflict icon. Reason is that switching a render + * engine or activating a render pass could lead to other conflicts that wouldn't be that clear + * for the user. */ +void BKE_view_layer_verify_aov(struct RenderEngine *engine, + struct Scene *scene, + struct ViewLayer *view_layer) +{ + viewlayer_aov_make_name_unique(view_layer); + + GHash *name_count = BLI_ghash_str_new(__func__); + RE_engine_update_render_passes( + engine, scene, view_layer, bke_view_layer_verify_aov_cb, name_count); + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + void **value_p = BLI_ghash_lookup(name_count, aov->name); + int count = POINTER_AS_INT(value_p); + SET_FLAG_FROM_TEST(aov->flag, count > 1, AOV_CONFLICT); + } + BLI_ghash_free(name_count, MEM_freeN, NULL); +} + +/* Check if the given view layer has at least one valid AOV. */ +bool BKE_view_layer_has_valid_aov(ViewLayer *view_layer) +{ + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + if ((aov->flag & AOV_CONFLICT) == 0) { + return true; + } + } + return false; +} + +ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *aov) +{ + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + if (BLI_findindex(&view_layer->aovs, aov) != -1) { + return view_layer; + } + } + return NULL; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/layer_test.cc b/source/blender/blenkernel/intern/layer_test.cc new file mode 100644 index 00000000000..84a96ed0895 --- /dev/null +++ b/source/blender/blenkernel/intern/layer_test.cc @@ -0,0 +1,177 @@ +/* + * 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) 2020 by Blender Foundation. + */ +#include "testing/testing.h" + +#include "MEM_guardedalloc.h" + +#include "BKE_appdir.h" +#include "BKE_idtype.h" +#include "BKE_layer.h" + +#include "BLI_string.h" + +#include "RE_engine.h" + +#include "IMB_imbuf.h" + +#include "CLG_log.h" + +#include "RNA_access.h" + +namespace blender::bke::tests { + +TEST(view_layer, aov_unique_names) +{ + /* Set Up */ + CLG_init(); + BKE_appdir_init(); + IMB_init(); + RE_engines_init(); + + Scene scene = {{NULL}}; + IDType_ID_SCE.init_data(&scene.id); + ViewLayer *view_layer = static_cast(scene.view_layers.first); + + RenderEngineType *engine_type = RE_engines_find(scene.r.engine); + RenderEngine *engine = RE_engine_create(engine_type); + + EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_EQ(view_layer->active_aov, nullptr); + + /* Add an AOV */ + ViewLayerAOV *aov1 = BKE_view_layer_add_aov(view_layer); + BKE_view_layer_verify_aov(engine, &scene, view_layer); + EXPECT_EQ(view_layer->active_aov, aov1); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0); + + /* Add a second AOV */ + ViewLayerAOV *aov2 = BKE_view_layer_add_aov(view_layer); + BKE_view_layer_verify_aov(engine, &scene, view_layer); + EXPECT_EQ(view_layer->active_aov, aov2); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0); + EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0); + EXPECT_TRUE(STREQ(aov1->name, "AOV")); + EXPECT_TRUE(STREQ(aov2->name, "AOV.001")); + + /* Revert previous resolution */ + BLI_strncpy(aov2->name, "AOV", MAX_NAME); + BKE_view_layer_verify_aov(engine, &scene, view_layer); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0); + EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0); + EXPECT_TRUE(STREQ(aov1->name, "AOV")); + EXPECT_TRUE(STREQ(aov2->name, "AOV.001")); + + /* Resolve by removing AOV resolution */ + BKE_view_layer_remove_aov(view_layer, aov2); + aov2 = NULL; + BKE_view_layer_verify_aov(engine, &scene, view_layer); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0); + + /* Tear down */ + RE_engine_free(engine); + RE_engines_exit(); + IDType_ID_SCE.free_data(&scene.id); + IMB_exit(); + BKE_appdir_exit(); + CLG_exit(); +} + +static void test_render_pass_conflict(Scene *scene, + RenderEngine *engine, + ViewLayer *view_layer, + ViewLayerAOV *aov, + const char *render_pass_name, + const char *rna_prop_name) +{ + PointerRNA ptr; + RNA_pointer_create(&scene->id, &RNA_ViewLayer, view_layer, &ptr); + RNA_boolean_set(&ptr, rna_prop_name, false); + + /* Rename to Conflicting name */ + BLI_strncpy(aov->name, render_pass_name, MAX_NAME); + BKE_view_layer_verify_aov(engine, scene, view_layer); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0); + EXPECT_TRUE(STREQ(aov->name, render_pass_name)); + + /* Activate render pass */ + RNA_boolean_set(&ptr, rna_prop_name, true); + BKE_view_layer_verify_aov(engine, scene, view_layer); + EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_TRUE((aov->flag & AOV_CONFLICT) != 0); + EXPECT_TRUE(STREQ(aov->name, render_pass_name)); + + /* Deactivate render pass */ + RNA_boolean_set(&ptr, rna_prop_name, false); + BKE_view_layer_verify_aov(engine, scene, view_layer); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0); + EXPECT_TRUE(STREQ(aov->name, render_pass_name)); +} + +TEST(view_layer, aov_conflict) +{ + /* Set Up */ + CLG_init(); + BKE_appdir_init(); + IMB_init(); + RE_engines_init(); + + Scene scene = {{NULL}}; + IDType_ID_SCE.init_data(&scene.id); + ViewLayer *view_layer = static_cast(scene.view_layers.first); + + RenderEngineType *engine_type = RE_engines_find(scene.r.engine); + RenderEngine *engine = RE_engine_create(engine_type); + + EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_EQ(view_layer->active_aov, nullptr); + + /* Add an AOV */ + ViewLayerAOV *aov = BKE_view_layer_add_aov(view_layer); + BKE_view_layer_verify_aov(engine, &scene, view_layer); + EXPECT_EQ(view_layer->active_aov, aov); + EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); + EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0); + + test_render_pass_conflict(&scene, engine, view_layer, aov, "Depth", "use_pass_z"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "Normal", "use_pass_normal"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "Mist", "use_pass_mist"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "Shadow", "use_pass_shadow"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "AO", "use_pass_ambient_occlusion"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "Emit", "use_pass_emit"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "Env", "use_pass_environment"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "DiffDir", "use_pass_diffuse_direct"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "DiffCol", "use_pass_diffuse_color"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "GlossDir", "use_pass_glossy_direct"); + test_render_pass_conflict(&scene, engine, view_layer, aov, "GlossCol", "use_pass_glossy_color"); + + /* Tear down */ + RE_engine_free(engine); + RE_engines_exit(); + IDType_ID_SCE.free_data(&scene.id); + IMB_exit(); + BKE_appdir_exit(); + CLG_exit(); +} + +} // namespace blender::bke::tests diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc index a3aabf6ac10..8d8dc3aebf7 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -103,7 +103,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase() BKE_blender_atexit(); BKE_tempdir_session_purge(); - + BKE_appdir_exit(); CLG_exit(); testing::Test::TearDownTestCase(); diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 5c4ee015c86..47068d0b843 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -240,6 +240,9 @@ void EEVEE_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light); DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit); DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.environment); + for (int aov_index = 0; aov_index < MAX_AOVS; aov_index++) { + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]); + } if (sldata->material_cache) { BLI_memblock_destroy(sldata->material_cache, NULL); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 58f182ecf8d..c7a8f7729eb 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -244,31 +244,31 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, /* Create RenderPass UBO */ if (sldata->renderpass_ubo.combined == NULL) { EEVEE_RenderPassData data; - data = (EEVEE_RenderPassData){true, true, true, true, true, false, false}; + data = (EEVEE_RenderPassData){true, true, true, true, true, false, false, false, 0}; sldata->renderpass_ubo.combined = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.combined"); - data = (EEVEE_RenderPassData){true, false, false, false, false, true, false}; + data = (EEVEE_RenderPassData){true, false, false, false, false, true, false, false, 0}; sldata->renderpass_ubo.diff_color = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.diff_color"); - data = (EEVEE_RenderPassData){true, true, false, false, false, false, false}; + data = (EEVEE_RenderPassData){true, true, false, false, false, false, false, false, 0}; sldata->renderpass_ubo.diff_light = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.diff_light"); - data = (EEVEE_RenderPassData){false, false, true, false, false, false, false}; + data = (EEVEE_RenderPassData){false, false, true, false, false, false, false, false, 0}; sldata->renderpass_ubo.spec_color = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.spec_color"); - data = (EEVEE_RenderPassData){false, false, true, true, false, false, false}; + data = (EEVEE_RenderPassData){false, false, true, true, false, false, false, false, 0}; sldata->renderpass_ubo.spec_light = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.spec_light"); - data = (EEVEE_RenderPassData){false, false, false, false, true, false, false}; + data = (EEVEE_RenderPassData){false, false, false, false, true, false, false, false, 0}; sldata->renderpass_ubo.emit = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.emit"); - data = (EEVEE_RenderPassData){true, true, true, true, true, false, true}; + data = (EEVEE_RenderPassData){true, true, true, true, true, false, true, false, 0}; sldata->renderpass_ubo.environment = GPU_uniformbuf_create_ex( sizeof(data), &data, "renderpass_ubo.environment"); } @@ -276,6 +276,51 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, /* Used combined pass by default. */ g_data->renderpass_ubo = sldata->renderpass_ubo.combined; + { + g_data->num_aovs_used = 0; + if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) { + EEVEE_RenderPassData data = {true, true, true, true, true, false, false, true, 0}; + if (stl->g_data->aov_hash == EEVEE_AOV_HASH_ALL) { + ViewLayer *view_layer = draw_ctx->view_layer; + int aov_index = 0; + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + if ((aov->flag & AOV_CONFLICT) != 0) { + continue; + } + if (aov_index == MAX_AOVS) { + break; + } + data.renderPassAOVActive = EEVEE_renderpasses_aov_hash(aov); + if (sldata->renderpass_ubo.aovs[aov_index]) { + GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[aov_index], &data); + } + else { + sldata->renderpass_ubo.aovs[aov_index] = GPU_uniformbuf_create_ex( + sizeof(data), &data, "renderpass_ubo.aovs"); + } + aov_index++; + } + g_data->num_aovs_used = aov_index; + } + else { + /* Rendering a single AOV in the 3d viewport */ + data.renderPassAOVActive = stl->g_data->aov_hash; + if (sldata->renderpass_ubo.aovs[0]) { + GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[0], &data); + } + else { + sldata->renderpass_ubo.aovs[0] = GPU_uniformbuf_create_ex( + sizeof(data), &data, "renderpass_ubo.aovs"); + } + g_data->num_aovs_used = 1; + } + } + /* Free AOV UBO's that are not in use. */ + for (int aov_index = g_data->num_aovs_used; aov_index < MAX_AOVS; aov_index++) { + DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]); + } + } + /* HACK: EEVEE_material_get can create a new context. This can only be * done when there is no active framebuffer. We do this here otherwise * `EEVEE_renderpasses_output_init` will fail. It cannot be done in @@ -949,6 +994,11 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear); } + if (pd->render_passes & EEVEE_RENDER_PASS_AOV) { + for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) { + material_renderpass_init(fbl, &txl->aov_surface_accum[aov_index], texture_format, do_clear); + } + } if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear); @@ -960,6 +1010,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, DRWPass *renderpass, + DRWPass *renderpass2, EEVEE_PrivateData *pd, GPUTexture *output_tx, struct GPUUniformBuf *renderpass_option_ubo) @@ -969,6 +1020,9 @@ static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, pd->renderpass_ubo = renderpass_option_ubo; DRW_draw_pass(renderpass); + if (renderpass2) { + DRW_draw_pass(renderpass2); + } GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx); } @@ -983,38 +1037,69 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v if (fbl->material_accum_fb != NULL) { DRWPass *material_accum_ps = psl->material_accum_ps; + DRWPass *background_accum_ps = psl->background_accum_ps; if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { material_renderpass_accumulate( - fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.environment); + fbl, background_accum_ps, NULL, pd, txl->env_accum, sldata->renderpass_ubo.environment); } if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { material_renderpass_accumulate( - fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit); + fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit); } if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { - material_renderpass_accumulate( - fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color); + material_renderpass_accumulate(fbl, + material_accum_ps, + NULL, + pd, + txl->diff_color_accum, + sldata->renderpass_ubo.diff_color); } if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { - material_renderpass_accumulate( - fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light); + material_renderpass_accumulate(fbl, + material_accum_ps, + NULL, + pd, + txl->diff_light_accum, + sldata->renderpass_ubo.diff_light); if (effects->enabled_effects & EFFECT_SSS) { EEVEE_subsurface_output_accumulate(sldata, vedata); } } if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { - material_renderpass_accumulate( - fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color); + material_renderpass_accumulate(fbl, + material_accum_ps, + NULL, + pd, + txl->spec_color_accum, + sldata->renderpass_ubo.spec_color); } if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { - material_renderpass_accumulate( - fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light); + material_renderpass_accumulate(fbl, + material_accum_ps, + NULL, + pd, + txl->spec_light_accum, + sldata->renderpass_ubo.spec_light); if (effects->enabled_effects & EFFECT_SSR) { EEVEE_reflection_output_accumulate(sldata, vedata); } } + if (pd->render_passes & EEVEE_RENDER_PASS_AOV) { + for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) { + material_renderpass_accumulate(fbl, + material_accum_ps, + background_accum_ps, + pd, + txl->aov_surface_accum[aov_index], + sldata->renderpass_ubo.aovs[aov_index]); + } + } + /* Free unused aov textures. */ + for (int aov_index = pd->num_aovs_used; aov_index < MAX_AOVS; aov_index++) { + DRW_TEXTURE_FREE_SAFE(txl->aov_surface_accum[aov_index]); + } /* Restore default. */ pd->renderpass_ubo = sldata->renderpass_ubo.combined; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index f5cef8f3c25..1385721a569 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -53,6 +53,7 @@ extern struct DrawEngineType draw_engine_eevee_type; #define MAX_SHADOW_CASCADE 8 #define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE) #define MAX_BLOOM_STEP 16 +#define MAX_AOVS 64 // #define DEBUG_SHADOW_DISTRIBUTION @@ -163,8 +164,9 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) #define EEVEE_RENDERPASSES_MATERIAL \ (EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \ EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \ - EEVEE_RENDER_PASS_ENVIRONMENT) - + EEVEE_RENDER_PASS_ENVIRONMENT | EEVEE_RENDER_PASS_AOV) +#define EEVEE_AOV_HASH_ALL -1 +#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1 /* Material shader variations */ enum { VAR_MAT_MESH = (1 << 0), @@ -376,6 +378,7 @@ typedef struct EEVEE_TextureList { struct GPUTexture *diff_light_accum; struct GPUTexture *spec_color_accum; struct GPUTexture *spec_light_accum; + struct GPUTexture *aov_surface_accum[MAX_AOVS]; struct GPUTexture *emit_accum; struct GPUTexture *bloom_accum; struct GPUTexture *ssr_accum; @@ -430,7 +433,9 @@ typedef struct EEVEE_RenderPassData { int renderPassEmit; int renderPassSSSColor; int renderPassEnvironment; - int _pad[1]; + int renderPassAOV; + int renderPassAOVActive; + int _pad[3]; } EEVEE_RenderPassData; /* ************ LIGHT UBO ************* */ @@ -860,6 +865,7 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuf *spec_color; struct GPUUniformBuf *spec_light; struct GPUUniformBuf *emit; + struct GPUUniformBuf *aovs[MAX_AOVS]; } renderpass_ubo; /* Common Uniform Buffer */ @@ -959,6 +965,9 @@ typedef struct EEVEE_PrivateData { /* Renderpasses */ /* Bitmask containing the active render_passes */ eViewLayerEEVEEPassType render_passes; + int aov_hash; + int num_aovs_used; + /* Uniform references that are referenced inside the `renderpass_pass`. They are updated * to reuse the drawing pass and the shading group. */ int renderpass_type; @@ -1284,10 +1293,12 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, bool post_effect); void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type); + eViewLayerEEVEEPassType renderpass_type, + int aov_index); void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata); bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata); +int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov); /* eevee_temporal_sampling.c */ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 504e4e1d336..32e6eac2402 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -301,7 +301,7 @@ static void eevee_render_result_normal(RenderLayer *rl, } if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_NORMAL) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL); + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL, 0); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata); } @@ -321,7 +321,7 @@ static void eevee_render_result_z(RenderLayer *rl, } if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_Z) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z); + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z, 0); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata); } @@ -334,7 +334,7 @@ static void eevee_render_result_mist(RenderLayer *rl, EEVEE_ViewLayerData *sldata) { if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_MIST) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST); + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST, 0); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata); } @@ -347,7 +347,7 @@ static void eevee_render_result_shadow(RenderLayer *rl, EEVEE_ViewLayerData *sldata) { if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_SHADOW) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW); + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW, 0); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_SHADOW, 3, vedata->fbl->renderpass_fb, vedata); } @@ -360,7 +360,7 @@ static void eevee_render_result_occlusion(RenderLayer *rl, EEVEE_ViewLayerData *sldata) { if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AO) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO); + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO, 0); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata); } @@ -378,7 +378,7 @@ static void eevee_render_result_bloom(RenderLayer *rl, } if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) != 0) { - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM); + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM, 0); eevee_render_color_result( rl, viewname, rect, RE_PASSNAME_BLOOM, 3, vedata->fbl->renderpass_fb, vedata); } @@ -386,7 +386,7 @@ static void eevee_render_result_bloom(RenderLayer *rl, #define EEVEE_RENDER_RESULT_MATERIAL_PASS(pass_name, eevee_pass_type) \ if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_##eevee_pass_type) != 0) { \ - EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type); \ + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type, 0); \ eevee_render_color_result( \ rl, viewname, rect, RE_PASSNAME_##pass_name, 3, vedata->fbl->renderpass_fb, vedata); \ } @@ -462,6 +462,35 @@ static void eevee_render_result_volume_transmittance(RenderLayer *rl, EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_TRANSMITTANCE, VOLUME_TRANSMITTANCE) } +static void eevee_render_result_aovs(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + int aov_index = 0; + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + if ((aov->flag & AOV_CONFLICT) != 0) { + continue; + } + EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AOV, aov_index); + switch (aov->type) { + case AOV_TYPE_COLOR: + eevee_render_color_result( + rl, viewname, rect, aov->name, 4, vedata->fbl->renderpass_fb, vedata); + break; + case AOV_TYPE_VALUE: + eevee_render_color_result( + rl, viewname, rect, aov->name, 1, vedata->fbl->renderpass_fb, vedata); + } + aov_index++; + } + } +} + #undef EEVEE_RENDER_RESULT_MATERIAL_PASS static void eevee_render_draw_background(EEVEE_Data *vedata) @@ -641,6 +670,7 @@ void EEVEE_render_read_result(EEVEE_Data *vedata, eevee_render_result_bloom(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata); + eevee_render_result_aovs(rl, viewname, rect, vedata, sldata); } void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) @@ -675,6 +705,22 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v CHECK_PASS_EEVEE(VOLUME_TRANSMITTANCE, SOCK_RGBA, 3, "RGB"); CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB"); + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + if ((aov->flag & AOV_CONFLICT) != 0) { + continue; + } + switch (aov->type) { + case AOV_TYPE_COLOR: + RE_engine_register_pass(engine, scene, view_layer, aov->name, 4, "RGBA", SOCK_RGBA); + break; + case AOV_TYPE_VALUE: + RE_engine_register_pass(engine, scene, view_layer, aov->name, 1, "X", SOCK_FLOAT); + break; + default: + break; + } + } + #undef CHECK_PASS_LEGACY #undef CHECK_PASS_EEVEE } diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index be73225b348..3f75f10b204 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -27,6 +27,7 @@ #include "BKE_global.h" /* for G.debug_value */ +#include "BLI_hash.h" #include "BLI_string_utils.h" #include "DEG_depsgraph_query.h" @@ -36,12 +37,13 @@ typedef enum eRenderPassPostProcessType { PASS_POST_UNDEFINED = 0, PASS_POST_ACCUMULATED_COLOR = 1, - PASS_POST_ACCUMULATED_LIGHT = 2, - PASS_POST_ACCUMULATED_VALUE = 3, - PASS_POST_DEPTH = 4, - PASS_POST_AO = 5, - PASS_POST_NORMAL = 6, - PASS_POST_TWO_LIGHT_BUFFERS = 7, + PASS_POST_ACCUMULATED_COLOR_ALPHA = 2, + PASS_POST_ACCUMULATED_LIGHT = 3, + PASS_POST_ACCUMULATED_VALUE = 4, + PASS_POST_DEPTH = 5, + PASS_POST_AO = 6, + PASS_POST_NORMAL = 7, + PASS_POST_TWO_LIGHT_BUFFERS = 8, } eRenderPassPostProcessType; /* bitmask containing all renderpasses that need post-processing */ @@ -70,6 +72,15 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata) return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0; } +/* Calculate the hash for an AOV. The least significant bit is used to store the AOV + * type the rest of the bits are used for the name hash. */ +int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov) +{ + int hash = BLI_hash_string(aov->name); + SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK); + return hash; +} + void EEVEE_renderpasses_init(EEVEE_Data *vedata) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -81,10 +92,24 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata) if (v3d) { const Scene *scene = draw_ctx->scene; eViewLayerEEVEEPassType render_pass = v3d->shading.render_pass; + g_data->aov_hash = 0; + if (render_pass == EEVEE_RENDER_PASS_BLOOM && ((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) { render_pass = EEVEE_RENDER_PASS_COMBINED; } + if (render_pass == EEVEE_RENDER_PASS_AOV) { + ViewLayerAOV *aov = BLI_findstring( + &view_layer->aovs, v3d->shading.aov_name, offsetof(ViewLayerAOV, name)); + if (aov != NULL) { + g_data->aov_hash = EEVEE_renderpasses_aov_hash(aov); + } + else { + /* AOV not found in view layer. */ + render_pass = EEVEE_RENDER_PASS_COMBINED; + } + } + g_data->render_passes = render_pass; } else { @@ -110,10 +135,14 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata) ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT) #undef ENABLE_FROM_LEGACY + if (DRW_state_is_image_render() && !BLI_listbase_is_empty(&view_layer->aovs)) { + enabled_render_passes |= EEVEE_RENDER_PASS_AOV; + g_data->aov_hash = EEVEE_AOV_HASH_ALL; + } + g_data->render_passes = (enabled_render_passes & EEVEE_RENDERPASSES_ALL) | EEVEE_RENDER_PASS_COMBINED; } - EEVEE_material_renderpasses_init(vedata); } @@ -216,7 +245,8 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) + eViewLayerEEVEEPassType renderpass_type, + int aov_index) { EEVEE_PassList *psl = vedata->psl; EEVEE_TextureList *txl = vedata->txl; @@ -311,6 +341,11 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), } break; } + case EEVEE_RENDER_PASS_AOV: { + g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR_ALPHA; + g_data->renderpass_input = txl->aov_surface_accum[aov_index]; + break; + } case EEVEE_RENDER_PASS_BLOOM: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; g_data->renderpass_input = txl->bloom_accum; @@ -392,7 +427,7 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if (is_valid) { - EEVEE_renderpasses_postprocess(sldata, vedata, render_pass); + EEVEE_renderpasses_postprocess(sldata, vedata, render_pass, 0); GPU_framebuffer_bind(dfbl->default_fb); DRW_transform_none(txl->renderpass); } diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl index 36cf3cecf40..3e0a5e76d00 100644 --- a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl @@ -1,3 +1,4 @@ +#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1 /* ---------------------------------------------------------------------- */ /** \name Resources @@ -12,6 +13,8 @@ layout(std140) uniform renderpass_block bool renderPassEmit; bool renderPassSSSColor; bool renderPassEnvironment; + bool renderPassAOV; + int renderPassAOVActive; }; /** \} */ @@ -40,4 +43,14 @@ vec3 render_pass_emission_mask(vec3 emission_light) return renderPassEmit ? emission_light : vec3(0.0); } +bool render_pass_aov_is_color() +{ + return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0; +} + +int render_pass_aov_hash() +{ + return renderPassAOVActive & ~EEVEE_AOV_HASH_COLOR_TYPE_MASK; +} + /** \} */ diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl index 89a411bc7cb..eb6ca4b9de8 100644 --- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl @@ -4,12 +4,13 @@ #define PASS_POST_UNDEFINED 0 #define PASS_POST_ACCUMULATED_COLOR 1 -#define PASS_POST_ACCUMULATED_LIGHT 2 -#define PASS_POST_ACCUMULATED_VALUE 3 -#define PASS_POST_DEPTH 4 -#define PASS_POST_AO 5 -#define PASS_POST_NORMAL 6 -#define PASS_POST_TWO_LIGHT_BUFFERS 7 +#define PASS_POST_ACCUMULATED_COLOR_ALPHA 2 +#define PASS_POST_ACCUMULATED_LIGHT 3 +#define PASS_POST_ACCUMULATED_VALUE 4 +#define PASS_POST_DEPTH 5 +#define PASS_POST_AO 6 +#define PASS_POST_NORMAL 7 +#define PASS_POST_TWO_LIGHT_BUFFERS 8 uniform int postProcessType; uniform int currentSample; @@ -55,7 +56,7 @@ vec3 safe_divide_even_color(vec3 a, vec3 b) void main() { - vec3 color; + vec4 color = vec4(0.0, 0.0, 0.0, 1.0); ivec2 texel = ivec2(gl_FragCoord.xy); if (postProcessType == PASS_POST_DEPTH) { @@ -66,11 +67,11 @@ void main() else { depth = -get_view_z_from_depth(depth); } - color = vec3(depth); + color.rgb = vec3(depth); } else if (postProcessType == PASS_POST_AO) { float ao_accum = texelFetch(inputBuffer, texel, 0).r; - color = vec3(min(1.0, ao_accum / currentSample)); + color.rgb = vec3(min(1.0, ao_accum / currentSample)); } else if (postProcessType == PASS_POST_NORMAL) { float depth = texelFetch(depthBuffer, texel, 0).r; @@ -80,35 +81,39 @@ void main() if (depth != 1.0 && any(notEqual(encoded_normal, vec2(0.0)))) { vec3 decoded_normal = normal_decode(texelFetch(inputBuffer, texel, 0).rg, vec3(0.0)); vec3 world_normal = mat3(ViewMatrixInverse) * decoded_normal; - color = world_normal; + color.rgb = world_normal; } else { - color = vec3(0.0); + color.rgb = vec3(0.0); } } else if (postProcessType == PASS_POST_ACCUMULATED_VALUE) { float accumulated_value = texelFetch(inputBuffer, texel, 0).r; - color = vec3(accumulated_value / currentSample); + color.rgb = vec3(accumulated_value / currentSample); } else if (postProcessType == PASS_POST_ACCUMULATED_COLOR) { vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb; + color.rgb = (accumulated_color / currentSample); + } + else if (postProcessType == PASS_POST_ACCUMULATED_COLOR_ALPHA) { + vec4 accumulated_color = texelFetch(inputBuffer, texel, 0); color = (accumulated_color / currentSample); } else if (postProcessType == PASS_POST_ACCUMULATED_LIGHT) { vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb; vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb; - color = safe_divide_even_color(accumulated_light, accumulated_color); + color.rgb = safe_divide_even_color(accumulated_light, accumulated_color); } else if (postProcessType == PASS_POST_TWO_LIGHT_BUFFERS) { vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb + texelFetch(inputSecondLightBuffer, texel, 0).rgb; vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb; - color = safe_divide_even_color(accumulated_light, accumulated_color); + color.rgb = safe_divide_even_color(accumulated_light, accumulated_color); } else { /* Output error color: Unknown how to post process this pass. */ - color = vec3(1.0, 0.0, 1.0); + color.rgb = vec3(1.0, 0.0, 1.0); } - fragColor = vec4(color, 1.0); + fragColor = color; } diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index d3a06f0fc2c..e1d03e6f3be 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -46,6 +46,8 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot); void SCENE_OT_view_layer_add(struct wmOperatorType *ot); void SCENE_OT_view_layer_remove(struct wmOperatorType *ot); +void SCENE_OT_view_layer_add_aov(struct wmOperatorType *ot); +void SCENE_OT_view_layer_remove_aov(struct wmOperatorType *ot); void SCENE_OT_light_cache_bake(struct wmOperatorType *ot); void SCENE_OT_light_cache_free(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c index 706249a3f8b..e0aa02b354d 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.c @@ -53,6 +53,8 @@ void ED_operatortypes_render(void) WM_operatortype_append(SCENE_OT_view_layer_add); WM_operatortype_append(SCENE_OT_view_layer_remove); + WM_operatortype_append(SCENE_OT_view_layer_add_aov); + WM_operatortype_append(SCENE_OT_view_layer_remove_aov); WM_operatortype_append(SCENE_OT_render_view_add); WM_operatortype_append(SCENE_OT_render_view_remove); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 60e5c2081fd..b69337b1621 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -90,6 +90,7 @@ #include "UI_interface.h" +#include "RE_engine.h" #include "RE_pipeline.h" #include "engines/eevee/eevee_lightcache.h" @@ -1013,6 +1014,93 @@ void SCENE_OT_view_layer_remove(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name View Layer Add AOV Operator + * \{ */ + +static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + BKE_view_layer_add_aov(view_layer); + + RenderEngineType *engine_type = RE_engines_find(scene->r.engine); + if (engine_type->update_render_passes) { + RenderEngine *engine = RE_engine_create(engine_type); + if (engine) { + BKE_view_layer_verify_aov(engine, scene, view_layer); + } + RE_engine_free(engine); + engine = NULL; + } + + DEG_id_tag_update(&scene->id, 0); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_view_layer_add_aov(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add AOV"; + ot->idname = "SCENE_OT_view_layer_add_aov"; + ot->description = "Add a Shader AOV"; + + /* api callbacks */ + ot->exec = view_layer_add_aov_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Layer Remove AOV Operator + * \{ */ + +static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + BKE_view_layer_remove_aov(view_layer, view_layer->active_aov); + + RenderEngineType *engine_type = RE_engines_find(scene->r.engine); + if (engine_type->update_render_passes) { + RenderEngine *engine = RE_engine_create(engine_type); + if (engine) { + BKE_view_layer_verify_aov(engine, scene, view_layer); + } + RE_engine_free(engine); + engine = NULL; + } + + DEG_id_tag_update(&scene->id, 0); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_view_layer_remove_aov(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove AOV"; + ot->idname = "SCENE_OT_view_layer_remove_aov"; + ot->description = "Remove Active AOV"; + + /* api callbacks */ + ot->exec = view_layer_remove_aov_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Light Cache Bake Operator * \{ */ diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 7e2fe753b7b..69a79e2f2ce 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -313,6 +313,7 @@ data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC) +data_to_c_simple(shaders/material/gpu_shader_material_output_aov.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC) diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 67cd1a61aed..312da491a36 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -173,6 +173,7 @@ GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat, const int index); void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); +void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash); void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 3ebe2edc89e..84da95f6fee 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -411,7 +411,7 @@ static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph) BLI_dynstr_append(ds, "\n"); } -static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *finaloutput) +static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph) { LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { BLI_dynstr_appendf(ds, " %s(", node->name); @@ -509,8 +509,11 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f BLI_dynstr_append(ds, ");\n"); } +} - BLI_dynstr_appendf(ds, "\n return tmp%d;\n", finaloutput->id); +static void codegen_final_output(DynStr *ds, GPUOutput *finaloutput) +{ + BLI_dynstr_appendf(ds, "return tmp%d;\n", finaloutput->id); } static char *code_generate_fragment(GPUMaterial *material, @@ -593,7 +596,35 @@ static char *code_generate_fragment(GPUMaterial *material, } codegen_declare_tmps(ds, graph); - codegen_call_functions(ds, graph, graph->outlink->output); + codegen_call_functions(ds, graph); + + BLI_dynstr_append(ds, " #ifndef VOLUMETRICS\n"); + BLI_dynstr_append(ds, " if (renderPassAOV) {\n"); + BLI_dynstr_append(ds, " switch (render_pass_aov_hash()) {\n"); + GSet *aovhashes_added = BLI_gset_int_new(__func__); + LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) { + void *aov_key = POINTER_FROM_INT(aovlink->hash); + if (BLI_gset_haskey(aovhashes_added, aov_key)) { + continue; + } + BLI_dynstr_appendf(ds, " case %d: {\n ", aovlink->hash); + codegen_final_output(ds, aovlink->outlink->output); + BLI_dynstr_append(ds, " }\n"); + BLI_gset_add(aovhashes_added, aov_key); + } + BLI_gset_free(aovhashes_added, NULL); + BLI_dynstr_append(ds, " default: {\n"); + BLI_dynstr_append(ds, " Closure no_aov = CLOSURE_DEFAULT;\n"); + BLI_dynstr_append(ds, " no_aov.holdout = 1.0;\n"); + BLI_dynstr_append(ds, " return no_aov;\n"); + BLI_dynstr_append(ds, " }\n"); + BLI_dynstr_append(ds, " }\n"); + BLI_dynstr_append(ds, " } else {\n"); + BLI_dynstr_append(ds, " #else /* VOLUMETRICS */\n"); + BLI_dynstr_append(ds, " {\n"); + BLI_dynstr_append(ds, " #endif /* VOLUMETRICS */\n "); + codegen_final_output(ds, graph->outlink->output); + BLI_dynstr_append(ds, " }\n"); BLI_dynstr_append(ds, "}\n"); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index a0fe77598f2..3f22424c7c9 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -597,6 +597,14 @@ void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) } } +void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash) +{ + GPUNodeGraphOutputLink *aov_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__); + aov_link->outlink = link; + aov_link->hash = hash; + BLI_addtail(&material->graph.outlink_aovs, aov_link); +} + GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material) { return &material->graph; diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c index e0165e1fa83..496988c4ba9 100644 --- a/source/blender/gpu/intern/gpu_material_library.c +++ b/source/blender/gpu/intern/gpu_material_library.c @@ -84,6 +84,7 @@ extern char datatoc_gpu_shader_material_noise_glsl[]; extern char datatoc_gpu_shader_material_normal_glsl[]; extern char datatoc_gpu_shader_material_normal_map_glsl[]; extern char datatoc_gpu_shader_material_object_info_glsl[]; +extern char datatoc_gpu_shader_material_output_aov_glsl[]; extern char datatoc_gpu_shader_material_output_material_glsl[]; extern char datatoc_gpu_shader_material_output_world_glsl[]; extern char datatoc_gpu_shader_material_particle_info_glsl[]; @@ -354,6 +355,11 @@ static GPUMaterialLibrary gpu_shader_material_object_info_library = { .dependencies = {NULL}, }; +static GPUMaterialLibrary gpu_shader_material_output_aov_library = { + .code = datatoc_gpu_shader_material_output_aov_glsl, + .dependencies = {NULL}, +}; + static GPUMaterialLibrary gpu_shader_material_output_material_library = { .code = datatoc_gpu_shader_material_output_material_glsl, .dependencies = {NULL}, @@ -619,6 +625,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = { &gpu_shader_material_normal_library, &gpu_shader_material_normal_map_library, &gpu_shader_material_object_info_library, + &gpu_shader_material_output_aov_library, &gpu_shader_material_output_material_library, &gpu_shader_material_output_world_library, &gpu_shader_material_particle_info_library, diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 2a2a51e32b3..08da49c3475 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -805,6 +805,7 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph) /* Free both node graph and requested attributes and textures. */ void gpu_node_graph_free(GPUNodeGraph *graph) { + BLI_freelistN(&graph->outlink_aovs); gpu_node_graph_free_nodes(graph); LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) { @@ -847,6 +848,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) } gpu_nodes_tag(graph->outlink); + LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) { + gpu_nodes_tag(aovlink->outlink); + } for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) { next = node->next; diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index a0e6298cd92..0ef95d94c0d 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -141,12 +141,20 @@ typedef struct GPUInput { }; } GPUInput; +typedef struct GPUNodeGraphOutputLink { + struct GPUNodeGraphOutputLink *next, *prev; + int hash; + GPUNodeLink *outlink; +} GPUNodeGraphOutputLink; + typedef struct GPUNodeGraph { /* Nodes */ ListBase nodes; - /* Output. */ + /* Main Output. */ GPUNodeLink *outlink; + /* List of GPUNodeGraphOutputLink */ + ListBase outlink_aovs; /* Requested attributes and textures. */ ListBase attributes; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl new file mode 100644 index 00000000000..648994739bf --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl @@ -0,0 +1,13 @@ + +void node_output_aov(vec4 color, float value, out Closure result) +{ + result = CLOSURE_DEFAULT; +#ifndef VOLUMETRICS + if (render_pass_aov_is_color()) { + result.radiance = color.rgb; + } + else { + result.radiance = vec3(value); + } +#endif +} diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 85065ba35d4..f2e3e0a3c9c 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -47,8 +47,20 @@ typedef enum eViewLayerEEVEEPassType { EEVEE_RENDER_PASS_SHADOW = (1 << 12), EEVEE_RENDER_PASS_AO = (1 << 13), EEVEE_RENDER_PASS_BLOOM = (1 << 14), + EEVEE_RENDER_PASS_AOV = (1 << 15), } eViewLayerEEVEEPassType; -#define EEVEE_RENDER_PASS_MAX_BIT 15 +#define EEVEE_RENDER_PASS_MAX_BIT 16 + +/* ViewLayerAOV.type */ +typedef enum eViewLayerAOVType { + AOV_TYPE_VALUE = 0, + AOV_TYPE_COLOR = 1, +} eViewLayerAOVType; + +/* ViewLayerAOV.type */ +typedef enum eViewLayerAOVFlag { + AOV_CONFLICT = (1 << 0), +} eViewLayerAOVFlag; typedef struct Base { struct Base *next, *prev; @@ -104,6 +116,17 @@ typedef struct ViewLayerEEVEE { int _pad[1]; } ViewLayerEEVEE; +/* AOV Renderpass definition. */ +typedef struct ViewLayerAOV { + struct ViewLayerAOV *next, *prev; + + /* Name of the AOV */ + char name[64]; + int flag; + /* Type of AOV (color/value) + * matches `eViewLayerAOVType` */ + int type; +} ViewLayerAOV; typedef struct ViewLayer { struct ViewLayer *next, *prev; /** MAX_NAME. */ @@ -136,6 +159,10 @@ typedef struct ViewLayer { struct FreestyleConfig freestyle_config; struct ViewLayerEEVEE eevee; + /* List containing the `ViewLayerAOV`s */ + ListBase aovs; + ViewLayerAOV *active_aov; + /* Runtime data */ /** ViewLayerEngineData. */ ListBase drawdata; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 9a233878840..b8e2256c3c6 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -192,6 +192,7 @@ typedef struct View3DShading { /* Render pass displayed in the viewport. Is an `eScenePassType` where one bit is set */ int render_pass; + char aov_name[64]; struct IDProperty *prop; void *_pad2; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f51202348b5..a581edcb04b 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -60,6 +60,7 @@ extern StructRNA RNA_AnimData; extern StructRNA RNA_AnimViz; extern StructRNA RNA_AnimVizMotionPaths; extern StructRNA RNA_AnyType; +extern StructRNA RNA_AOV; extern StructRNA RNA_Area; extern StructRNA RNA_AreaLight; extern StructRNA RNA_Armature; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 31e920a6799..1c6f83efd65 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -345,6 +345,10 @@ void rna_ViewLayer_material_override_update(struct Main *bmain, void rna_ViewLayer_pass_update(struct Main *bmain, struct Scene *activescene, struct PointerRNA *ptr); +void rna_ViewLayer_active_aov_index_range( + PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax); +int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr); +void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value); /* named internal so as not to conflict with obj.update() rna func */ void rna_Object_internal_update_data(struct Main *bmain, diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index c7a53757296..0dcbd8a070b 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -152,7 +152,18 @@ static void rna_ViewLayer_update_render_passes(ID *id) if (scene->nodetree) { ntreeCompositUpdateRLayers(scene->nodetree); } -} + + RenderEngineType *engine_type = RE_engines_find(scene->r.engine); + if (engine_type->update_render_passes) { + RenderEngine *engine = RE_engine_create(engine_type); + if (engine) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + BKE_view_layer_verify_aov(engine, scene, view_layer); + } + } + RE_engine_free(engine); + engine = NULL; + }} static PointerRNA rna_ViewLayer_objects_get(CollectionPropertyIterator *iter) { diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 235042122e6..0f13ba29d3b 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -529,6 +529,12 @@ const EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_view_layer_aov_type_items[] = { + {AOV_TYPE_COLOR, "COLOR", 0, "Color", ""}, + {AOV_TYPE_VALUE, "VALUE", 0, "Value", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #ifndef RNA_RUNTIME static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { /* interpolation */ @@ -1779,6 +1785,27 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr) ntreeCompositUpdateRLayers(scene->nodetree); } + ViewLayer *view_layer = NULL; + if (ptr->type == &RNA_ViewLayer) { + view_layer = (ViewLayer *)ptr->data; + } + else if (ptr->type == &RNA_AOV) { + ViewLayerAOV *aov = (ViewLayerAOV *)ptr->data; + view_layer = BKE_view_layer_find_with_aov(scene, aov); + } + + if (view_layer) { + RenderEngineType *engine_type = RE_engines_find(scene->r.engine); + if (engine_type->update_render_passes) { + RenderEngine *engine = RE_engine_create(engine_type); + if (engine) { + BKE_view_layer_verify_aov(engine, scene, view_layer); + } + RE_engine_free(engine); + engine = NULL; + } + } + rna_Scene_glsl_update(bmain, activescene, ptr); } @@ -2397,6 +2424,28 @@ static void rna_ViewLayer_remove( } } +void rna_ViewLayer_active_aov_index_range( + PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax)) +{ + ViewLayer *view_layer = (ViewLayer *)ptr->data; + + *min = 0; + *max = max_ii(0, BLI_listbase_count(&view_layer->aovs) - 1); +} + +int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr) +{ + ViewLayer *view_layer = (ViewLayer *)ptr->data; + return BLI_findindex(&view_layer->aovs, view_layer->active_aov); +} + +void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value) +{ + ViewLayer *view_layer = (ViewLayer *)ptr->data; + ViewLayerAOV *aov = BLI_findlink(&view_layer->aovs, value); + view_layer->active_aov = aov; +} + /* Fake value, used internally (not saved to DNA). */ # define V3D_ORIENT_DEFAULT -1 @@ -3963,6 +4012,33 @@ static void rna_def_view_layer_eevee(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); } +static void rna_def_view_layer_aov(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + srna = RNA_def_struct(brna, "AOV", NULL); + RNA_def_struct_sdna(srna, "ViewLayerAOV"); + RNA_def_struct_ui_text(srna, "Shader AOV", ""); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Name", "Name of the AOV"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + RNA_def_struct_name_property(srna, prop); + + prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", AOV_CONFLICT); + RNA_def_property_ui_text(prop, "Valid", "Is the name of the AOV conflicting"); + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rna_enum_view_layer_aov_type_items); + RNA_def_property_enum_default(prop, AOV_TYPE_COLOR); + RNA_def_property_ui_text(prop, "Type", "Data type of the AOV"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); +} + void rna_def_view_layer_common(StructRNA *srna, const bool scene) { PropertyRNA *prop; @@ -4013,6 +4089,24 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "ViewLayerEEVEE"); RNA_def_property_ui_text(prop, "EEVEE Settings", "View layer settings for EEVEE"); + + prop = RNA_def_property(srna, "aovs", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "aovs", NULL); + RNA_def_property_struct_type(prop, "AOV"); + RNA_def_property_ui_text(prop, "Shader AOV", ""); + + prop = RNA_def_property(srna, "active_aov", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "AOV"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Shader AOV", "Active AOV"); + + prop = RNA_def_property(srna, "active_aov_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, + "rna_ViewLayer_active_aov_index_get", + "rna_ViewLayer_active_aov_index_set", + "rna_ViewLayer_active_aov_index_range"); + RNA_def_property_ui_text(prop, "Active AOV Index", "Index of active aov"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); } /* layer options */ @@ -7848,6 +7942,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_view_layer_aov(brna); rna_def_view_layer_eevee(brna); rna_def_scene_gpencil(brna); RNA_define_animate_sdna(true); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 8ff4336ba83..eabb71c79d3 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -426,6 +426,9 @@ static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = {EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""}, {EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""}, + {0, "", ICON_NONE, "Shader AOV", ""}, + {EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""}, + {0, NULL, 0, NULL, NULL}, }; @@ -1065,6 +1068,19 @@ static Scene *rna_3DViewShading_scene(PointerRNA *ptr) } } +static ViewLayer *rna_3DViewShading_view_layer(PointerRNA *ptr) +{ + /* Get scene, depends if using 3D view or OpenGL render settings. */ + ID *id = ptr->owner_id; + if (GS(id->name) == ID_SCE) { + return NULL; + } + else { + bScreen *screen = (bScreen *)ptr->owner_id; + return WM_windows_view_layer_get_from_screen(G_MAIN->wm.first, screen); + } +} + static int rna_3DViewShading_type_get(PointerRNA *ptr) { /* Available shading types depend on render engine. */ @@ -1292,15 +1308,33 @@ static const EnumPropertyItem *rna_3DViewShading_render_pass_itemf(bContext *C, bool *r_free) { Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); const bool bloom_enabled = scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED; + const bool aov_available = BKE_view_layer_has_valid_aov(view_layer); int totitem = 0; EnumPropertyItem *result = NULL; + EnumPropertyItem aov_template; for (int i = 0; rna_enum_view3dshading_render_pass_type_items[i].identifier != NULL; i++) { const EnumPropertyItem *item = &rna_enum_view3dshading_render_pass_type_items[i]; - if (!((!bloom_enabled && - (item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))))) { + if (item->value == EEVEE_RENDER_PASS_AOV) { + aov_template.value = item->value; + aov_template.icon = 0; + aov_template.description = item->description; + LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { + if ((aov->flag & AOV_CONFLICT) != 0) { + continue; + } + aov_template.name = aov->name; + aov_template.identifier = aov->name; + RNA_enum_item_add(&result, &totitem, &aov_template); + aov_template.value++; + } + } + else if (!((!bloom_enabled && + (item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))) || + (!aov_available && STREQ(item->name, "Shader AOV")))) { RNA_enum_item_add(&result, &totitem, item); } } @@ -1314,14 +1348,58 @@ static int rna_3DViewShading_render_pass_get(PointerRNA *ptr) View3DShading *shading = (View3DShading *)ptr->data; eViewLayerEEVEEPassType result = shading->render_pass; Scene *scene = rna_3DViewShading_scene(ptr); + ViewLayer *view_layer = rna_3DViewShading_view_layer(ptr); if (result == EEVEE_RENDER_PASS_BLOOM && ((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) { - result = EEVEE_RENDER_PASS_COMBINED; + return EEVEE_RENDER_PASS_COMBINED; + } + else if (result == EEVEE_RENDER_PASS_AOV) { + if (!view_layer) { + return EEVEE_RENDER_PASS_COMBINED; + } + const int aov_index = BLI_findstringindex( + &view_layer->aovs, shading->aov_name, offsetof(ViewLayerAOV, name)); + if (aov_index == -1) { + return EEVEE_RENDER_PASS_COMBINED; + } + return result + aov_index; } return result; } +static void rna_3DViewShading_render_pass_set(PointerRNA *ptr, int value) +{ + View3DShading *shading = (View3DShading *)ptr->data; + Scene *scene = rna_3DViewShading_scene(ptr); + ViewLayer *view_layer = rna_3DViewShading_view_layer(ptr); + shading->aov_name[0] = 0; + + if ((value & EEVEE_RENDER_PASS_AOV) != 0) { + if (!view_layer) { + shading->render_pass = EEVEE_RENDER_PASS_COMBINED; + return; + } + const int aov_index = value & ~EEVEE_RENDER_PASS_AOV; + ViewLayerAOV *aov = BLI_findlink(&view_layer->aovs, aov_index); + if (!aov) { + /* AOV not found, cannot select AOV. */ + shading->render_pass = EEVEE_RENDER_PASS_COMBINED; + return; + } + + shading->render_pass = EEVEE_RENDER_PASS_AOV; + BLI_strncpy(shading->aov_name, aov->name, sizeof(aov->name)); + } + else if (value == EEVEE_RENDER_PASS_BLOOM && + ((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) { + shading->render_pass = EEVEE_RENDER_PASS_COMBINED; + } + else { + shading->render_pass = value; + } +} + static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr) { Main *bmain = CTX_data_main(C); @@ -3488,9 +3566,17 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "render_pass"); RNA_def_property_enum_items(prop, rna_enum_view3dshading_render_pass_type_items); RNA_def_property_ui_text(prop, "Render Pass", "Render Pass to show in the viewport"); - RNA_def_property_enum_funcs( - prop, "rna_3DViewShading_render_pass_get", NULL, "rna_3DViewShading_render_pass_itemf"); + RNA_def_property_enum_funcs(prop, + "rna_3DViewShading_render_pass_get", + "rna_3DViewShading_render_pass_set", + "rna_3DViewShading_render_pass_itemf"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL); + + prop = RNA_def_property(srna, "aov_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "aov_name"); + RNA_def_property_ui_text(prop, "Shader AOV Name", "Name of the active Shader AOV"); + RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); } static void rna_def_space_view3d_overlay(BlenderRNA *brna) diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index efd0e48f41a..a385cb7039f 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -903,6 +903,16 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, /* Duplicate bump height branches for manual derivatives. */ nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0); + LISTBASE_FOREACH (bNode *, node, &localtree->nodes) { + if (node->type == SH_NODE_OUTPUT_AOV) { + nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0); + nTreeTags tags = { + .ssr_id = 1.0, + .sss_id = 1.0, + }; + ntree_shader_tag_nodes(localtree, node, &tags); + } + } /* TODO(fclem): consider moving this to the gpu shader tree evaluation. */ nTreeTags tags = { @@ -913,6 +923,11 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, exec = ntreeShaderBeginExecTree(localtree); ntreeExecGPUNodes(exec, mat, output); + LISTBASE_FOREACH (bNode *, node, &localtree->nodes) { + if (node->type == SH_NODE_OUTPUT_AOV) { + ntreeExecGPUNodes(exec, mat, node); + } + } ntreeShaderEndExecTree(exec); /* EEVEE: Find which material domain was used (volume, surface ...). */ diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.c index 8e73a547bf7..403b3e6d9d6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.c @@ -19,6 +19,8 @@ #include "../node_shader_util.h" +#include "BLI_hash.h" + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_output_aov_in[] = { @@ -33,6 +35,22 @@ static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node) node->storage = aov; } +static int node_shader_gpu_output_aov(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + GPUNodeLink *outlink; + NodeShaderOutputAOV *aov = (NodeShaderOutputAOV *)node->storage; + /* Keep in sync with `renderpass_lib.glsl#render_pass_aov_hash`. */ + unsigned int hash = BLI_hash_string(aov->name) & ~1; + GPU_stack_link(mat, node, "node_output_aov", in, out, &outlink); + GPU_material_add_output_link_aov(mat, outlink, hash); + + return true; +} + /* node type definition */ void register_node_type_sh_output_aov(void) { @@ -43,6 +61,7 @@ void register_node_type_sh_output_aov(void) node_type_init(&ntype, node_shader_init_output_aov); node_type_storage( &ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage); + node_type_gpu(&ntype, node_shader_gpu_output_aov); /* Do not allow muting output node. */ node_type_internal_links(&ntype, NULL); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 47c5487a458..430130d4727 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -130,6 +130,9 @@ void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATT struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +struct ViewLayer *WM_windows_view_layer_get_from_screen(const struct wmWindowManager *wm, + const struct bScreen *screen) + ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 926e61f4a0e..74f352c0b62 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -656,6 +656,7 @@ void WM_exit_ex(bContext *C, const bool do_python) * pieces of Blender using sound may exit cleanly, see also T50676. */ BKE_sound_exit(); + BKE_appdir_exit(); CLG_exit(); BKE_blender_atexit(); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 589b8e2f156..14798653a31 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -2261,6 +2261,17 @@ Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen return NULL; } +ViewLayer *WM_windows_view_layer_get_from_screen(const wmWindowManager *wm, const bScreen *screen) +{ + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + if (WM_window_get_active_screen(win) == screen) { + return WM_window_get_active_view_layer(win); + } + } + + return NULL; +} + WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { diff --git a/source/tools b/source/tools index 7011d02c292..d7d7e9d41f7 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 7011d02c292ac1c91a5c9cc1a075ea2727982cee +Subproject commit d7d7e9d41f7499aa4639f96c843156ff834385ba -- cgit v1.2.3 From 76a0b322e4d3244e59a154c8255b84a4fbc33117 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 4 Dec 2020 08:28:43 +0100 Subject: EEVEE Cryptomatte MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cryptomatte is a standard to efficiently create mattes for compositing. The renderer outputs the required render passes, which can then be used in the compositor to create masks for specified objects. Unlike the Material and Object Index passes, the objects to isolate are selected in compositing, and mattes will be anti-aliased. Cryptomatte was already available in Cycles this patch adds it to the EEVEE render engine. Original specification can be found at https://raw.githubusercontent.com/Psyop/Cryptomatte/master/specification/IDmattes_poster.pdf **Accurate mode** Following Cycles, there are two accuracy modes. The difference between the two modes is the number of render samples they take into account to create the render passes. When accurate mode is off the number of levels is used. When accuracy mode is active, the number of render samples is used. **Deviation from standard** Cryptomatte specification is based on a path trace approach where samples and coverage are calculated at the same time. In EEVEE a sample is an exact match on top of a prepared depth buffer. Coverage is at that moment always 1. By sampling multiple times the number of surface hits decides the actual surface coverage for a matte per pixel. **Implementation Overview** When drawing to the cryptomatte GPU buffer the depth of the fragment is matched to the active depth buffer. The hashes of each cryptomatte layer is written in the GPU buffer. The exact layout depends on the active cryptomatte layers. The GPU buffer is downloaded and integrated into an accumulation buffer (stored in CPU RAM). The accumulation buffer stores the hashes + weights for a number of levels, layers per pixel. When a hash already exists the weight will be increased. When the hash doesn't exists it will be added to the buffer. After all the samples have been calculated the accumulation buffer is processed. During this phase the total pixel weights of each layer is mapped to be in a range between 0 and 1. The hashes are also sorted (highest weight first). Blender Kernel now has a `BKE_cryptomatte` header that access to common functions for cryptomatte. This will in the future be used by the API. * Alpha blended materials aren't supported. Alpha blended materials support in render passes needs research how to implement it in a maintainable way for any render pass. This is a list of tasks that needs to be done for the same release that this patch lands on (Blender 2.92) * T82571 Add render tests. * T82572 Documentation. * T82573 Store hashes + Object names in the render result header. * T82574 Use threading to increase performance in accumulation and post processing. * T82575 Merge the cycles and EEVEE settings as they are identical. * T82576 Add RNA to extract the cryptomatte hashes to use in python scripts. Reviewed By: Clément Foucault Maniphest Tasks: T81058 Differential Revision: https://developer.blender.org/D9165 --- .../scripts/startup/bl_ui/properties_view_layer.py | 26 + source/blender/blenkernel/BKE_cryptomatte.h | 42 ++ source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/cryptomatte.c | 87 +++ source/blender/blenkernel/intern/layer.c | 2 + source/blender/blenloader/intern/versioning_290.c | 10 + source/blender/draw/CMakeLists.txt | 2 + .../blender/draw/engines/eevee/eevee_cryptomatte.c | 654 +++++++++++++++++++++ source/blender/draw/engines/eevee/eevee_engine.c | 2 + source/blender/draw/engines/eevee/eevee_private.h | 38 ++ source/blender/draw/engines/eevee/eevee_render.c | 30 + .../draw/engines/eevee/eevee_renderpasses.c | 9 + source/blender/draw/engines/eevee/eevee_shaders.c | 32 + .../engines/eevee/shaders/cryptomatte_frag.glsl | 7 + source/blender/draw/tests/shaders_test.cc | 2 + source/blender/makesdna/DNA_layer_types.h | 20 +- source/blender/makesrna/intern/rna_scene.c | 40 ++ 17 files changed, 1001 insertions(+), 3 deletions(-) create mode 100644 source/blender/blenkernel/BKE_cryptomatte.h create mode 100644 source/blender/blenkernel/intern/cryptomatte.c create mode 100644 source/blender/draw/engines/eevee/eevee_cryptomatte.c create mode 100644 source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 35cd7ae5ab9..b7aacd0c8be 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -171,12 +171,38 @@ class VIEWLAYER_PT_layer_passes_aov(ViewLayerButtonsPanel, Panel): layout.label(text="Conflicts with another render pass with the same name", icon='ERROR') +class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerButtonsPanel, Panel): + bl_label = "Cryptomatte" + bl_parent_id = "VIEWLAYER_PT_layer_passes" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + + layout.use_property_split = True + layout.use_property_decorate = False + + view_layer = context.view_layer + + col = layout.column() + col.prop(view_layer, "use_pass_cryptomatte_object", text="Object") + col.prop(view_layer, "use_pass_cryptomatte_material", text="Material") + col.prop(view_layer, "use_pass_cryptomatte_asset", text="Asset") + col = layout.column() + col.active = any((view_layer.use_pass_cryptomatte_object, + view_layer.use_pass_cryptomatte_material, + view_layer.use_pass_cryptomatte_asset)) + col.prop(view_layer, "pass_cryptomatte_depth", text="Levels") + col.prop(view_layer, "use_pass_cryptomatte_accurate", text="Accurate Mode") + + classes = ( VIEWLAYER_PT_layer, VIEWLAYER_PT_layer_passes, VIEWLAYER_PT_eevee_layer_passes_data, VIEWLAYER_PT_eevee_layer_passes_light, VIEWLAYER_PT_eevee_layer_passes_effects, + VIEWLAYER_PT_layer_passes_cryptomatte, VIEWLAYER_PT_layer_passes_aov, VIEWLAYER_UL_aov, ) diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h new file mode 100644 index 00000000000..9ad4770c754 --- /dev/null +++ b/source/blender/blenkernel/BKE_cryptomatte.h @@ -0,0 +1,42 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#pragma once + +#include "BLI_sys_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Object; +struct Material; + +uint32_t BKE_cryptomatte_object_hash(const struct Object *object); +uint32_t BKE_cryptomatte_material_hash(const struct Material *material); +uint32_t BKE_cryptomatte_asset_hash(const struct Object *object); +float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index a328c600eac..c962f0a6a8c 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -101,6 +101,7 @@ set(SRC intern/constraint.c intern/context.c intern/crazyspace.c + intern/cryptomatte.c intern/curve.c intern/curve_bevel.c intern/curve_decimate.c diff --git a/source/blender/blenkernel/intern/cryptomatte.c b/source/blender/blenkernel/intern/cryptomatte.c new file mode 100644 index 00000000000..6570ffce920 --- /dev/null +++ b/source/blender/blenkernel/intern/cryptomatte.c @@ -0,0 +1,87 @@ +/* + * 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 bke + */ + +#include "BKE_cryptomatte.h" + +#include "DNA_material_types.h" +#include "DNA_object_types.h" + +#include "BLI_compiler_attrs.h" +#include "BLI_hash_mm3.h" +#include "BLI_string.h" +#include + +static uint32_t cryptomatte_hash(const ID *id) +{ + const char *name = &id->name[2]; + const int len = BLI_strnlen(name, MAX_NAME - 2); + uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, len, 0); + return cryptohash_int; +} + +uint32_t BKE_cryptomatte_object_hash(const Object *object) +{ + return cryptomatte_hash(&object->id); +} + +uint32_t BKE_cryptomatte_material_hash(const Material *material) +{ + if (material == NULL) { + return 0.0f; + } + return cryptomatte_hash(&material->id); +} + +uint32_t BKE_cryptomatte_asset_hash(const Object *object) +{ + const Object *asset_object = object; + while (asset_object->parent != NULL) { + asset_object = asset_object->parent; + } + return cryptomatte_hash(&asset_object->id); +} + +/* Convert a cryptomatte hash to a float. + * + * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the + * cryptomatte specification. See Floating point conversion section in + * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf. + * + * The conversion uses as many 32 bit floating point values as possible to minimize hash + * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic. + * + * Note that this conversion assumes to be running on a L-endian system. */ +float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) +{ + uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1); + uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1); + exponent = MAX2(exponent, (uint32_t)1); + exponent = MIN2(exponent, (uint32_t)254); + exponent = exponent << 23; + uint32_t sign = (cryptomatte_hash >> 31); + sign = sign << 31; + uint32_t float_bits = sign | exponent | mantissa; + float f; + memcpy(&f, &float_bits, sizeof(uint32_t)); + return f; +} diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 6b346d7a337..8a699e31f37 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -177,6 +177,8 @@ static ViewLayer *view_layer_add(const char *name) view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; view_layer->pass_alpha_threshold = 0.5f; + view_layer->cryptomatte_levels = 6; + view_layer->cryptomatte_flag = VIEW_LAYER_CRYPTOMATTE_ACCURATE; BKE_freestyle_config_init(&view_layer->freestyle_config); return view_layer; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index cebeef1fc46..99e113f5c36 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1230,5 +1230,15 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) LISTBASE_FOREACH (PointCloud *, pointcloud, &bmain->pointclouds) { do_versions_point_attribute_names(&pointcloud->pdata); } + + /* Cryptomatte render pass */ + if (!DNA_struct_elem_find(fd->filesdna, "ViewLayer", "short", "cryptomatte_levels")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + view_layer->cryptomatte_levels = 6; + view_layer->cryptomatte_flag = VIEW_LAYER_CRYPTOMATTE_ACCURATE; + } + } + } } } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 2de6ee1f57d..a6cc9fddd69 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -80,6 +80,7 @@ set(SRC engines/image/image_engine.c engines/image/image_shader.c engines/eevee/eevee_bloom.c + engines/eevee/eevee_cryptomatte.c engines/eevee/eevee_data.c engines/eevee/eevee_depth_of_field.c engines/eevee/eevee_effects.c @@ -250,6 +251,7 @@ data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/renderpass_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/cryptomatte_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/surface_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c new file mode 100644 index 00000000000..7bf7955eeb4 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -0,0 +1,654 @@ +/* + * 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 2020, Blender Foundation. + */ + +/** \file + * \ingroup EEVEE + * + * This file implements Cryptomatte for EEVEE. Cryptomatte is used to extract mattes using + * information already available at render time. See + * https://raw.githubusercontent.com/Psyop/Cryptomatte/master/specification/IDmattes_poster.pdf + * for reference to the cryptomatte specification. + * + * The challenge with cryptomatte in EEVEE is the merging and sorting of the samples. + * User can enable upto 3 cryptomatte layers (Object, Material and Asset). + * + * Process + * + * - Cryptomatte sample: Rendering of a cryptomatte sample is stored in a GPUBuffer. The buffer + * holds a single float per pixel per number of active cryptomatte layers. The float is the + * cryptomatte hash of each layer. After drawing the cryptomatte sample the intermediate result is + * downloaded to a CPU buffer (`cryptomatte_download_buffer`). + * + * Accurate mode + * + * There are two accuracy modes. The difference between the two is the number of render samples + * they take into account to create the render passes. When accurate mode is off the number of + * levels is used as the number of cryptomatte samples to take. When accuracy mode is on the number + * of render samples is used. + * + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BKE_cryptomatte.h" + +#include "GPU_batch.h" + +#include "RE_pipeline.h" + +#include "BLI_alloca.h" +#include "BLI_math_bits.h" +#include "BLI_rect.h" + +#include "DNA_hair_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_particle_types.h" + +#include "eevee_private.h" + +/* -------------------------------------------------------------------- */ +/** \name Data Management cryptomatte accum buffer + * \{ */ + +BLI_INLINE eViewLayerCryptomatteFlags eevee_cryptomatte_active_layers(const ViewLayer *view_layer) +{ + const eViewLayerCryptomatteFlags cryptomatte_layers = view_layer->cryptomatte_flag & + VIEW_LAYER_CRYPTOMATTE_ALL; + return cryptomatte_layers; +} + +/* The number of cryptomatte layers that are enabled */ +BLI_INLINE int eevee_cryptomatte_layers_count(const ViewLayer *view_layer) +{ + const eViewLayerCryptomatteFlags cryptomatte_layers = eevee_cryptomatte_active_layers( + view_layer); + return count_bits_i(cryptomatte_layers); +} + +/* The number of render result passes are needed to store a single cryptomatte layer. Per + * renderpass 2 cryptomatte samples can be stored. */ +BLI_INLINE int eevee_cryptomatte_passes_per_layer(const ViewLayer *view_layer) +{ + const int num_cryptomatte_levels = view_layer->cryptomatte_levels; + const int num_cryptomatte_passes = (num_cryptomatte_levels + 1) / 2; + return num_cryptomatte_passes; +} + +BLI_INLINE int eevee_cryptomatte_layer_stride(const ViewLayer *view_layer) +{ + return view_layer->cryptomatte_levels; +} + +BLI_INLINE int eevee_cryptomatte_layer_offset(const ViewLayer *view_layer, const int layer) +{ + return view_layer->cryptomatte_levels * layer; +} + +BLI_INLINE int eevee_cryptomatte_pixel_stride(const ViewLayer *view_layer) +{ + return eevee_cryptomatte_layer_stride(view_layer) * eevee_cryptomatte_layers_count(view_layer); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Init Renderpasses + * \{ */ + +void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + /* Cryptomatte is only rendered for final image renders */ + if (!DRW_state_is_image_render()) { + return; + } + if (eevee_cryptomatte_active_layers(view_layer) != 0) { + g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE; + g_data->cryptomatte_accurate_mode = (view_layer->cryptomatte_flag & + VIEW_LAYER_CRYPTOMATTE_ACCURATE) != 0; + } +} + +void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + int UNUSED(tot_samples)) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_PrivateData *g_data = vedata->stl->g_data; + + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + + const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer); + eGPUDataFormat format = (num_cryptomatte_layers == 1) ? + GPU_R32F : + (num_cryptomatte_layers == 2) ? GPU_RG32F : GPU_RGBA32F; + const float *viewport_size = DRW_viewport_size_get(); + const int buffer_size = viewport_size[0] * viewport_size[1]; + + if (g_data->cryptomatte_accum_buffer == NULL) { + g_data->cryptomatte_accum_buffer = MEM_calloc_arrayN( + sizeof(EEVEE_CryptomatteSample), + buffer_size * eevee_cryptomatte_pixel_stride(view_layer), + __func__); + /* Download buffer should store a float per active cryptomatte layer. */ + g_data->cryptomatte_download_buffer = MEM_malloc_arrayN( + sizeof(float), buffer_size * num_cryptomatte_layers, __func__); + } + + DRW_texture_ensure_fullscreen_2d(&txl->cryptomatte, format, 0); + GPU_framebuffer_ensure_config(&fbl->cryptomatte_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->cryptomatte), + }); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Populate Cache + * \{ */ + +void EEVEE_cryptomatte_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) { + DRW_PASS_CREATE(psl->cryptomatte_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + } +} + +static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedata, + EEVEE_ViewLayerData *UNUSED(sldata), + Object *ob, + Material *material, + bool is_hair) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + const eViewLayerCryptomatteFlags cryptomatte_layers = eevee_cryptomatte_active_layers( + view_layer); + float cryptohash[4] = {0.0f}; + + EEVEE_PassList *psl = vedata->psl; + int layer_offset = 0; + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) { + uint32_t cryptomatte_hash = BKE_cryptomatte_object_hash(ob); + float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash); + cryptohash[layer_offset] = cryptomatte_color_value; + layer_offset++; + } + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { + uint32_t cryptomatte_hash = BKE_cryptomatte_material_hash(material); + float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash); + cryptohash[layer_offset] = cryptomatte_color_value; + layer_offset++; + } + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) { + uint32_t cryptomatte_hash = BKE_cryptomatte_asset_hash(ob); + float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash); + cryptohash[layer_offset] = cryptomatte_color_value; + layer_offset++; + } + + DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_cryptomatte_sh_get(is_hair), + psl->cryptomatte_ps); + DRW_shgroup_uniform_vec4_copy(grp, "cryptohash", cryptohash); + + return grp; +} + +static void eevee_cryptomatte_hair_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob, + ParticleSystem *psys, + ModifierData *md, + Material *material) +{ + DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create( + vedata, sldata, ob, material, true); + DRW_shgroup_hair_create_sub(ob, psys, md, grp); +} + +void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob) +{ + BLI_assert(ob->type == OB_HAIR); + Hair *hair = ob->data; + Material *material = hair->mat ? hair->mat[HAIR_MATERIAL_NR - 1] : NULL; + eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, NULL, NULL, material); +} + +void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + + if (ob->type == OB_MESH) { + if (ob != draw_ctx->object_edit) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_ParticleSystem) { + continue; + } + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; + if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { + continue; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + if (draw_as != PART_DRAW_PATH) { + continue; + } + Mesh *mesh = ob->data; + Material *material = part->omat - 1 < mesh->totcol ? NULL : mesh->mat[part->omat - 1]; + eevee_cryptomatte_hair_cache_populate(vedata, sldata, ob, psys, md, material); + } + } + } +} + +void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + const eViewLayerCryptomatteFlags cryptomatte_layers = eevee_cryptomatte_active_layers( + view_layer); + + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { + const int materials_len = DRW_cache_object_material_count_get(ob); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); + struct GPUBatch **geoms = DRW_cache_object_surface_material_get( + ob, gpumat_array, materials_len); + if (geoms) { + for (int i = 0; i < materials_len; i++) { + struct GPUBatch *geom = geoms[i]; + if (geom == NULL) { + continue; + } + Material *material = BKE_object_material_get(ob, i + 1); + DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create( + vedata, sldata, ob, material, false); + DRW_shgroup_call(grp, geom, ob); + } + } + } + else { + GPUBatch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create( + vedata, sldata, ob, false, NULL); + DRW_shgroup_call(grp, geom, ob); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Accumulate Samples + * \{ */ + +/* Downloads cryptomatte sample buffer from the GPU and integrate the samples with the accumulated + * cryptomatte samples. */ +static void eevee_cryptomatte_download_buffer(EEVEE_Data *vedata, GPUFrameBuffer *framebuffer) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer); + const int num_levels = view_layer->cryptomatte_levels; + const float *viewport_size = DRW_viewport_size_get(); + const int buffer_size = viewport_size[0] * viewport_size[1]; + + EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer; + float *download_buffer = g_data->cryptomatte_download_buffer; + + BLI_assert(accum_buffer); + BLI_assert(download_buffer); + + GPU_framebuffer_read_color(framebuffer, + 0, + 0, + viewport_size[0], + viewport_size[1], + num_cryptomatte_layers, + 0, + GPU_DATA_FLOAT, + download_buffer); + + /* Integrate download buffer into the accum buffer. + * The download buffer contains upto 3 floats per pixel (one float per cryptomatte layer. + * + * NOTE: here we deviate from the cryptomatte standard. During integration the standard always + * sort the samples by its weight to make sure that samples with the lowest weight + * are discarded first. In our case the weight of each sample is always 1 as we don't have + * subsamples and apply the coverage during the post processing. When there is no room for new + * samples the new samples has a weight of 1 and will always be discarded. */ + int download_pixel_index = 0; + int accum_pixel_index = 0; + int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer); + for (int pixel_index = 0; pixel_index < buffer_size; pixel_index++) { + for (int layer = 0; layer < num_cryptomatte_layers; layer++) { + const int layer_offset = eevee_cryptomatte_layer_offset(view_layer, layer); + float download_hash = download_buffer[download_pixel_index++]; + for (int level = 0; level < num_levels; level++) { + EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level]; + if (sample->hash == download_hash) { + sample->weight += 1.0f; + break; + } + /* We test against weight as hash 0.0f is used for samples hitting the world background. */ + if (sample->weight == 0.0f) { + sample->hash = download_hash; + sample->weight = 1.0f; + break; + } + } + } + accum_pixel_index += accum_pixel_stride; + } +} + +void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + const int cryptomatte_levels = view_layer->cryptomatte_levels; + const int current_sample = effects->taa_current_sample; + + /* In accurate mode all render samples are evaluated. In inaccurate mode this is limited to the + * number of cryptomatte levels. This will reduce the overhead of downloading the GPU buffer and + * integrating it into the accum buffer. */ + if (g_data->cryptomatte_accurate_mode || current_sample < cryptomatte_levels) { + static float clear_color[4] = {0.0}; + GPU_framebuffer_bind(fbl->cryptomatte_fb); + GPU_framebuffer_clear_color(fbl->cryptomatte_fb, clear_color); + DRW_draw_pass(psl->cryptomatte_ps); + + eevee_cryptomatte_download_buffer(vedata, fbl->cryptomatte_fb); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update Render Passes + * \{ */ + +/* Register the render passes needed for cryptomatte + * normally this is done in `EEVEE_render_update_passes`, but it has been placed here to keep + * related code side-by-side for clarity. */ +void EEVEE_cryptomatte_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) +{ + char cryptomatte_pass_name[MAX_NAME]; + const short num_passes = eevee_cryptomatte_passes_per_layer(view_layer); + if ((view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) { + for (short pass = 0; pass < num_passes; pass++) { + BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, "CryptoObject%02d", pass); + RE_engine_register_pass( + engine, scene, view_layer, cryptomatte_pass_name, 4, "RGBA", SOCK_RGBA); + } + } + if ((view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { + for (short pass = 0; pass < num_passes; pass++) { + BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, "CryptoMaterial%02d", pass); + RE_engine_register_pass( + engine, scene, view_layer, cryptomatte_pass_name, 4, "RGBA", SOCK_RGBA); + } + } + if ((view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) { + for (short pass = 0; pass < num_passes; pass++) { + BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, "CryptoAsset%02d", pass); + RE_engine_register_pass( + engine, scene, view_layer, cryptomatte_pass_name, 4, "RGBA", SOCK_RGBA); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Construct Render Result + * \{ */ + +/* Compare function for cryptomatte samples. Samples with the highest weight will be at the + * beginning of the list. */ +static int eevee_cryptomatte_sample_cmp_reverse(const void *a_, const void *b_) +{ + const EEVEE_CryptomatteSample *a = a_; + const EEVEE_CryptomatteSample *b = b_; + if (a->weight < b->weight) { + return 1; + } + if (a->weight > b->weight) { + return -1; + } + + return 0; +} + +/* Post process the weights. The accumulated weights buffer adds one to each weight per sample. + * During post processing ensure that the total of weights per sample is between 0 and 1. */ +static void eevee_cryptomatte_postprocess_weights(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer); + const int num_levels = view_layer->cryptomatte_levels; + const float *viewport_size = DRW_viewport_size_get(); + const int buffer_size = viewport_size[0] * viewport_size[1]; + + EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer; + BLI_assert(accum_buffer); + int accum_pixel_index = 0; + int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer); + + for (int pixel_index = 0; pixel_index < buffer_size; + pixel_index++, accum_pixel_index += accum_pixel_stride) { + for (int layer = 0; layer < num_cryptomatte_layers; layer++) { + const int layer_offset = eevee_cryptomatte_layer_offset(view_layer, layer); + /* Calculate the total weight of the sample. */ + float total_weight = 0.0f; + for (int level = 0; level < num_levels; level++) { + EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level]; + total_weight += sample->weight; + } + BLI_assert(total_weight > 0.0f); + + float total_weight_inv = 1.0f / total_weight; + for (int level = 0; level < num_levels; level++) { + EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level]; + /* Remove background samples. These samples were used to determine the correct weight + * but won't be part of the final result. */ + if (sample->hash == 0.0f) { + sample->weight = 0.0f; + } + sample->weight *= total_weight_inv; + } + + /* Sort accum buffer by coverage of each sample. */ + qsort(&accum_buffer[accum_pixel_index + layer_offset], + num_levels, + sizeof(EEVEE_CryptomatteSample), + eevee_cryptomatte_sample_cmp_reverse); + } + } +} + +/* Extract cryptomatte layer from the cryptomatte_accum_buffer to render passes. */ +static void eevee_cryptomatte_extract_render_passes( + RenderLayer *rl, + const char *viewname, + const char *render_pass_name_format, + EEVEE_CryptomatteSample *accum_buffer, + /* number of render passes per cryptomatte layer. */ + const int num_cryptomatte_passes, + const int num_cryptomatte_levels, + const int accum_pixel_stride, + const int layer_stride, + const int layer_index, + const int rect_width, + const int rect_height, + const int rect_offset_x, + const int rect_offset_y, + const int viewport_width) +{ + char cryptomatte_pass_name[MAX_NAME]; + /* A pass can store 2 levels. Technically the last pass can have a single level if the number of + * levels is an odd number. This parameter counts the number of levels it has processed. */ + int levels_done = 0; + for (int pass = 0; pass < num_cryptomatte_passes; pass++) { + /* Each pass holds 2 cryptomatte samples. */ + const int pass_offset = pass * 2; + BLI_snprintf_rlen(cryptomatte_pass_name, MAX_NAME, render_pass_name_format, pass); + RenderPass *rp_object = RE_pass_find_by_name(rl, cryptomatte_pass_name, viewname); + for (int y = 0; y < rect_height; y++) { + for (int x = 0; x < rect_width; x++) { + const int accum_buffer_offset = (rect_offset_x + x + + (rect_offset_y + y) * viewport_width) * + accum_pixel_stride + + layer_index * layer_stride + pass_offset; + const int render_pass_offset = (y * rect_width + x) * 4; + rp_object->rect[render_pass_offset] = accum_buffer[accum_buffer_offset].hash; + rp_object->rect[render_pass_offset + 1] = accum_buffer[accum_buffer_offset].weight; + if (levels_done + 1 < num_cryptomatte_levels) { + rp_object->rect[render_pass_offset + 2] = accum_buffer[accum_buffer_offset + 1].hash; + rp_object->rect[render_pass_offset + 3] = accum_buffer[accum_buffer_offset + 1].weight; + } + else { + rp_object->rect[render_pass_offset + 2] = 0.0f; + rp_object->rect[render_pass_offset + 3] = 0.0f; + } + } + } + levels_done++; + } +} + +void EEVEE_cryptomatte_render_result(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *UNUSED(sldata)) +{ + EEVEE_PrivateData *g_data = vedata->stl->g_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ViewLayer *view_layer = draw_ctx->view_layer; + const eViewLayerCryptomatteFlags cryptomatte_layers = view_layer->cryptomatte_flag & + VIEW_LAYER_CRYPTOMATTE_ALL; + + eevee_cryptomatte_postprocess_weights(vedata); + + const int rect_width = BLI_rcti_size_x(rect); + const int rect_height = BLI_rcti_size_y(rect); + const int rect_offset_x = vedata->stl->g_data->overscan_pixels + rect->xmin; + const int rect_offset_y = vedata->stl->g_data->overscan_pixels + rect->ymin; + const float *viewport_size = DRW_viewport_size_get(); + const int viewport_width = viewport_size[0]; + EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer; + BLI_assert(accum_buffer); + const int num_cryptomatte_levels = view_layer->cryptomatte_levels; + const int num_cryptomatte_passes = eevee_cryptomatte_passes_per_layer(view_layer); + const int layer_stride = eevee_cryptomatte_layer_stride(view_layer); + const int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer); + + int layer_index = 0; + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) { + eevee_cryptomatte_extract_render_passes(rl, + viewname, + "CryptoObject%02d", + accum_buffer, + num_cryptomatte_passes, + num_cryptomatte_levels, + accum_pixel_stride, + layer_stride, + layer_index, + rect_width, + rect_height, + rect_offset_x, + rect_offset_y, + viewport_width); + layer_index++; + } + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { + eevee_cryptomatte_extract_render_passes(rl, + viewname, + "CryptoMaterial%02d", + accum_buffer, + num_cryptomatte_passes, + num_cryptomatte_levels, + accum_pixel_stride, + layer_stride, + layer_index, + rect_width, + rect_height, + rect_offset_x, + rect_offset_y, + viewport_width); + layer_index++; + } + if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) { + eevee_cryptomatte_extract_render_passes(rl, + viewname, + "CryptoAsset%02d", + accum_buffer, + num_cryptomatte_passes, + num_cryptomatte_levels, + accum_pixel_stride, + layer_stride, + layer_index, + rect_width, + rect_height, + rect_offset_x, + rect_offset_y, + viewport_width); + layer_index++; + } +} + +/** \} */ + +void EEVEE_cryptomatte_free(EEVEE_Data *vedata) +{ + EEVEE_PrivateData *g_data = vedata->stl->g_data; + MEM_SAFE_FREE(g_data->cryptomatte_accum_buffer); + MEM_SAFE_FREE(g_data->cryptomatte_download_buffer); +} \ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 7d1f40ba5d8..f233b0fda96 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -570,6 +570,8 @@ static void eevee_render_to_image(void *vedata, EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur); if (RE_engine_test_break(engine)) { + /* Cryptomatte buffers are freed during render_read_result */ + EEVEE_cryptomatte_free(vedata); return; } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 1385721a569..a6a480ca967 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -167,6 +167,8 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) EEVEE_RENDER_PASS_ENVIRONMENT | EEVEE_RENDER_PASS_AOV) #define EEVEE_AOV_HASH_ALL -1 #define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1 +#define MAX_CRYPTOMATTE_LAYERS 3 + /* Material shader variations */ enum { VAR_MAT_MESH = (1 << 0), @@ -295,6 +297,7 @@ typedef struct EEVEE_PassList { /* Renderpass Accumulation. */ struct DRWPass *material_accum_ps; struct DRWPass *background_accum_ps; + struct DRWPass *cryptomatte_ps; struct DRWPass *depth_ps; struct DRWPass *depth_cull_ps; @@ -327,6 +330,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP]; struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1]; struct GPUFrameBuffer *bloom_pass_accum_fb; + struct GPUFrameBuffer *cryptomatte_fb; struct GPUFrameBuffer *shadow_accum_fb; struct GPUFrameBuffer *ssr_accum_fb; struct GPUFrameBuffer *sss_blur_fb; @@ -383,6 +387,7 @@ typedef struct EEVEE_TextureList { struct GPUTexture *bloom_accum; struct GPUTexture *ssr_accum; struct GPUTexture *shadow_accum; + struct GPUTexture *cryptomatte; struct GPUTexture *refract_color; struct GPUTexture *taa_history; @@ -910,6 +915,11 @@ typedef struct EEVEE_WorldEngineData { DrawData dd; } EEVEE_WorldEngineData; +typedef struct EEVEE_CryptomatteSample { + float hash; + float weight; +} EEVEE_CryptomatteSample; + /* *********************************** */ typedef struct EEVEE_Data { @@ -967,6 +977,9 @@ typedef struct EEVEE_PrivateData { eViewLayerEEVEEPassType render_passes; int aov_hash; int num_aovs_used; + bool cryptomatte_accurate_mode; + EEVEE_CryptomatteSample *cryptomatte_accum_buffer; + float *cryptomatte_download_buffer; /* Uniform references that are referenced inside the `renderpass_pass`. They are updated * to reuse the drawing pass and the shading group. */ @@ -1120,6 +1133,7 @@ struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_layer_sh_get(void); struct GPUShader *EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(void); struct GPUShader *EEVEE_shaders_effect_screen_raytrace_sh_get(EEVEE_SSRShaderOptions options); struct GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void); +struct GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair); struct GPUShader *EEVEE_shaders_shadow_sh_get(void); struct GPUShader *EEVEE_shaders_shadow_accum_sh_get(void); struct GPUShader *EEVEE_shaders_subsurface_first_pass_sh_get(void); @@ -1224,6 +1238,30 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata); void EEVEE_bloom_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +/* eevee_cryptomatte.c */ +void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata); +void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + int tot_samples); +void EEVEE_cryptomatte_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob); +void EEVEE_cryptomatte_particle_hair_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob); +void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob); +void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_cryptomatte_update_passes(struct RenderEngine *engine, + struct Scene *scene, + struct ViewLayer *view_layer); +void EEVEE_cryptomatte_render_result(struct RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata); +void EEVEE_cryptomatte_free(EEVEE_Data *vedata); + /* eevee_occlusion.c */ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 32e6eac2402..2b2ff2e5c90 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -191,6 +191,7 @@ void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_subsurface_cache_init(sldata, vedata); EEVEE_temporal_sampling_cache_init(sldata, vedata); EEVEE_volumes_cache_init(sldata, vedata); + EEVEE_cryptomatte_cache_init(sldata, vedata); } /* Used by light cache. in this case engine is NULL. */ @@ -200,9 +201,15 @@ void EEVEE_render_cache(void *vedata, struct Depsgraph *depsgraph) { EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_Data *data = vedata; + EEVEE_StorageList *stl = data->stl; + EEVEE_PrivateData *g_data = stl->g_data; EEVEE_LightProbesInfo *pinfo = sldata->probes; bool cast_shadow = false; + const bool do_cryptomatte = (engine != NULL) && + ((g_data->render_passes & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0); + eevee_id_update(vedata, &ob->id); if (pinfo->vis_data.collection) { @@ -227,14 +234,23 @@ void EEVEE_render_cache(void *vedata, const int ob_visibility = DRW_object_visibility_in_active_context(ob); if (ob_visibility & OB_VISIBLE_PARTICLES) { EEVEE_particle_hair_cache_populate(vedata, sldata, ob, &cast_shadow); + if (do_cryptomatte) { + EEVEE_cryptomatte_particle_hair_cache_populate(data, sldata, ob); + } } if (ob_visibility & OB_VISIBLE_SELF) { if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); + if (do_cryptomatte) { + EEVEE_cryptomatte_cache_populate(data, sldata, ob); + } } else if (ob->type == OB_HAIR) { EEVEE_object_hair_cache_populate(vedata, sldata, ob, &cast_shadow); + if (do_cryptomatte) { + EEVEE_cryptomatte_object_hair_cache_populate(data, sldata, ob); + } } else if (ob->type == OB_VOLUME) { Scene *scene = DEG_get_evaluated_scene(depsgraph); @@ -493,6 +509,18 @@ static void eevee_render_result_aovs(RenderLayer *rl, #undef EEVEE_RENDER_RESULT_MATERIAL_PASS +static void eevee_render_result_cryptomatte(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) +{ + if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) { + EEVEE_cryptomatte_render_result(rl, viewname, rect, vedata, sldata); + } + EEVEE_cryptomatte_free(vedata); +} + static void eevee_render_draw_background(EEVEE_Data *vedata) { EEVEE_FramebufferList *fbl = vedata->fbl; @@ -671,6 +699,7 @@ void EEVEE_render_read_result(EEVEE_Data *vedata, eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata); eevee_render_result_aovs(rl, viewname, rect, vedata, sldata); + eevee_render_result_cryptomatte(rl, viewname, rect, vedata, sldata); } void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) @@ -720,6 +749,7 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v break; } } + EEVEE_cryptomatte_update_passes(engine, scene, view_layer); #undef CHECK_PASS_LEGACY #undef CHECK_PASS_EEVEE diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 3f75f10b204..e7a03c678a8 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -144,6 +144,7 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata) EEVEE_RENDER_PASS_COMBINED; } EEVEE_material_renderpasses_init(vedata); + EEVEE_cryptomatte_renderpasses_init(vedata); } void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, @@ -203,6 +204,11 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, DRW_TEXTURE_FREE_SAFE(txl->renderpass); GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); } + + /* Cryptomatte doesn't use the GPU shader for post processing */ + if ((g_data->render_passes & (EEVEE_RENDER_PASS_CRYPTOMATTE)) != 0) { + EEVEE_cryptomatte_output_init(sldata, vedata, tot_samples); + } } void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -385,6 +391,9 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, (EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_VOLUME_SCATTER)) != 0) { EEVEE_volumes_output_accumulate(sldata, vedata); } + if ((render_pass & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) { + EEVEE_cryptomatte_output_accumulate(sldata, vedata); + } } else { if ((render_pass & EEVEE_RENDER_PASS_BLOOM) != 0 && diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index f46a98ed845..7a277c18f01 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -121,6 +121,7 @@ static struct { /* Render Passes */ struct GPUShader *postprocess_sh; + struct GPUShader *cryptomatte_sh[2]; /* Screen Space Reflection */ struct GPUShader *ssr_sh[SSR_MAX_SHADER]; @@ -186,6 +187,7 @@ extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_closure_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_utiltex_lib_glsl[]; +extern char datatoc_cryptomatte_frag_glsl[]; extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_default_frag_glsl[]; extern char datatoc_lookdev_world_frag_glsl[]; @@ -694,6 +696,34 @@ GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Cryptomatte + * \{ */ + +GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair) +{ + const int index = is_hair ? 1 : 0; + if (e_data.cryptomatte_sh[index] == NULL) { + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, SHADER_DEFINES); + + if (is_hair) { + BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); + } + else { + BLI_dynstr_append(ds, "#define MESH_SHADER\n"); + } + char *defines = BLI_dynstr_get_cstring(ds); + e_data.cryptomatte_sh[index] = DRW_shader_create_with_shaderlib( + datatoc_surface_vert_glsl, NULL, datatoc_cryptomatte_frag_glsl, e_data.lib, defines); + BLI_dynstr_free(ds); + MEM_freeN(defines); + } + return e_data.cryptomatte_sh[index]; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Screen Raytrace * \{ */ @@ -1428,6 +1458,8 @@ void EEVEE_shaders_free(void) DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh); + DRW_SHADER_FREE_SAFE(e_data.cryptomatte_sh[0]); + DRW_SHADER_FREE_SAFE(e_data.cryptomatte_sh[1]); for (int i = 0; i < 2; i++) { DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]); DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]); diff --git a/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl b/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl new file mode 100644 index 00000000000..1e499dbf991 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl @@ -0,0 +1,7 @@ +uniform vec4 cryptohash; +out vec4 fragColor; + +void main() +{ + fragColor = cryptohash; +} \ No newline at end of file diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index 39d8e45cc19..6674e3eccc1 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -332,6 +332,8 @@ TEST_F(DrawTest, eevee_glsl_shaders_static) EXPECT_NE(EEVEE_shaders_probe_grid_fill_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_probe_planar_downsample_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_renderpasses_post_process_sh_get(), nullptr); + EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(index, false), nullptr); + EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(index, true), nullptr); EXPECT_NE(EEVEE_shaders_shadow_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_shadow_accum_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_subsurface_first_pass_sh_get(), nullptr); diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index f2e3e0a3c9c..0da7c6b5937 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -48,20 +48,30 @@ typedef enum eViewLayerEEVEEPassType { EEVEE_RENDER_PASS_AO = (1 << 13), EEVEE_RENDER_PASS_BLOOM = (1 << 14), EEVEE_RENDER_PASS_AOV = (1 << 15), + EEVEE_RENDER_PASS_CRYPTOMATTE = (1 << 16), } eViewLayerEEVEEPassType; -#define EEVEE_RENDER_PASS_MAX_BIT 16 +#define EEVEE_RENDER_PASS_MAX_BIT 17 -/* ViewLayerAOV.type */ +/* #ViewLayerAOV.type */ typedef enum eViewLayerAOVType { AOV_TYPE_VALUE = 0, AOV_TYPE_COLOR = 1, } eViewLayerAOVType; -/* ViewLayerAOV.type */ +/* #ViewLayerAOV.flag */ typedef enum eViewLayerAOVFlag { AOV_CONFLICT = (1 << 0), } eViewLayerAOVFlag; +/* #ViewLayer.cryptomatte_flag */ +typedef enum eViewLayerCryptomatteFlags { + VIEW_LAYER_CRYPTOMATTE_OBJECT = (1<<0), + VIEW_LAYER_CRYPTOMATTE_MATERIAL = (1<<1), + VIEW_LAYER_CRYPTOMATTE_ASSET = (1<<2), + VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1<<3), +} eViewLayerCryptomatteFlags; +#define VIEW_LAYER_CRYPTOMATTE_ALL (VIEW_LAYER_CRYPTOMATTE_OBJECT | VIEW_LAYER_CRYPTOMATTE_MATERIAL | VIEW_LAYER_CRYPTOMATTE_ASSET) + typedef struct Base { struct Base *next, *prev; @@ -150,6 +160,10 @@ typedef struct ViewLayer { /** Pass_xor has to be after passflag. */ int passflag; float pass_alpha_threshold; + short cryptomatte_flag; + short cryptomatte_levels; + char _pad1[4]; + int samples; struct Material *mat_override; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 0f13ba29d3b..08b3d4f210e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4107,6 +4107,46 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) "rna_ViewLayer_active_aov_index_range"); RNA_def_property_ui_text(prop, "Active AOV Index", "Index of active aov"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + + prop = RNA_def_property(srna, "use_pass_cryptomatte_object", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cryptomatte_flag", VIEW_LAYER_CRYPTOMATTE_OBJECT); + RNA_def_property_ui_text( + prop, + "Cryptomatte Object", + "Render cryptomatte object pass, for isolating objects in compositing"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "use_pass_cryptomatte_material", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cryptomatte_flag", VIEW_LAYER_CRYPTOMATTE_MATERIAL); + RNA_def_property_ui_text( + prop, + "Cryptomatte Material", + "Render cryptomatte material pass, for isolating materials in compositing"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "use_pass_cryptomatte_asset", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cryptomatte_flag", VIEW_LAYER_CRYPTOMATTE_ASSET); + RNA_def_property_ui_text( + prop, + "Cryptomatte Asset", + "Render cryptomatte asset pass, for isolating groups of objects with the same parent"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "pass_cryptomatte_depth", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "cryptomatte_levels"); + RNA_def_property_int_default(prop, 6); + RNA_def_property_range(prop, 2.0, 16.0); + RNA_def_property_ui_text( + prop, "Cryptomatte Levels", "Sets how many unique objects can be distinguished per pixel"); + RNA_def_property_ui_range(prop, 2.0, 16.0, 2.0, 0.0); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + + prop = RNA_def_property(srna, "use_pass_cryptomatte_accurate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cryptomatte_flag", VIEW_LAYER_CRYPTOMATTE_ACCURATE); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text( + prop, "Cryptomatte Accurate", "Generate a more accurate cryptomatte pass"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); } /* layer options */ -- cgit v1.2.3 From 6ed6741ee35930bf81fad9a5eb6bb17eea168725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 10:13:55 +0100 Subject: Point users to new location of "Show Group Colors" option In ad85256e7108 the "Show Group Colors" option was changed from a per-editor option to a user preference. Since so many people wanted to turn this option off, this makes sense. However, this move caused some confusion because the option was just gone from the menu. This commit adds a dummy menu item. It's disabled, and the tooltip explains that the option can now be found in Preferences. T83390 was created to track the removal of these hints. Reviewed by: Severin Differential Revision: https://developer.blender.org/D9735 --- release/scripts/startup/bl_operators/anim.py | 13 +++++++++++++ release/scripts/startup/bl_ui/space_dopesheet.py | 2 ++ release/scripts/startup/bl_ui/space_graph.py | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index ab79ebe3957..bb414b5ff89 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -429,9 +429,22 @@ class UpdateAnimatedTransformConstraint(Operator): return {'FINISHED'} +class ANIM_OT_show_group_colors_deprecated(Operator): + """This option moved to Preferences > Animation""" + + bl_idname = "anim.show_group_colors_deprecated" + bl_label = "Show Group Colors" + bl_options = {'REGISTER'} + + @classmethod + def poll(cls, context) -> bool: + return False + + classes = ( ANIM_OT_keying_set_export, NLA_OT_bake, ClearUselessActions, UpdateAnimatedTransformConstraint, + ANIM_OT_show_group_colors_deprecated, ) diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 676e93f4ce9..0c222e8c023 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -347,6 +347,8 @@ class DOPESHEET_MT_view(Menu): col.active = context.space_data.mode != 'SHAPEKEY' col.prop(st, "show_sliders") + if bpy.app.version < (2, 93): + layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT') layout.prop(st, "show_interpolation") layout.prop(st, "show_extremes") layout.prop(st, "use_auto_merge_keyframes") diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 0c37b58a583..6ece6a4c841 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -18,6 +18,7 @@ # +import bpy from bpy.types import Header, Menu, Panel from bl_ui.space_dopesheet import ( DopesheetFilterPopoverBase, @@ -119,6 +120,10 @@ class GRAPH_MT_view(Menu): layout.prop(st, "use_realtime_update") layout.prop(st, "show_cursor") layout.prop(st, "show_sliders") + + if bpy.app.version < (2, 93): + layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT') + layout.prop(st, "use_auto_merge_keyframes") if st.mode != 'DRIVERS': -- cgit v1.2.3 From f0df46287adf8553bac03bbaf8bbe67ad8652080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 10:50:06 +0100 Subject: Cleanup: replace NULL with nullptr in C++ code No functional changes. --- source/blender/blenkernel/intern/layer_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/layer_test.cc b/source/blender/blenkernel/intern/layer_test.cc index 84a96ed0895..e241c12d714 100644 --- a/source/blender/blenkernel/intern/layer_test.cc +++ b/source/blender/blenkernel/intern/layer_test.cc @@ -43,7 +43,7 @@ TEST(view_layer, aov_unique_names) IMB_init(); RE_engines_init(); - Scene scene = {{NULL}}; + Scene scene = {{nullptr}}; IDType_ID_SCE.init_data(&scene.id); ViewLayer *view_layer = static_cast(scene.view_layers.first); @@ -81,7 +81,7 @@ TEST(view_layer, aov_unique_names) /* Resolve by removing AOV resolution */ BKE_view_layer_remove_aov(view_layer, aov2); - aov2 = NULL; + aov2 = nullptr; BKE_view_layer_verify_aov(engine, &scene, view_layer); EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer)); EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0); @@ -136,7 +136,7 @@ TEST(view_layer, aov_conflict) IMB_init(); RE_engines_init(); - Scene scene = {{NULL}}; + Scene scene = {{nullptr}}; IDType_ID_SCE.init_data(&scene.id); ViewLayer *view_layer = static_cast(scene.view_layers.first); -- cgit v1.2.3 From 958df2ed1b6037b98eb73bb8e063732ba851854f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 11:28:09 +0100 Subject: Cleanup: Clang-Tidy, modernize-deprecated-headers No functional changes. --- .clang-tidy | 1 - source/blender/blenlib/intern/rand.cc | 8 ++++---- source/blender/blenlib/intern/task_pool.cc | 2 +- source/blender/blenlib/intern/task_range.cc | 2 +- source/blender/blenlib/intern/threads.cc | 6 +++--- source/blender/blenlib/tests/BLI_expr_pylike_eval_test.cc | 2 +- source/blender/blenlib/tests/BLI_heap_simple_test.cc | 2 +- source/blender/blenlib/tests/BLI_heap_test.cc | 2 +- source/blender/blenlib/tests/BLI_math_rotation_test.cc | 2 +- source/blender/blenlib/tests/BLI_stack_test.cc | 2 +- source/blender/blenlib/tests/BLI_task_test.cc | 2 +- source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp | 2 +- source/blender/compositor/intern/COM_CompositorContext.cpp | 2 +- source/blender/compositor/intern/COM_Converter.cpp | 2 +- source/blender/compositor/intern/COM_ExecutionGroup.cpp | 4 ++-- source/blender/compositor/intern/COM_Node.cpp | 2 +- source/blender/compositor/intern/COM_NodeOperation.cpp | 2 +- source/blender/compositor/intern/COM_WorkScheduler.cpp | 2 +- .../blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp | 2 +- .../compositor/operations/COM_FastGaussianBlurOperation.cpp | 2 +- .../compositor/operations/COM_OutputFileMultiViewOperation.cpp | 2 +- source/blender/compositor/operations/COM_OutputFileOperation.cpp | 2 +- source/blender/compositor/operations/COM_VectorBlurOperation.cpp | 2 +- source/blender/compositor/operations/COM_WrapOperation.cpp | 2 +- source/blender/compositor/operations/COM_WriteBufferOperation.cpp | 2 +- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 4 ++-- source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc | 4 ++-- .../depsgraph/intern/builder/deg_builder_nodes_view_layer.cc | 4 ++-- source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc | 4 ++-- source/blender/depsgraph/intern/builder/deg_builder_relations.cc | 4 ++-- .../blender/depsgraph/intern/builder/deg_builder_relations_rig.cc | 4 ++-- .../depsgraph/intern/builder/deg_builder_relations_view_layer.cc | 4 ++-- source/blender/depsgraph/intern/depsgraph_query.cc | 2 +- source/blender/depsgraph/intern/depsgraph_tag.cc | 2 +- .../depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc | 2 +- source/blender/depsgraph/intern/node/deg_node.cc | 2 +- source/blender/depsgraph/intern/node/deg_node_component.cc | 2 +- source/blender/depsgraph/intern/node/deg_node_id.cc | 2 +- source/blender/freestyle/intern/application/Controller.cpp | 2 +- .../freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp | 2 +- source/blender/freestyle/intern/geometry/FitCurve.cpp | 4 ++-- source/blender/freestyle/intern/geometry/GeomCleaner.cpp | 2 +- source/blender/freestyle/intern/geometry/Noise.cpp | 8 ++++---- source/blender/freestyle/intern/image/GaussianFilter.cpp | 2 +- source/blender/freestyle/intern/scene_graph/NodeCamera.cpp | 4 ++-- source/blender/freestyle/intern/stroke/Curve.cpp | 2 +- source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp | 2 +- source/blender/freestyle/intern/view_map/ViewMap.cpp | 2 +- source/blender/freestyle/intern/view_map/ViewMapIO.cpp | 2 +- source/blender/freestyle/intern/winged_edge/Curvature.cpp | 2 +- source/blender/gpu/intern/gpu_batch.cc | 2 +- source/blender/gpu/intern/gpu_select_sample_query.cc | 2 +- source/blender/gpu/intern/gpu_uniform_buffer.cc | 2 +- source/blender/gpu/intern/gpu_vertex_format.cc | 4 ++-- source/blender/gpu/opengl/gl_debug.cc | 2 +- source/blender/gpu/opengl/gl_drawlist.cc | 2 +- source/blender/ikplugin/intern/itasc_plugin.cpp | 4 ++-- source/blender/imbuf/intern/dds/DirectDrawSurface.cpp | 6 +++--- source/blender/imbuf/intern/dds/FlipDXT.cpp | 2 +- source/blender/imbuf/intern/dds/Image.cpp | 2 +- source/blender/imbuf/intern/dds/Stream.cpp | 4 ++-- source/blender/imbuf/intern/dds/dds_api.cpp | 4 ++-- source/blender/imbuf/intern/openexr/openexr_api.cpp | 8 ++++---- source/blender/io/alembic/exporter/abc_subdiv_disabler.cc | 2 +- source/blender/io/collada/AnimationImporter.cpp | 2 +- source/blender/io/collada/DocumentExporter.cpp | 8 ++++---- source/blender/io/collada/ErrorHandler.cpp | 2 +- source/blender/io/collada/ExtraHandler.cpp | 2 +- source/blender/io/collada/ExtraTags.cpp | 4 ++-- source/blender/io/collada/SkinInfo.cpp | 2 +- source/blender/io/common/intern/abstract_hierarchy_iterator.cc | 4 ++-- source/blender/io/common/intern/object_identifier.cc | 2 +- source/blender/nodes/geometry/node_geometry_tree.cc | 2 +- source/blender/nodes/intern/node_socket.cc | 2 +- 74 files changed, 105 insertions(+), 106 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 49b238d8708..0b6bc23c5bc 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -34,7 +34,6 @@ Checks: > modernize-*, -modernize-use-auto, -modernize-use-trailing-return-type, - -modernize-deprecated-headers, -modernize-avoid-c-arrays, -modernize-use-equals-default, -modernize-use-nodiscard, diff --git a/source/blender/blenlib/intern/rand.cc b/source/blender/blenlib/intern/rand.cc index c61e17e6627..8dbfffbad20 100644 --- a/source/blender/blenlib/intern/rand.cc +++ b/source/blender/blenlib/intern/rand.cc @@ -21,10 +21,10 @@ * \ingroup bli */ -#include -#include -#include -#include +#include +#include +#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc index 1a119e135d5..142496dce20 100644 --- a/source/blender/blenlib/intern/task_pool.cc +++ b/source/blender/blenlib/intern/task_pool.cc @@ -20,8 +20,8 @@ * Task pool to run tasks in parallel. */ +#include #include -#include #include #include "MEM_guardedalloc.h" diff --git a/source/blender/blenlib/intern/task_range.cc b/source/blender/blenlib/intern/task_range.cc index 229129bd088..c2498de1af8 100644 --- a/source/blender/blenlib/intern/task_range.cc +++ b/source/blender/blenlib/intern/task_range.cc @@ -20,7 +20,7 @@ * Task parallel range functions. */ -#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc index a2b1a12c783..0586c361350 100644 --- a/source/blender/blenlib/intern/threads.cc +++ b/source/blender/blenlib/intern/threads.cc @@ -21,9 +21,9 @@ * \ingroup bli */ -#include -#include -#include +#include +#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/blenlib/tests/BLI_expr_pylike_eval_test.cc b/source/blender/blenlib/tests/BLI_expr_pylike_eval_test.cc index 390f687dbd1..e9ca3c68a71 100644 --- a/source/blender/blenlib/tests/BLI_expr_pylike_eval_test.cc +++ b/source/blender/blenlib/tests/BLI_expr_pylike_eval_test.cc @@ -2,7 +2,7 @@ #include "testing/testing.h" -#include +#include #include "BLI_expr_pylike_eval.h" #include "BLI_math.h" diff --git a/source/blender/blenlib/tests/BLI_heap_simple_test.cc b/source/blender/blenlib/tests/BLI_heap_simple_test.cc index f3a65125eeb..97644fc26ab 100644 --- a/source/blender/blenlib/tests/BLI_heap_simple_test.cc +++ b/source/blender/blenlib/tests/BLI_heap_simple_test.cc @@ -1,7 +1,7 @@ /* Apache License, Version 2.0 */ #include "testing/testing.h" -#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/blenlib/tests/BLI_heap_test.cc b/source/blender/blenlib/tests/BLI_heap_test.cc index 8b207c17c84..b8fc62e46ca 100644 --- a/source/blender/blenlib/tests/BLI_heap_test.cc +++ b/source/blender/blenlib/tests/BLI_heap_test.cc @@ -1,7 +1,7 @@ /* Apache License, Version 2.0 */ #include "testing/testing.h" -#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc index 1b1c4ef24a1..02257ba83dd 100644 --- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc +++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc @@ -4,7 +4,7 @@ #include "BLI_math_rotation.h" -#include +#include /* Test that quaternion converts to itself via matrix. */ static void test_quat_to_mat_to_quat(float w, float x, float y, float z) diff --git a/source/blender/blenlib/tests/BLI_stack_test.cc b/source/blender/blenlib/tests/BLI_stack_test.cc index 211916e3193..1fef5998b99 100644 --- a/source/blender/blenlib/tests/BLI_stack_test.cc +++ b/source/blender/blenlib/tests/BLI_stack_test.cc @@ -1,7 +1,7 @@ /* Apache License, Version 2.0 */ #include "testing/testing.h" -#include +#include #include "BLI_array.h" #include "BLI_stack.h" diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc index 2a3fddf5e3d..fce3e56d105 100644 --- a/source/blender/blenlib/tests/BLI_task_test.cc +++ b/source/blender/blenlib/tests/BLI_task_test.cc @@ -1,7 +1,7 @@ /* Apache License, Version 2.0 */ #include "testing/testing.h" -#include +#include #include "atomic_ops.h" diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp index e95dd4233c4..b111fba44b7 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp @@ -17,7 +17,7 @@ */ #include "COM_ChunkOrderHotspot.h" -#include +#include ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition) { diff --git a/source/blender/compositor/intern/COM_CompositorContext.cpp b/source/blender/compositor/intern/COM_CompositorContext.cpp index 52e705ffb79..2e168221b7b 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.cpp +++ b/source/blender/compositor/intern/COM_CompositorContext.cpp @@ -18,7 +18,7 @@ #include "COM_CompositorContext.h" #include "COM_defines.h" -#include +#include CompositorContext::CompositorContext() { diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 9b3355f535a..d8f67571ee5 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include "DNA_node_types.h" diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 27cec28f5d5..b026d2e60d9 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -17,9 +17,9 @@ */ #include -#include +#include +#include #include -#include #include "atomic_ops.h" diff --git a/source/blender/compositor/intern/COM_Node.cpp b/source/blender/compositor/intern/COM_Node.cpp index 74aefaf0e6d..897d4e1df02 100644 --- a/source/blender/compositor/intern/COM_Node.cpp +++ b/source/blender/compositor/intern/COM_Node.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include "BKE_node.h" diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cpp index 0842721a9e5..1a30806f28c 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cpp +++ b/source/blender/compositor/intern/COM_NodeOperation.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include #include "COM_ExecutionSystem.h" diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index 450b64eec5a..f726caa3d66 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -16,8 +16,8 @@ * Copyright 2011, Blender Foundation. */ +#include #include -#include #include "COM_CPUDevice.h" #include "COM_OpenCLDevice.h" diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp index 7ef0d7b7606..fbbd373ba09 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include "BLI_math.h" #include "COM_DoubleEdgeMaskOperation.h" diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp index e87d40b4c86..157c595afcb 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include "BLI_utildefines.h" #include "COM_FastGaussianBlurOperation.h" diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp index f7fabfb9572..21d9177ddd5 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp @@ -19,7 +19,7 @@ #include "COM_OutputFileMultiViewOperation.h" #include "COM_OutputFileOperation.h" -#include +#include #include "BLI_listbase.h" #include "BLI_path_util.h" diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index c5623fdbd37..2676ab1b9ca 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -18,7 +18,7 @@ #include "COM_OutputFileOperation.h" -#include +#include #include "BLI_listbase.h" #include "BLI_path_util.h" diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp index 0776c97563e..d3f59ffcb15 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cpp index 7f7c1b7b639..37b7d68d495 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.cpp +++ b/source/blender/compositor/operations/COM_WrapOperation.cpp @@ -16,7 +16,7 @@ * Copyright 2011, Blender Foundation. */ -#include +#include #include "COM_WrapOperation.h" diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp index 574978e5a5f..9fb995bf463 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp @@ -19,7 +19,7 @@ #include "COM_WriteBufferOperation.h" #include "COM_OpenCLDevice.h" #include "COM_defines.h" -#include +#include WriteBufferOperation::WriteBufferOperation(DataType datatype) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 9cae343dcde..d71cdea1974 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -25,8 +25,8 @@ #include "intern/builder/deg_builder_nodes.h" -#include -#include +#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 3c55d832568..8ba4b4a427f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -25,8 +25,8 @@ #include "intern/builder/deg_builder_nodes.h" -#include -#include +#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 7a6dc6e2315..c7669b9fecb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -25,8 +25,8 @@ #include "intern/builder/deg_builder_nodes.h" -#include -#include +#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 4406cc83a0d..197e14c1a21 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -23,8 +23,8 @@ #include "intern/builder/deg_builder_pchanmap.h" -#include -#include +#include +#include #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index a55966632d8..3f6aa778b59 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -25,9 +25,9 @@ #include "intern/builder/deg_builder_relations.h" +#include +#include #include /* required for STREQ later on. */ -#include -#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 39a60c9029c..32c36d78250 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -25,9 +25,9 @@ #include "intern/builder/deg_builder_relations.h" +#include +#include #include /* required for STREQ later on. */ -#include -#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index b58d4a22712..8df8d4914c3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -25,9 +25,9 @@ #include "intern/builder/deg_builder_relations.h" +#include +#include #include /* required for STREQ later on. */ -#include -#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index d0eedd6d811..1a334d8a451 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -25,7 +25,7 @@ #include "MEM_guardedalloc.h" -#include /* XXX: memcpy */ +#include /* XXX: memcpy */ #include "BLI_listbase.h" #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index aec3dd4b9ea..95ee8234ef3 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -25,9 +25,9 @@ #include "intern/depsgraph_tag.h" +#include #include /* required for memset */ #include -#include #include "BLI_math_bits.h" #include "BLI_task.h" diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc index 8e9fff56023..8fe0dd95bc2 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.cc @@ -31,7 +31,7 @@ #include "BKE_volume.h" -#include +#include namespace blender::deg { diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 6266acae651..0d3563ee3de 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -23,7 +23,7 @@ #include "intern/node/deg_node.h" -#include +#include #include "BLI_utildefines.h" diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 6ffe5db3fec..d824fb14718 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -23,8 +23,8 @@ #include "intern/node/deg_node_component.h" +#include #include /* required for STREQ later on. */ -#include #include "BLI_ghash.h" #include "BLI_hash.hh" diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 345da466960..4f2fcab5823 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -23,8 +23,8 @@ #include "intern/node/deg_node_id.h" +#include #include /* required for STREQ later on. */ -#include #include "BLI_string.h" #include "BLI_utildefines.h" diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 63612694e65..e24700a57d8 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -22,7 +22,7 @@ extern "C" { #include } -#include +#include #include #include diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 8aaffd4dde8..f761b1f6243 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -64,7 +64,7 @@ #include "render_types.h" -#include +#include namespace Freestyle { diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp index 5682ccc9298..66914929960 100644 --- a/source/blender/freestyle/intern/geometry/FitCurve.cpp +++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp @@ -20,9 +20,9 @@ * \brief from "Graphics Gems", Academic Press, 1990 */ +#include +#include #include // for malloc and free -#include -#include #include "FitCurve.h" diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp index b1d0a6c7e2a..6a499c07061 100644 --- a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp +++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp @@ -29,9 +29,9 @@ # endif #endif +#include #include #include -#include #include "GeomCleaner.h" diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp index 7c42c332370..e3ea2ac154f 100644 --- a/source/blender/freestyle/intern/geometry/Noise.cpp +++ b/source/blender/freestyle/intern/geometry/Noise.cpp @@ -19,10 +19,10 @@ * \brief Class to define Perlin noise */ -#include -#include -#include -#include +#include +#include +#include +#include #include "BLI_compiler_attrs.h" #include "BLI_rand.h" diff --git a/source/blender/freestyle/intern/image/GaussianFilter.cpp b/source/blender/freestyle/intern/image/GaussianFilter.cpp index 3bbe86ee986..3c8bf5bd3a1 100644 --- a/source/blender/freestyle/intern/image/GaussianFilter.cpp +++ b/source/blender/freestyle/intern/image/GaussianFilter.cpp @@ -19,7 +19,7 @@ * \brief Class to perform gaussian filtering operations on an image */ -#include +#include #include "GaussianFilter.h" diff --git a/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp b/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp index 052ae73da43..4fc1f227172 100644 --- a/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp +++ b/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp @@ -19,8 +19,8 @@ * \brief Class to represent a light node */ -#include -#include // for memcpy +#include +#include // for memcpy #include "NodeCamera.h" diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp index c3dac81477d..768e9efa15d 100644 --- a/source/blender/freestyle/intern/stroke/Curve.cpp +++ b/source/blender/freestyle/intern/stroke/Curve.cpp @@ -19,7 +19,7 @@ * \brief Class to define a container for curves */ -#include /* printf */ +#include /* printf */ #include "Curve.h" #include "CurveAdvancedIterators.h" diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index 7e8937bfe80..9bf00ed7092 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -19,7 +19,7 @@ * \brief Detects/flags/builds extended features edges on the WXEdge structure */ -#include +#include #include "FEdgeXDetector.h" diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp index 60d0e45b9fb..d304c3616d7 100644 --- a/source/blender/freestyle/intern/view_map/ViewMap.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp @@ -19,7 +19,7 @@ * \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.) */ -#include +#include #include "ViewMap.h" #include "ViewMapAdvancedIterators.h" diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp index aed5d6b5adc..774751a2589 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp @@ -19,7 +19,7 @@ * \brief Functions to manage I/O for the view map */ -#include +#include #include "ViewMapIO.h" diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp index 1702a22c678..0ee491a071c 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp +++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp @@ -33,7 +33,7 @@ * \brief OGF/Graphite: Geometry and Graphics Programming Library + Utilities */ -#include +#include #include // for malloc and free #include #include diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 3bf1233c000..cdb158572b7 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -42,7 +42,7 @@ #include "gpu_batch_private.hh" -#include +#include using namespace blender::gpu; diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc index 6ca811895a5..74506232655 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.cc +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -24,7 +24,7 @@ * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. */ -#include +#include #include "GPU_debug.h" #include "GPU_framebuffer.h" diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc index 89c70c47e4a..3edb090d81c 100644 --- a/source/blender/gpu/intern/gpu_uniform_buffer.cc +++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc @@ -22,7 +22,7 @@ */ #include "MEM_guardedalloc.h" -#include +#include #include "BLI_blenlib.h" #include "BLI_math_base.h" diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index 3b0aa055588..cd6d78a185d 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -27,8 +27,8 @@ #include "gpu_shader_private.hh" #include "gpu_vertex_format_private.h" -#include -#include +#include +#include #include "BLI_ghash.h" #include "BLI_string.h" diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc index 4e45ff11fc7..0914c117241 100644 --- a/source/blender/gpu/opengl/gl_debug.cc +++ b/source/blender/gpu/opengl/gl_debug.cc @@ -42,7 +42,7 @@ #include "gl_debug.hh" -#include +#include static CLG_LogRef LOG = {"gpu.debug"}; diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc index aecadc4d14a..c374a7bdc9d 100644 --- a/source/blender/gpu/opengl/gl_drawlist.cc +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -39,7 +39,7 @@ #include "gl_drawlist.hh" #include "gl_primitive.hh" -#include +#include using namespace blender::gpu; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 61f2153cf6c..6846a09f57b 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -23,8 +23,8 @@ */ #include -#include -#include +#include +#include #include /* iTaSC headers */ diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp index 37e30d30e2c..2a36946df8f 100644 --- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp +++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp @@ -52,9 +52,9 @@ #include #include -#include /* sqrt */ -#include /* printf */ -#include /* malloc */ +#include /* sqrt */ +#include /* printf */ +#include /* malloc */ #include /*** declarations ***/ diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp index 9b07084bf81..e96b7891f1e 100644 --- a/source/blender/imbuf/intern/dds/FlipDXT.cpp +++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp @@ -36,7 +36,7 @@ #include "IMB_imbuf_types.h" -#include +#include #include #include diff --git a/source/blender/imbuf/intern/dds/Image.cpp b/source/blender/imbuf/intern/dds/Image.cpp index 7958a586c7d..9dfa5dd2621 100644 --- a/source/blender/imbuf/intern/dds/Image.cpp +++ b/source/blender/imbuf/intern/dds/Image.cpp @@ -30,7 +30,7 @@ #include #include -#include /* printf */ +#include /* printf */ Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(nullptr) { diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp index 59892a0a228..3dab3c35675 100644 --- a/source/blender/imbuf/intern/dds/Stream.cpp +++ b/source/blender/imbuf/intern/dds/Stream.cpp @@ -20,8 +20,8 @@ #include -#include /* printf */ -#include /* memcpy */ +#include /* printf */ +#include /* memcpy */ static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)"; static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)"; diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp index 804d8130b4c..e767cb14b1a 100644 --- a/source/blender/imbuf/intern/dds/dds_api.cpp +++ b/source/blender/imbuf/intern/dds/dds_api.cpp @@ -23,10 +23,10 @@ #include #include #include +#include +#include /* printf */ #include #include -#include -#include /* printf */ #if defined(WIN32) # include "utfconv.h" diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 56188fbe98a..28d73bff47d 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -22,14 +22,14 @@ */ #include -#include +#include +#include +#include +#include #include #include #include -#include #include -#include -#include #include #include diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc index 334a26df784..8073e157c13 100644 --- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc +++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc @@ -18,7 +18,7 @@ */ #include "abc_subdiv_disabler.h" -#include +#include #include "BLI_listbase.h" diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 2e7977d89bb..850b6a813ed 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -18,7 +18,7 @@ * \ingroup collada */ -#include +#include /* COLLADABU_ASSERT, may be able to remove later */ #include "COLLADABUPlatform.h" diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp index 241afbd4034..46dfdda4ede 100644 --- a/source/blender/io/collada/DocumentExporter.cpp +++ b/source/blender/io/collada/DocumentExporter.cpp @@ -19,9 +19,9 @@ */ #include /* std::find */ -#include -#include -#include +#include +#include +#include #include #include "COLLADASWAsset.h" @@ -121,7 +121,7 @@ extern "C" char build_hash[]; #include "MaterialExporter.h" #include "SceneExporter.h" -#include +#include char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n) { diff --git a/source/blender/io/collada/ErrorHandler.cpp b/source/blender/io/collada/ErrorHandler.cpp index 7467d519f28..844065e3ba3 100644 --- a/source/blender/io/collada/ErrorHandler.cpp +++ b/source/blender/io/collada/ErrorHandler.cpp @@ -26,7 +26,7 @@ #include "GeneratedSaxParserParserError.h" -#include +#include #include "BLI_utildefines.h" diff --git a/source/blender/io/collada/ExtraHandler.cpp b/source/blender/io/collada/ExtraHandler.cpp index 8aefb321dd6..11cb75fb5e9 100644 --- a/source/blender/io/collada/ExtraHandler.cpp +++ b/source/blender/io/collada/ExtraHandler.cpp @@ -19,7 +19,7 @@ */ #include "BLI_string.h" -#include +#include #include "ExtraHandler.h" diff --git a/source/blender/io/collada/ExtraTags.cpp b/source/blender/io/collada/ExtraTags.cpp index d8fbf96db51..8c63a21f88a 100644 --- a/source/blender/io/collada/ExtraTags.cpp +++ b/source/blender/io/collada/ExtraTags.cpp @@ -19,8 +19,8 @@ */ #include "BLI_string.h" -#include -#include +#include +#include #include diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp index 19a4a4f61c2..8f6f1e467d9 100644 --- a/source/blender/io/collada/SkinInfo.cpp +++ b/source/blender/io/collada/SkinInfo.cpp @@ -21,7 +21,7 @@ #include #if !defined(WIN32) -# include +# include #endif /* COLLADABU_ASSERT, may be able to remove later */ diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index fc47b024be1..eaa4d2fdde7 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -19,10 +19,10 @@ #include "IO_abstract_hierarchy_iterator.h" #include "dupli_parent_finder.hh" +#include +#include #include -#include #include -#include #include #include "BKE_anim_data.h" diff --git a/source/blender/io/common/intern/object_identifier.cc b/source/blender/io/common/intern/object_identifier.cc index a2d2d998bec..5d0b89b0630 100644 --- a/source/blender/io/common/intern/object_identifier.cc +++ b/source/blender/io/common/intern/object_identifier.cc @@ -21,7 +21,7 @@ #include "BKE_duplilist.h" extern "C" { -#include /* For INT_MAX. */ +#include /* For INT_MAX. */ } #include #include diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 69f9f7fb4ed..da77e8896fb 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -14,7 +14,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include #include "MEM_guardedalloc.h" diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index d4b1df2f3f0..ebc70956147 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -21,7 +21,7 @@ * \ingroup nodes */ -#include +#include #include "DNA_node_types.h" -- cgit v1.2.3 From 1166110a9d66af9c5a47cee2be591f50fdc445e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 11:28:56 +0100 Subject: Cleanup: clang-format Rerun `make format`. No functional changes. --- source/blender/blenkernel/intern/constraint.c | 8 ++++---- source/blender/draw/engines/image/image_private.h | 2 +- source/blender/editors/sculpt_paint/sculpt_face_set.c | 4 ++-- source/blender/editors/space_graph/graph_select.c | 1 - source/blender/makesdna/DNA_layer_types.h | 11 ++++++----- source/blender/makesdna/DNA_modifier_types.h | 2 +- source/blender/makesrna/intern/rna_layer.c | 3 ++- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 1a16f1d3c6e..28121206a90 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1627,7 +1627,7 @@ static bConstraintTypeInfo CTI_LOCLIMIT = { "Limit Location", /* name */ "bLocLimitConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ NULL, /* new data */ get_space_tar, /* get constraint targets */ @@ -1690,7 +1690,7 @@ static bConstraintTypeInfo CTI_ROTLIMIT = { "Limit Rotation", /* name */ "bRotLimitConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ NULL, /* new data */ get_space_tar, /* get constraint targets */ @@ -1757,7 +1757,7 @@ static bConstraintTypeInfo CTI_SIZELIMIT = { "Limit Scale", /* name */ "bSizeLimitConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ NULL, /* new data */ get_space_tar, /* get constraint targets */ @@ -2318,7 +2318,7 @@ static bConstraintTypeInfo CTI_SAMEVOL = { "Maintain Volume", /* name */ "bSameVolumeConstraint", /* struct name */ NULL, /* free data */ - custom_space_id_looper, /* id looper */ + custom_space_id_looper, /* id looper */ NULL, /* copy data */ samevolume_new_data, /* new data */ get_space_tar, /* get constraint targets */ diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/image/image_private.h index ad7ff78cb41..d5821cc5d70 100644 --- a/source/blender/draw/engines/image/image_private.h +++ b/source/blender/draw/engines/image/image_private.h @@ -43,7 +43,7 @@ typedef struct IMAGE_PrivateData { void *lock; struct ImBuf *ibuf; struct Image *image; - struct DRWView* view; + struct DRWView *view; struct GPUTexture *texture; bool owns_texture; diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 7c8a4c5a857..ad42750bb92 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -1307,8 +1307,8 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven SculptCursorGeometryInfo sgi; const float mouse[2] = {event->mval[0], event->mval[1]}; if (!SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) { - /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */ - return OPERATOR_CANCELLED; + /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */ + return OPERATOR_CANCELLED; } const int active_face_set = SCULPT_active_face_set_get(ss); diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 007f99e3ce5..12035ab6b61 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -501,7 +501,6 @@ void GRAPH_OT_select_all(wmOperatorType *ot) * The selection backend is also reused for the Lasso and Circle select operators. */ - static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view) { const View2D *v2d = &ac->region->v2d; diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 0da7c6b5937..6a91f4857b4 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -65,12 +65,13 @@ typedef enum eViewLayerAOVFlag { /* #ViewLayer.cryptomatte_flag */ typedef enum eViewLayerCryptomatteFlags { - VIEW_LAYER_CRYPTOMATTE_OBJECT = (1<<0), - VIEW_LAYER_CRYPTOMATTE_MATERIAL = (1<<1), - VIEW_LAYER_CRYPTOMATTE_ASSET = (1<<2), - VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1<<3), + VIEW_LAYER_CRYPTOMATTE_OBJECT = (1 << 0), + VIEW_LAYER_CRYPTOMATTE_MATERIAL = (1 << 1), + VIEW_LAYER_CRYPTOMATTE_ASSET = (1 << 2), + VIEW_LAYER_CRYPTOMATTE_ACCURATE = (1 << 3), } eViewLayerCryptomatteFlags; -#define VIEW_LAYER_CRYPTOMATTE_ALL (VIEW_LAYER_CRYPTOMATTE_OBJECT | VIEW_LAYER_CRYPTOMATTE_MATERIAL | VIEW_LAYER_CRYPTOMATTE_ASSET) +#define VIEW_LAYER_CRYPTOMATTE_ALL \ + (VIEW_LAYER_CRYPTOMATTE_OBJECT | VIEW_LAYER_CRYPTOMATTE_MATERIAL | VIEW_LAYER_CRYPTOMATTE_ASSET) typedef struct Base { struct Base *next, *prev; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index edb0a4439d6..af7d7e9310f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1588,7 +1588,7 @@ typedef struct WeightVGProximityModifierData { /** Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ char defgrp_name[64]; - + /* Mapping stuff. */ /** The custom mapping curve!. */ struct CurveMapping *cmap_curve; diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 0dcbd8a070b..abc4136bae8 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -163,7 +163,8 @@ static void rna_ViewLayer_update_render_passes(ID *id) } RE_engine_free(engine); engine = NULL; - }} + } +} static PointerRNA rna_ViewLayer_objects_get(CollectionPropertyIterator *iter) { -- cgit v1.2.3 From 168909d9741393e5a94e964d078a05f303f45c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 12:02:52 +0100 Subject: Cleanup: Clang-Tidy, modernize-use-override No functional changes. --- .../blender/blenkernel/intern/attribute_access.cc | 2 +- .../intern/builder/pipeline_all_objects.cc | 4 +-- .../depsgraph/intern/builder/pipeline_from_ids.cc | 8 +++--- .../freestyle/intern/view_map/ViewMapBuilder.cpp | 2 +- .../blender/imbuf/intern/openexr/openexr_api.cpp | 30 +++++++++++----------- source/blender/io/alembic/tests/abc_export_test.cc | 4 +-- .../intern/abstract_hierarchy_iterator_test.cc | 6 ++--- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 2345c834be4..9f5795291f0 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -325,7 +325,7 @@ class ConstantReadAttribute final : public ReadAttribute { type.copy_to_uninitialized(value, value_); } - ~ConstantReadAttribute() + ~ConstantReadAttribute() override { this->cpp_type_.destruct(value_); MEM_freeN(value_); diff --git a/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc b/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc index d02aa16f26b..dd71cc0504e 100644 --- a/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc +++ b/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc @@ -36,7 +36,7 @@ class AllObjectsNodeBuilder : public DepsgraphNodeBuilder { { } - virtual bool need_pull_base_into_graph(Base * /*base*/) override + bool need_pull_base_into_graph(Base * /*base*/) override { return true; } @@ -49,7 +49,7 @@ class AllObjectsRelationBuilder : public DepsgraphRelationBuilder { { } - virtual bool need_pull_base_into_graph(Base * /*base*/) override + bool need_pull_base_into_graph(Base * /*base*/) override { return true; } diff --git a/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc b/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc index 5fd4a0fc3dd..9e62432ea54 100644 --- a/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc +++ b/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc @@ -55,7 +55,7 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder { { } - virtual bool need_pull_base_into_graph(Base *base) override + bool need_pull_base_into_graph(Base *base) override { if (!filter_.contains(&base->object->id)) { return false; @@ -63,7 +63,7 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder { return DepsgraphNodeBuilder::need_pull_base_into_graph(base); } - virtual void build_object_proxy_group(Object *object, bool is_visible) override + void build_object_proxy_group(Object *object, bool is_visible) override { if (object->proxy_group == nullptr) { return; @@ -88,7 +88,7 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder { { } - virtual bool need_pull_base_into_graph(Base *base) override + bool need_pull_base_into_graph(Base *base) override { if (!filter_.contains(&base->object->id)) { return false; @@ -96,7 +96,7 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder { return DepsgraphRelationBuilder::need_pull_base_into_graph(base); } - virtual void build_object_proxy_group(Object *object) override + void build_object_proxy_group(Object *object) override { if (object->proxy_group == nullptr) { return; diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index de30ee0460a..54f4da7ca40 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -2326,7 +2326,7 @@ struct silhouette_binary_rule : public binary_rule { { } - virtual bool operator()(segment &s1, segment &s2) + bool operator()(segment &s1, segment &s2) override { FEdge *f1 = s1.edge(); FEdge *f2 = s2.edge(); diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 28d73bff47d..cb933062d37 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -120,11 +120,11 @@ class IMemStream : public Imf::IStream { _exrbuf = exrbuf; } - virtual ~IMemStream() + ~IMemStream() override { } - virtual bool read(char c[], int n) + bool read(char c[], int n) override { if (n + _exrpos <= _exrsize) { memcpy(c, (void *)(&_exrbuf[_exrpos]), n); @@ -135,17 +135,17 @@ class IMemStream : public Imf::IStream { return false; } - virtual Int64 tellg() + Int64 tellg() override { return _exrpos; } - virtual void seekg(Int64 pos) + void seekg(Int64 pos) override { _exrpos = pos; } - virtual void clear() + void clear() override { } @@ -175,7 +175,7 @@ class IFileStream : public Imf::IStream { } } - virtual bool read(char c[], int n) + bool read(char c[], int n) override { if (!ifs) { throw Iex::InputExc("Unexpected end of file."); @@ -186,18 +186,18 @@ class IFileStream : public Imf::IStream { return check_error(); } - virtual Int64 tellg() + Int64 tellg() override { return std::streamoff(ifs.tellg()); } - virtual void seekg(Int64 pos) + void seekg(Int64 pos) override { ifs.seekg(pos); check_error(); } - virtual void clear() + void clear() override { ifs.clear(); } @@ -227,7 +227,7 @@ class OMemStream : public OStream { { } - virtual void write(const char c[], int n) + void write(const char c[], int n) override { ensure_size(offset + n); memcpy(ibuf->encodedbuffer + offset, c, n); @@ -235,12 +235,12 @@ class OMemStream : public OStream { ibuf->encodedsize += n; } - virtual Int64 tellp() + Int64 tellp() override { return offset; } - virtual void seekp(Int64 pos) + void seekp(Int64 pos) override { offset = pos; ensure_size(offset); @@ -281,19 +281,19 @@ class OFileStream : public OStream { } } - virtual void write(const char c[], int n) + void write(const char c[], int n) override { errno = 0; ofs.write(c, n); check_error(); } - virtual Int64 tellp() + Int64 tellp() override { return std::streamoff(ofs.tellp()); } - virtual void seekp(Int64 pos) + void seekp(Int64 pos) override { ofs.seekp(pos); check_error(); diff --git a/source/blender/io/alembic/tests/abc_export_test.cc b/source/blender/io/alembic/tests/abc_export_test.cc index e1a9bd34f6b..e20fe2ff492 100644 --- a/source/blender/io/alembic/tests/abc_export_test.cc +++ b/source/blender/io/alembic/tests/abc_export_test.cc @@ -23,7 +23,7 @@ class AlembicExportTest : public testing::Test { Depsgraph *depsgraph; Main *bmain; - virtual void SetUp() + void SetUp() override { abc_archive = nullptr; @@ -41,7 +41,7 @@ class AlembicExportTest : public testing::Test { depsgraph = DEG_graph_new(bmain, &scene, view_layer, DAG_EVAL_RENDER); } - virtual void TearDown() + void TearDown() override { BKE_main_free(bmain); DEG_graph_free(depsgraph); diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc index ad0d6820e2b..8acdba416d3 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc @@ -73,7 +73,7 @@ class TestingHierarchyIterator : public AbstractHierarchyIterator { explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph) { } - virtual ~TestingHierarchyIterator() + ~TestingHierarchyIterator() override { release_writers(); } @@ -106,13 +106,13 @@ class AbstractHierarchyIteratorTest : public BlendfileLoadingBaseTest { protected: TestingHierarchyIterator *iterator; - virtual void SetUp() + void SetUp() override { BlendfileLoadingBaseTest::SetUp(); iterator = nullptr; } - virtual void TearDown() + void TearDown() override { iterator_free(); BlendfileLoadingBaseTest::TearDown(); -- cgit v1.2.3 From 10a8286a267d1796983f321dd01668d6072570ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 12:31:49 +0100 Subject: Cleanup: Clang-tidy, actually enable the modernize-use-override rule Forgot this in rB168909d9741. No functional changes. --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 0b6bc23c5bc..8e94b83c0db 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -43,7 +43,6 @@ Checks: > -modernize-use-default-member-init, -modernize-raw-string-literal, -modernize-avoid-bind, - -modernize-use-override, -modernize-use-transparent-functors, WarningsAsErrors: '*' -- cgit v1.2.3 From 7f2d356a672d838c90cf47e9ff4006b15c104148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 4 Dec 2020 12:46:43 +0100 Subject: Cleanup: Clang-Tidy, modernize-use-using Replace `typedef` with `using` in C++ code. In the case of `typedef struct SomeName { ... } SomeName;` I removed the `typedef` altogether, as this is unnecessary in C++. Such cases have been rewritten to `struct SomeName { ... };` No functional changes. --- .clang-tidy | 1 - source/blender/blenlib/intern/threads.cc | 4 ++-- source/blender/blenlib/tests/BLI_array_store_test.cc | 8 ++++---- .../compositor/intern/COM_NodeOperationBuilder.cpp | 2 +- .../compositor/operations/COM_VectorBlurOperation.cpp | 4 ++-- .../blender/depsgraph/intern/depsgraph_query_foreach.cc | 2 +- .../blender/freestyle/intern/view_map/ViewMapBuilder.cpp | 4 ++-- source/blender/gpu/intern/gpu_matrix.cc | 12 ++++++------ source/blender/gpu/intern/gpu_select_sample_query.cc | 4 ++-- source/blender/gpu/opengl/gl_drawlist.cc | 8 ++++---- source/blender/ikplugin/intern/itasc_plugin.cpp | 4 ++-- source/blender/imbuf/intern/openexr/openexr_api.cpp | 16 ++++++++-------- source/blender/simulation/intern/hair_volume.cpp | 4 ++-- 13 files changed, 36 insertions(+), 37 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 8e94b83c0db..d65027687bb 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -37,7 +37,6 @@ Checks: > -modernize-avoid-c-arrays, -modernize-use-equals-default, -modernize-use-nodiscard, - -modernize-use-using, -modernize-loop-convert, -modernize-pass-by-value, -modernize-use-default-member-init, diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc index 0586c361350..0b88cf53442 100644 --- a/source/blender/blenlib/intern/threads.cc +++ b/source/blender/blenlib/intern/threads.cc @@ -132,13 +132,13 @@ static int num_threads_override = 0; /* just a max for security reasons */ #define RE_MAX_THREAD BLENDER_MAX_THREADS -typedef struct ThreadSlot { +struct ThreadSlot { struct ThreadSlot *next, *prev; void *(*do_thread)(void *); void *callerdata; pthread_t pthread; int avail; -} ThreadSlot; +}; void BLI_threadapi_init(void) { diff --git a/source/blender/blenlib/tests/BLI_array_store_test.cc b/source/blender/blenlib/tests/BLI_array_store_test.cc index ff050ce24db..8bbd109fb81 100644 --- a/source/blender/blenlib/tests/BLI_array_store_test.cc +++ b/source/blender/blenlib/tests/BLI_array_store_test.cc @@ -32,11 +32,11 @@ static void print_mem_saved(const char *id, const BArrayStore *bs) /* -------------------------------------------------------------------- */ /* Test Chunks (building data from list of chunks) */ -typedef struct TestChunk { +struct TestChunk { struct TestChunk *next, *prev; const void *data; size_t data_len; -} TestChunk; +}; static TestChunk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len) { @@ -111,14 +111,14 @@ static char *testchunk_as_data_array(TestChunk **tc_array, int tc_array_len, siz /* Test Buffer */ /* API to handle local allocation of data so we can compare it with the data in the array_store */ -typedef struct TestBuffer { +struct TestBuffer { struct TestBuffer *next, *prev; const void *data; size_t data_len; /* for reference */ BArrayState *state; -} TestBuffer; +}; static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len) { diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 1237e728079..43928f6f915 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -597,7 +597,7 @@ void NodeOperationBuilder::add_complex_operation_buffers() } } -typedef std::set Tags; +using Tags = std::set; static void find_reachable_operations_recursive(Tags &reachable, NodeOperation *op) { diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp index d3f59ffcb15..6254f93472e 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp @@ -294,10 +294,10 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2]) /* ******************** VECBLUR ACCUM BUF ************************* */ -typedef struct DrawBufPixel { +struct DrawBufPixel { const float *colpoin; float alpha; -} DrawBufPixel; +}; static void zbuf_fill_in_rgba( ZSpan *zspan, DrawBufPixel *col, float *v1, float *v2, float *v3, float *v4) diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index ed7011ba306..1c050edc386 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -49,7 +49,7 @@ namespace { typedef deque TraversalQueue; -typedef void (*DEGForeachOperation)(OperationNode *op_node, void *user_data); +using DEGForeachOperation = void (*)(OperationNode *, void *); bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags) { diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 54f4da7ca40..cbb5c730b2b 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -2299,8 +2299,8 @@ struct less_SVertex2D { } }; -typedef Segment segment; -typedef Intersection intersection; +using segment = Segment; +using intersection = Intersection; struct less_Intersection { segment *edge; diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index dae56e39db6..4ccb28fedbd 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -39,15 +39,15 @@ using namespace blender::gpu; #define MATRIX_STACK_DEPTH 32 -typedef float Mat4[4][4]; -typedef float Mat3[3][3]; +using Mat4 = float[4][4]; +using Mat3 = float[3][3]; -typedef struct MatrixStack { +struct MatrixStack { Mat4 stack[MATRIX_STACK_DEPTH]; uint top; -} MatrixStack; +}; -typedef struct GPUMatrixState { +struct GPUMatrixState { MatrixStack model_view_stack; MatrixStack projection_stack; @@ -59,7 +59,7 @@ typedef struct GPUMatrixState { * TODO: separate Model from View transform? Batches/objects have model, * camera/eye has view & projection */ -} GPUMatrixState; +}; #define ModelViewStack Context::get()->matrix_state->model_view_stack #define ModelView ModelViewStack.stack[ModelViewStack.top] diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc index 74506232655..5d8689c0d6a 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.cc +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -47,7 +47,7 @@ using namespace blender; using namespace blender::gpu; -typedef struct GPUSelectQueryState { +struct GPUSelectQueryState { /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ bool query_issued; /* GPU queries abstraction. Contains an array of queries. */ @@ -68,7 +68,7 @@ typedef struct GPUSelectQueryState { int scissor[4]; eGPUWriteMask write_mask; eGPUDepthTest depth_test; -} GPUSelectQueryState; +}; static GPUSelectQueryState g_query_state = {false}; diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc index c374a7bdc9d..f0a18deafd3 100644 --- a/source/blender/gpu/opengl/gl_drawlist.cc +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -43,20 +43,20 @@ using namespace blender::gpu; -typedef struct GLDrawCommand { +struct GLDrawCommand { GLuint v_count; GLuint i_count; GLuint v_first; GLuint i_first; -} GLDrawCommand; +}; -typedef struct GLDrawCommandIndexed { +struct GLDrawCommandIndexed { GLuint v_count; GLuint i_count; GLuint v_first; GLuint base_index; GLuint i_first; -} GLDrawCommandIndexed; +}; #define MDI_ENABLED (buffer_size_ != 0) #define MDI_DISABLED (buffer_size_ == 0) diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 6846a09f57b..7047b6f3727 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -73,8 +73,8 @@ struct IK_Data { struct IK_Scene *first; }; -typedef float Vector3[3]; -typedef float Vector4[4]; +using Vector3 = float[3]; +using Vector4 = float[4]; struct IK_Target; typedef void (*ErrorCallback)(const iTaSC::ConstraintValues *values, unsigned int nvalues, diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index cb933062d37..087e001b0b3 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -620,7 +620,7 @@ bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags) static ListBase exrhandles = {nullptr, nullptr}; -typedef struct ExrHandle { +struct ExrHandle { struct ExrHandle *next, *prev; char name[FILE_MAX]; @@ -645,10 +645,10 @@ typedef struct ExrHandle { ListBase layers; /* hierarchical, pointing in end to ExrChannel */ int num_half_channels; /* used during filr save, allows faster temporary buffers allocation */ -} ExrHandle; +}; /* flattened out channel */ -typedef struct ExrChannel { +struct ExrChannel { struct ExrChannel *next, *prev; char name[EXR_TOT_MAXNAME + 1]; /* full name with everything */ @@ -658,10 +658,10 @@ typedef struct ExrChannel { char chan_id; /* quick lookup of channel char */ int view_id; /* quick lookup of channel view */ bool use_half_float; /* when saving use half float for file storage */ -} ExrChannel; +}; /* hierarchical; layers -> passes -> channels[] */ -typedef struct ExrPass { +struct ExrPass { struct ExrPass *next, *prev; char name[EXR_PASS_MAXNAME]; int totchan; @@ -672,13 +672,13 @@ typedef struct ExrPass { char internal_name[EXR_PASS_MAXNAME]; /* name with no view */ char view[EXR_VIEW_MAXNAME]; int view_id; -} ExrPass; +}; -typedef struct ExrLayer { +struct ExrLayer { struct ExrLayer *next, *prev; char name[EXR_LAY_MAXNAME + 1]; ListBase passes; -} ExrLayer; +}; /* ********************** */ diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp index 123b91edaac..1b65dd8f22c 100644 --- a/source/blender/simulation/intern/hair_volume.cpp +++ b/source/blender/simulation/intern/hair_volume.cpp @@ -76,12 +76,12 @@ typedef struct HairGridVert { float velocity_smooth[3]; } HairGridVert; -typedef struct HairGrid { +struct HairGrid { HairGridVert *verts; int res[3]; float gmin[3], gmax[3]; float cellsize, inv_cellsize; -} HairGrid; +}; #define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) \ (min_ii(max_ii((int)((vec[axis] - gmin[axis]) * scale), 0), res[axis] - 2)) -- cgit v1.2.3 From c10546f5e9fe2a300b6a21e1e16b22c93060d0e9 Mon Sep 17 00:00:00 2001 From: Patrick Mours Date: Thu, 3 Dec 2020 12:19:36 +0100 Subject: Cycles: Add support for shader raytracing in OptiX Support for the AO and bevel shader nodes requires calling "optixTrace" from within the shading VM, which is only allowed from inlined functions to the raygen program or callables. This patch therefore converts the shading VM to use direct callables to make it work. To prevent performance regressions a separate kernel module is compiled and used for this purpose. Reviewed By: brecht Differential Revision: https://developer.blender.org/D9733 --- intern/cycles/device/device_optix.cpp | 147 +++++++++++++++++++++---------- intern/cycles/kernel/CMakeLists.txt | 15 ++-- intern/cycles/kernel/kernel_subsurface.h | 29 ++++-- intern/cycles/kernel/kernel_types.h | 2 - intern/cycles/kernel/kernel_volume.h | 23 +++-- intern/cycles/kernel/svm/svm.h | 26 ++++-- 6 files changed, 168 insertions(+), 74 deletions(-) diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index 95234845f98..682540a51fd 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -141,7 +141,8 @@ class OptiXDevice : public CUDADevice { PG_BAKE, // kernel_bake_evaluate PG_DISP, // kernel_displace_evaluate PG_BACK, // kernel_background_evaluate - NUM_PROGRAM_GROUPS + PG_CALL, + NUM_PROGRAM_GROUPS = PG_CALL + 3 }; // List of OptiX pipelines @@ -334,11 +335,6 @@ class OptiXDevice : public CUDADevice { set_error("OptiX backend does not support baking yet"); return false; } - // Disable shader raytracing support for now, since continuation callables are slow - if (requested_features.use_shader_raytrace) { - set_error("OptiX backend does not support 'Ambient Occlusion' and 'Bevel' shader nodes yet"); - return false; - } const CUDAContextScope scope(cuContext); @@ -410,7 +406,9 @@ class OptiXDevice : public CUDADevice { } { // Load and compile PTX module with OptiX kernels - string ptx_data, ptx_filename = path_get("lib/kernel_optix.ptx"); + string ptx_data, ptx_filename = path_get(requested_features.use_shader_raytrace ? + "lib/kernel_optix_shader_raytrace.ptx" : + "lib/kernel_optix.ptx"); if (use_adaptive_compilation() || path_file_size(ptx_filename) == -1) { if (!getenv("OPTIX_ROOT_DIR")) { set_error( @@ -525,6 +523,21 @@ class OptiXDevice : public CUDADevice { group_descs[PG_BACK].raygen.entryFunctionName = "__raygen__kernel_optix_background"; } + // Shader raytracing replaces some functions with direct callables + if (requested_features.use_shader_raytrace) { + group_descs[PG_CALL + 0].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES; + group_descs[PG_CALL + 0].callables.moduleDC = optix_module; + group_descs[PG_CALL + 0].callables.entryFunctionNameDC = "__direct_callable__svm_eval_nodes"; + group_descs[PG_CALL + 1].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES; + group_descs[PG_CALL + 1].callables.moduleDC = optix_module; + group_descs[PG_CALL + 1].callables.entryFunctionNameDC = + "__direct_callable__kernel_volume_shadow"; + group_descs[PG_CALL + 2].kind = OPTIX_PROGRAM_GROUP_KIND_CALLABLES; + group_descs[PG_CALL + 2].callables.moduleDC = optix_module; + group_descs[PG_CALL + 2].callables.entryFunctionNameDC = + "__direct_callable__subsurface_scatter_multi_setup"; + } + check_result_optix_ret(optixProgramGroupCreate( context, group_descs, NUM_PROGRAM_GROUPS, &group_options, nullptr, 0, groups)); @@ -564,33 +577,51 @@ class OptiXDevice : public CUDADevice { # endif { // Create path tracing pipeline - OptixProgramGroup pipeline_groups[] = { - groups[PG_RGEN], - groups[PG_MISS], - groups[PG_HITD], - groups[PG_HITS], - groups[PG_HITL], + vector pipeline_groups; + pipeline_groups.reserve(NUM_PROGRAM_GROUPS); + pipeline_groups.push_back(groups[PG_RGEN]); + pipeline_groups.push_back(groups[PG_MISS]); + pipeline_groups.push_back(groups[PG_HITD]); + pipeline_groups.push_back(groups[PG_HITS]); + pipeline_groups.push_back(groups[PG_HITL]); # if OPTIX_ABI_VERSION >= 36 - groups[PG_HITD_MOTION], - groups[PG_HITS_MOTION], + if (motion_blur) { + pipeline_groups.push_back(groups[PG_HITD_MOTION]); + pipeline_groups.push_back(groups[PG_HITS_MOTION]); + } # endif - }; - check_result_optix_ret( - optixPipelineCreate(context, - &pipeline_options, - &link_options, - pipeline_groups, - (sizeof(pipeline_groups) / sizeof(pipeline_groups[0])), - nullptr, - 0, - &pipelines[PIP_PATH_TRACE])); + if (requested_features.use_shader_raytrace) { + pipeline_groups.push_back(groups[PG_CALL + 0]); + pipeline_groups.push_back(groups[PG_CALL + 1]); + pipeline_groups.push_back(groups[PG_CALL + 2]); + } + + check_result_optix_ret(optixPipelineCreate(context, + &pipeline_options, + &link_options, + pipeline_groups.data(), + pipeline_groups.size(), + nullptr, + 0, + &pipelines[PIP_PATH_TRACE])); // Combine ray generation and trace continuation stack size const unsigned int css = stack_size[PG_RGEN].cssRG + link_options.maxTraceDepth * trace_css; + // Max direct callable depth is one of the following, so combine accordingly + // - __raygen__ -> svm_eval_nodes + // - __raygen__ -> kernel_volume_shadow -> svm_eval_nodes + // - __raygen__ -> subsurface_scatter_multi_setup -> svm_eval_nodes + const unsigned int dss = stack_size[PG_CALL + 0].dssDC + + std::max(stack_size[PG_CALL + 1].dssDC, + stack_size[PG_CALL + 2].dssDC); // Set stack size depending on pipeline options check_result_optix_ret( - optixPipelineSetStackSize(pipelines[PIP_PATH_TRACE], 0, 0, css, (motion_blur ? 3 : 2))); + optixPipelineSetStackSize(pipelines[PIP_PATH_TRACE], + 0, + requested_features.use_shader_raytrace ? dss : 0, + css, + motion_blur ? 3 : 2)); } // Only need to create shader evaluation pipeline if one of these features is used: @@ -599,37 +630,51 @@ class OptiXDevice : public CUDADevice { requested_features.use_true_displacement; if (use_shader_eval_pipeline) { // Create shader evaluation pipeline - OptixProgramGroup pipeline_groups[] = { - groups[PG_BAKE], - groups[PG_DISP], - groups[PG_BACK], - groups[PG_MISS], - groups[PG_HITD], - groups[PG_HITS], - groups[PG_HITL], + vector pipeline_groups; + pipeline_groups.reserve(NUM_PROGRAM_GROUPS); + pipeline_groups.push_back(groups[PG_BAKE]); + pipeline_groups.push_back(groups[PG_DISP]); + pipeline_groups.push_back(groups[PG_BACK]); + pipeline_groups.push_back(groups[PG_MISS]); + pipeline_groups.push_back(groups[PG_HITD]); + pipeline_groups.push_back(groups[PG_HITS]); + pipeline_groups.push_back(groups[PG_HITL]); # if OPTIX_ABI_VERSION >= 36 - groups[PG_HITD_MOTION], - groups[PG_HITS_MOTION], + if (motion_blur) { + pipeline_groups.push_back(groups[PG_HITD_MOTION]); + pipeline_groups.push_back(groups[PG_HITS_MOTION]); + } # endif - }; - check_result_optix_ret( - optixPipelineCreate(context, - &pipeline_options, - &link_options, - pipeline_groups, - (sizeof(pipeline_groups) / sizeof(pipeline_groups[0])), - nullptr, - 0, - &pipelines[PIP_SHADER_EVAL])); + if (requested_features.use_shader_raytrace) { + pipeline_groups.push_back(groups[PG_CALL + 0]); + pipeline_groups.push_back(groups[PG_CALL + 1]); + pipeline_groups.push_back(groups[PG_CALL + 2]); + } + + check_result_optix_ret(optixPipelineCreate(context, + &pipeline_options, + &link_options, + pipeline_groups.data(), + pipeline_groups.size(), + nullptr, + 0, + &pipelines[PIP_SHADER_EVAL])); // Calculate continuation stack size based on the maximum of all ray generation stack sizes const unsigned int css = std::max(stack_size[PG_BAKE].cssRG, std::max(stack_size[PG_DISP].cssRG, stack_size[PG_BACK].cssRG)) + link_options.maxTraceDepth * trace_css; + const unsigned int dss = stack_size[PG_CALL + 0].dssDC + + std::max(stack_size[PG_CALL + 1].dssDC, + stack_size[PG_CALL + 2].dssDC); - check_result_optix_ret(optixPipelineSetStackSize( - pipelines[PIP_SHADER_EVAL], 0, 0, css, (pipeline_options.usesMotionBlur ? 3 : 2))); + check_result_optix_ret( + optixPipelineSetStackSize(pipelines[PIP_SHADER_EVAL], + 0, + requested_features.use_shader_raytrace ? dss : 0, + css, + motion_blur ? 3 : 2)); } // Clean up program group objects @@ -734,6 +779,9 @@ class OptiXDevice : public CUDADevice { # else sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITS, PG_HITL # endif + sbt_params.callablesRecordBase = sbt_data.device_pointer + PG_CALL * sizeof(SbtRecord); + sbt_params.callablesRecordCount = 3; + sbt_params.callablesRecordStrideInBytes = sizeof(SbtRecord); // Launch the ray generation program check_result_optix(optixLaunch(pipelines[PIP_PATH_TRACE], @@ -1061,6 +1109,9 @@ class OptiXDevice : public CUDADevice { # else sbt_params.hitgroupRecordCount = 3; // PG_HITD, PG_HITS, PG_HITL # endif + sbt_params.callablesRecordBase = sbt_data.device_pointer + PG_CALL * sizeof(SbtRecord); + sbt_params.callablesRecordCount = 3; + sbt_params.callablesRecordStrideInBytes = sizeof(SbtRecord); check_result_optix(optixLaunch(pipelines[PIP_SHADER_EVAL], cuda_stream[thread_index], diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index c39c67afb5a..f6b4b963a7a 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -423,7 +423,7 @@ if(WITH_CYCLES_CUDA_BINARIES) set(cuda_kernel_src "/kernels/cuda/${name}.cu") - set(cuda_flags + set(cuda_flags ${flags} -D CCL_NAMESPACE_BEGIN= -D CCL_NAMESPACE_END= -D NVCC @@ -545,11 +545,11 @@ endif() # OptiX PTX modules if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES) - foreach(input ${SRC_OPTIX_KERNELS}) - get_filename_component(input_we ${input} NAME_WE) + macro(CYCLES_OPTIX_KERNEL_ADD name flags) + set(input "kernels/optix/kernel_optix.cu") + set(output "${CMAKE_CURRENT_BINARY_DIR}/${name}.ptx") - set(output "${CMAKE_CURRENT_BINARY_DIR}/${input_we}.ptx") - set(cuda_flags + set(cuda_flags ${flags} -I "${OPTIX_INCLUDE_DIR}" -I "${CMAKE_CURRENT_SOURCE_DIR}/.." -I "${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda" @@ -625,7 +625,10 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES) list(APPEND optix_ptx ${output}) delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${output}" ${CYCLES_INSTALL_PATH}/lib) - endforeach() + endmacro() + + CYCLES_OPTIX_KERNEL_ADD(kernel_optix "-D __NO_SHADER_RAYTRACE__") + CYCLES_OPTIX_KERNEL_ADD(kernel_optix_shader_raytrace "--keep-device-functions") add_custom_target(cycles_kernel_optix ALL DEPENDS ${optix_ptx}) cycles_set_solution_folder(cycles_kernel_optix) diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index ed8572467ea..917f35d37dc 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -281,13 +281,28 @@ ccl_device_inline int subsurface_scatter_disk(KernelGlobals *kg, return num_eval_hits; } -ccl_device_noinline void subsurface_scatter_multi_setup(KernelGlobals *kg, - LocalIntersection *ss_isect, - int hit, - ShaderData *sd, - ccl_addr_space PathState *state, - ClosureType type, - float roughness) +#if defined(__KERNEL_OPTIX__) && defined(__SHADER_RAYTRACE__) +ccl_device_inline void subsurface_scatter_multi_setup(KernelGlobals *kg, + LocalIntersection *ss_isect, + int hit, + ShaderData *sd, + ccl_addr_space PathState *state, + ClosureType type, + float roughness) +{ + optixDirectCall(2, kg, ss_isect, hit, sd, state, type, roughness); +} +extern "C" __device__ void __direct_callable__subsurface_scatter_multi_setup( +#else +ccl_device_noinline void subsurface_scatter_multi_setup( +#endif + KernelGlobals *kg, + LocalIntersection *ss_isect, + int hit, + ShaderData *sd, + ccl_addr_space PathState *state, + ClosureType type, + float roughness) { #ifdef __SPLIT_KERNEL__ Ray ray_object = ss_isect->ray; diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 8e2b0e46a66..6beabebb92f 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -139,8 +139,6 @@ CCL_NAMESPACE_BEGIN #ifdef __KERNEL_OPTIX__ # undef __BAKING__ # undef __BRANCHED_PATH__ -/* TODO(pmours): Cannot use optixTrace in non-inlined functions */ -# undef __SHADER_RAYTRACE__ #endif /* __KERNEL_OPTIX__ */ #ifdef __KERNEL_OPENCL__ diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index f5d10c0ca8a..fdf712293e7 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -274,11 +274,24 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, /* get the volume attenuation over line segment defined by ray, with the * assumption that there are no surfaces blocking light between the endpoints */ -ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, - ShaderData *shadow_sd, - ccl_addr_space PathState *state, - Ray *ray, - float3 *throughput) +# if defined(__KERNEL_OPTIX__) && defined(__SHADER_RAYTRACE__) +ccl_device_inline void kernel_volume_shadow(KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + float3 *throughput) +{ + optixDirectCall(1, kg, shadow_sd, state, ray, throughput); +} +extern "C" __device__ void __direct_callable__kernel_volume_shadow( +# else +ccl_device_noinline void kernel_volume_shadow( +# endif + KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + float3 *throughput) { shader_setup_from_volume(kg, shadow_sd, ray); diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 6c849f5b2fc..000da1fa615 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -217,12 +217,26 @@ CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN /* Main Interpreter Loop */ -ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, - ShaderData *sd, - ccl_addr_space PathState *state, - ccl_global float *buffer, - ShaderType type, - int path_flag) +#if defined(__KERNEL_OPTIX__) && defined(__SHADER_RAYTRACE__) +ccl_device_inline void svm_eval_nodes(KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + ccl_global float *buffer, + ShaderType type, + int path_flag) +{ + optixDirectCall(0, kg, sd, state, buffer, type, path_flag); +} +extern "C" __device__ void __direct_callable__svm_eval_nodes( +#else +ccl_device_noinline void svm_eval_nodes( +#endif + KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + ccl_global float *buffer, + ShaderType type, + int path_flag) { float stack[SVM_STACK_SIZE]; int offset = sd->shader & SHADER_MASK; -- cgit v1.2.3 From 2de49d1ff7e2ea5e632aaaabb3664d6cf6210153 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 4 Dec 2020 10:35:26 -0300 Subject: Revert "Fix T83177: Industry Compatible keymap: MMB-dragging to transform engages axis-constraining on release" This reverts commit c0677b662f4b13429c0738b99ace85403385ff38. --- source/blender/editors/transform/transform.c | 59 ++++++++++++++++++---- source/blender/editors/transform/transform.h | 3 +- .../blender/editors/transform/transform_generics.c | 44 +--------------- source/blender/editors/transform/transform_ops.c | 4 +- source/blender/windowmanager/WM_api.h | 4 -- .../blender/windowmanager/intern/wm_event_system.c | 7 --- 6 files changed, 54 insertions(+), 67 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 356ad8643f8..bba0b750d0c 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -818,15 +818,9 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw |= handleSnapping(t, event); handled = true; } - else if (event->val == t->release_confirm_event_val && - event->type == t->release_confirm_event_type) { - /* Confirm transform if launch key is released after mouse move. */ - BLI_assert(t->flag & T_RELEASE_CONFIRM); - t->state = TRANS_CONFIRM; - } + /* handle modal keymap first */ + /* enforce redraw of transform when modifiers are used */ else if (event->type == EVT_MODAL_MAP) { - /* Handle modal keymap first. */ - /* Enforce redraw of transform when modifiers are used */ switch (event->val) { case TFM_MODAL_CANCEL: t->state = TRANS_CANCEL; @@ -1128,8 +1122,8 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } } + /* Else do non-mapped events. */ else if (event->val == KM_PRESS) { - /* Do non-mapped events. */ switch (event->type) { case EVT_CKEY: if (event->is_repeat) { @@ -1217,6 +1211,11 @@ int transformEvent(TransInfo *t, const wmEvent *event) } break; } + + /* confirm transform if launch key is released after mouse move */ + if ((t->flag & T_RELEASE_CONFIRM) && event->type == t->launch_event) { + t->state = TRANS_CONFIRM; + } } /* if we change snap options, get the unsnapped values back */ @@ -1688,6 +1687,17 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->mode = mode; + /* Needed to translate tweak events to mouse buttons. */ + t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1; + t->is_launch_event_tweak = event ? ISTWEAK(event->type) : false; + + /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate + * (which can have type = 0) */ + /* For gizmo only, so assume LEFTMOUSE. */ + if (t->launch_event == 0) { + t->launch_event = LEFTMOUSE; + } + unit_m3(t->spacemtx); initTransInfo(C, t, op, event); @@ -1761,6 +1771,37 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } + if (event) { + /* keymap for shortcut header prints */ + t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap); + + /* Stupid code to have Ctrl-Click on gizmo work ok. + * + * Do this only for translation/rotation/resize because only these + * modes are available from gizmo and doing such check could + * lead to keymap conflicts for other modes (see T31584) + */ + if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) { + wmKeyMapItem *kmi; + + for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) { + if (kmi->flag & KMI_INACTIVE) { + continue; + } + + if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) { + if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) || + (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) || + (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) || + ((kmi->type == EVT_OSKEY) && event->oskey)) { + t->modifiers |= MOD_SNAP_INVERT; + } + break; + } + } + } + } + initSnapping(t, op); /* Initialize snapping data AFTER mode flags */ initSnapSpatial(t, t->snap_spatial); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 485d5282a62..227330e8524 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -351,8 +351,7 @@ typedef struct TransInfo { /*************** NEW STUFF *********************/ /** event type used to launch transform. */ - short release_confirm_event_type; - short release_confirm_event_val; + short launch_event; /** Is the actual launch event a tweak event? (launch_event above is set to the corresponding * mouse button then.) */ bool is_launch_event_tweak; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 27346c9e974..5b41f6b51bf 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -593,60 +593,18 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0); } - if (event) { - t->release_confirm_event_type = WM_userdef_event_type_from_keymap_type(event->type); - t->is_launch_event_tweak = ISTWEAK(event->type); - - /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate - * (which can have type = 0) */ - /* For gizmo only, so assume LEFTMOUSE. */ - if (t->release_confirm_event_type == 0) { - t->release_confirm_event_type = LEFTMOUSE; - } - } - else { - /* Needed to translate tweak events to mouse buttons. */ - t->release_confirm_event_type = -1; - } - - t->release_confirm_event_val = -2; - if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop))) { if (RNA_property_boolean_get(op->ptr, prop)) { t->flag |= T_RELEASE_CONFIRM; - t->release_confirm_event_val = KM_RELEASE; } } else { /* Release confirms preference should not affect node editor (T69288, T70504). */ - if (ISMOUSE(t->release_confirm_event_type) && + if (ISMOUSE(t->launch_event) && ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) { /* Global "release confirm" on mouse bindings */ t->flag |= T_RELEASE_CONFIRM; - t->release_confirm_event_val = KM_RELEASE; - } - } - - if (op && event) { - /* Keymap for shortcut header prints. */ - t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap); - - /* Stupid code to have Relase confirm and Ctrl-Click on gizmo work ok. */ - wmKeyMapItem *kmi = WM_event_match_modal_keymap_item(t->keymap, op, event); - if (kmi) { - if ((t->flag & T_RELEASE_CONFIRM) && (event->val == KM_PRESS) && (kmi->val != KM_PRESS)) { - t->release_confirm_event_type = EVT_MODAL_MAP; - t->release_confirm_event_val = kmi->propvalue; - } - - if ((kmi->propvalue == TFM_MODAL_SNAP_INV_ON) && - ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) { - /* Do this only for translation/rotation/resize because only these - * modes are available from gizmo and doing such check could - * lead to keymap conflicts for other modes (see T31584) */ - t->modifiers |= MOD_SNAP_INVERT; - } } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7282c35ea0f..5153fdedcae 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -376,7 +376,7 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event) { int retval = 1; if (op->customdata == NULL) { - TransInfo *t = op->customdata = MEM_callocN(sizeof(TransInfo), "TransInfo data2"); + TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data2"); TransformModeItem *tmode; int mode = -1; @@ -396,10 +396,10 @@ static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event) /* store data */ if (retval) { G.moving = special_transform_moving(t); + op->customdata = t; } else { MEM_freeN(t); - op->customdata = NULL; } } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 430130d4727..da2115e12fb 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -47,7 +47,6 @@ struct ImBuf; struct ImageFormatData; struct Main; struct MenuType; -struct Operator; struct PointerRNA; struct PropertyRNA; struct ScrArea; @@ -259,9 +258,6 @@ void WM_event_set_keymap_handler_post_callback(struct wmEventHandler_Keymap *han wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, struct wmEventHandler_Keymap *handler); -wmKeyMapItem *WM_event_match_modal_keymap_item(const wmKeyMap *keymap, - struct wmOperator *op, - const struct wmEvent *event); wmKeyMapItem *WM_event_match_keymap_item(struct bContext *C, wmKeyMap *keymap, const struct wmEvent *event); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 587abf6fa0a..1bd8c675807 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1911,13 +1911,6 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, return NULL; } -wmKeyMapItem *WM_event_match_modal_keymap_item(const wmKeyMap *keymap, - wmOperator *op, - const wmEvent *event) -{ - return wm_eventmatch_modal_keymap_items(keymap, op, event); -} - /** * This function prepares events for use with #wmOperatorType.modal by: * -- cgit v1.2.3 From 6fda30cc54d24730d81b96b2e3b542bf94f52137 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 4 Dec 2020 10:49:45 -0300 Subject: Fix T83177: Industry Compatible keymap: MMB-dragging to transform engages axis-constraining on release With rBc0677b662f4b, we try to track all modal events in order to detect the one corresponding to the release. But modifier keys can mask the modal event and thus confirm realease ends up being skipped. This resulted in the T83387. With this commit we now read the actual key drop value in the modal event. This fixes T83387 --- source/blender/editors/transform/transform.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index bba0b750d0c..3b8f7f90edc 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1082,7 +1082,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_AUTOCONSTRAINT: case TFM_MODAL_AUTOCONSTRAINTPLANE: - if ((t->flag & T_NO_CONSTRAINT) == 0) { + if ((t->flag & T_RELEASE_CONFIRM) && (event->prevval == KM_RELEASE) && + event->prevtype == t->launch_event) { + /* Confirm transform if launch key is released after mouse move. */ + t->state = TRANS_CONFIRM; + } + else if ((t->flag & T_NO_CONSTRAINT) == 0) { if (t->modifiers & (MOD_CONSTRAINT_SELECT | MOD_CONSTRAINT_PLANE)) { /* Confirm. */ postSelectConstraint(t); -- cgit v1.2.3 From 4bb531475490c36c57065fb3db3d41974fb14897 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 4 Dec 2020 08:01:54 -0600 Subject: Cleanup: Use typedef for button string info type Before, it wasn't clear what the int in `uiStringInfo` was supposed to store. Using a typedef can make this someone more explicit. --- source/blender/editors/include/UI_interface.h | 6 +++--- source/blender/editors/interface/interface.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index f9dc23502c7..a190194d89d 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1351,7 +1351,7 @@ struct PointerRNA *UI_but_operator_ptr_get(uiBut *but); void UI_but_unit_type_set(uiBut *but, const int unit_type); int UI_but_unit_type_get(const uiBut *but); -enum { +typedef enum uiStringInfoType { BUT_GET_RNAPROP_IDENTIFIER = 1, BUT_GET_RNASTRUCT_IDENTIFIER, BUT_GET_RNAENUM_IDENTIFIER, @@ -1364,10 +1364,10 @@ enum { BUT_GET_RNAENUM_TIP, BUT_GET_OP_KEYMAP, BUT_GET_PROP_KEYMAP, -}; +} uiStringInfoType; typedef struct uiStringInfo { - int type; + uiStringInfoType type; char *strinfo; } uiStringInfo; diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 685b34b7185..4a02c6b6e88 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -6795,7 +6795,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) va_start(args, but); while ((si = (uiStringInfo *)va_arg(args, void *))) { - int type = si->type; + uiStringInfoType type = si->type; char *tmp = NULL; if (type == BUT_GET_LABEL) { -- cgit v1.2.3 From 04d3b54000bedd06bc767fa908772c0b20cb792f Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 4 Dec 2020 08:03:14 -0600 Subject: Cleanup: Declare variables where initialized --- .../editors/interface/interface_context_menu.c | 248 ++++++++++----------- 1 file changed, 117 insertions(+), 131 deletions(-) diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 02a9c3742d7..39b405a02b8 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -90,9 +90,8 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but) } /* Create ID property of data path, to pass to the operator. */ - IDProperty *prop; const IDPropertyTemplate val = {0}; - prop = IDP_New(IDP_GROUP, &val, __func__); + IDProperty *prop = IDP_New(IDP_GROUP, &val, __func__); IDP_AddToGroup(prop, IDP_NewString(final_data_path, "data_path", strlen(final_data_path) + 1)); MEM_freeN((void *)final_data_path); @@ -167,43 +166,40 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event)) static uiBlock *menu_change_shortcut(bContext *C, ARegion *region, void *arg) { wmWindowManager *wm = CTX_wm_manager(C); - uiBlock *block; uiBut *but = (uiBut *)arg; - wmKeyMap *km; - wmKeyMapItem *kmi; PointerRNA ptr; - uiLayout *layout; const uiStyle *style = UI_style_get_dpi(); IDProperty *prop; const char *idname = shortcut_get_operator_property(C, but, &prop); - kmi = WM_key_event_operator(C, - idname, - but->opcontext, - prop, - EVT_TYPE_MASK_HOTKEY_INCLUDE, - EVT_TYPE_MASK_HOTKEY_EXCLUDE, - &km); + wmKeyMap *km; + wmKeyMapItem *kmi = WM_key_event_operator(C, + idname, + but->opcontext, + prop, + EVT_TYPE_MASK_HOTKEY_INCLUDE, + EVT_TYPE_MASK_HOTKEY_EXCLUDE, + &km); U.runtime.is_dirty = true; BLI_assert(kmi != NULL); RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); - block = UI_block_begin(C, region, "_popup", UI_EMBOSS); + uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS); UI_block_func_handle_set(block, but_shortcut_name_func, but); UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT); UI_block_direction_set(block, UI_DIR_CENTER_Y); - layout = UI_block_layout(block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - 0, - 0, - U.widget_unit * 10, - U.widget_unit * 2, - 0, - style); + uiLayout *layout = UI_block_layout(block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + 0, + 0, + U.widget_unit * 10, + U.widget_unit * 2, + 0, + style); uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), ICON_HAND); uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE); @@ -223,22 +219,17 @@ static int g_kmi_id_hack; static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg) { wmWindowManager *wm = CTX_wm_manager(C); - uiBlock *block; uiBut *but = (uiBut *)arg; - wmKeyMap *km; - wmKeyMapItem *kmi; PointerRNA ptr; - uiLayout *layout; const uiStyle *style = UI_style_get_dpi(); - int kmi_id; IDProperty *prop; const char *idname = shortcut_get_operator_property(C, but, &prop); /* XXX this guess_opname can potentially return a different keymap * than being found on adding later... */ - km = WM_keymap_guess_opname(C, idname); - kmi = WM_keymap_add_item(km, idname, EVT_AKEY, KM_PRESS, 0, 0); - kmi_id = kmi->id; + wmKeyMap *km = WM_keymap_guess_opname(C, idname); + wmKeyMapItem *kmi = WM_keymap_add_item(km, idname, EVT_AKEY, KM_PRESS, 0, 0); + int kmi_id = kmi->id; /* This takes ownership of prop, or prop can be NULL for reset. */ WM_keymap_item_properties_reset(kmi, prop); @@ -252,19 +243,19 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg) RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); - block = UI_block_begin(C, region, "_popup", UI_EMBOSS); + uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS); UI_block_func_handle_set(block, but_shortcut_name_func, but); UI_block_direction_set(block, UI_DIR_CENTER_Y); - layout = UI_block_layout(block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - 0, - 0, - U.widget_unit * 10, - U.widget_unit * 2, - 0, - style); + uiLayout *layout = UI_block_layout(block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + 0, + 0, + U.widget_unit * 10, + U.widget_unit * 2, + 0, + style); uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), ICON_HAND); uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE); @@ -282,24 +273,21 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg) static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) { uiBut *but = (uiBut *)arg1; - wmKeyMap *km; - wmKeyMapItem *kmi; - int kmi_id; IDProperty *prop; const char *idname = shortcut_get_operator_property(C, but, &prop); #ifdef USE_KEYMAP_ADD_HACK - km = WM_keymap_guess_opname(C, idname); - kmi_id = g_kmi_id_hack; + wmKeyMap *km = WM_keymap_guess_opname(C, idname); + int kmi_id = g_kmi_id_hack; UNUSED_VARS(but); #else - kmi_id = WM_key_event_operator_id(C, idname, but->opcontext, prop, true, &km); + int kmi_id = WM_key_event_operator_id(C, idname, but->opcontext, prop, true, &km); #endif shortcut_free_operator_property(prop); - kmi = WM_keymap_item_find_id(km, kmi_id); + wmKeyMapItem *kmi = WM_keymap_item_find_id(km, kmi_id); WM_keymap_remove_item(km, kmi); } @@ -312,18 +300,17 @@ static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) { uiBut *but = (uiBut *)arg1; - wmKeyMap *km; - wmKeyMapItem *kmi; IDProperty *prop; const char *idname = shortcut_get_operator_property(C, but, &prop); - kmi = WM_key_event_operator(C, - idname, - but->opcontext, - prop, - EVT_TYPE_MASK_HOTKEY_INCLUDE, - EVT_TYPE_MASK_HOTKEY_EXCLUDE, - &km); + wmKeyMap *km; + wmKeyMapItem *kmi = WM_key_event_operator(C, + idname, + but->opcontext, + prop, + EVT_TYPE_MASK_HOTKEY_INCLUDE, + EVT_TYPE_MASK_HOTKEY_EXCLUDE, + &km); BLI_assert(kmi != NULL); WM_keymap_remove_item(km, kmi); @@ -349,7 +336,6 @@ static bool ui_but_is_user_menu_compatible(bContext *C, uiBut *but) static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *um) { - MenuType *mt = NULL; if (but->optype) { IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; return (bUserMenuItem *)ED_screen_user_menu_item_find_operator( @@ -373,7 +359,9 @@ static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu * } return umi; } - if ((mt = UI_but_menutype_get(but))) { + + MenuType *mt = UI_but_menutype_get(but); + if (mt != NULL) { return (bUserMenuItem *)ED_screen_user_menu_item_find_menu(&um->items, mt); } return NULL; @@ -515,7 +503,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) uiPopupMenu *pup; uiLayout *layout; - { uiStringInfo label = {BUT_GET_LABEL, NULL}; @@ -979,7 +966,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) if (ui_but_is_user_menu_compatible(C, but)) { uiBlock *block = uiLayoutGetBlock(layout); const int w = uiLayoutGetWidth(layout); - uiBut *but2; bool item_found = false; uint um_array_len; @@ -991,7 +977,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } bUserMenuItem *umi = ui_but_user_menu_find(C, but, um); if (umi != NULL) { - but2 = uiDefIconTextBut( + uiBut *but2 = uiDefIconTextBut( block, UI_BTYPE_BUT, 0, @@ -1016,7 +1002,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } if (!item_found) { - but2 = uiDefIconTextBut( + uiBut *but2 = uiDefIconTextBut( block, UI_BTYPE_BUT, 0, @@ -1043,11 +1029,10 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const char *idname = shortcut_get_operator_property(C, but, &prop); if (idname != NULL) { uiBlock *block = uiLayoutGetBlock(layout); - uiBut *but2; const int w = uiLayoutGetWidth(layout); - wmKeyMap *km; /* We want to know if this op has a shortcut, be it hotkey or not. */ + wmKeyMap *km; wmKeyMapItem *kmi = WM_key_event_operator( C, idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km); @@ -1066,77 +1051,80 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) ""); #endif - but2 = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_HAND, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); + uiBut *but2 = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_HAND, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), + 0, + 0, + w, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + ""); UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); } else { - but2 = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_HAND, - IFACE_("Non-Keyboard Shortcut"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Only keyboard shortcuts can be edited that way, " - "please use User Preferences otherwise")); + uiBut *but2 = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_HAND, + IFACE_("Non-Keyboard Shortcut"), + 0, + 0, + w, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Only keyboard shortcuts can be edited that way, " + "please use User Preferences otherwise")); UI_but_flag_enable(but2, UI_BUT_DISABLED); } - but2 = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_BLANK1, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); + uiBut *but2 = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), + 0, + 0, + w, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + ""); UI_but_func_set(but2, remove_shortcut_func, but, NULL); } /* only show 'assign' if there's a suitable key map for it to go in */ else if (WM_keymap_guess_opname(C, idname)) { - but2 = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_HAND, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); + uiBut *but2 = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_HAND, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), + 0, + 0, + w, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + ""); UI_but_func_set(but2, popup_add_shortcut_func, but, NULL); } @@ -1239,9 +1227,6 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel) bScreen *screen = CTX_wm_screen(C); const bool has_panel_category = UI_panel_category_is_visible(region); const bool any_item_visible = has_panel_category; - PointerRNA ptr; - uiPopupMenu *pup; - uiLayout *layout; if (!any_item_visible) { return; @@ -1250,10 +1235,11 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel) return; } + PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Panel, panel, &ptr); - pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE); - layout = UI_popup_menu_layout(pup); + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); if (has_panel_category) { char tmpstr[80]; -- cgit v1.2.3 From 69dd7e42c8bbe0e6feb0aee0eeb424f21f5da0af Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 14:55:23 +0100 Subject: i18n utils: Cleanup. --- release/scripts/modules/bl_i18n_utils/utils_languages_menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py index 7c98faebe9d..63981310839 100755 --- a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py +++ b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py @@ -40,7 +40,7 @@ def gen_menu_file(stats, settings): # Generate languages file used by Blender's i18n system. # First, match all entries in LANGUAGES to a lang in stats, if possible! tmp = [] - for uid_num, label, uid, in settings.LANGUAGES: + for uid_num, label, uid in settings.LANGUAGES: if uid in stats: if uid in settings.IMPORT_LANGUAGES_SKIP: tmp.append((stats[uid], uid_num, label, uid, FORBIDDEN)) -- cgit v1.2.3 From 7bd8b8cdacd2cd7036851a77b41c4c7767f09e5e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 15:04:28 +0100 Subject: i18n utils: reduce dependency to Blender bpy API, step 1. This involves re-implementing some of Blender-defined helpers in utils, we keep debug code to ensure those are still matching on behavior/results sides. This will allow to get more i18n tools independent from blender executable. --- release/scripts/modules/bl_i18n_utils/utils.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index 4cb25816a34..14587100aea 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -39,9 +39,6 @@ import bpy ##### Misc Utils ##### -from bpy.app.translations import locale_explode - - _valid_po_path_re = re.compile(r"^\S+:[0-9]+$") @@ -79,6 +76,28 @@ def get_best_similar(data): return key, tmp +_locale_explode_re = re.compile(r"^([a-z]{2,})(?:_([A-Z]{2,}))?(?:@([a-z]{2,}))?$") + + +def locale_explode(locale): + """Copies behavior of `BLT_lang_locale_explode`, keep them in sync.""" + ret = (None, None, None, None, None) + m = _locale_explode_re.match(locale) + if m: + lang, country, variant = m.groups() + return (lang, country, variant, + "%s_%s" % (lang, country) if country else None, + "%s@%s" % (lang, variant) if variant else None) + + try: + import bpy.app.translations as bpy_translations + assert(ret == bpy_translations.locale_explode(locale)) + except ModuleNotFoundError: + pass + + return ret + + def locale_match(loc1, loc2): """ Return: -- cgit v1.2.3 From 06ae2e3a609fdc2081108e4163b7c62540618310 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 15:08:11 +0100 Subject: i18n utils : Reduce dependency to Blender bpy API, step 2. Remove some top imports of bpy, only import it in a few specific functions that only make sense when used whithin Blender anyway. --- release/scripts/modules/bl_i18n_utils/settings.py | 12 +++++++++--- release/scripts/modules/bl_i18n_utils/utils.py | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index e304ef5ea17..cfa4fcac17f 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -30,7 +30,11 @@ import os import sys import types -import bpy +try: + import bpy +except ModuleNotFoundError: + print("Could not import bpy, some features are not available when not run from Blender.") + bpy = None ############################################################################### # MISC @@ -98,8 +102,10 @@ LANGUAGES = ( (47, "Slovak (Slovenčina)", "sk_SK"), ) -# Default context, in py! -DEFAULT_CONTEXT = bpy.app.translations.contexts.default +# Default context, in py (keep in sync with `BLT_translation.h`)! +if bpy is not None: + assert(bpy.app.translations.contexts.default == "*") +DEFAULT_CONTEXT = "*" # Name of language file used by Blender to generate translations' menu. LANGUAGES_FILE = "languages" diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index 14587100aea..2224c39e48c 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -35,8 +35,6 @@ from bl_i18n_utils import ( utils_rtl, ) -import bpy - ##### Misc Utils ##### _valid_po_path_re = re.compile(r"^\S+:[0-9]+$") @@ -191,6 +189,12 @@ def enable_addons(addons=None, support=None, disable=False, check_only=False): """ import addon_utils + try: + import bpy + except ModuleNotFoundError: + print("Could not import bpy, enable_addons must be run from whithin Blender.") + return + if addons is None: addons = {} if support is None: @@ -744,6 +748,13 @@ class I18nMessages: rna_ctxt: the labels' i18n context. rna_struct_name, rna_prop_name, rna_enum_name: should be self-explanatory! """ + try: + import bpy + except ModuleNotFoundError: + print("Could not import bpy, find_best_messages_matches must be run from whithin Blender.") + return + + # Build helper mappings. # Note it's user responsibility to know when to invalidate (and hence force rebuild) this cache! if self._reverse_cache is None: @@ -1294,7 +1305,7 @@ class I18n: msgs.print_stats(prefix=msgs_prefix) print(prefix) - nbr_contexts = len(self.contexts - {bpy.app.translations.contexts.default}) + nbr_contexts = len(self.contexts - {self.settings.DEFAULT_CONTEXT}) if nbr_contexts != 1: if nbr_contexts == 0: nbr_contexts = "No" @@ -1312,7 +1323,7 @@ class I18n: " The org msgids are currently made of {} signs.\n".format(self.nbr_signs), " All processed translations are currently made of {} signs.\n".format(self.nbr_trans_signs), " {} specific context{} present:\n".format(self.nbr_contexts, _ctx_txt)) + - tuple(" " + c + "\n" for c in self.contexts - {bpy.app.translations.contexts.default}) + + tuple(" " + c + "\n" for c in self.contexts - {self.settings.DEFAULT_CONTEXT}) + ("\n",) ) print(prefix.join(lines)) -- cgit v1.2.3 From b3306cf669fb1035c6ec2ac3569a4f3dca4aa1c2 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 15:10:43 +0100 Subject: i18n utils: Add a helper to list and match po files with languages codes. This code was previously done in the add-on, but we'll need it for the CLI tool as well, so now it is a utils generator instead. --- release/scripts/modules/bl_i18n_utils/utils.py | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index 2224c39e48c..40b76b617b3 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -181,6 +181,36 @@ def get_po_files_from_dir(root_dir, langs=set()): yield uid, po_file +def list_po_dir(root_path, settings): + """ + Generator. List given directory (expecting one sub-directory per languages) + and return all files matching languages listed in settings. + + Yield tuples (can_use, uid, num_id, name, isocode, po_path) + + Note that po_path may not actually exists. + """ + isocodes = ((e, os.path.join(root_path, e, e + ".po")) for e in os.listdir(root_path)) + isocodes = dict(e for e in isocodes if os.path.isfile(e[1])) + for num_id, name, uid in settings.LANGUAGES[2:]: # Skip "default" and "en" languages! + best_po = find_best_isocode_matches(uid, isocodes) + #print(uid, "->", best_po) + if best_po: + isocode = best_po[0] + yield (True, uid, num_id, name, isocode, isocodes[isocode]) + else: + yielded = False + language, _1, _2, language_country, language_variant = locale_explode(uid) + for isocode in (language, language_variant, language_country, uid): + p = os.path.join(root_path, isocode, isocode + ".po") + if not os.path.exists(p): + yield (True, uid, num_id, name, isocode, p) + yielded = True + break + if not yielded: + yield (False, uid, num_id, name, None, None) + + def enable_addons(addons=None, support=None, disable=False, check_only=False): """ Enable (or disable) addons based either on a set of names, or a set of 'support' types. -- cgit v1.2.3 From ca4b809e63cf1f6d809b82ea6d0d41cae8eab82a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 15:13:07 +0100 Subject: i18n utils: Add first version of the CLI wrapper around i18n tools. Plan is to use that in new 'buildbot' pipeline to automate generation of i18n files for Blender. --- release/scripts/modules/bl_i18n_utils/utils_cli.py | 130 +++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 release/scripts/modules/bl_i18n_utils/utils_cli.py diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py new file mode 100644 index 00000000000..4390544ec17 --- /dev/null +++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py @@ -0,0 +1,130 @@ +# ***** 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 ***** + +# + +# Some useful operations from utils' I18nMessages class exposed as a CLI. + +import os + +if __package__ is None: + import settings as settings_i18n + import utils as utils_i18n + import utils_languages_menu +else: + from . import settings as settings_i18n + from . import utils as utils_i18n + from . import utils_languages_menu + + +def update_po(args, settings): + pot = utils_i18n.I18nMessages(uid=None, kind='PO', src=args.template, settings=settings) + if os.path.isfile(args.dst): + uid = os.path.splitext(os.path.basename(args.dst))[0] + po = utils_i18n.I18nMessages(uid=uid, kind='PO', src=args.dst, settings=settings) + po.update(pot) + else: + po = pot + po.write(kind="PO", dest=args.dst) + + +def cleanup_po(args, settings): + uid = os.path.splitext(os.path.basename(args.src))[0] + if not args.dst: + args.dst = args.src + po = utils_i18n.I18nMessages(uid=uid, kind='PO', src=args.src, settings=settings) + po.check(fix=True) + po.clean_commented() + po.write(kind="PO", dest=args.dst) + + +def strip_po(args, settings): + uid = os.path.splitext(os.path.basename(args.src))[0] + if not args.dst: + args.dst = args.src + po = utils_i18n.I18nMessages(uid=uid, kind='PO', src=args.src, settings=settings) + po.clean_commented() + po.write(kind="PO_COMPACT", dest=args.dst) + + +def language_menu(args, settings): + # 'DEFAULT' and en_US are always valid, fully-translated "languages"! + stats = {"DEFAULT": 1.0, "en_US": 1.0} + + po_to_uid = {os.path.basename(po_path_branch): uid + for can_use, uid, _num_id, _name, _isocode, po_path_branch + in utils_i18n.list_po_dir(settings.BRANCHES_DIR, settings) + if can_use} + for po_dir in os.listdir(settings.BRANCHES_DIR): + po_dir = os.path.join(settings.BRANCHES_DIR, po_dir) + if not os.path.isdir(po_dir): + continue + for po_path in os.listdir(po_dir): + uid = po_to_uid.get(po_path, None) + #print("Checking %s, found uid %s" % (po_path, uid)) + po_path = os.path.join(settings.TRUNK_PO_DIR, po_path) + if uid is not None: + po = utils_i18n.I18nMessages(uid=uid, kind='PO', src=po_path, settings=settings) + stats[uid] = po.nbr_trans_msgs / po.nbr_msgs if po.nbr_msgs > 0 else 0 + utils_languages_menu.gen_menu_file(stats, settings) + + +def main(): + import sys + import argparse + + parser = argparse.ArgumentParser(description="Tool to perform common actions over PO/MO files.") + parser.add_argument('-s', '--settings', default=None, + help="Override (some) default settings. Either a JSon file name, or a JSon string.") + sub_parsers = parser.add_subparsers() + + sub_parser = sub_parsers.add_parser('update_po', help="Update a PO file from a given POT template file") + sub_parser.add_argument('--template', metavar='template.pot', required=True, + help="The source pot file to use as template for the update.") + sub_parser.add_argument('--dst', metavar='dst.po', required=True, help="The destination po to update.") + sub_parser.set_defaults(func=update_po) + + sub_parser = sub_parsers.add_parser('cleanup_po', + help="Cleanup a PO file (check for and fix some common errors, remove commented messages).") + sub_parser.add_argument('--src', metavar='src.po', required=True, help="The source po file to clean up.") + sub_parser.add_argument('--dst', metavar='dst.po', help="The destination po to write to.") + sub_parser.set_defaults(func=cleanup_po) + + sub_parser = sub_parsers.add_parser('strip_po', + help="Reduce all non-essential data from given PO file (reduce its size).") + sub_parser.add_argument('--src', metavar='src.po', required=True, help="The source po file to strip.") + sub_parser.add_argument('--dst', metavar='dst.po', help="The destination po to write to.") + sub_parser.set_defaults(func=strip_po) + + sub_parser = sub_parsers.add_parser('language_menu', + help="Generate the text file used by Blender to create its language menu.") + sub_parser.set_defaults(func=language_menu) + + args = parser.parse_args(sys.argv[1:]) + + settings = settings_i18n.I18nSettings() + settings.load(args.settings) + + if getattr(args, 'template', None) is not None: + settings.FILE_NAME_POT = args.template + + args.func(args=args, settings=settings) + +if __name__ == "__main__": + print("\n\n *** Running {} *** \n".format(__file__)) + main() -- cgit v1.2.3 From fe1f05de1b77798650b91c4e5f8c2b02c3276b18 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 15:54:50 +0100 Subject: i18n utils CLI: add missing RTL process command. --- release/scripts/modules/bl_i18n_utils/utils_cli.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py index 4390544ec17..d38911c122d 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_cli.py +++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py @@ -62,6 +62,15 @@ def strip_po(args, settings): po.write(kind="PO_COMPACT", dest=args.dst) +def rtl_process_po(args, settings): + uid = os.path.splitext(os.path.basename(args.src))[0] + if not args.dst: + args.dst = args.src + po = utils_i18n.I18nMessages(uid=uid, kind='PO', src=args.src, settings=settings) + po.rtl_process() + po.write(kind="PO", dest=args.dst) + + def language_menu(args, settings): # 'DEFAULT' and en_US are always valid, fully-translated "languages"! stats = {"DEFAULT": 1.0, "en_US": 1.0} @@ -111,6 +120,12 @@ def main(): sub_parser.add_argument('--dst', metavar='dst.po', help="The destination po to write to.") sub_parser.set_defaults(func=strip_po) + sub_parser = sub_parsers.add_parser('rtl_process_po', + help="Pre-process PO files for RTL languages.") + sub_parser.add_argument('--src', metavar='src.po', required=True, help="The source po file to process.") + sub_parser.add_argument('--dst', metavar='dst.po', help="The destination po to write to.") + sub_parser.set_defaults(func=rtl_process_po) + sub_parser = sub_parsers.add_parser('language_menu', help="Generate the text file used by Blender to create its language menu.") sub_parser.set_defaults(func=language_menu) -- cgit v1.2.3 From b9195116075420b09969eacd4ba91c4cce7b7b5c Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 4 Dec 2020 12:22:50 -0300 Subject: Cleanup: Deduplicate constraint event code --- source/blender/editors/transform/transform.c | 119 +++++++++------------ .../editors/transform/transform_constraints.c | 10 -- 2 files changed, 48 insertions(+), 81 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 3b8f7f90edc..2004e3b052d 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -713,55 +713,67 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) return keymap; } -static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane) +static bool transform_event_modal_constraint(TransInfo *t, short modal_type) { if (!(t->flag & T_NO_CONSTRAINT)) { - char cmode = constraintModeToChar(t); - int constraint_axis, constraint_plane; - const bool edit_2d = (t->flag & T_2D_EDIT) != 0; - const char *msg1 = "", *msg2 = "", *msg3 = ""; - char axis; + if (t->flag & T_2D_EDIT && ELEM(modal_type, TFM_MODAL_AXIS_Z, TFM_MODAL_PLANE_Z)) { + return false; + } + int constraint_curr = (t->con.mode & CON_APPLY) ? + t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2) : + -1; + int constraint_new; + const char *msg_2d = "", *msg_3d = ""; /* Initialize */ - switch (key_type) { - case EVT_XKEY: - msg1 = TIP_("along X"); - msg2 = TIP_("along %s X"); - msg3 = TIP_("locking %s X"); - axis = 'X'; - constraint_axis = CON_AXIS0; + switch (modal_type) { + case TFM_MODAL_AXIS_X: + msg_2d = TIP_("along X"); + msg_3d = TIP_("along %s X"); + constraint_new = CON_AXIS0; + break; + case TFM_MODAL_AXIS_Y: + msg_2d = TIP_("along Y"); + msg_3d = TIP_("along %s Y"); + constraint_new = CON_AXIS1; break; - case EVT_YKEY: - msg1 = TIP_("along Y"); - msg2 = TIP_("along %s Y"); - msg3 = TIP_("locking %s Y"); - axis = 'Y'; - constraint_axis = CON_AXIS1; + case TFM_MODAL_AXIS_Z: + msg_2d = TIP_("along Z"); + msg_3d = TIP_("along %s Z"); + constraint_new = CON_AXIS2; break; - case EVT_ZKEY: - msg1 = TIP_("along Z"); - msg2 = TIP_("along %s Z"); - msg3 = TIP_("locking %s Z"); - axis = 'Z'; - constraint_axis = CON_AXIS2; + case TFM_MODAL_PLANE_X: + msg_3d = TIP_("locking %s X"); + constraint_new = CON_AXIS1 | CON_AXIS2; + break; + case TFM_MODAL_PLANE_Y: + msg_3d = TIP_("locking %s Y"); + constraint_new = CON_AXIS0 | CON_AXIS2; + break; + case TFM_MODAL_PLANE_Z: + msg_3d = TIP_("locking %s Z"); + constraint_new = CON_AXIS0 | CON_AXIS1; break; default: /* Invalid key */ - return; + return false; } - constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis)); - if (edit_2d && (key_type != EVT_ZKEY)) { - if (cmode == axis) { + if (t->flag & T_2D_EDIT) { + BLI_assert(modal_type < TFM_MODAL_PLANE_X); + if (constraint_new == CON_AXIS2) { + return false; + } + if (constraint_curr == constraint_new) { stopConstraint(t); } else { - setUserConstraint(t, constraint_axis, msg1); + setUserConstraint(t, constraint_new, msg_2d); } } - else if (!edit_2d) { + else { short orient_index = 1; - if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) { + if (t->orient_curr == 0 || ELEM(constraint_curr, -1, constraint_new)) { /* Successive presses on existing axis, cycle orientation modes. */ orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); } @@ -771,16 +783,13 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is stopConstraint(t); } else { - if (is_plane == false) { - setUserConstraint(t, constraint_axis, msg2); - } - else { - setUserConstraint(t, constraint_plane, msg3); - } + setUserConstraint(t, constraint_new, msg_3d); } } t->redraw |= TREDRAW_HARD; + return true; } + return false; } int transformEvent(TransInfo *t, const wmEvent *event) @@ -949,44 +958,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; break; case TFM_MODAL_AXIS_X: - if (!(t->flag & T_NO_CONSTRAINT)) { - transform_event_xyz_constraint(t, EVT_XKEY, false); - t->redraw |= TREDRAW_HARD; - handled = true; - } - break; case TFM_MODAL_AXIS_Y: - if ((t->flag & T_NO_CONSTRAINT) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, false); - t->redraw |= TREDRAW_HARD; - handled = true; - } - break; case TFM_MODAL_AXIS_Z: - if ((t->flag & (T_NO_CONSTRAINT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, false); - t->redraw |= TREDRAW_HARD; - handled = true; - } - break; case TFM_MODAL_PLANE_X: - if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_XKEY, true); - t->redraw |= TREDRAW_HARD; - handled = true; - } - break; case TFM_MODAL_PLANE_Y: - if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, true); - t->redraw |= TREDRAW_HARD; - handled = true; - } - break; case TFM_MODAL_PLANE_Z: - if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, true); - t->redraw |= TREDRAW_HARD; + if (transform_event_modal_constraint(t, event->val)) { handled = true; } break; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 5e2a8be8db0..54533bf43e5 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -1127,16 +1127,6 @@ int constraintModeToIndex(const TransInfo *t) } } -char constraintModeToChar(const TransInfo *t) -{ - int index = constraintModeToIndex(t); - if (index == -1) { - return '\0'; - } - BLI_assert((uint)index < 3); - return 'X' + index; -} - bool isLockConstraint(TransInfo *t) { int mode = t->con.mode; -- cgit v1.2.3 From d07009498ac36d067fbccd61cfbcd51d4e2ba310 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 4 Dec 2020 12:30:52 -0300 Subject: Transform: Don't use Automatic Constraint Plane in 2D editors Technically it shouldn't have any effect on these editors. The key tips in the header can be misleading. The effect it previously had was not intended. --- source/blender/editors/transform/transform.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 2004e3b052d..5969de5b5da 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -599,7 +599,8 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) case TFM_MODAL_AXIS_Z: case TFM_MODAL_PLANE_X: case TFM_MODAL_PLANE_Y: - case TFM_MODAL_PLANE_Z: { + case TFM_MODAL_PLANE_Z: + case TFM_MODAL_AUTOCONSTRAINTPLANE: { if (t->flag & T_NO_CONSTRAINT) { return false; } -- cgit v1.2.3 From 719dfd40889aa50d39d27b3264388768f42b2984 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Fri, 4 Dec 2020 21:11:19 +0530 Subject: macOS deps: Support building clang tidy This patch builds clang-extra-tools on macOS for the clang-tidy binary. The script "run-clang-tidy.py" is also harvested because using the `CMAKE_C[XX]_CLANG_TIDY` option can miss out some files (like makesrna), and using the script is faster as it does not compile the files. Thanks to `@LazyDodo` for the base patch D8502. Reviewed By: LazyDodo, sebbas, #platform_macos Differential Revision: https://developer.blender.org/D9450 --- build_files/build_environment/cmake/clang.cmake | 34 ++++++++++++++++++++-- build_files/build_environment/cmake/harvest.cmake | 4 +++ build_files/build_environment/cmake/versions.cmake | 3 ++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/build_files/build_environment/cmake/clang.cmake b/build_files/build_environment/cmake/clang.cmake index 9de0ec1b182..d8d83619e1a 100644 --- a/build_files/build_environment/cmake/clang.cmake +++ b/build_files/build_environment/cmake/clang.cmake @@ -17,13 +17,14 @@ # ***** END GPL LICENSE BLOCK ***** set(CLANG_EXTRA_ARGS - -DCLANG_PATH_TO_LLVM_SOURCE=${BUILD_DIR}/ll/src/ll - -DCLANG_PATH_TO_LLVM_BUILD=${LIBDIR}/llvm + -DLLVM_DIR="${LIBDIR}/llvm/lib/cmake/llvm/" -DLLVM_USE_CRT_RELEASE=MD -DLLVM_USE_CRT_DEBUG=MDd -DLLVM_CONFIG=${LIBDIR}/llvm/bin/llvm-config ) +set(BUILD_CLANG_TOOLS OFF) + if(WIN32) set(CLANG_GENERATOR "Ninja") else() @@ -31,11 +32,32 @@ else() endif() if(APPLE) + set(BUILD_CLANG_TOOLS ON) set(CLANG_EXTRA_ARGS ${CLANG_EXTRA_ARGS} -DLIBXML2_LIBRARY=${LIBDIR}/xml2/lib/libxml2.a ) endif() +if(BUILD_CLANG_TOOLS) + # ExternalProject_Add does not allow multiple tarballs to be + # downloaded. Work around this by having an empty build action + # for the extra tools, and referring the clang build to the location + # of the clang-tools-extra source. + ExternalProject_Add(external_clang_tools + URL ${CLANG_TOOLS_URI} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH MD5=${CLANG_TOOLS_HASH} + INSTALL_DIR ${LIBDIR}/clang_tools + PREFIX ${BUILD_DIR}/clang_tools + CONFIGURE_COMMAND echo "." + BUILD_COMMAND echo "." + INSTALL_COMMAND echo "." + ) + list(APPEND CLANG_EXTRA_ARGS + -DLLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR=${BUILD_DIR}/clang_tools/src/external_clang_tools/ + ) +endif() + ExternalProject_Add(external_clang URL ${CLANG_URI} DOWNLOAD_DIR ${DOWNLOAD_DIR} @@ -65,6 +87,14 @@ add_dependencies( ll ) +if(BUILD_CLANG_TOOLS) + # `external_clang_tools` is for downloading the source, not compiling it. + add_dependencies( + external_clang + external_clang_tools + ) +endif() + # We currently do not build libxml2 on Windows. if(NOT WIN32) add_dependencies( diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake index 0f9b67a3d44..536907f563d 100644 --- a/build_files/build_environment/cmake/harvest.cmake +++ b/build_files/build_environment/cmake/harvest.cmake @@ -98,6 +98,10 @@ harvest(jpg/include jpeg/include "*.h") harvest(jpg/lib jpeg/lib "libjpeg.a") harvest(lame/lib ffmpeg/lib "*.a") harvest(clang/bin llvm/bin "clang-format") +if(BUILD_CLANG_TOOLS) + harvest(clang/bin llvm/bin "clang-tidy") + harvest(clang/share/clang llvm/share "run-clang-tidy.py") +endif() harvest(clang/include llvm/include "*") harvest(llvm/include llvm/include "*") harvest(llvm/bin llvm/bin "llvm-config") diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake index 653db9f740c..d4a2c715ecc 100644 --- a/build_files/build_environment/cmake/versions.cmake +++ b/build_files/build_environment/cmake/versions.cmake @@ -120,6 +120,9 @@ set(LLVM_HASH 31eb9ce73dd2a0f8dcab8319fb03f8fc) set(CLANG_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang-${LLVM_VERSION}.src.tar.xz) set(CLANG_HASH 13468e4a44940efef1b75e8641752f90) +set(CLANG_TOOLS_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang-tools-extra-${LLVM_VERSION}.src.tar.xz) +set(CLANG_TOOLS_HASH c76293870b564c6a7968622b475b7646) + set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/openmp-${LLVM_VERSION}.src.tar.xz) set(OPENMP_HASH 6eade16057edbdecb3c4eef9daa2bfcf) -- cgit v1.2.3 From 1d2c70d7615c14b380e00ae993e58cc14376dcf7 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Dec 2020 16:44:22 +0100 Subject: Fix API doc generation. BMesh auto-extracting API info does not support comments inside BMesh operators parameters definition. --- source/blender/bmesh/intern/bmesh_opdefines.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index cf58dfc684e..4ce70e7bd5a 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1787,8 +1787,8 @@ static BMOpDefine bmo_bevel_def = { {"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"smoothresh", BMO_OP_SLOT_FLT}, /* for passing mesh's smoothresh, used in hardening */ {"custom_profile", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_STRUCT}}, /* CurveProfile */ - {"vmesh_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, /* the method to use to create meshes at intersections */ - bmo_enum_bevel_vmesh_method}, + {"vmesh_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, + bmo_enum_bevel_vmesh_method}, /* The method to use to create meshes at intersections. */ {{'\0'}}, }, /* slots_out */ -- cgit v1.2.3 From f5eaf67e34df088a2f0a19c744be7f8a51e7d9be Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 4 Dec 2020 16:25:49 +0100 Subject: Atomics: Add 16 bit fetch + AND and fetch + OR signed integer operations I could use a 16 bit atomic fetch + AND for D9719. The alternative would be to turn a `short` into a `int` in DNA, which isn't a nice workaround. Also adds tests for the new functions. --- intern/atomic/atomic_ops.h | 3 +++ intern/atomic/intern/atomic_ops_msvc.h | 14 ++++++++++++++ intern/atomic/intern/atomic_ops_unix.h | 19 +++++++++++++++++++ intern/atomic/tests/atomic_test.cc | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h index e6ca7a105ba..ad404c756ce 100644 --- a/intern/atomic/atomic_ops.h +++ b/intern/atomic/atomic_ops.h @@ -87,6 +87,9 @@ ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x); ATOMIC_INLINE int32_t atomic_fetch_and_or_int32(int32_t *p, int32_t x); ATOMIC_INLINE int32_t atomic_fetch_and_and_int32(int32_t *p, int32_t x); +ATOMIC_INLINE int16_t atomic_fetch_and_or_int16(int16_t *p, int16_t b); +ATOMIC_INLINE int16_t atomic_fetch_and_and_int16(int16_t *p, int16_t b); + ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b); ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b); diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h index 356140541ba..c9ad1a46ab9 100644 --- a/intern/atomic/intern/atomic_ops_msvc.h +++ b/intern/atomic/intern/atomic_ops_msvc.h @@ -162,6 +162,20 @@ ATOMIC_INLINE int32_t atomic_fetch_and_and_int32(int32_t *p, int32_t x) return InterlockedAnd((long *)p, x); } +/******************************************************************************/ +/* 16-bit operations. */ + +/* Signed */ +ATOMIC_INLINE int16_t atomic_fetch_and_or_int16(int16_t *p, int16_t x) +{ + return InterlockedOr16((short *)p, x); +} + +ATOMIC_INLINE int16_t atomic_fetch_and_and_int16(int16_t *p, int16_t x) +{ + return InterlockedAnd16((short *)p, x); +} + /******************************************************************************/ /* 8-bit operations. */ diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h index 0de9daaaf5f..dc1e71cda76 100644 --- a/intern/atomic/intern/atomic_ops_unix.h +++ b/intern/atomic/intern/atomic_ops_unix.h @@ -55,6 +55,7 @@ * its gcc doesn't have __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n defined. */ # define JE_FORCE_SYNC_COMPARE_AND_SWAP_1 +# define JE_FORCE_SYNC_COMPARE_AND_SWAP_2 # define JE_FORCE_SYNC_COMPARE_AND_SWAP_4 # define JE_FORCE_SYNC_COMPARE_AND_SWAP_8 #endif @@ -325,6 +326,24 @@ ATOMIC_INLINE int32_t atomic_fetch_and_and_int32(int32_t *p, int32_t x) # error "Missing implementation for 32-bit atomic operations" #endif +/******************************************************************************/ +/* 16-bit operations. */ +#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_2)) + +/* Signed */ +ATOMIC_INLINE int16_t atomic_fetch_and_and_int16(int16_t *p, int16_t b) +{ + return __sync_fetch_and_and(p, b); +} +ATOMIC_INLINE int16_t atomic_fetch_and_or_int16(int16_t *p, int16_t b) +{ + return __sync_fetch_and_or(p, b); +} + +#else +# error "Missing implementation for 16-bit atomic operations" +#endif + /******************************************************************************/ /* 8-bit operations. */ #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_1)) diff --git a/intern/atomic/tests/atomic_test.cc b/intern/atomic/tests/atomic_test.cc index 6178b5074a7..661c130c65d 100644 --- a/intern/atomic/tests/atomic_test.cc +++ b/intern/atomic/tests/atomic_test.cc @@ -559,6 +559,39 @@ TEST(atomic, atomic_fetch_and_and_int32) /** \} */ +/** \name 16 bit signed int atomics + * \{ */ + +TEST(atomic, atomic_fetch_and_or_int16) +{ + { + int16_t value = 12; + EXPECT_EQ(atomic_fetch_and_or_int16(&value, 5), 12); + EXPECT_EQ(value, 13); + } + + { + int16_t value = 0x1234; + EXPECT_EQ(atomic_fetch_and_or_int16(&value, -0x5678), 0x1234); + EXPECT_EQ(value, -0x4444); + } +} + +TEST(atomic, atomic_fetch_and_and_int16) +{ + { + int16_t value = 12; + EXPECT_EQ(atomic_fetch_and_and_int16(&value, 5), 12); + EXPECT_EQ(value, 4); + } + + { + int16_t value = 0x1234; + EXPECT_EQ(atomic_fetch_and_and_int16(&value, -0x789A), 0x1234); + EXPECT_EQ(value, 0x224); + } +} + /** \name 8 bit unsigned int atomics * \{ */ -- cgit v1.2.3 From 3daf28388b7372208cbec870f51b37be3aeac1e9 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 4 Dec 2020 19:43:33 +0100 Subject: Cleanup: Move Outliner runtime hash into internal runtime struct, out of DNA This way Outliner internal data stays internal, non-Outliner code will not be able to access and mess with this. Further it allows us to use the real type (rather than `void *`), change the type to a C++ container if needed and slightly reduces the size for every Outliner stored in files. Slightly changed how we set the `SO_TREESTORE_REBUILD` for this, but it should effectively behave the same way as before. --- source/blender/blenkernel/intern/screen.c | 7 ++---- source/blender/blenloader/intern/readfile.c | 6 ++--- .../editors/space_outliner/outliner_intern.h | 9 ++++--- .../blender/editors/space_outliner/outliner_tree.c | 28 +++++++++++----------- .../editors/space_outliner/outliner_utils.c | 3 ++- .../editors/space_outliner/space_outliner.c | 10 ++++---- source/blender/makesdna/DNA_space_types.h | 7 +----- 7 files changed, 32 insertions(+), 38 deletions(-) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 97bef99944a..355db8f0d60 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1561,7 +1561,6 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) /* we only saved what was used */ space_outliner->storeflag |= SO_TREESTORE_CLEANUP; /* at first draw */ } - space_outliner->treehash = NULL; space_outliner->tree.first = space_outliner->tree.last = NULL; space_outliner->runtime = NULL; } @@ -1825,10 +1824,8 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr while ((tselem = BLI_mempool_iterstep(&iter))) { BLO_read_id_address(reader, NULL, &tselem->id); } - if (space_outliner->treehash) { - /* rebuild hash table, because it depends on ids too */ - space_outliner->storeflag |= SO_TREESTORE_REBUILD; - } + /* rebuild hash table, because it depends on ids too */ + space_outliner->storeflag |= SO_TREESTORE_REBUILD; } break; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2c10dd446f1..9ce767b7ce1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2834,10 +2834,8 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, tselem->id = NULL; } } - if (space_outliner->treehash) { - /* rebuild hash table, because it depends on ids too */ - space_outliner->storeflag |= SO_TREESTORE_REBUILD; - } + /* rebuild hash table, because it depends on ids too */ + space_outliner->storeflag |= SO_TREESTORE_REBUILD; } } else if (sl->spacetype == SPACE_NODE) { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index aefba929c5e..0b432d932ca 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -47,10 +47,13 @@ struct wmKeyConfig; struct wmOperatorType; typedef struct SpaceOutliner_Runtime { - /** - * Internal C++ object to create and manage the tree for a specific display type (View Layers, - * Scenes, Blender File, etc.). */ + /** Internal C++ object to create and manage the tree for a specific display type (View Layers, + * Scenes, Blender File, etc.). */ struct TreeDisplay *tree_display; + + /** Pointers to treestore elements, grouped by (id, type, nr) + * in hashtable for faster searching */ + struct GHash *treehash; } SpaceOutliner_Runtime; typedef enum TreeElementInsertType { diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 159511546be..94d55b13073 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -132,9 +132,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) if (BLI_mempool_len(ts) == unused) { BLI_mempool_destroy(ts); space_outliner->treestore = NULL; - if (space_outliner->treehash) { - BKE_outliner_treehash_free(space_outliner->treehash); - space_outliner->treehash = NULL; + if (space_outliner->runtime->treehash) { + BKE_outliner_treehash_free(space_outliner->runtime->treehash); + space_outliner->runtime->treehash = NULL; } } else { @@ -150,16 +150,16 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) } BLI_mempool_destroy(ts); space_outliner->treestore = new_ts; - if (space_outliner->treehash) { + if (space_outliner->runtime->treehash) { /* update hash table to fix broken pointers */ - BKE_outliner_treehash_rebuild_from_treestore(space_outliner->treehash, + BKE_outliner_treehash_rebuild_from_treestore(space_outliner->runtime->treehash, space_outliner->treestore); } } } } - else if (space_outliner->treehash) { - BKE_outliner_treehash_clear_used(space_outliner->treehash); + else if (space_outliner->runtime->treehash) { + BKE_outliner_treehash_clear_used(space_outliner->runtime->treehash); } } } @@ -174,14 +174,14 @@ static void check_persistent( space_outliner->treestore = BLI_mempool_create( sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); } - if (space_outliner->treehash == NULL) { - space_outliner->treehash = BKE_outliner_treehash_create_from_treestore( + if (space_outliner->runtime->treehash == NULL) { + space_outliner->runtime->treehash = BKE_outliner_treehash_create_from_treestore( space_outliner->treestore); } /* find any unused tree element in treestore and mark it as used * (note that there may be multiple unused elements in case of linked objects) */ - tselem = BKE_outliner_treehash_lookup_unused(space_outliner->treehash, type, nr, id); + tselem = BKE_outliner_treehash_lookup_unused(space_outliner->runtime->treehash, type, nr, id); if (tselem) { te->store_elem = tselem; tselem->used = 1; @@ -196,7 +196,7 @@ static void check_persistent( tselem->used = 0; tselem->flag = TSE_CLOSED; te->store_elem = tselem; - BKE_outliner_treehash_add_element(space_outliner->treehash, tselem); + BKE_outliner_treehash_add_element(space_outliner->runtime->treehash, tselem); } /* ********************************************************* */ @@ -2197,12 +2197,12 @@ void outliner_build_tree(Main *mainvar, space_outliner->search_flags &= ~SO_SEARCH_RECURSIVE; } - if (space_outliner->treehash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) && + if (space_outliner->runtime->treehash && (space_outliner->storeflag & SO_TREESTORE_REBUILD) && space_outliner->treestore) { - space_outliner->storeflag &= ~SO_TREESTORE_REBUILD; - BKE_outliner_treehash_rebuild_from_treestore(space_outliner->treehash, + BKE_outliner_treehash_rebuild_from_treestore(space_outliner->runtime->treehash, space_outliner->treestore); } + space_outliner->storeflag &= ~SO_TREESTORE_REBUILD; if (region->do_draw & RGN_DRAW_NO_REBUILD) { return; diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 3328f3169c3..fe4cc29b738 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -212,7 +212,8 @@ TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreEle } /* check if 'tse' is in treestore */ - tselem = BKE_outliner_treehash_lookup_any(space_outliner->treehash, tse->type, tse->nr, tse->id); + tselem = BKE_outliner_treehash_lookup_any( + space_outliner->runtime->treehash, tse->type, tse->nr, tse->id); if (tselem) { return outliner_find_tree_element(&space_outliner->tree, tselem); } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index cd8e8a0be98..3c6369d3090 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -349,12 +349,12 @@ static void outliner_free(SpaceLink *sl) if (space_outliner->treestore) { BLI_mempool_destroy(space_outliner->treestore); } - if (space_outliner->treehash) { - BKE_outliner_treehash_free(space_outliner->treehash); - } if (space_outliner->runtime) { outliner_tree_display_destroy(&space_outliner->runtime->tree_display); + if (space_outliner->runtime->treehash) { + BKE_outliner_treehash_free(space_outliner->runtime->treehash); + } MEM_freeN(space_outliner->runtime); } } @@ -377,13 +377,13 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl) BLI_listbase_clear(&space_outliner_new->tree); space_outliner_new->treestore = NULL; - space_outliner_new->treehash = NULL; space_outliner_new->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL; if (space_outliner->runtime) { space_outliner_new->runtime = MEM_dupallocN(space_outliner->runtime); space_outliner_new->runtime->tree_display = NULL; + space_outliner_new->runtime->treehash = NULL; } return (SpaceLink *)space_outliner_new; @@ -414,7 +414,7 @@ static void outliner_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_i changed = true; } } - if (space_outliner->treehash && changed) { + if (space_outliner->runtime->treehash && changed) { /* rebuild hash table, because it depends on ids too */ /* postpone a full rebuild because this can be called many times on-free */ space_outliner->storeflag |= SO_TREESTORE_REBUILD; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index cbf6e900416..a554caccc4e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -279,11 +279,6 @@ typedef struct SpaceOutliner { char show_restrict_flags; short filter_id_type; - /** - * Pointers to treestore elements, grouped by (id, type, nr) - * in hashtable for faster searching */ - void *treehash; - SpaceOutliner_Runtime *runtime; } SpaceOutliner; -- cgit v1.2.3 From 67faa85fb05defa5c596ac6549deb52a3654c3a7 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 4 Dec 2020 13:50:53 -0600 Subject: Cleanup: Use LISTBASE_FOREACH macro in windowmanager intern Also decrease the scope of variables related to the loops. --- .../blender/windowmanager/intern/wm_event_system.c | 30 ++-- source/blender/windowmanager/intern/wm_files.c | 31 ++-- source/blender/windowmanager/intern/wm_init_exit.c | 4 +- source/blender/windowmanager/intern/wm_jobs.c | 57 ++----- source/blender/windowmanager/intern/wm_keymap.c | 181 ++++++++------------- .../windowmanager/intern/wm_operator_type.c | 4 +- source/blender/windowmanager/intern/wm_surface.c | 3 +- 7 files changed, 107 insertions(+), 203 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 1bd8c675807..9d118b70e43 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -376,10 +376,9 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) /* Cached: editor refresh callbacks now, they get context. */ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { const bScreen *screen = WM_window_get_active_screen(win); - ScrArea *area; CTX_wm_window_set(C, win); - for (area = screen->areabase.first; area; area = area->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->do_refresh) { CTX_wm_area_set(C, area); ED_area_do_refresh(C, area); @@ -516,7 +515,7 @@ void wm_event_do_notifiers(bContext *C) bScreen *screen = WM_window_get_active_screen(win); WorkSpace *workspace = WM_window_get_active_workspace(win); - /* Dilter out notifiers. */ + /* Filter out notifiers. */ if (note->category == NC_SCREEN && note->reference && note->reference != screen && note->reference != workspace && note->reference != WM_window_get_active_layout(win)) { /* Pass. */ @@ -525,8 +524,6 @@ void wm_event_do_notifiers(bContext *C) /* Pass. */ } else { - ARegion *region; - /* XXX context in notifiers? */ CTX_wm_window_set(C, win); @@ -538,13 +535,13 @@ void wm_event_do_notifiers(bContext *C) # endif ED_screen_do_listen(C, note); - for (region = screen->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { ED_region_do_listen(win, NULL, region, note, scene); } ED_screen_areas_iter (win, screen, area) { ED_area_do_listen(win, area, note, scene); - for (region = area->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { ED_region_do_listen(win, area, region, note, scene); } } @@ -1708,7 +1705,8 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const } if (region == NULL) { - for (region = area->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) { + region = region_iter; if (region == handler->context.region) { break; } @@ -2247,23 +2245,23 @@ static int wm_handler_fileselect_do(bContext *C, } } else { - wmWindow *temp_win; ScrArea *ctx_area = CTX_wm_area(C); - for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) { + wmWindow *temp_win = NULL; + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { bScreen *screen = WM_window_get_active_screen(temp_win); ScrArea *file_area = screen->areabase.first; if (screen->temp && (file_area->spacetype == SPACE_FILE)) { int win_size[2]; bool is_maximized; - ED_fileselect_window_params_get(temp_win, win_size, &is_maximized); + ED_fileselect_window_params_get(win, win_size, &is_maximized); ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized); if (BLI_listbase_is_single(&file_area->spacedata)) { - BLI_assert(ctx_win != temp_win); + BLI_assert(ctx_win != win); - wm_window_close(C, wm, temp_win); + wm_window_close(C, wm, win); CTX_wm_window_set(C, ctx_win); /* #wm_window_close() NULLs. */ /* Some operators expect a drawable context (for EVT_FILESELECT_EXEC). */ @@ -2272,7 +2270,7 @@ static int wm_handler_fileselect_do(bContext *C, * opening (UI_BLOCK_MOVEMOUSE_QUIT). */ wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); wm->winactive = ctx_win; /* Reports use this... */ - if (handler->context.win == temp_win) { + if (handler->context.win == win) { handler->context.win = NULL; } } @@ -2283,6 +2281,7 @@ static int wm_handler_fileselect_do(bContext *C, ED_area_prevspace(C, file_area); } + temp_win = win; break; } } @@ -2485,14 +2484,13 @@ static int wm_handlers_do_keymap_with_gizmo_handler( { int action = WM_HANDLER_CONTINUE; bool keymap_poll = false; - wmKeyMapItem *kmi; PRINT("%s: checking '%s' ...", __func__, keymap->idname); if (WM_keymap_poll(C, keymap)) { keymap_poll = true; PRINT("pass\n"); - for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if (wm_eventmatch(event, kmi)) { PRINT("%s: item matched '%s'\n", __func__, kmi->idname); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 3ddac8babd4..6ec6f3d9a6f 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -178,22 +178,17 @@ bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm) */ static void wm_window_match_init(bContext *C, ListBase *wmlist) { - wmWindowManager *wm; - wmWindow *win, *active_win; - *wmlist = G_MAIN->wm; BLI_listbase_clear(&G_MAIN->wm); - active_win = CTX_wm_window(C); + wmWindow *active_win = CTX_wm_window(C); /* first wrap up running stuff */ /* code copied from wm_init_exit.c */ - for (wm = wmlist->first; wm; wm = wm->id.next) { - + LISTBASE_FOREACH (wmWindowManager *, wm, wmlist) { WM_jobs_kill_all(wm); - for (win = wm->windows.first; win; win = win->next) { - + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); @@ -519,11 +514,9 @@ void WM_file_autoexec_init(const char *filepath) void wm_file_read_report(bContext *C, Main *bmain) { ReportList *reports = NULL; - Scene *sce; - - for (sce = bmain->scenes.first; sce; sce = sce->id.next) { - if (sce->r.engine[0] && - BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->r.engine[0] && + BLI_findstring(&R_engines, scene->r.engine, offsetof(RenderEngineType, idname)) == NULL) { if (reports == NULL) { reports = CTX_wm_reports(C); } @@ -532,8 +525,8 @@ void wm_file_read_report(bContext *C, Main *bmain) RPT_ERROR, "Engine '%s' not available for scene '%s' (an add-on may need to be installed " "or enabled)", - sce->r.engine, - sce->id.name + 2); + scene->r.engine, + scene->id.name + 2); } } @@ -1136,7 +1129,7 @@ void wm_homefile_read(bContext *C, if (use_userdef) { /* Clear keymaps because the current default keymap may have been initialized * from user preferences, which have been reset. */ - for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { + LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) { if (wm->defaultconf) { wm->defaultconf->flag &= ~KEYCONF_INIT_DEFAULT; } @@ -1236,8 +1229,7 @@ static void wm_history_file_write(void) fp = BLI_fopen(name, "w"); if (fp) { - struct RecentFile *recent; - for (recent = G.recent_files.first; recent; recent = recent->next) { + LISTBASE_FOREACH (RecentFile *, recent, &G.recent_files) { fprintf(fp, "%s\n", recent->filepath); } fclose(fp); @@ -1430,7 +1422,6 @@ static bool wm_file_write(bContext *C, ReportList *reports) { Main *bmain = CTX_data_main(C); - Library *li; int len; int ok = false; BlendThumbnail *thumb, *main_thumb; @@ -1459,7 +1450,7 @@ static bool wm_file_write(bContext *C, * its handy for scripts to save to a predefined name without blender editing it */ /* send the OnSave event */ - for (li = bmain->libraries.first; li; li = li->id.next) { + LISTBASE_FOREACH (Library *, li, &bmain->libraries) { if (BLI_path_cmp(li->filepath_abs, filepath) == 0) { BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath); return ok; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 74f352c0b62..7984c2fd879 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -412,9 +412,7 @@ void WM_init_splash(bContext *C) /* free strings of open recent files */ static void free_openrecent(void) { - struct RecentFile *recent; - - for (recent = G.recent_files.first; recent; recent = recent->next) { + LISTBASE_FOREACH (RecentFile *, recent, &G.recent_files) { MEM_freeN(recent->filepath); } diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index a1140c01d44..443a6fd1979 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -222,10 +222,8 @@ wmJob *WM_jobs_get( /* returns true if job runs, for UI (progress) indicators */ bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type) { - wmJob *wm_job; - /* job can be running or about to run (suspended) */ - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { if (wm_job->owner == owner) { if (ELEM(job_type, WM_JOB_TYPE_ANY, wm_job->job_type)) { if (wm_job->running || wm_job->suspended) { @@ -266,17 +264,14 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm) /* if there are running jobs, set the global progress indicator */ if (jobs_progress > 0) { - wmWindow *win; float progress = total_progress / (float)jobs_progress; - for (win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { WM_progress_set(win, progress); } } else { - wmWindow *win; - - for (win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { WM_progress_clear(win); } } @@ -400,7 +395,6 @@ static void *do_job_thread(void *job_v) /* don't allow same startjob to be executed twice */ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) { - wmJob *wm_job; bool suspend = false; /* job added with suspend flag, we wait 1 timer step before activating it */ @@ -410,7 +404,7 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) } else { /* check other jobs */ - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { /* obvious case, no test needed */ if (wm_job == test || !wm_job->running) { continue; @@ -568,11 +562,7 @@ void WM_jobs_kill_all(wmWindowManager *wm) /* wait until every job ended, except for one owner (used in undo to keep screen job alive) */ void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner) { - wmJob *wm_job, *next_job; - - for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) { - next_job = wm_job->next; - + LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) { if (wm_job->owner != owner) { wm_jobs_kill_job(wm, wm_job); } @@ -581,11 +571,7 @@ void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner) void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type) { - wmJob *wm_job, *next_job; - - for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) { - next_job = wm_job->next; - + LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) { if (!owner || wm_job->owner == owner) { if (ELEM(job_type, WM_JOB_TYPE_ANY, wm_job->job_type)) { wm_jobs_kill_job(wm, wm_job); @@ -597,9 +583,7 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type) /* signal job(s) from this owner or callback to stop, timer is required to get handled */ void WM_jobs_stop(wmWindowManager *wm, void *owner, void *startjob) { - wmJob *wm_job; - - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { if (wm_job->owner == owner || wm_job->startjob == startjob) { if (wm_job->running) { wm_job->stop = true; @@ -613,17 +597,9 @@ void WM_jobs_kill(wmWindowManager *wm, void *owner, void (*startjob)(void *, short int *, short int *, float *)) { - wmJob *wm_job; - - wm_job = wm->jobs.first; - while (wm_job) { + LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) { if (wm_job->owner == owner || wm_job->startjob == startjob) { - wmJob *wm_job_kill = wm_job; - wm_job = wm_job->next; - wm_jobs_kill_job(wm, wm_job_kill); - } - else { - wm_job = wm_job->next; + wm_jobs_kill_job(wm, wm_job); } } } @@ -631,9 +607,7 @@ void WM_jobs_kill(wmWindowManager *wm, /* kill job entirely, also removes timer itself */ void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt) { - wmJob *wm_job; - - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { if (wm_job->wt == wt) { wm_jobs_kill_job(wm, wm_job); return; @@ -644,13 +618,8 @@ void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt) /* hardcoded to event TIMERJOBS */ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt) { - wmJob *wm_job, *wm_jobnext; - - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_jobnext) { - wm_jobnext = wm_job->next; - + LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) { if (wm_job->wt == wt) { - /* running threads */ if (wm_job->threads.first) { @@ -735,9 +704,7 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt) bool WM_jobs_has_running(wmWindowManager *wm) { - wmJob *wm_job; - - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { if (wm_job->running) { return true; } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 1daab07812d..1f730be8c82 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -392,8 +392,6 @@ static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid) static wmKeyMap *wm_keymap_copy(wmKeyMap *keymap) { wmKeyMap *keymapn = MEM_dupallocN(keymap); - wmKeyMapItem *kmi, *kmin; - wmKeyMapDiffItem *kmdi, *kmdin; keymapn->modal_items = keymap->modal_items; keymapn->poll = keymap->poll; @@ -401,14 +399,14 @@ static wmKeyMap *wm_keymap_copy(wmKeyMap *keymap) BLI_listbase_clear(&keymapn->items); keymapn->flag &= ~(KEYMAP_UPDATE | KEYMAP_EXPANDED); - for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) { - kmdin = wm_keymap_diff_item_copy(kmdi); - BLI_addtail(&keymapn->items, kmdin); + LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) { + wmKeyMapDiffItem *kmdi_new = wm_keymap_diff_item_copy(kmdi); + BLI_addtail(&keymapn->items, kmdi_new); } - for (kmi = keymap->items.first; kmi; kmi = kmi->next) { - kmin = wm_keymap_item_copy(kmi); - BLI_addtail(&keymapn->items, kmin); + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { + wmKeyMapItem *kmi_new = wm_keymap_item_copy(kmi); + BLI_addtail(&keymapn->items, kmi_new); } return keymapn; @@ -416,14 +414,11 @@ static wmKeyMap *wm_keymap_copy(wmKeyMap *keymap) void WM_keymap_clear(wmKeyMap *keymap) { - wmKeyMapItem *kmi; - wmKeyMapDiffItem *kmdi; - - for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) { + LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) { wm_keymap_diff_item_free(kmdi); } - for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { wm_keymap_item_free(kmi); } @@ -558,20 +553,16 @@ bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) static void wm_keymap_addon_add(wmKeyMap *keymap, wmKeyMap *addonmap) { - wmKeyMapItem *kmi, *kmin; - - for (kmi = addonmap->items.first; kmi; kmi = kmi->next) { - kmin = wm_keymap_item_copy(kmi); - keymap_item_set_id(keymap, kmin); - BLI_addhead(&keymap->items, kmin); + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &addonmap->items) { + wmKeyMapItem *kmi_new = wm_keymap_item_copy(kmi); + keymap_item_set_id(keymap, kmi_new); + BLI_addhead(&keymap->items, kmi_new); } } static wmKeyMapItem *wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *needle) { - wmKeyMapItem *kmi; - - for (kmi = km->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) { if (wm_keymap_item_equals(kmi, needle)) { return kmi; } @@ -582,9 +573,7 @@ static wmKeyMapItem *wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *need static wmKeyMapItem *wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapItem *needle) { - wmKeyMapItem *kmi; - - for (kmi = km->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) { if (wm_keymap_item_equals_result(kmi, needle)) { return kmi; } @@ -596,21 +585,18 @@ static wmKeyMapItem *wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapIte static void wm_keymap_diff( wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km, wmKeyMap *orig_km, wmKeyMap *addon_km) { - wmKeyMapItem *kmi, *to_kmi, *orig_kmi; - wmKeyMapDiffItem *kmdi; - - for (kmi = from_km->items.first; kmi; kmi = kmi->next) { - to_kmi = WM_keymap_item_find_id(to_km, kmi->id); + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &from_km->items) { + wmKeyMapItem *to_kmi = WM_keymap_item_find_id(to_km, kmi->id); if (!to_kmi) { /* remove item */ - kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"); + wmKeyMapDiffItem *kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"); kmdi->remove_item = wm_keymap_item_copy(kmi); BLI_addtail(&diff_km->diff_items, kmdi); } else if (to_kmi && !wm_keymap_item_equals(kmi, to_kmi)) { /* replace item */ - kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"); + wmKeyMapDiffItem *kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"); kmdi->remove_item = wm_keymap_item_copy(kmi); kmdi->add_item = wm_keymap_item_copy(to_kmi); BLI_addtail(&diff_km->diff_items, kmdi); @@ -618,7 +604,7 @@ static void wm_keymap_diff( /* sync expanded flag back to original so we don't lose it on repatch */ if (to_kmi) { - orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id); + wmKeyMapItem *orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id); if (!orig_kmi && addon_km) { orig_kmi = wm_keymap_find_item_equals(addon_km, kmi); @@ -631,10 +617,10 @@ static void wm_keymap_diff( } } - for (kmi = to_km->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &to_km->items) { if (kmi->id < 0) { /* add item */ - kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"); + wmKeyMapDiffItem *kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"); kmdi->add_item = wm_keymap_item_copy(kmi); BLI_addtail(&diff_km->diff_items, kmdi); } @@ -643,12 +629,9 @@ static void wm_keymap_diff( static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km) { - wmKeyMapDiffItem *kmdi; - wmKeyMapItem *kmi_remove, *kmi_add; - - for (kmdi = diff_km->diff_items.first; kmdi; kmdi = kmdi->next) { + LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &diff_km->diff_items) { /* find item to remove */ - kmi_remove = NULL; + wmKeyMapItem *kmi_remove = NULL; if (kmdi->remove_item) { kmi_remove = wm_keymap_find_item_equals(km, kmdi->remove_item); if (!kmi_remove) { @@ -660,7 +643,7 @@ static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km) if (kmdi->add_item) { /* Do not re-add an already existing keymap item! See T42088. */ /* We seek only for exact copy here! See T42137. */ - kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item); + wmKeyMapItem *kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item); /** If kmi_add is same as kmi_remove (can happen in some cases, * typically when we got kmi_remove from #wm_keymap_find_item_equals_result()), @@ -712,11 +695,11 @@ static wmKeyMap *wm_keymap_patch_update(ListBase *lb, wmKeyMap *addonmap, wmKeyMap *usermap) { - wmKeyMap *km; int expanded = 0; /* remove previous keymap in list, we will replace it */ - km = WM_keymap_list_find(lb, defaultmap->idname, defaultmap->spaceid, defaultmap->regionid); + wmKeyMap *km = WM_keymap_list_find( + lb, defaultmap->idname, defaultmap->spaceid, defaultmap->regionid); if (km) { expanded = (km->flag & (KEYMAP_EXPANDED | KEYMAP_CHILDREN_EXPANDED)); WM_keymap_clear(km); @@ -727,13 +710,12 @@ static wmKeyMap *wm_keymap_patch_update(ListBase *lb, if (usermap && !(usermap->flag & KEYMAP_DIFF)) { /* for compatibility with old user preferences with non-diff * keymaps we override the original entirely */ - wmKeyMapItem *kmi, *orig_kmi; km = wm_keymap_copy(usermap); /* try to find corresponding id's for items */ - for (kmi = km->items.first; kmi; kmi = kmi->next) { - orig_kmi = wm_keymap_find_item_equals(defaultmap, kmi); + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) { + wmKeyMapItem *orig_kmi = wm_keymap_find_item_equals(defaultmap, kmi); if (!orig_kmi) { orig_kmi = wm_keymap_find_item_equals_result(defaultmap, kmi); } @@ -779,10 +761,8 @@ static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *addonmap, wmKeyMap *km) { - wmKeyMap *diffmap, *prevmap, *origmap; - /* create temporary default + addon keymap for diff */ - origmap = defaultmap; + wmKeyMap *origmap = defaultmap; if (addonmap) { defaultmap = wm_keymap_copy(defaultmap); @@ -790,14 +770,14 @@ static void wm_keymap_diff_update(ListBase *lb, } /* remove previous diff keymap in list, we will replace it */ - prevmap = WM_keymap_list_find(lb, km->idname, km->spaceid, km->regionid); + wmKeyMap *prevmap = WM_keymap_list_find(lb, km->idname, km->spaceid, km->regionid); if (prevmap) { WM_keymap_clear(prevmap); BLI_freelinkN(lb, prevmap); } /* create diff keymap */ - diffmap = wm_keymap_new(km->idname, km->spaceid, km->regionid); + wmKeyMap *diffmap = wm_keymap_new(km->idname, km->spaceid, km->regionid); diffmap->flag |= KEYMAP_DIFF; if (defaultmap->flag & KEYMAP_MODAL) { diffmap->flag |= KEYMAP_MODAL; @@ -833,9 +813,7 @@ static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid) { - wmKeyMap *km; - - for (km = lb->first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, lb) { if (km->spaceid == spaceid && km->regionid == regionid) { if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) { return km; @@ -851,9 +829,7 @@ wmKeyMap *WM_keymap_list_find_spaceid_or_empty(ListBase *lb, int spaceid, int regionid) { - wmKeyMap *km; - - for (km = lb->first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, lb) { if (ELEM(km->spaceid, spaceid, SPACE_EMPTY) && km->regionid == regionid) { if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) { return km; @@ -928,17 +904,16 @@ wmKeyMap *WM_modalkeymap_ensure(wmKeyConfig *keyconf, wmKeyMap *WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname) { - wmKeyMap *km; - - for (km = keyconf->keymaps.first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) { if (km->flag & KEYMAP_MODAL) { if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) { + return km; break; } } } - return km; + return NULL; } wmKeyMapItem *WM_modalkeymap_add_item( @@ -1015,17 +990,13 @@ static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km) { /* here we convert propvalue string values delayed, due to python keymaps * being created before the actual modal keymaps, so no modal_items */ - wmKeyMap *defaultkm; - wmKeyMapItem *kmi; - int propvalue; if (km && (km->flag & KEYMAP_MODAL) && !km->modal_items) { if (wm->defaultconf == NULL) { return; } - defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0); - + wmKeyMap *defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0); if (!defaultkm) { return; } @@ -1035,8 +1006,9 @@ static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km) km->poll_modal_item = defaultkm->poll_modal_item; if (km->modal_items) { - for (kmi = km->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) { if (kmi->propvalue_str[0]) { + int propvalue; if (RNA_enum_value_from_id(km->modal_items, kmi->propvalue_str, &propvalue)) { kmi->propvalue = propvalue; } @@ -1510,8 +1482,6 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const struct wmKeyMapItemFind_Params *params, wmKeyMap **r_keymap) { - wmKeyMapItem *found; - /* XXX Hack! Macro operators in menu entry have their whole props defined, * which is not the case for relevant keymap entries. * Could be good to check and harmonize this, @@ -1521,7 +1491,8 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0); } - found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, params, r_keymap); + wmKeyMapItem *found = wm_keymap_item_find_props( + C, opname, opcontext, properties, is_strict, params, r_keymap); /* This block is *only* useful in one case: when op uses an enum menu in its prop member * (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle, @@ -1556,8 +1527,6 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, /* Debug only, helps spotting mismatches between menu entries and shortcuts! */ if (G.debug & G_DEBUG_WM) { if (!found && is_strict && properties) { - wmKeyMap *km; - wmKeyMapItem *kmi; if (ot) { /* make a copy of the properties and set unset ones to their default values. */ PointerRNA opptr; @@ -1566,7 +1535,8 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, RNA_pointer_create(NULL, ot->srna, properties_default, &opptr); WM_operator_properties_default(&opptr, true); - kmi = wm_keymap_item_find_props( + wmKeyMap *km; + wmKeyMapItem *kmi = wm_keymap_item_find_props( C, opname, opcontext, properties_default, is_strict, params, &km); if (kmi) { char kmi_str[128]; @@ -1687,15 +1657,13 @@ wmKeyMapItem *WM_key_event_operator_from_keymap(wmKeyMap *keymap, bool WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2) { - int k1type, k2type; - if (k1->flag & KMI_INACTIVE || k2->flag & KMI_INACTIVE) { return 0; } /* take event mapping into account */ - k1type = WM_userdef_event_map(k1->type); - k2type = WM_userdef_event_map(k2->type); + int k1type = WM_userdef_event_map(k1->type); + int k2type = WM_userdef_event_map(k2->type); if (k1type != KM_ANY && k2type != KM_ANY && k1type != k2type) { return 0; @@ -1777,13 +1745,10 @@ void WM_keyconfig_update_operatortype(void) static bool wm_keymap_test_and_clear_update(wmKeyMap *km) { - wmKeyMapItem *kmi; - int update; - - update = (km->flag & KEYMAP_UPDATE); + int update = (km->flag & KEYMAP_UPDATE); km->flag &= ~KEYMAP_UPDATE; - for (kmi = km->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) { update = update || (kmi->flag & KMI_UPDATE); kmi->flag &= ~KMI_UPDATE; } @@ -1794,9 +1759,7 @@ static bool wm_keymap_test_and_clear_update(wmKeyMap *km) static wmKeyMap *wm_keymap_preset(wmWindowManager *wm, wmKeyMap *km) { wmKeyConfig *keyconf = WM_keyconfig_active(wm); - wmKeyMap *keymap; - - keymap = WM_keymap_list_find(&keyconf->keymaps, km->idname, km->spaceid, km->regionid); + wmKeyMap *keymap = WM_keymap_list_find(&keyconf->keymaps, km->idname, km->spaceid, km->regionid); if (!keymap && wm->defaultconf) { keymap = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, km->spaceid, km->regionid); } @@ -1806,9 +1769,6 @@ static wmKeyMap *wm_keymap_preset(wmWindowManager *wm, wmKeyMap *km) void WM_keyconfig_update(wmWindowManager *wm) { - wmKeyMap *km, *defaultmap, *addonmap, *usermap, *kmn; - wmKeyMapItem *kmi; - wmKeyMapDiffItem *kmdi; bool compat_update = false; if (G.background) { @@ -1822,8 +1782,6 @@ void WM_keyconfig_update(wmWindowManager *wm) if (wm_keymap_update_flag & WM_KEYMAP_UPDATE_OPERATORTYPE) { /* an operatortype has been removed, this wont happen often * but when it does we have to check _every_ keymap item */ - wmKeyConfig *kc; - ListBase *keymaps_lb[] = { &U.user_keymaps, &wm->userconf->keymaps, @@ -1838,7 +1796,7 @@ void WM_keyconfig_update(wmWindowManager *wm) wm_keymap_item_properties_update_ot_from_list(keymaps_lb[i]); } - for (kc = wm->keyconfigs.first; kc; kc = kc->next) { + LISTBASE_FOREACH (wmKeyConfig *, kc, &wm->keyconfigs) { wm_keymap_item_properties_update_ot_from_list(&kc->keymaps); } @@ -1850,9 +1808,9 @@ void WM_keyconfig_update(wmWindowManager *wm) } /* update operator properties for non-modal user keymaps */ - for (km = U.user_keymaps.first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, &U.user_keymaps) { if ((km->flag & KEYMAP_MODAL) == 0) { - for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) { + LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) { if (kmdi->add_item) { wm_keymap_item_properties_set(kmdi->add_item); } @@ -1861,19 +1819,19 @@ void WM_keyconfig_update(wmWindowManager *wm) } } - for (kmi = km->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) { wm_keymap_item_properties_set(kmi); } } } /* update U.user_keymaps with user key configuration changes */ - for (km = wm->userconf->keymaps.first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, &wm->userconf->keymaps) { /* only diff if the user keymap was modified */ if (wm_keymap_test_and_clear_update(km)) { /* find keymaps */ - defaultmap = wm_keymap_preset(wm, km); - addonmap = WM_keymap_list_find( + wmKeyMap *defaultmap = wm_keymap_preset(wm, km); + wmKeyMap *addonmap = WM_keymap_list_find( &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid); /* diff */ @@ -1884,18 +1842,20 @@ void WM_keyconfig_update(wmWindowManager *wm) } /* create user key configuration from preset + addon + user preferences */ - for (km = wm->defaultconf->keymaps.first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, &wm->defaultconf->keymaps) { /* find keymaps */ - defaultmap = wm_keymap_preset(wm, km); - addonmap = WM_keymap_list_find(&wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid); - usermap = WM_keymap_list_find(&U.user_keymaps, km->idname, km->spaceid, km->regionid); + wmKeyMap *defaultmap = wm_keymap_preset(wm, km); + wmKeyMap *addonmap = WM_keymap_list_find( + &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid); + wmKeyMap *usermap = WM_keymap_list_find( + &U.user_keymaps, km->idname, km->spaceid, km->regionid); /* For now only the default map defines modal key-maps, * if we support modal keymaps for 'addonmap', these will need to be enabled too. */ wm_user_modal_keymap_set_items(wm, defaultmap); /* add */ - kmn = wm_keymap_patch_update(&wm->userconf->keymaps, defaultmap, addonmap, usermap); + wmKeyMap *kmn = wm_keymap_patch_update(&wm->userconf->keymaps, defaultmap, addonmap, usermap); if (kmn) { kmn->modal_items = km->modal_items; @@ -1928,14 +1888,12 @@ void WM_keyconfig_update(wmWindowManager *wm) wmKeyMap *WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap) { - wmKeyMap *km; - if (!keymap) { return NULL; } /* first user defined keymaps */ - km = WM_keymap_list_find( + wmKeyMap *km = WM_keymap_list_find( &wm->userconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid); if (km) { @@ -1955,16 +1913,13 @@ wmKeyMap *WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap) void WM_keymap_item_restore_to_default(wmWindowManager *wm, wmKeyMap *keymap, wmKeyMapItem *kmi) { - wmKeyMap *defaultmap, *addonmap; - wmKeyMapItem *orig; - if (!keymap) { return; } /* construct default keymap from preset + addons */ - defaultmap = wm_keymap_preset(wm, keymap); - addonmap = WM_keymap_list_find( + wmKeyMap *defaultmap = wm_keymap_preset(wm, keymap); + wmKeyMap *addonmap = WM_keymap_list_find( &wm->addonconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid); if (addonmap) { @@ -1973,7 +1928,7 @@ void WM_keymap_item_restore_to_default(wmWindowManager *wm, wmKeyMap *keymap, wm } /* find original item */ - orig = WM_keymap_item_find_id(defaultmap, kmi->id); + wmKeyMapItem *orig = WM_keymap_item_find_id(defaultmap, kmi->id); if (orig) { /* restore to original */ @@ -2030,9 +1985,7 @@ void WM_keymap_restore_to_default(wmKeyMap *keymap, wmWindowManager *wm) wmKeyMapItem *WM_keymap_item_find_id(wmKeyMap *keymap, int id) { - wmKeyMapItem *kmi; - - for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if (kmi->id == id) { return kmi; } diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index 7621862708e..4c4fd2b1a8e 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -572,9 +572,7 @@ wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char static void wm_operatortype_free_macro(wmOperatorType *ot) { - wmOperatorTypeMacro *otmacro; - - for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { + LISTBASE_FOREACH (wmOperatorTypeMacro *, otmacro, &ot->macro) { if (otmacro->ptr) { WM_operator_properties_free(otmacro->ptr); MEM_freeN(otmacro->ptr); diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c index 4139574460b..715f72d70cf 100644 --- a/source/blender/windowmanager/intern/wm_surface.c +++ b/source/blender/windowmanager/intern/wm_surface.c @@ -116,8 +116,7 @@ void wm_surfaces_free(void) { wm_surface_clear_drawable(); - for (wmSurface *surf = global_surface_list.first, *surf_next; surf; surf = surf_next) { - surf_next = surf->next; + LISTBASE_FOREACH_MUTABLE (wmSurface *, surf, &global_surface_list) { wm_surface_remove(surf); } -- cgit v1.2.3 From ea37e4ea5a712f637e52ef5972a48920fa7e092f Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 4 Dec 2020 14:46:51 -0600 Subject: Fix incorrect variable name after last commit --- source/blender/windowmanager/intern/wm_event_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 9d118b70e43..ac27862d507 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2249,7 +2249,7 @@ static int wm_handler_fileselect_do(bContext *C, wmWindow *temp_win = NULL; LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - bScreen *screen = WM_window_get_active_screen(temp_win); + bScreen *screen = WM_window_get_active_screen(win); ScrArea *file_area = screen->areabase.first; if (screen->temp && (file_area->spacetype == SPACE_FILE)) { -- cgit v1.2.3 From 1cc0a59be66a1d42ec316e0c29c2e3e184b26f7d Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Wed, 25 Nov 2020 14:55:09 -0700 Subject: Cleanup: Outliner video sequencer display mode No functional changes. Code is ported to C++. Variable names and logic are also improved. Differential Revision: https://developer.blender.org/D9741 --- .../blender/editors/space_outliner/CMakeLists.txt | 1 + .../blender/editors/space_outliner/outliner_tree.c | 97 +--------------- .../editors/space_outliner/tree/tree_display.cc | 2 + .../editors/space_outliner/tree/tree_display.hh | 24 ++++ .../space_outliner/tree/tree_display_sequencer.cc | 122 +++++++++++++++++++++ 5 files changed, 151 insertions(+), 95 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_display_sequencer.cc diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 996570fae25..41e54ee8b86 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC tree/tree_display.cc tree/tree_display_libraries.cc tree/tree_display_view_layer.cc + tree/tree_display_sequencer.cc outliner_intern.h tree/tree_display.h diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 94d55b13073..d3976821f8f 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -80,8 +80,6 @@ #include "RNA_access.h" -#include "SEQ_sequencer.h" - #include "UI_interface.h" #include "outliner_intern.h" @@ -1314,73 +1312,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, } /* ======================================================= */ -/* Sequencer mode tree building */ - -/* Helped function to put duplicate sequence in the same tree. */ -static int need_add_seq_dup(Sequence *seq) -{ - Sequence *p; - - if ((!seq->strip) || (!seq->strip->stripdata)) { - return 1; - } - - /* - * First check backward, if we found a duplicate - * sequence before this, don't need it, just return. - */ - p = seq->prev; - while (p) { - if ((!p->strip) || (!p->strip->stripdata)) { - p = p->prev; - continue; - } - - if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - return 2; - } - p = p->prev; - } - - p = seq->next; - while (p) { - if ((!p->strip) || (!p->strip->stripdata)) { - p = p->next; - continue; - } - - if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - return 0; - } - p = p->next; - } - return 1; -} - -static void outliner_add_seq_dup(SpaceOutliner *space_outliner, - Sequence *seq, - TreeElement *te, - short index) -{ - /* TreeElement *ch; */ /* UNUSED */ - Sequence *p; - - p = seq; - while (p) { - if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { - p = p->next; - continue; - } - - if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - /* ch = */ /* UNUSED */ outliner_add_element( - space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); - } - p = p->next; - } -} - -/* ----------------------------------------------- */ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOutliner *space_outliner) { @@ -2246,32 +2177,8 @@ void outliner_build_tree(Main *mainvar, } } else if (space_outliner->outlinevis == SO_SEQUENCE) { - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - int op; - - if (ed == NULL) { - return; - } - - seq = ed->seqbasep->first; - if (!seq) { - return; - } - - while (seq) { - op = need_add_seq_dup(seq); - if (op == 1) { - /* ten = */ outliner_add_element( - space_outliner, &space_outliner->tree, (void *)seq, NULL, TSE_SEQUENCE, 0); - } - else if (op == 0) { - ten = outliner_add_element( - space_outliner, &space_outliner->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0); - outliner_add_seq_dup(space_outliner, seq, ten, 0); - } - seq = seq->next; - } + /* Ported to new tree-display, should be built there already. */ + BLI_assert(false); } else if (space_outliner->outlinevis == SO_DATA_API) { PointerRNA mainptr; diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index 12599733275..1419295c81c 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -37,6 +37,8 @@ TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutline tree_display = new TreeDisplayLibraries(*space_outliner); break; case SO_SEQUENCE: + tree_display = new TreeDisplaySequencer(*space_outliner); + break; case SO_DATA_API: case SO_ID_ORPHANS: break; diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index a3d9a626d1d..0901451e5d3 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -110,4 +110,28 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay { short id_filter_get() const; }; +/* -------------------------------------------------------------------- */ +/* Video Sequencer Tree-Display */ + +enum SequenceAddOp { + SEQUENCE_DUPLICATE_NOOP = 0, + SEQUENCE_DUPLICATE_ADD, + SEQUENCE_DUPLICATE_NONE +}; + +/** + * \brief Tree-Display for the Video Sequencer display mode + */ +class TreeDisplaySequencer final : public AbstractTreeDisplay { + public: + TreeDisplaySequencer(SpaceOutliner &space_outliner); + + ListBase buildTree(const TreeSourceData &source_data) override; + + private: + TreeElement *add_sequencer_contents() const; + SequenceAddOp need_add_seq_dup(Sequence *seq) const; + void add_seq_dup(Sequence *seq, TreeElement *te, short index) const; +}; + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc new file mode 100644 index 00000000000..486f735be9f --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc @@ -0,0 +1,122 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include + +#include "BLI_listbase.h" +#include "BLI_listbase_wrapper.hh" +#include "BLI_utildefines.h" + +#include "SEQ_sequencer.h" + +#include "../outliner_intern.h" +#include "tree_display.hh" + +namespace blender::ed::outliner { + +/* Convenience/readability. */ +template using List = ListBaseWrapper; + +TreeDisplaySequencer::TreeDisplaySequencer(SpaceOutliner &space_outliner) + : AbstractTreeDisplay(space_outliner) +{ +} + +ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) +{ + ListBase tree = {nullptr}; + + Editing *ed = BKE_sequencer_editing_get(source_data.scene, false); + if (ed == nullptr) { + return tree; + } + + for (Sequence *seq : List(ed->seqbasep)) { + SequenceAddOp op = need_add_seq_dup(seq); + if (op == SEQUENCE_DUPLICATE_NONE) { + outliner_add_element(&space_outliner_, &tree, seq, NULL, TSE_SEQUENCE, 0); + } + else if (op == SEQUENCE_DUPLICATE_ADD) { + TreeElement *te = outliner_add_element( + &space_outliner_, &tree, seq, NULL, TSE_SEQUENCE_DUP, 0); + add_seq_dup(seq, te, 0); + } + } + + return tree; +} + +/* Helped function to put duplicate sequence in the same tree. */ +SequenceAddOp TreeDisplaySequencer::need_add_seq_dup(Sequence *seq) const +{ + if ((!seq->strip) || (!seq->strip->stripdata)) { + return SEQUENCE_DUPLICATE_NONE; + } + + /* + * First check backward, if we found a duplicate + * sequence before this, don't need it, just return. + */ + Sequence *p = seq->prev; + while (p) { + if ((!p->strip) || (!p->strip->stripdata)) { + p = p->prev; + continue; + } + + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + return SEQUENCE_DUPLICATE_NOOP; + } + p = p->prev; + } + + p = seq->next; + while (p) { + if ((!p->strip) || (!p->strip->stripdata)) { + p = p->next; + continue; + } + + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + return SEQUENCE_DUPLICATE_ADD; + } + p = p->next; + } + + return SEQUENCE_DUPLICATE_NONE; +} + +void TreeDisplaySequencer::add_seq_dup(Sequence *seq, TreeElement *te, short index) const +{ + Sequence *p = seq; + while (p) { + if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { + p = p->next; + continue; + } + + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + outliner_add_element(&space_outliner_, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); + } + p = p->next; + } +} + +} // namespace blender::ed::outliner -- cgit v1.2.3 From 1db40c29e5f30f2d8b854f67129d9d44cd844a34 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Thu, 3 Dec 2020 09:46:03 -0700 Subject: Cleanup: Outliner orphan data display mode No functional changes. Code is ported to C++ with additional cleanups to the logic and variable names. Differential Revision: https://developer.blender.org/D9741 --- .../blender/editors/space_outliner/CMakeLists.txt | 1 + .../blender/editors/space_outliner/outliner_tree.c | 55 +----------- .../editors/space_outliner/tree/tree_display.cc | 2 + .../editors/space_outliner/tree/tree_display.hh | 16 ++++ .../space_outliner/tree/tree_display_orphaned.cc | 97 ++++++++++++++++++++++ 5 files changed, 118 insertions(+), 53 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_display_orphaned.cc diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 41e54ee8b86..363e8ed8bb7 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC tree/tree_display_libraries.cc tree/tree_display_view_layer.cc tree/tree_display_sequencer.cc + tree/tree_display_orphaned.cc outliner_intern.h tree/tree_display.h diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index d3976821f8f..f3c982d5995 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1313,58 +1313,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* ======================================================= */ -static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOutliner *space_outliner) -{ - TreeElement *ten; - ListBase *lbarray[MAX_LIBARRAY]; - int a, tot; - short filter_id_type = (space_outliner->filter & SO_FILTER_ID_TYPE) ? - space_outliner->filter_id_type : - 0; - - if (filter_id_type) { - lbarray[0] = which_libbase(mainvar, space_outliner->filter_id_type); - tot = 1; - } - else { - tot = set_listbasepointers(mainvar, lbarray); - } - - for (a = 0; a < tot; a++) { - if (lbarray[a] && lbarray[a]->first) { - ID *id = lbarray[a]->first; - - /* check if there are any data-blocks of this type which are orphans */ - for (; id; id = id->next) { - if (ID_REAL_USERS(id) <= 0) { - break; - } - } - - if (id) { - /* header for this type of data-block */ - if (filter_id_type) { - ten = NULL; - } - else { - ten = outliner_add_element( - space_outliner, &space_outliner->tree, lbarray[a], NULL, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - ten->name = outliner_idcode_to_plural(GS(id->name)); - } - - /* add the orphaned data-blocks - these will not be added with any subtrees attached */ - for (id = lbarray[a]->first; id; id = id->next) { - if (ID_REAL_USERS(id) <= 0) { - outliner_add_element( - space_outliner, (ten) ? &ten->subtree : &space_outliner->tree, id, ten, 0, 0); - } - } - } - } - } -} - BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection) { te->name = BKE_collection_ui_name_get(collection); @@ -2194,7 +2142,8 @@ void outliner_build_tree(Main *mainvar, } } else if (space_outliner->outlinevis == SO_ID_ORPHANS) { - outliner_add_orphaned_datablocks(mainvar, space_outliner); + /* Ported to new tree-display, should be built there already. */ + BLI_assert(false); } else if (space_outliner->outlinevis == SO_VIEW_LAYER) { /* Ported to new tree-display, should be built there already. */ diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index 1419295c81c..bf976d79103 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -40,7 +40,9 @@ TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutline tree_display = new TreeDisplaySequencer(*space_outliner); break; case SO_DATA_API: + break; case SO_ID_ORPHANS: + tree_display = new TreeDisplayIDOrphans(*space_outliner); break; case SO_VIEW_LAYER: tree_display = new TreeDisplayViewLayer(*space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index 0901451e5d3..a933a8d7609 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -134,4 +134,20 @@ class TreeDisplaySequencer final : public AbstractTreeDisplay { void add_seq_dup(Sequence *seq, TreeElement *te, short index) const; }; +/* -------------------------------------------------------------------- */ +/* Orphaned Data Tree-Display */ + +/** + * \brief Tree-Display for the Orphaned Data display mode + */ +class TreeDisplayIDOrphans final : public AbstractTreeDisplay { + public: + TreeDisplayIDOrphans(SpaceOutliner &space_outliner); + + ListBase buildTree(const TreeSourceData &source_data) override; + + private: + bool datablock_has_orphans(ListBase &) const; +}; + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc new file mode 100644 index 00000000000..71c1d344057 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_ID.h" + +#include "BLI_listbase.h" +#include "BLI_listbase_wrapper.hh" +#include "BLI_utildefines.h" + +#include "BKE_main.h" + +#include "../outliner_intern.h" +#include "tree_display.hh" + +namespace blender::ed::outliner { + +/* Convenience/readability. */ +template using List = ListBaseWrapper; + +TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner) + : AbstractTreeDisplay(space_outliner) +{ +} + +ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) +{ + ListBase tree = {nullptr}; + ListBase *lbarray[MAX_LIBARRAY]; + short filter_id_type = (space_outliner_.filter & SO_FILTER_ID_TYPE) ? + space_outliner_.filter_id_type : + 0; + + int tot; + if (filter_id_type) { + lbarray[0] = which_libbase(source_data.bmain, filter_id_type); + tot = 1; + } + else { + tot = set_listbasepointers(source_data.bmain, lbarray); + } + + for (int a = 0; a < tot; a++) { + if (BLI_listbase_is_empty(lbarray[a])) { + continue; + } + if (!datablock_has_orphans(*lbarray[a])) { + continue; + } + + /* Header for this type of data-block. */ + TreeElement *te = nullptr; + if (!filter_id_type) { + ID *id = (ID *)lbarray[a]->first; + te = outliner_add_element(&space_outliner_, &tree, lbarray[a], NULL, TSE_ID_BASE, 0); + te->directdata = lbarray[a]; + te->name = outliner_idcode_to_plural(GS(id->name)); + } + + /* Add the orphaned data-blocks - these will not be added with any subtrees attached. */ + for (ID *id : List(lbarray[a])) { + if (ID_REAL_USERS(id) <= 0) { + outliner_add_element(&space_outliner_, (te) ? &te->subtree : &tree, id, te, 0, 0); + } + } + } + + return tree; +} + +bool TreeDisplayIDOrphans::datablock_has_orphans(ListBase &lb) const +{ + for (ID *id : List(lb)) { + if (ID_REAL_USERS(id) <= 0) { + return true; + } + } + return false; +} + +} // namespace blender::ed::outliner -- cgit v1.2.3 From aaa02984d3978bcf94d9a98d1ac9139d5fbfca2d Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Thu, 3 Dec 2020 10:34:09 -0700 Subject: Cleanup: Outliner scenes display mode No functional changes. The scene display building code has been moved to C++. Differential Revision: https://developer.blender.org/D9741 --- .../blender/editors/space_outliner/CMakeLists.txt | 1 + .../blender/editors/space_outliner/outliner_tree.c | 16 ++---- .../editors/space_outliner/tree/tree_display.cc | 1 + .../editors/space_outliner/tree/tree_display.hh | 13 +++++ .../space_outliner/tree/tree_display_scenes.cc | 63 ++++++++++++++++++++++ 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_display_scenes.cc diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 363e8ed8bb7..6b941eb3e62 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -50,6 +50,7 @@ set(SRC tree/tree_display_view_layer.cc tree/tree_display_sequencer.cc tree/tree_display_orphaned.cc + tree/tree_display_scenes.cc outliner_intern.h tree/tree_display.h diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f3c982d5995..85203d1f4dd 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -2061,7 +2061,7 @@ void outliner_build_tree(Main *mainvar, SpaceOutliner *space_outliner, ARegion *region) { - TreeElement *te = NULL, *ten; + TreeElement *ten; TreeStoreElem *tselem; /* on first view, we open scenes */ int show_opened = !space_outliner->treestore || !BLI_mempool_len(space_outliner->treestore); @@ -2111,18 +2111,8 @@ void outliner_build_tree(Main *mainvar, BLI_assert(false); } else if (space_outliner->outlinevis == SO_SCENES) { - Scene *sce; - for (sce = mainvar->scenes.first; sce; sce = sce->id.next) { - te = outliner_add_element(space_outliner, &space_outliner->tree, sce, NULL, 0, 0); - tselem = TREESTORE(te); - - /* New scene elements open by default */ - if ((sce == scene && show_opened) || !tselem->used) { - tselem->flag &= ~TSE_CLOSED; - } - - outliner_make_object_parent_hierarchy(&te->subtree); - } + /* Ported to new tree-display, should be built there already. */ + BLI_assert(false); } else if (space_outliner->outlinevis == SO_SEQUENCE) { /* Ported to new tree-display, should be built there already. */ diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index bf976d79103..f94c643d2bb 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -32,6 +32,7 @@ TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutline switch (mode) { case SO_SCENES: + tree_display = new TreeDisplayScenes(*space_outliner); break; case SO_LIBRARIES: tree_display = new TreeDisplayLibraries(*space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index a933a8d7609..4a2559d94ab 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -150,4 +150,17 @@ class TreeDisplayIDOrphans final : public AbstractTreeDisplay { bool datablock_has_orphans(ListBase &) const; }; +/* -------------------------------------------------------------------- */ +/* Scenes Tree-Display */ + +/** + * \brief Tree-Display for the Scenes display mode + */ +class TreeDisplayScenes final : public AbstractTreeDisplay { + public: + TreeDisplayScenes(SpaceOutliner &space_outliner); + + ListBase buildTree(const TreeSourceData &source_data) override; +}; + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc new file mode 100644 index 00000000000..c4a5688504d --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase.h" +#include "BLI_listbase_wrapper.hh" +#include "BLI_mempool.h" + +#include "BKE_main.h" + +#include "../outliner_intern.h" +#include "tree_display.hh" + +namespace blender::ed::outliner { + +/* Convenience/readability. */ +template using List = ListBaseWrapper; + +TreeDisplayScenes::TreeDisplayScenes(SpaceOutliner &space_outliner) + : AbstractTreeDisplay(space_outliner) +{ +} + +ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) +{ + /* On first view we open scenes. */ + const int show_opened = !space_outliner_.treestore || + !BLI_mempool_len(space_outliner_.treestore); + ListBase tree = {nullptr}; + + for (ID *id : List(source_data.bmain->scenes)) { + Scene *scene = reinterpret_cast(id); + TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, NULL, 0, 0); + TreeStoreElem *tselem = TREESTORE(te); + + /* New scene elements open by default */ + if ((scene == source_data.scene && show_opened) || !tselem->used) { + tselem->flag &= ~TSE_CLOSED; + } + + outliner_make_object_parent_hierarchy(&te->subtree); + } + + return tree; +} + +} // namespace blender::ed::outliner \ No newline at end of file -- cgit v1.2.3 From 48acf15f9856d6ffcd29cdd8b3a64dd9eb983cd0 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Thu, 3 Dec 2020 10:52:08 -0700 Subject: Cleanup: Outliner Data API display mode No functional changes. Moves the data API display building code to C++. Differential Revision: https://developer.blender.org/D9741 --- .../blender/editors/space_outliner/CMakeLists.txt | 1 + .../blender/editors/space_outliner/outliner_tree.c | 18 +------ .../editors/space_outliner/tree/tree_display.cc | 1 + .../editors/space_outliner/tree/tree_display.hh | 13 +++++ .../space_outliner/tree/tree_display_data.cc | 56 ++++++++++++++++++++++ 5 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_display_data.cc diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 6b941eb3e62..b21b969493a 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -51,6 +51,7 @@ set(SRC tree/tree_display_sequencer.cc tree/tree_display_orphaned.cc tree/tree_display_scenes.cc + tree/tree_display_data.cc outliner_intern.h tree/tree_display.h diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 85203d1f4dd..52f91781967 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -2061,11 +2061,6 @@ void outliner_build_tree(Main *mainvar, SpaceOutliner *space_outliner, ARegion *region) { - TreeElement *ten; - TreeStoreElem *tselem; - /* on first view, we open scenes */ - int show_opened = !space_outliner->treestore || !BLI_mempool_len(space_outliner->treestore); - /* Are we looking for something - we want to tag parents to filter child matches * - NOT in data-blocks view - searching all data-blocks takes way too long to be useful * - this variable is only set once per tree build */ @@ -2119,17 +2114,8 @@ void outliner_build_tree(Main *mainvar, BLI_assert(false); } else if (space_outliner->outlinevis == SO_DATA_API) { - PointerRNA mainptr; - - RNA_main_pointer_create(mainvar, &mainptr); - - ten = outliner_add_element( - space_outliner, &space_outliner->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1); - - if (show_opened) { - tselem = TREESTORE(ten); - tselem->flag &= ~TSE_CLOSED; - } + /* Ported to new tree-display, should be built there already. */ + BLI_assert(false); } else if (space_outliner->outlinevis == SO_ID_ORPHANS) { /* Ported to new tree-display, should be built there already. */ diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index f94c643d2bb..d2070fb9b1c 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -41,6 +41,7 @@ TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutline tree_display = new TreeDisplaySequencer(*space_outliner); break; case SO_DATA_API: + tree_display = new TreeDisplayDataAPI(*space_outliner); break; case SO_ID_ORPHANS: tree_display = new TreeDisplayIDOrphans(*space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index 4a2559d94ab..b6183050e82 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -163,4 +163,17 @@ class TreeDisplayScenes final : public AbstractTreeDisplay { ListBase buildTree(const TreeSourceData &source_data) override; }; +/* -------------------------------------------------------------------- */ +/* Data API Tree-Display */ + +/** + * \brief Tree-Display for the Scenes display mode + */ +class TreeDisplayDataAPI final : public AbstractTreeDisplay { + public: + TreeDisplayDataAPI(SpaceOutliner &space_outliner); + + ListBase buildTree(const TreeSourceData &source_data) override; +}; + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc new file mode 100644 index 00000000000..41ca4f72903 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase.h" +#include "BLI_mempool.h" + +#include "RNA_access.h" + +#include "../outliner_intern.h" +#include "tree_display.hh" + +namespace blender::ed::outliner { + +TreeDisplayDataAPI::TreeDisplayDataAPI(SpaceOutliner &space_outliner) + : AbstractTreeDisplay(space_outliner) +{ +} + +ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data) +{ + ListBase tree = {nullptr}; + + PointerRNA mainptr; + RNA_main_pointer_create(source_data.bmain, &mainptr); + + TreeElement *te = outliner_add_element( + &space_outliner_, &tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1); + + /* On first view open parent data elements */ + const int show_opened = !space_outliner_.treestore || + !BLI_mempool_len(space_outliner_.treestore); + if (show_opened) { + TreeStoreElem *tselem = TREESTORE(te); + tselem->flag &= ~TSE_CLOSED; + } + return tree; +} + +} // namespace blender::ed::outliner -- cgit v1.2.3 From 887a602448286fe57b77046001a72d488415b1b8 Mon Sep 17 00:00:00 2001 From: Nathan Craddock Date: Thu, 3 Dec 2020 10:56:37 -0700 Subject: Cleanup: Finish porting outliner tree building to C++ No functional changes. This is a few minor cleanups to the remaining C code for building the outliner tree after parts have been moved to C++. Differential Revision: https://developer.blender.org/D9741 --- .../blender/editors/space_outliner/outliner_tree.c | 40 ++++------------------ 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 52f91781967..37f748692f9 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -2054,7 +2054,6 @@ static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_ /* Main Tree Building API */ /* Main entry point for building the tree data-structure that the outliner represents. */ -/* TODO: split each mode into its own function? */ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, @@ -2091,40 +2090,13 @@ void outliner_build_tree(Main *mainvar, space_outliner->runtime->tree_display = outliner_tree_display_create(space_outliner->outlinevis, space_outliner); - if (space_outliner->runtime->tree_display) { - TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer}; - space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display, - &source_data); - } - if (space_outliner->runtime->tree_display) { - /* Skip if there's a tree-display that's responsible for adding all elements. */ - } - /* options */ - else if (space_outliner->outlinevis == SO_LIBRARIES) { - /* Ported to new tree-display, should be built there already. */ - BLI_assert(false); - } - else if (space_outliner->outlinevis == SO_SCENES) { - /* Ported to new tree-display, should be built there already. */ - BLI_assert(false); - } - else if (space_outliner->outlinevis == SO_SEQUENCE) { - /* Ported to new tree-display, should be built there already. */ - BLI_assert(false); - } - else if (space_outliner->outlinevis == SO_DATA_API) { - /* Ported to new tree-display, should be built there already. */ - BLI_assert(false); - } - else if (space_outliner->outlinevis == SO_ID_ORPHANS) { - /* Ported to new tree-display, should be built there already. */ - BLI_assert(false); - } - else if (space_outliner->outlinevis == SO_VIEW_LAYER) { - /* Ported to new tree-display, should be built there already. */ - BLI_assert(false); - } + /* All tree displays should be created as sub-classes of AbstractTreeDisplay. */ + BLI_assert(space_outliner->runtime->tree_display != NULL); + + TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer}; + space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display, + &source_data); if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) { outliner_sort(&space_outliner->tree); -- cgit v1.2.3 From 8982a315b76e70ecf244243c3002d46ca73761f8 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sat, 5 Dec 2020 07:48:41 -0500 Subject: Add more timing hooks for boolean. --- source/blender/blenlib/intern/mesh_intersect.cc | 4 ++-- source/blender/bmesh/tools/bmesh_boolean.cc | 20 ++++++++++++++++ source/blender/modifiers/intern/MOD_boolean.c | 32 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc index 64ea25ccc90..ab956c5c735 100644 --- a/source/blender/blenlib/intern/mesh_intersect.cc +++ b/source/blender/blenlib/intern/mesh_intersect.cc @@ -2178,8 +2178,8 @@ static void calc_overlap_itts_range_func(void *__restrict userdata, } /** - * Fill in itt_map with the vector of ITT_values that result from intersecting the triangles in ov. - * Use a canonical order for triangles: (a,b) where a < b. + * Fill in itt_map with the vector of ITT_values that result from intersecting the triangles in + * ov. Use a canonical order for triangles: (a,b) where a < b. */ static void calc_overlap_itts(Map, ITT_value> &itt_map, const IMesh &tm, diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index 6031e160c8c..bfb093c569f 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -30,6 +30,10 @@ #include "bmesh_boolean.h" #include "bmesh_edgesplit.h" +#include "PIL_time.h" + +// #define PERF_DEBUG + namespace blender::meshintersect { #ifdef WITH_GMP @@ -354,7 +358,14 @@ static bool bmesh_boolean(BMesh *bm, { IMeshArena arena; IMesh m_triangulated; +# ifdef PERF_DEBUG + double start_time = PIL_check_seconds_timer(); +# endif IMesh m_in = mesh_from_bm(bm, looptris, looptris_tot, &m_triangulated, &arena); +# ifdef PERF_DEBUG + double mesh_time = PIL_check_seconds_timer(); + std::cout << "bmesh_boolean, imesh_from_bm done, time = " << mesh_time - start_time << "\n"; +# endif std::function shape_fn; if (use_self && boolean_mode == BoolOpType::None) { /* Unary knife operation. Want every face where test_fn doesn't return -1. */ @@ -379,7 +390,16 @@ static bool bmesh_boolean(BMesh *bm, } IMesh m_out = boolean_mesh( m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena); +# ifdef PERF_DEBUG + double boolean_time = PIL_check_seconds_timer(); + std::cout << "boolean done, time = " << boolean_time - mesh_time << "\n"; +# endif bool any_change = apply_mesh_output_to_bmesh(bm, m_out, keep_hidden); +# ifdef PERF_DEBUG + double apply_mesh_time = PIL_check_seconds_timer(); + std::cout << "applied boolean output to bmesh, time = " << apply_mesh_time - boolean_time + << "\n"; +# endif if (use_separate_all) { /* We are supposed to separate all faces that are incident on intersection edges. */ BM_mesh_edgesplit(bm, false, true, false); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 4152e8633e5..0513d3af13a 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -630,7 +630,15 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * Object *operand_ob = bmd->object; +#ifdef DEBUG_TIME + TIMEIT_BLOCK_INIT(operand_get_evaluated_mesh); + TIMEIT_BLOCK_START(operand_get_evaluated_mesh); +#endif mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob, false); +#ifdef DEBUG_TIME + TIMEIT_BLOCK_END(operand_get_evaluated_mesh); + TIMEIT_BLOCK_STATS(operand_get_evaluated_mesh); +#endif if (mesh_operand_ob) { /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh! @@ -642,11 +650,35 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * result = get_quick_mesh(object, mesh, operand_ob, mesh_operand_ob, bmd->operation); if (result == NULL) { +#ifdef DEBUG_TIME + TIMEIT_BLOCK_INIT(object_BMD_mesh_bm_create); + TIMEIT_BLOCK_START(object_BMD_mesh_bm_create); +#endif bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip); +#ifdef DEBUG_TIME + TIMEIT_BLOCK_END(object_BMD_mesh_bm_create); + TIMEIT_BLOCK_STATS(object_BMD_mesh_bm_create); +#endif +#ifdef DEBUG_TIME + TIMEIT_BLOCK_INIT(BMD_mesh_intersection); + TIMEIT_BLOCK_START(BMD_mesh_intersection); +#endif BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); +#ifdef DEBUG_TIME + TIMEIT_BLOCK_END(BMD_mesh_intersection); + TIMEIT_BLOCK_STATS(BMD_mesh_intersection); +#endif +#ifdef DEBUG_TIME + TIMEIT_BLOCK_INIT(BKE_mesh_from_bmesh_for_eval_nomain); + TIMEIT_BLOCK_START(BKE_mesh_from_bmesh_for_eval_nomain); +#endif result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); +#ifdef DEBUG_TIME + TIMEIT_BLOCK_END(BKE_mesh_from_bmesh_for_eval_nomain); + TIMEIT_BLOCK_STATS(BKE_mesh_from_bmesh_for_eval_nomain); +#endif BM_mesh_free(bm); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; } -- cgit v1.2.3 From 237f9da4a0b397f22e356c08c6968f8d2a461a9c Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sat, 5 Dec 2020 13:54:43 +0100 Subject: Fix T83400: GPencil onion skin not visible when Edit Lines is enabled The Edit Lines flag was not checking if Onion was enabled. In 2D template this is disabled by default, but default template has enabled it. --- source/blender/draw/engines/gpencil/gpencil_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 368530fde05..388deec07bf 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -498,7 +498,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, bool hide_onion = gpl && gpf && gpf->runtime.onion_id != 0 && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0); - if (hide_material || (!show_stroke && !show_fill) || only_lines || hide_onion) { + if (hide_material || (!show_stroke && !show_fill) || (only_lines && hide_onion) || hide_onion) { return; } -- cgit v1.2.3 From 52a6c4f34d4aba55bc179aa8df9d33883ea68ed3 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Sat, 5 Dec 2020 14:41:20 +0100 Subject: Fix crashes with invisible Outliners on fullscreen or window closing I didn't actually confirm this is caused by invisible Outliners. But I'm pretty sure the error happens with Outliners that aren't initialized (so were open in an area before, but another editor is active there currently). In that case, the runtime data may not be set yet and that is fine. Fixes T83420. --- source/blender/editors/space_outliner/space_outliner.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 3c6369d3090..3d675fdd9e4 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -414,7 +414,10 @@ static void outliner_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_i changed = true; } } - if (space_outliner->runtime->treehash && changed) { + + /* Note that the Outliner may not be the active editor of the area, and hence not initialized. + * So runtime data might not have been created yet. */ + if (space_outliner->runtime && space_outliner->runtime->treehash && changed) { /* rebuild hash table, because it depends on ids too */ /* postpone a full rebuild because this can be called many times on-free */ space_outliner->storeflag |= SO_TREESTORE_REBUILD; -- cgit v1.2.3 From eb4eb07065e6c9216d64b4e68e534f1d4ace1a96 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sat, 5 Dec 2020 09:16:23 -0500 Subject: Doxygen: Disable HTMLHELP This feature is intended to generate Microsoft Compiled HTML Help files which is not something we use/need. This also fixes an error in generation because the executable cannot be found. --- doc/doxygen/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index ca545eec4ca..c363519cefe 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -1321,7 +1321,7 @@ DOCSET_PUBLISHER_NAME = Publisher # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_HTMLHELP = YES +GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be -- cgit v1.2.3 From 538f41e949de1180b293eade11d2899354c0f6e9 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sat, 5 Dec 2020 09:25:12 -0500 Subject: Doxygen: Increase lookup cache I could not measure any major speedup/memory usage but this resolves a message while running doxygen. --- doc/doxygen/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index c363519cefe..772fac56f63 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -453,7 +453,7 @@ TYPEDEF_HIDES_STRUCT = NO # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. -LOOKUP_CACHE_SIZE = 0 +LOOKUP_CACHE_SIZE = 3 #--------------------------------------------------------------------------- # Build related configuration options -- cgit v1.2.3 From a90504303e78030d5be2c039848d7134a829942f Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sun, 6 Dec 2020 10:58:14 -0500 Subject: Reorder fields in boolean's ITT_value to save memory. --- source/blender/blenlib/intern/mesh_intersect.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc index ab956c5c735..85a6ab42013 100644 --- a/source/blender/blenlib/intern/mesh_intersect.cc +++ b/source/blender/blenlib/intern/mesh_intersect.cc @@ -1055,36 +1055,36 @@ static std::ostream &operator<<(std::ostream &os, const CoplanarClusterInfo &cli enum ITT_value_kind { INONE, IPOINT, ISEGMENT, ICOPLANAR }; struct ITT_value { - enum ITT_value_kind kind; mpq3 p1; /* Only relevant for IPOINT and ISEGMENT kind. */ mpq3 p2; /* Only relevant for ISEGMENT kind. */ int t_source; /* Index of the source triangle that intersected the target one. */ + enum ITT_value_kind kind; - ITT_value() : kind(INONE), t_source(-1) + ITT_value() : t_source(-1), kind(INONE) { } - ITT_value(ITT_value_kind k) : kind(k), t_source(-1) + ITT_value(ITT_value_kind k) : t_source(-1), kind(k) { } - ITT_value(ITT_value_kind k, int tsrc) : kind(k), t_source(tsrc) + ITT_value(ITT_value_kind k, int tsrc) : t_source(tsrc), kind(k) { } - ITT_value(ITT_value_kind k, const mpq3 &p1) : kind(k), p1(p1), t_source(-1) + ITT_value(ITT_value_kind k, const mpq3 &p1) : p1(p1), t_source(-1), kind(k) { } ITT_value(ITT_value_kind k, const mpq3 &p1, const mpq3 &p2) - : kind(k), p1(p1), p2(p2), t_source(-1) + : p1(p1), p2(p2), t_source(-1), kind(k) { } ITT_value(const ITT_value &other) - : kind(other.kind), p1(other.p1), p2(other.p2), t_source(other.t_source) + : p1(other.p1), p2(other.p2), t_source(other.t_source), kind(other.kind) { } ITT_value(ITT_value &&other) noexcept - : kind(other.kind), - p1(std::move(other.p1)), + : p1(std::move(other.p1)), p2(std::move(other.p2)), - t_source(other.t_source) + t_source(other.t_source), + kind(other.kind) { } ~ITT_value() -- cgit v1.2.3 From 79eeabafb39f8771c0f41c46dc8b819097e403cb Mon Sep 17 00:00:00 2001 From: Yevgeny Makarov Date: Sun, 6 Dec 2020 10:29:26 -0800 Subject: UI: 'About Blender' with Full Logo New layout for the 'About' dialog featuring the full version of the Blender logo. Differential Revision: https://developer.blender.org/D9507 Reviewed by Hans Goudey --- release/datafiles/blender_logo.png | Bin 0 -> 19535 bytes release/scripts/startup/bl_operators/wm.py | 43 ++++++------ source/blender/editors/datafiles/CMakeLists.txt | 1 + source/blender/editors/include/ED_datafiles.h | 3 + .../windowmanager/intern/wm_splash_screen.c | 77 +++++++++------------ 5 files changed, 61 insertions(+), 63 deletions(-) create mode 100644 release/datafiles/blender_logo.png diff --git a/release/datafiles/blender_logo.png b/release/datafiles/blender_logo.png new file mode 100644 index 00000000000..17ffef7df5d Binary files /dev/null and b/release/datafiles/blender_logo.png differ diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index bd1ae2ca8e1..387e93cb769 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -31,6 +31,7 @@ from bpy.props import ( IntProperty, StringProperty, ) +from bpy.app.translations import pgettext_iface as iface_ # FIXME, we need a way to detect key repeat events. # unfortunately checking event previous values isn't reliable. @@ -2642,26 +2643,28 @@ class WM_MT_splash_about(Menu): layout = self.layout layout.operator_context = 'EXEC_DEFAULT' - layout.label(text="Blender is free software") - layout.label(text="Licensed under the GNU General Public License") - layout.separator() - layout.separator() - - split = layout.split() - split.emboss = 'PULLDOWN_MENU' - split.scale_y = 1.3 - - col1 = split.column() - - col1.operator("wm.url_open_preset", text="Release Notes", icon='URL').type = 'RELEASE_NOTES' - col1.operator("wm.url_open_preset", text="Credits", icon='URL').type = 'CREDITS' - col1.operator("wm.url_open", text="License", icon='URL').url = "https://www.blender.org/about/license/" - - col2 = split.column() - - col2.operator("wm.url_open_preset", text="Blender Website", icon='URL').type = 'BLENDER' - col2.operator("wm.url_open", text="Blender Store", icon='URL').url = "https://store.blender.org" - col2.operator("wm.url_open_preset", text="Development Fund", icon='FUND').type = 'FUND' + split = layout.split(factor=0.65) + + col = split.column(align=True) + col.scale_y = 0.8 + col.label(text=bpy.app.version_string, translate=False) + col.separator(factor=2.5) + col.label(text=iface_("Date: %s %s") % (bpy.app.build_commit_date.decode('utf-8', 'replace'), + bpy.app.build_commit_time.decode('utf-8', 'replace')), translate=False) + col.label(text=iface_("Hash: %s") % bpy.app.build_hash.decode('ascii'), translate=False) + col.label(text=iface_("Branch: %s") % bpy.app.build_branch.decode('utf-8', 'replace'), translate=False) + col.separator(factor=2.0) + col.label(text="Blender is free software") + col.label(text="Licensed under the GNU General Public License") + + col = split.column(align=True) + col.emboss = 'PULLDOWN_MENU' + col.operator("wm.url_open_preset", text="Release Notes", icon='URL').type = 'RELEASE_NOTES' + col.operator("wm.url_open_preset", text="Credits", icon='URL').type = 'CREDITS' + col.operator("wm.url_open", text="License", icon='URL').url = "https://www.blender.org/about/license/" + col.operator("wm.url_open_preset", text="Blender Website", icon='URL').type = 'BLENDER' + col.operator("wm.url_open", text="Blender Store", icon='URL').url = "https://store.blender.org" + col.operator("wm.url_open_preset", text="Development Fund", icon='FUND').type = 'FUND' class WM_OT_drop_blend_file(Operator): diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index e374010cf44..337fb18f835 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -791,6 +791,7 @@ if(WITH_BLENDER) # images data_to_c_simple(../../../../release/datafiles/splash.png SRC) data_to_c_simple(../../../../release/datafiles/alert_icons.png SRC) + data_to_c_simple(../../../../release/datafiles/blender_logo.png SRC) # XXX These are handy, but give nasty "false changes" in svn :/ # svg_to_png(../../../../release/datafiles/blender_icons.svg # ../../../../release/datafiles/blender_icons16.png diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index ba77da24406..40b0a8d96b1 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -50,6 +50,9 @@ extern char datatoc_prvicons_png[]; extern int datatoc_alert_icons_png_size; extern char datatoc_alert_icons_png[]; +extern int datatoc_blender_logo_png_size; +extern char datatoc_blender_logo_png[]; + extern int datatoc_splash_png_size; extern char datatoc_splash_png[]; diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index d732393b631..a3619a69152 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -256,71 +256,62 @@ void WM_OT_splash(wmOperatorType *ot) static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED(arg)) { const uiStyle *style = UI_style_get_dpi(); - const short logo_size = 128 * U.dpi_fac; const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); - const int dialog_width = logo_size + (text_points_max * 32 * U.dpi_fac); - - /* Calculate icon column factor. */ - const float split_factor = (float)logo_size / (float)(dialog_width - style->columnspace); + const int dialog_width = text_points_max * 42 * U.dpi_fac; uiBlock *block = UI_block_begin(C, region, "about", UI_EMBOSS); - UI_block_flag_enable( - block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - UI_block_emboss_set(block, UI_EMBOSS); - uiLayout *block_layout = UI_block_layout( + uiLayout *layout = UI_block_layout( block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style); - /* Split layout to put Blender logo on left side. */ - uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false); - - /* Blender Logo. */ - uiLayout *layout = uiLayoutColumn(split_block, false); - uiDefButAlert(block, ALERT_ICON_BLENDER, 0, 0, 0, logo_size); - - /* The rest of the content on the right. */ - layout = uiLayoutColumn(split_block, false); - - uiLayoutSetScaleY(layout, 0.7f); - - uiItemS_ex(layout, 1.0f); - - /* Title. */ - uiItemL_ex(layout, "Blender", ICON_NONE, true, false); + /* Blender logo. */ +#ifndef WITH_HEADLESS + extern char datatoc_blender_logo_png[]; + extern int datatoc_blender_logo_png_size; - /* Version. */ - uiItemL(layout, BKE_blender_version_string(), ICON_NONE); + const uchar *blender_logo_data = (const uchar *)datatoc_blender_logo_png; + size_t blender_logo_data_size = datatoc_blender_logo_png_size; + ImBuf *ibuf = IMB_ibImageFromMemory( + blender_logo_data, blender_logo_data_size, IB_rect, NULL, "blender_logo"); - uiItemS_ex(layout, 3.0f); + if (ibuf) { + int width = 0.5 * dialog_width; + int height = (width * ibuf->y) / ibuf->x; -#ifdef WITH_BUILDINFO + IMB_premultiply_alpha(ibuf); + IMB_scaleImBuf(ibuf, width, height); - extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; + bTheme *btheme = UI_GetTheme(); + const uchar *color = btheme->tui.wcol_menu_back.text_sel; - char str_buf[256] = "\0"; - BLI_snprintf(str_buf, sizeof(str_buf), "Date: %s %s", build_commit_date, build_commit_time); - uiItemL(layout, str_buf, ICON_NONE); + /* The top margin. */ + uiLayout *row = uiLayoutRow(layout, false); + uiItemS_ex(row, 0.2f); - BLI_snprintf(str_buf, sizeof(str_buf), "Hash: %s", build_hash); - uiItemL(layout, str_buf, ICON_NONE); + /* The logo image. */ + row = uiLayoutRow(layout, false); + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT); + uiDefButImage(block, ibuf, 0, U.widget_unit, width, height, color); - BLI_snprintf(str_buf, sizeof(str_buf), "Branch: %s", build_branch); - uiItemL(layout, str_buf, ICON_NONE); + /* Padding below the logo. */ + row = uiLayoutRow(layout, false); + uiItemS_ex(row, 2.7f); + } +#endif /* WITH_HEADLESS */ -#endif /* WITH_BUILDINFO */ + uiLayout *col = uiLayoutColumn(layout, true); - uiItemS_ex(layout, 1.5f); + uiItemL_ex(col, N_("Blender"), ICON_NONE, true, false); MenuType *mt = WM_menutype_find("WM_MT_splash_about", true); if (mt) { - UI_menutype_draw(C, mt, layout); + UI_menutype_draw(C, mt, col); } - uiItemS_ex(layout, 2.0f); - - UI_block_bounds_set_centered(block, 14 * U.dpi_fac); + UI_block_bounds_set_centered(block, 22 * U.dpi_fac); return block; } -- cgit v1.2.3 From ee70eb96cf321e8aca2248b96c64680a33c7766f Mon Sep 17 00:00:00 2001 From: Yevgeny Makarov Date: Sun, 6 Dec 2020 11:17:51 -0800 Subject: UI: Alert Dialog Helper Function Shared helper function to create a split layout with an alert icon for popup dialogs. Differential Revision: https://developer.blender.org/D9486 Reviewed by Julian Eisel --- source/blender/editors/include/UI_interface.h | 4 +++ .../blender/editors/interface/interface_layout.c | 42 ++++++++++++++++++++++ source/blender/windowmanager/intern/wm_files.c | 30 +--------------- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a190194d89d..005dbf0e381 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -26,6 +26,7 @@ #include "BLI_compiler_attrs.h" #include "BLI_sys_types.h" /* size_t */ #include "RNA_types.h" +#include "UI_interface_icons.h" #ifdef __cplusplus extern "C" { @@ -2431,6 +2432,9 @@ void uiItemTabsEnumR_prop(uiLayout *layout, /* Only for testing, inspecting layouts. */ const char *UI_layout_introspect(uiLayout *layout); +/* Helper to add a big icon and create a split layout for alert boxes. */ +uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon); + /* UI Operators */ typedef struct uiDragColorHandle { float color[3]; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index d61e80e6505..0403287125c 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -5951,3 +5951,45 @@ const char *UI_layout_introspect(uiLayout *layout) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Alert Box with Big Icon + * \{ */ + +/** + * Helper to add a big icon and create a split layout for alert popups. + * Returns the layout to place further items into the alert box. + */ +uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon) +{ + const uiStyle *style = UI_style_get_dpi(); + const short icon_size = 64 * U.dpi_fac; + const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); + const int dialog_width = icon_size + (text_points_max * size * U.dpi_fac); + /* By default, the space between icon and text/buttons will be equal to the 'columnspace', + this extra padding will add some space by increasing the left column width, + making the icon placement more symmetrical, between the block edge and the text. */ + const float icon_padding = 5.0f * U.dpi_fac; + /* Calculate the factor of the fixed icon column depending on the block width. */ + const float split_factor = ((float)icon_size + icon_padding) / + (float)(dialog_width - style->columnspace); + + uiLayout *block_layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style); + + /* Split layout to put alert icon on left side. */ + uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false); + + /* Alert icon on the left. */ + uiLayout *layout = uiLayoutRow(split_block, false); + /* Using 'align_left' with 'row' avoids stretching the icon along the width of column. */ + uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_LEFT); + uiDefButAlert(block, icon, 0, 0, icon_size, icon_size); + + /* The rest of the content on the right. */ + layout = uiLayoutColumn(split_block, false); + + return layout; +} + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 6ec6f3d9a6f..5b21b2397e7 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -115,7 +115,6 @@ #include "GHOST_Path-api.h" #include "UI_interface.h" -#include "UI_interface_icons.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -3197,40 +3196,13 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, { wmGenericCallback *post_action = (wmGenericCallback *)arg1; Main *bmain = CTX_data_main(C); - const uiStyle *style = UI_style_get_dpi(); - const short icon_size = 64 * U.dpi_fac; - const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); - const int dialog_width = icon_size + (text_points_max * 34 * U.dpi_fac); - - /* By default, the space between icon and text/buttons will be equal to the 'columnspace', - this extra padding will add some space by increasing the left column width, - making the icon placement more symmetrical, between the block edge and the text. */ - const float icon_padding = 6.0f * U.dpi_fac; - /* Calculate icon column factor. */ - const float split_factor = ((float)icon_size + icon_padding) / - (float)(dialog_width - style->columnspace); uiBlock *block = UI_block_begin(C, region, close_file_dialog_name, UI_EMBOSS); - UI_block_flag_enable( block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - UI_block_emboss_set(block, UI_EMBOSS); - - uiLayout *block_layout = UI_block_layout( - block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style); - - /* Split layout to put alert icon on left side. */ - uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false); - - /* Alert Icon. */ - uiLayout *layout = uiLayoutRow(split_block, false); - /* Using 'align_left' with 'row' avoids stretching the icon along the width of column. */ - uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_LEFT); - uiDefButAlert(block, ALERT_ICON_QUESTION, 0, 0, icon_size, icon_size); - /* The rest of the content on the right. */ - layout = uiLayoutColumn(split_block, false); + uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION); /* Title. */ uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false); -- cgit v1.2.3 From 6f22a536e690133f7b7f9e62e6affd58d5ee2b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Barschkis?= Date: Sun, 6 Dec 2020 21:56:43 +0100 Subject: Fluid: Updated Mantaflow source files Includes outflow optimization - might have been the cause of instabilities. --- extern/mantaflow/preprocessed/gitinfo.h | 2 +- extern/mantaflow/preprocessed/plugin/advection.cpp | 8 ++++---- extern/mantaflow/preprocessed/plugin/pressure.cpp | 14 +++----------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index d7a69564a3b..a0590e6a0b0 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit bb7cde47b6e04fa62815c70775dc70f02065599f" +#define MANTA_GIT_VERSION "commit 327917cd59b03bef3a953b5f58fc1637b3a83e01" diff --git a/extern/mantaflow/preprocessed/plugin/advection.cpp b/extern/mantaflow/preprocessed/plugin/advection.cpp index 4ccf33cc362..dd891e22088 100644 --- a/extern/mantaflow/preprocessed/plugin/advection.cpp +++ b/extern/mantaflow/preprocessed/plugin/advection.cpp @@ -1090,8 +1090,8 @@ struct extrapolateVelConvectiveBC : public KernelBase { Real timeStep) const { if (flags.isOutflow(i, j, k)) { - Vec3 bulkVel = getBulkVel(flags, vel, i, j, k); - int dim = flags.is3D() ? 3 : 2; + const Vec3 bulkVel = getBulkVel(flags, vel, i, j, k); + const int dim = flags.is3D() ? 3 : 2; const Vec3i cur = Vec3i(i, j, k); Vec3i low, up, flLow, flUp; int cnt = 0; @@ -1099,8 +1099,8 @@ struct extrapolateVelConvectiveBC : public KernelBase { for (int c = 0; c < dim; c++) { low = up = flLow = flUp = cur; Real factor = timeStep * - max((Real)1.0, bulkVel[c]); // prevent the extrapolated velocity from - // exploding when bulk velocity below 1 + max((Real)1.0, abs(bulkVel[c])); // prevent the extrapolated velocity from + // exploding when bulk velocity below 1 low[c] = flLow[c] = cur[c] - 1; up[c] = flUp[c] = cur[c] + 1; // iterate over bWidth to allow for extrapolation into more distant outflow cells; diff --git a/extern/mantaflow/preprocessed/plugin/pressure.cpp b/extern/mantaflow/preprocessed/plugin/pressure.cpp index dfba8e0082b..1100a58db47 100644 --- a/extern/mantaflow/preprocessed/plugin/pressure.cpp +++ b/extern/mantaflow/preprocessed/plugin/pressure.cpp @@ -1147,26 +1147,18 @@ void solvePressureSystem(Grid &rhs, gcg->setAccuracy(cgAccuracy); gcg->setUseL2Norm(useL2Norm); - int maxIter = 0; + int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4); Grid *pca0 = nullptr, *pca1 = nullptr, *pca2 = nullptr, *pca3 = nullptr; GridMg *pmg = nullptr; // optional preconditioning - if (preconditioner == PcNone || preconditioner == PcMIC) { - maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4); - + if (preconditioner == PcMIC) { pca0 = new Grid(parent); pca1 = new Grid(parent); pca2 = new Grid(parent); pca3 = new Grid(parent); - - gcg->setICPreconditioner(preconditioner == PcMIC ? GridCgInterface::PC_mICP : - GridCgInterface::PC_None, - pca0, - pca1, - pca2, - pca3); + gcg->setICPreconditioner(GridCgInterface::PC_mICP, pca0, pca1, pca2, pca3); } else if (preconditioner == PcMGDynamic || preconditioner == PcMGStatic) { maxIter = 100; -- cgit v1.2.3 From ba740ad2abc678b7832159033215ce27f1e94ac3 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sun, 6 Dec 2020 22:27:20 +0100 Subject: GPencil: Enable Layer Onion Skin by default --- source/blender/blenkernel/intern/gpencil.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 98e83bfb789..f68a390db64 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -671,6 +671,8 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f); /* Default vertex mix. */ gpl->vertex_paint_opacity = 1.0f; + /* Enable onion skin. */ + gpl->onion_flag |= GP_LAYER_ONIONSKIN; } /* auto-name */ -- cgit v1.2.3 From 5c3fa5a42474f0a831bcdef03a60f6a84594ccd9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 7 Dec 2020 13:24:51 +1100 Subject: Cleanup: correct enum type --- source/blender/draw/engines/eevee/eevee_cryptomatte.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 7bf7955eeb4..3d13871946b 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -144,9 +144,9 @@ void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *UNUSED(sldata), const ViewLayer *view_layer = draw_ctx->view_layer; const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer); - eGPUDataFormat format = (num_cryptomatte_layers == 1) ? - GPU_R32F : - (num_cryptomatte_layers == 2) ? GPU_RG32F : GPU_RGBA32F; + eGPUTextureFormat format = (num_cryptomatte_layers == 1) ? + GPU_R32F : + (num_cryptomatte_layers == 2) ? GPU_RG32F : GPU_RGBA32F; const float *viewport_size = DRW_viewport_size_get(); const int buffer_size = viewport_size[0] * viewport_size[1]; @@ -651,4 +651,4 @@ void EEVEE_cryptomatte_free(EEVEE_Data *vedata) EEVEE_PrivateData *g_data = vedata->stl->g_data; MEM_SAFE_FREE(g_data->cryptomatte_accum_buffer); MEM_SAFE_FREE(g_data->cryptomatte_download_buffer); -} \ No newline at end of file +} -- cgit v1.2.3 From fff0032a25710da0fb8497f882c9a24a827d9089 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 7 Dec 2020 13:24:58 +1100 Subject: Cleanup: spelling --- source/blender/blenkernel/intern/tracking_auto.c | 8 ++++---- source/blender/draw/engines/eevee/eevee_cryptomatte.c | 2 +- source/blender/editors/sculpt_paint/sculpt_transform.c | 4 ++-- source/blender/editors/space_outliner/outliner_intern.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 7351372b6c4..d5e878a9a75 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -99,7 +99,7 @@ typedef struct AutoTrackContext { /* True when tracking backwards (from higher frame number to lower frame number.) */ bool is_backwards; - /* Movie clips used during the trackign process. */ + /* Movie clips used during the tracking process. */ int num_clips; AutoTrackClip autotrack_clips[MAX_ACCESSOR_CLIP]; @@ -182,7 +182,7 @@ static void libmv_frame_to_normalized_relative(const float frame_coord[2], /** \} */ /* -------------------------------------------------------------------- */ -/** \name Coversion of markers between Blender's DNA and Libmv. +/** \name Conversion of markers between Blender's DNA and Libmv. * \{ */ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, @@ -704,7 +704,7 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) /* -------------------------------------------------------------------- */ /** \name Context data synchronization. * - * Used to copy trackign result to Blender side, while the trackign is still happening in its + * Used to copy tracking result to Blender side, while the tracking is still happening in its * thread. * * \{ */ @@ -740,7 +740,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context) } BKE_tracking_marker_insert(track, &marker); - /* Insetr disabled marker at the end of tracked segment. + /* Insert disabled marker at the end of tracked segment. * When tracking forward the disabled marker is added at the next frame from the result, * when tracking backwards the marker is added at the previous frame. */ tracking_marker_insert_disabled(track, &marker, context->is_backwards, false); diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 3d13871946b..44ff86b3333 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -25,7 +25,7 @@ * for reference to the cryptomatte specification. * * The challenge with cryptomatte in EEVEE is the merging and sorting of the samples. - * User can enable upto 3 cryptomatte layers (Object, Material and Asset). + * User can enable up to 3 cryptomatte layers (Object, Material and Asset). * * Process * diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index 88585745467..f74d59e1987 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -212,8 +212,8 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob) sculpt_transform_matrices_init( ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats); - /* Regular transform applies all symmetry passes at once as it is split by symmetry areas (each - * vertex can only be transformed once by the transform matix of its area). */ + /* Regular transform applies all symmetry passes at once as it is split by symmetry areas + * (each vertex can only be transformed once by the transform matrix of its area). */ TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode); BLI_task_parallel_range( diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 0b432d932ca..ecf8cc0f800 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -51,8 +51,8 @@ typedef struct SpaceOutliner_Runtime { * Scenes, Blender File, etc.). */ struct TreeDisplay *tree_display; - /** Pointers to treestore elements, grouped by (id, type, nr) - * in hashtable for faster searching */ + /** Pointers to tree-store elements, grouped by `(id, type, nr)` + * in hash-table for faster searching. */ struct GHash *treehash; } SpaceOutliner_Runtime; -- cgit v1.2.3 From c2a01a6c118ed03fa48aa4f537fe9e5cf711b536 Mon Sep 17 00:00:00 2001 From: Greg Neumiller Date: Mon, 7 Dec 2020 13:30:05 +1100 Subject: Fix T83347: Smart UV project crashes with wire edges Missing NULL check. Regression in 9296ba867462f7ff3c55bc0c9129af4121243bed Ref D9757 --- source/blender/editors/uvedit/uvedit_islands.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c index 8a8259d335a..93948b5ae1b 100644 --- a/source/blender/editors/uvedit/uvedit_islands.c +++ b/source/blender/editors/uvedit/uvedit_islands.c @@ -144,18 +144,20 @@ static float (*bm_face_array_calc_unique_uv_coords( BMEdge *e_first = v_pivot->e; const BMEdge *e = e_first; do { - const BMLoop *l_radial = e->l; - do { - if (l_radial->v == l_iter->v) { - if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) { - const MLoopUV *luv_radial = BM_ELEM_CD_GET_VOID_P(l_radial, cd_loop_uv_offset); - if (equals_v2v2(luv->uv, luv_radial->uv)) { - /* Don't add this UV when met in another face in `faces`. */ - BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + if (e->l != NULL) { + const BMLoop *l_radial = e->l; + do { + if (l_radial->v == l_iter->v) { + if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) { + const MLoopUV *luv_radial = BM_ELEM_CD_GET_VOID_P(l_radial, cd_loop_uv_offset); + if (equals_v2v2(luv->uv, luv_radial->uv)) { + /* Don't add this UV when met in another face in `faces`. */ + BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + } } } - } - } while ((l_radial = l_radial->radial_next) != e->l); + } while ((l_radial = l_radial->radial_next) != e->l); + } } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != e_first); } while ((l_iter = l_iter->next) != l_first); } -- cgit v1.2.3 From 3d0b65f89b2ddad5141acb00685885a995fdc9f3 Mon Sep 17 00:00:00 2001 From: Greg Neumiller Date: Mon, 7 Dec 2020 13:32:36 +1100 Subject: Fix T83296: Unknown actions no longer perform an undo push str_len_clip is initialized to 0, so when "Unknown Action" occurs, set str_len_clip appropriately. Regression in 0688309988e546382748b9e755d84ae8a5059192 Ref D9759 --- source/blender/editors/interface/interface_handlers.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 3c028977a36..f914ccd7497 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -838,6 +838,7 @@ static void ui_apply_but_undo(uiBut *but) /* fallback, else we don't get an undo! */ if (str == NULL || str[0] == '\0' || str_len_clip == 0) { str = "Unknown Action"; + str_len_clip = strlen(str); } /* Optionally override undo when undo system doesn't support storing properties. */ -- cgit v1.2.3 From 5baae026a86f7a926a3fca0bd9fecee209ab717c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 7 Dec 2020 07:50:14 +0100 Subject: Cycles: Use Blender Cryptomatte Settings. Blender has now the place to store the Cryptomatte settings. This patch migrates Cycles to use the new settings. Reviewed By: Brecht van Lommel Differential Revision: https://developer.blender.org/D9746 --- intern/cycles/blender/addon/engine.py | 8 +++---- intern/cycles/blender/addon/properties.py | 31 --------------------------- intern/cycles/blender/addon/ui.py | 23 ++------------------ intern/cycles/blender/addon/version_update.py | 12 ++++++++++- intern/cycles/blender/blender_sync.cpp | 10 ++++----- release/scripts/addons | 2 +- 6 files changed, 23 insertions(+), 63 deletions(-) diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 807dcaf7f43..69ad1321c1a 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -270,14 +270,14 @@ def list_render_passes(scene, srl): if crl.use_pass_volume_indirect: yield ("VolumeInd", "RGB", 'COLOR') # Cryptomatte passes. - crypto_depth = (crl.pass_crypto_depth + 1) // 2 - if crl.use_pass_crypto_object: + crypto_depth = (srl.pass_cryptomatte_depth + 1) // 2 + if srl.use_pass_cryptomatte_object: for i in range(0, crypto_depth): yield ("CryptoObject" + '{:02d}'.format(i), "RGBA", 'COLOR') - if crl.use_pass_crypto_material: + if srl.use_pass_cryptomatte_material: for i in range(0, crypto_depth): yield ("CryptoMaterial" + '{:02d}'.format(i), "RGBA", 'COLOR') - if srl.cycles.use_pass_crypto_asset: + if srl.use_pass_cryptomatte_asset: for i in range(0, crypto_depth): yield ("CryptoAsset" + '{:02d}'.format(i), "RGBA", 'COLOR') diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 054fd900419..0d861fde6fc 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1470,37 +1470,6 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): default='RGB_ALBEDO_NORMAL', ) - use_pass_crypto_object: BoolProperty( - name="Cryptomatte Object", - description="Render cryptomatte object pass, for isolating objects in compositing", - default=False, - update=update_render_passes, - ) - use_pass_crypto_material: BoolProperty( - name="Cryptomatte Material", - description="Render cryptomatte material pass, for isolating materials in compositing", - default=False, - update=update_render_passes, - ) - use_pass_crypto_asset: BoolProperty( - name="Cryptomatte Asset", - description="Render cryptomatte asset pass, for isolating groups of objects with the same parent", - default=False, - update=update_render_passes, - ) - pass_crypto_depth: IntProperty( - name="Cryptomatte Levels", - description="Sets how many unique objects can be distinguished per pixel", - default=6, min=2, max=16, step=2, - update=update_render_passes, - ) - pass_crypto_accurate: BoolProperty( - name="Cryptomatte Accurate", - description="Generate a more accurate Cryptomatte pass. CPU only, may render slower and use more memory", - default=True, - update=update_render_passes, - ) - aovs: CollectionProperty( type=CyclesAOVPass, description="Custom render passes that can be output by shader nodes", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 6b88be3e7aa..aecdb3e7572 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -23,6 +23,7 @@ from bl_ui.utils import PresetPanel from bpy.types import Panel from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel +from bl_ui.properties_view_layer import VIEWLAYER_PT_layer_passes_cryptomatte class CYCLES_PT_sampling_presets(PresetPanel, Panel): @@ -885,31 +886,11 @@ class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel): col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion") -class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, Panel): +class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, VIEWLAYER_PT_layer_passes_cryptomatte): bl_label = "Cryptomatte" bl_context = "view_layer" bl_parent_id = "CYCLES_RENDER_PT_passes" - def draw(self, context): - import _cycles - - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - cycles_view_layer = context.view_layer.cycles - - col = layout.column(heading="Include", align=True) - col.prop(cycles_view_layer, "use_pass_crypto_object", text="Object") - col.prop(cycles_view_layer, "use_pass_crypto_material", text="Material") - col.prop(cycles_view_layer, "use_pass_crypto_asset", text="Asset") - - layout.prop(cycles_view_layer, "pass_crypto_depth", text="Levels") - - row = layout.row(align=True) - row.active = use_cpu(context) - row.prop(cycles_view_layer, "pass_crypto_accurate", text="Accurate Mode") - class CYCLES_RENDER_PT_passes_debug(CyclesButtonsPanel, Panel): bl_label = "Debug" diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index f7e3e693858..474d782ddfb 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -108,7 +108,7 @@ def do_versions(self): library_versions.setdefault(library.version, []).append(library) # Do versioning per library, since they might have different versions. - max_need_versioning = (2, 80, 41) + max_need_versioning = (2, 90, 0) for version, libraries in library_versions.items(): if version > max_need_versioning: continue @@ -194,6 +194,16 @@ def do_versions(self): if not cscene.is_property_set("sample_clamp_indirect"): cscene.sample_clamp_indirect = 0.0 + if version <= (2, 91, 0): + if scene.render.engine == 'CYCLES': + for view_layer in scene.view_layers: + cview_layer = view_layer.cycles + view_layer.use_pass_cryptomatte_object = cview_layer.get("use_pass_crypto_object") + view_layer.use_pass_cryptomatte_material = cview_layer.get("use_pass_crypto_material") + view_layer.use_pass_cryptomatte_asset = cview_layer.get("use_pass_crypto_asset") + view_layer.pass_cryptomatte_depth = cview_layer.get("pass_crypto_depth") + view_layer.use_pass_cryptomatte_accurate = cview_layer.get("pass_crypto_accurate") + # Lamps for light in bpy.data.lights: if light.library not in libraries: diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 94ff0ff1473..b830db7485b 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -667,10 +667,10 @@ vector BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, /* Cryptomatte stores two ID/weight pairs per RGBA layer. * User facing parameter is the number of pairs. */ - int crypto_depth = divide_up(min(16, get_int(crl, "pass_crypto_depth")), 2); + int crypto_depth = divide_up(min(16, b_view_layer.pass_cryptomatte_depth()), 2); scene->film->set_cryptomatte_depth(crypto_depth); CryptomatteType cryptomatte_passes = CRYPT_NONE; - if (get_boolean(crl, "use_pass_crypto_object")) { + if (b_view_layer.use_pass_cryptomatte_object()) { for (int i = 0; i < crypto_depth; i++) { string passname = cryptomatte_prefix + string_printf("Object%02d", i); b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); @@ -678,7 +678,7 @@ vector BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT); } - if (get_boolean(crl, "use_pass_crypto_material")) { + if (b_view_layer.use_pass_cryptomatte_material()) { for (int i = 0; i < crypto_depth; i++) { string passname = cryptomatte_prefix + string_printf("Material%02d", i); b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); @@ -686,7 +686,7 @@ vector BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL); } - if (get_boolean(crl, "use_pass_crypto_asset")) { + if (b_view_layer.use_pass_cryptomatte_asset()) { for (int i = 0; i < crypto_depth; i++) { string passname = cryptomatte_prefix + string_printf("Asset%02d", i); b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); @@ -694,7 +694,7 @@ vector BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, } cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET); } - if (get_boolean(crl, "pass_crypto_accurate") && cryptomatte_passes != CRYPT_NONE) { + if (b_view_layer.use_pass_cryptomatte_accurate() && cryptomatte_passes != CRYPT_NONE) { cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ACCURATE); } scene->film->set_cryptomatte_passes(cryptomatte_passes); diff --git a/release/scripts/addons b/release/scripts/addons index 672cfe9c85e..7faa6b379fd 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 672cfe9c85e2ac71b97b5331d9034d23c9723d71 +Subproject commit 7faa6b379fd818b8af8cf8279ff9f43cbdbb169e -- cgit v1.2.3 From 9ac6ef703602ad336b0f41c214285b4deba3ccf4 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 7 Dec 2020 08:07:18 +0100 Subject: File Subversion Bump: 2.92.5 --- intern/cycles/blender/addon/version_update.py | 4 ++-- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_290.c | 25 ++++++++++++---------- .../blender/blenloader/intern/versioning_userdef.c | 15 +++++++------ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 474d782ddfb..053603fa15c 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -108,7 +108,7 @@ def do_versions(self): library_versions.setdefault(library.version, []).append(library) # Do versioning per library, since they might have different versions. - max_need_versioning = (2, 90, 0) + max_need_versioning = (2, 92, 4) for version, libraries in library_versions.items(): if version > max_need_versioning: continue @@ -194,7 +194,7 @@ def do_versions(self): if not cscene.is_property_set("sample_clamp_indirect"): cscene.sample_clamp_indirect = 0.0 - if version <= (2, 91, 0): + if version <= (2, 92, 4): if scene.render.engine == 'CYCLES': for view_layer in scene.view_layers: cview_layer = view_layer.cycles diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9fa32013ba6..2ec9e0048a6 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 4 +#define BLENDER_FILE_SUBVERSION 5 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 99e113f5c36..956cf1aee8a 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1171,17 +1171,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + if (!MAIN_VERSION_ATLEAST(bmain, 292, 5)) { /* Initialize the opacity of the overlay wireframe */ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_opacity")) { for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { @@ -1241,4 +1231,17 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index f9050183dda..1266a0c01f8 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -246,6 +246,15 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_graph.vertex_active); } + if (!USER_VERSION_ATLEAST(292, 5)) { + for (int i = 0; i < COLLECTION_COLOR_TOT; ++i) { + FROM_DEFAULT_V4_UCHAR(collection_color[i].color); + } + FROM_DEFAULT_V4_UCHAR(space_sequencer.row_alternate); + FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_geometry); + FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_attribute); + } + /** * Versioning code until next subversion bump goes here. * @@ -257,12 +266,6 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) */ { /* Keep this block, even when empty. */ - for (int i = 0; i < COLLECTION_COLOR_TOT; ++i) { - FROM_DEFAULT_V4_UCHAR(collection_color[i].color); - } - FROM_DEFAULT_V4_UCHAR(space_sequencer.row_alternate); - FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_geometry); - FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_attribute); } #undef FROM_DEFAULT_V4_UCHAR -- cgit v1.2.3 From 7d2745f8b3bf2db6edcf6af388ef4958ebd2f1b8 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 7 Dec 2020 09:31:05 +0100 Subject: Fix Cryptomatte panel not visible in EEVEE Caused by {rB5baae026a86f} --- intern/cycles/blender/addon/ui.py | 4 ++-- release/scripts/startup/bl_ui/properties_view_layer.py | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index aecdb3e7572..623e5cf9e37 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -23,7 +23,7 @@ from bl_ui.utils import PresetPanel from bpy.types import Panel from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel -from bl_ui.properties_view_layer import VIEWLAYER_PT_layer_passes_cryptomatte +from bl_ui.properties_view_layer import ViewLayerCryptomattePanel class CYCLES_PT_sampling_presets(PresetPanel, Panel): @@ -886,7 +886,7 @@ class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel): col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion") -class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, VIEWLAYER_PT_layer_passes_cryptomatte): +class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, ViewLayerCryptomattePanel): bl_label = "Cryptomatte" bl_context = "view_layer" bl_parent_id = "CYCLES_RENDER_PT_passes" diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index b7aacd0c8be..27df3b10853 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -171,10 +171,8 @@ class VIEWLAYER_PT_layer_passes_aov(ViewLayerButtonsPanel, Panel): layout.label(text="Conflicts with another render pass with the same name", icon='ERROR') -class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerButtonsPanel, Panel): +class ViewLayerCryptomattePanel(ViewLayerButtonsPanel, Panel): bl_label = "Cryptomatte" - bl_parent_id = "VIEWLAYER_PT_layer_passes" - COMPAT_ENGINES = {'BLENDER_EEVEE'} def draw(self, context): layout = self.layout @@ -196,6 +194,11 @@ class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerButtonsPanel, Panel): col.prop(view_layer, "use_pass_cryptomatte_accurate", text="Accurate Mode") +class VIEWLAYER_PT_layer_passes_cryptomatte(ViewLayerCryptomattePanel): + bl_parent_id = "VIEWLAYER_PT_layer_passes" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + classes = ( VIEWLAYER_PT_layer, VIEWLAYER_PT_layer_passes, -- cgit v1.2.3 From 2072134faadf4fd901c88ed7440e2289d61e0299 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 7 Dec 2020 10:57:08 +0100 Subject: UI: Fix mistakes in UI messages. --- release/scripts/modules/bl_i18n_utils/utils_spell_check.py | 6 +++++- source/blender/editors/gpencil/gpencil_edit.c | 2 +- source/blender/editors/sculpt_paint/paint_mask.c | 2 +- source/blender/editors/sculpt_paint/sculpt_pose.c | 2 +- source/blender/editors/space_graph/graph_edit.c | 8 ++++---- source/blender/makesrna/intern/rna_sequencer.c | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index 05985cac868..b1f72408a45 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -80,7 +80,8 @@ class SpellChecker: "autoexecution", "autogenerated", "autolock", - "automasking", + "automask", "automasking", + "automerge", "autoname", "autopack", "autosave", @@ -143,6 +144,7 @@ class SpellChecker: "midlevel", "midground", "mixdown", + "monospaced", "multi", "multifractal", "multiframe", @@ -464,6 +466,7 @@ class SpellChecker: "eigenvectors", "emissive", "equirectangular", + "filmlike", "fisheye", "framerate", "gimbal", @@ -642,6 +645,7 @@ class SpellChecker: "aa", "msaa", "ao", "api", + "apic", # Affine Particle-In-Cell "asc", "cdl", "ascii", "atrac", diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index a183c34fd9d..95c94f8cfed 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3577,7 +3577,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op) if (tot_strokes == max_join_strokes) { BKE_reportf(op->reports, RPT_WARNING, - "Too many strokes selected. Only joined first %d strokes.", + "Too many strokes selected, only joined first %d strokes", max_join_strokes); break; } diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 11d897cf76f..17690757fa5 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -335,7 +335,7 @@ static void sculpt_gesture_operator_properties(wmOperatorType *ot) false, "Limit to Segment", "Apply the gesture action only to the area that is contained within the " - "segement without extending its effect to the entire line"); + "segment without extending its effect to the entire line"); } static void sculpt_gesture_context_init_common(bContext *C, diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index 4b318a05591..1bf9ba60073 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -1197,7 +1197,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot); } - /* Apply segement scale to the transform. */ + /* Apply segment scale to the transform. */ for (int scale_i = 0; scale_i < 3; scale_i++) { mul_v3_fl(ik_chain->segments[i].trans_mat[symm_it][scale_i], ik_chain->segments[i].scale[scale_i]); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 1647fd4a6a6..ae34cd6cf6d 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1903,7 +1903,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) if (curves_seen < 3) { /* Showing the entire error message makes no sense when the artist is only trying to filter * one or two curves. */ - BKE_report(op->reports, RPT_WARNING, "No Euler Rotations could be corrected."); + BKE_report(op->reports, RPT_WARNING, "No Euler Rotations could be corrected"); } else { BKE_report(op->reports, @@ -1919,15 +1919,15 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) BLI_assert(curves_filtered < curves_seen); BKE_reportf(op->reports, RPT_INFO, - "%d of %d rotation channels were filtered. See the Info window for details.", + "%d of %d rotation channels were filtered (see the Info window for details)", curves_filtered, curves_seen); } else if (curves_seen == 1) { - BKE_report(op->reports, RPT_INFO, "The rotation channel was filtered."); + BKE_report(op->reports, RPT_INFO, "The rotation channel was filtered"); } else { - BKE_reportf(op->reports, RPT_INFO, "All %d rotation channels were filtered.", curves_seen); + BKE_reportf(op->reports, RPT_INFO, "All %d rotation channels were filtered", curves_seen); } /* Set notifier that keyframes have changed. */ diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index ac45cd5c5ff..4313b468deb 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1408,7 +1408,7 @@ static void rna_def_strip_transform(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "rotation"); - RNA_def_property_ui_text(prop, "Rotation", "Rotate around image centr"); + RNA_def_property_ui_text(prop, "Rotation", "Rotate around image center"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); RNA_def_struct_path_func(srna, "rna_SequenceTransform_path"); -- cgit v1.2.3 From 11c4066159e12ff630673c5fd94b37fb8c0f9102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 7 Dec 2020 12:21:11 +0100 Subject: Cleanup: partial Clang-Tidy modernize-loop-convert Modernize loops by using the `for(type variable : container)` syntax. Some loops were trivial to fix, whereas others required more attention to avoid semantic changes. I couldn't address all old-style loops, so this commit doesn't enable the `modernize-loop-convert` rule. Although Clang-Tidy's auto-fixer prefers to use `auto` for the loop variable declaration, I made as many declarations as possible explicit. To me this increases local readability, as you don't need to fully understand the container in order to understand the loop variable type. No functional changes. --- .../blenlib/tests/BLI_linklist_lockfree_test.cc | 4 +- .../depsgraph/intern/builder/deg_builder_nodes.cc | 3 +- .../intern/builder/deg_builder_relations.cc | 3 +- source/blender/depsgraph/intern/depsgraph_query.cc | 4 +- source/blender/gpu/intern/gpu_batch.cc | 4 +- source/blender/gpu/intern/gpu_framebuffer.cc | 52 +++++++++++----------- source/blender/gpu/intern/gpu_shader.cc | 6 +-- source/blender/ikplugin/intern/itasc_plugin.cpp | 4 +- source/blender/imbuf/intern/dds/BlockDXT.cpp | 4 +- source/blender/imbuf/intern/dds/ColorBlock.cpp | 16 +++---- .../blender/imbuf/intern/openexr/openexr_api.cpp | 51 +++++++++------------ .../blender/io/alembic/intern/abc_reader_mesh.cc | 4 +- source/blender/io/collada/AnimationImporter.cpp | 9 ++-- source/blender/io/collada/BCMath.cpp | 14 +++--- source/blender/io/collada/BlenderContext.cpp | 4 +- source/blender/io/collada/ControllerExporter.cpp | 14 +++--- source/blender/io/collada/DocumentImporter.cpp | 15 ++----- source/blender/io/collada/MeshImporter.cpp | 11 ++--- source/blender/io/collada/SceneExporter.cpp | 3 +- source/blender/io/collada/collada_internal.cpp | 3 +- source/blender/io/collada/collada_utils.cpp | 12 ++--- 21 files changed, 105 insertions(+), 135 deletions(-) diff --git a/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc b/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc index f2ae121e8ae..e9810aed179 100644 --- a/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc +++ b/source/blender/blenlib/tests/BLI_linklist_lockfree_test.cc @@ -37,8 +37,8 @@ TEST(LockfreeLinkList, InsertMultiple) LockfreeLinkNode nodes[num_nodes]; BLI_linklist_lockfree_init(&list); /* Insert all the nodes. */ - for (int i = 0; i < num_nodes; ++i) { - BLI_linklist_lockfree_insert(&list, &nodes[i]); + for (LockfreeLinkNode &node : nodes) { + BLI_linklist_lockfree_insert(&list, &node); } /* Check head and tail. */ EXPECT_EQ(list.head, &list.dummy_node); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index d71cdea1974..5af70305e13 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1247,8 +1247,7 @@ void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_se &particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); op_node->set_as_exit(); /* Texture slots. */ - for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) { - MTex *mtex = particle_settings->mtex[mtex_index]; + for (MTex *mtex : particle_settings->mtex) { if (mtex == nullptr || mtex->tex == nullptr) { continue; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 3f6aa778b59..11d34782569 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1907,8 +1907,7 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part) particle_settings_init_key, particle_settings_eval_key, "Particle Settings Init Order"); add_relation(particle_settings_reset_key, particle_settings_eval_key, "Particle Settings Reset"); /* Texture slots. */ - for (int mtex_index = 0; mtex_index < MAX_MTEX; mtex_index++) { - MTex *mtex = part->mtex[mtex_index]; + for (MTex *mtex : part->mtex) { if (mtex == nullptr || mtex->tex == nullptr) { continue; } diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 1a334d8a451..57de62e1880 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -90,8 +90,8 @@ bool DEG_id_type_any_updated(const Depsgraph *graph) const deg::Depsgraph *deg_graph = reinterpret_cast(graph); /* Loop over all ID types. */ - for (int id_type_index = 0; id_type_index < MAX_LIBARRAY; id_type_index++) { - if (deg_graph->id_type_updated[id_type_index]) { + for (char id_type_index : deg_graph->id_type_updated) { + if (id_type_index) { return true; } } diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index cdb158572b7..08b2e3c0f00 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -81,8 +81,8 @@ void GPU_batch_init_ex(GPUBatch *batch, for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) { batch->verts[v] = nullptr; } - for (int v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) { - batch->inst[v] = nullptr; + for (auto & v : batch->inst) { + v = nullptr; } batch->elem = elem; batch->prim_type = prim_type; diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index f11f1cea753..d5d7994a154 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -57,18 +57,18 @@ FrameBuffer::FrameBuffer(const char *name) dirty_attachments_ = true; dirty_state_ = true; - for (int i = 0; i < ARRAY_SIZE(attachments_); i++) { - attachments_[i].tex = nullptr; - attachments_[i].mip = -1; - attachments_[i].layer = -1; + for (GPUAttachment &attachment : attachments_) { + attachment.tex = nullptr; + attachment.mip = -1; + attachment.layer = -1; } } FrameBuffer::~FrameBuffer() { - for (int i = 0; i < ARRAY_SIZE(attachments_); i++) { - if (attachments_[i].tex != nullptr) { - reinterpret_cast(attachments_[i].tex)->detach_from(this); + for (GPUAttachment &attachment : attachments_) { + if (attachment.tex != nullptr) { + reinterpret_cast(attachment.tex)->detach_from(this); } } } @@ -148,8 +148,8 @@ void FrameBuffer::recursive_downsample(int max_lvl, for (int mip_lvl = 1; mip_lvl <= max_lvl; mip_lvl++) { /* Replace attached mip-level for each attachment. */ - for (int att = 0; att < ARRAY_SIZE(attachments_); att++) { - Texture *tex = reinterpret_cast(attachments_[att].tex); + for (GPUAttachment &attachment : attachments_) { + Texture *tex = reinterpret_cast(attachment.tex); if (tex != nullptr) { /* Some Intel HDXXX have issue with rendering to a mipmap that is below * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case @@ -158,7 +158,7 @@ void FrameBuffer::recursive_downsample(int max_lvl, /* Restrict fetches only to previous level. */ tex->mip_range_set(mip_lvl - 1, mip_max); /* Bind next level. */ - attachments_[att].mip = mip_lvl; + attachment.mip = mip_lvl; } } /* Update the internal attachments and viewport size. */ @@ -168,12 +168,12 @@ void FrameBuffer::recursive_downsample(int max_lvl, callback(userData, mip_lvl); } - for (int att = 0; att < ARRAY_SIZE(attachments_); att++) { - if (attachments_[att].tex != nullptr) { + for (GPUAttachment &attachment : attachments_) { + if (attachment.tex != nullptr) { /* Reset mipmap level range. */ - reinterpret_cast(attachments_[att].tex)->mip_range_set(0, max_lvl); + reinterpret_cast(attachment.tex)->mip_range_set(0, max_lvl); /* Reset base level. NOTE: might not be the one bound at the start of this function. */ - attachments_[att].mip = 0; + attachment.mip = 0; } } dirty_attachments_ = true; @@ -525,18 +525,18 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) Context *ctx = Context::get(); BLI_assert(ctx); - for (int i = 0; i < MAX_CTX_FB_LEN; i++) { - if (ofs->framebuffers[i].fb == nullptr) { - ofs->framebuffers[i].ctx = ctx; - GPU_framebuffer_ensure_config(&ofs->framebuffers[i].fb, + for (auto &framebuffer : ofs->framebuffers) { + if (framebuffer.fb == nullptr) { + framebuffer.ctx = ctx; + GPU_framebuffer_ensure_config(&framebuffer.fb, { GPU_ATTACHMENT_TEXTURE(ofs->depth), GPU_ATTACHMENT_TEXTURE(ofs->color), }); } - if (ofs->framebuffers[i].ctx == ctx) { - return ofs->framebuffers[i].fb; + if (framebuffer.ctx == ctx) { + return framebuffer.fb; } } @@ -550,9 +550,9 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) "Warning: GPUOffscreen used in more than 3 GPUContext. " "This may create performance drop.\n"); - for (int i = 0; i < MAX_CTX_FB_LEN; i++) { - GPU_framebuffer_free(ofs->framebuffers[i].fb); - ofs->framebuffers[i].fb = nullptr; + for (auto &framebuffer : ofs->framebuffers) { + GPU_framebuffer_free(framebuffer.fb); + framebuffer.fb = nullptr; } return gpu_offscreen_fb_get(ofs); @@ -595,9 +595,9 @@ GPUOffScreen *GPU_offscreen_create( void GPU_offscreen_free(GPUOffScreen *ofs) { - for (int i = 0; i < MAX_CTX_FB_LEN; i++) { - if (ofs->framebuffers[i].fb) { - GPU_framebuffer_free(ofs->framebuffers[i].fb); + for (auto &framebuffer : ofs->framebuffers) { + if (framebuffer.fb) { + GPU_framebuffer_free(framebuffer.fb); } } if (ofs->color) { diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 827ea06686f..d47ad5e0100 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -470,9 +470,9 @@ struct GPUShader *GPU_shader_create_from_arrays_impl( GPUShader *sh = GPU_shader_create( str_dst[0].str, str_dst[1].str, str_dst[2].str, nullptr, str_dst[3].str, name); - for (int i = 0; i < ARRAY_SIZE(str_dst); i++) { - if (str_dst[i].is_alloc) { - MEM_freeN((void *)str_dst[i].str); + for (auto &i : str_dst) { + if (i.is_alloc) { + MEM_freeN((void *)i.str); } } return sh; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 7047b6f3727..c91da839d25 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -194,8 +194,8 @@ struct IK_Scene { { /* delete scene first */ delete scene; - for (std::vector::iterator it = targets.begin(); it != targets.end(); ++it) { - delete (*it); + for (IK_Target *target : targets) { + delete target; } targets.clear(); delete[] channels; diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp index 2d9c300a147..4e4fca864a0 100644 --- a/source/blender/imbuf/intern/dds/BlockDXT.cpp +++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp @@ -608,8 +608,8 @@ void mem_read(Stream &mem, BlockDXT1 &block) void mem_read(Stream &mem, AlphaBlockDXT3 &block) { - for (unsigned int i = 0; i < 4; i++) { - mem_read(mem, block.row[i]); + for (unsigned short &alpha : block.row) { + mem_read(mem, alpha); } } diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp index 7c8b7c1d345..00fa0111d1c 100644 --- a/source/blender/imbuf/intern/dds/ColorBlock.cpp +++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp @@ -150,12 +150,12 @@ static inline uint8 component(Color32 c, uint i) void ColorBlock::swizzle(uint x, uint y, uint z, uint w) { - for (int i = 0; i < 16; i++) { - Color32 c = m_color[i]; - m_color[i].r = component(c, x); - m_color[i].g = component(c, y); - m_color[i].b = component(c, z); - m_color[i].a = component(c, w); + for (Color32 &color : m_color) { + const Color32 c = color; + color.r = component(c, x); + color.g = component(c, y); + color.b = component(c, z); + color.a = component(c, w); } } @@ -243,8 +243,8 @@ Color32 ColorBlock::averageColor() const /** Return true if the block is not fully opaque. */ bool ColorBlock::hasAlpha() const { - for (uint i = 0; i < 16; i++) { - if (m_color[i].a != 255) { + for (const auto &i : m_color) { + if (i.a != 255) { return true; } } diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 087e001b0b3..12faa48c81c 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -733,8 +733,8 @@ static void imb_exr_get_views(MultiPartInputFile &file, StringVector &views) if (exr_has_multipart_file(file) == false) { if (exr_has_multiview(file)) { StringVector sv = multiView(file.header(0)); - for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) { - views.push_back(*i); + for (const std::string &view_name : sv) { + views.push_back(view_name); } } } @@ -991,21 +991,15 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig std::vector channels; GetChannelsInMultiPartFile(*data->ifile, channels); - for (size_t i = 0; i < channels.size(); i++) { - IMB_exr_add_channel(data, - nullptr, - channels[i].name.c_str(), - channels[i].view.c_str(), - 0, - 0, - nullptr, - false); + for (const MultiViewChannelName &channel : channels) { + IMB_exr_add_channel( + data, nullptr, channel.name.c_str(), channel.view.c_str(), 0, 0, nullptr, false); echan = (ExrChannel *)data->channels.last; - echan->m->name = channels[i].name; - echan->m->view = channels[i].view; - echan->m->part_number = channels[i].part_number; - echan->m->internal_name = channels[i].internal_name; + echan->m->name = channel.name; + echan->m->view = channel.view; + echan->m->part_number = channel.part_number; + echan->m->internal_name = channel.internal_name; } return 1; @@ -1311,9 +1305,8 @@ void IMB_exr_multilayer_convert(void *handle, } else { /* add views to RenderResult */ - for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); - ++i) { - addview(base, (*i).c_str()); + for (const std::string &view_name : *data->multiView) { + addview(base, view_name.c_str()); } } @@ -1554,15 +1547,15 @@ static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, imb_exr_get_views(*data->ifile, *data->multiView); - for (size_t i = 0; i < channels.size(); i++) { + for (const MultiViewChannelName &channel : channels) { IMB_exr_add_channel( - data, nullptr, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, nullptr, false); + data, nullptr, channel.name.c_str(), channel.view.c_str(), 0, 0, nullptr, false); echan = (ExrChannel *)data->channels.last; - echan->m->name = channels[i].name; - echan->m->view = channels[i].view; - echan->m->part_number = channels[i].part_number; - echan->m->internal_name = channels[i].internal_name; + echan->m->name = channel.name; + echan->m->view = channel.view; + echan->m->part_number = channel.part_number; + echan->m->internal_name = channel.internal_name; } /* now try to sort out how to assign memory to the channels */ @@ -1689,8 +1682,8 @@ static void exr_print_filecontents(MultiPartInputFile &file) const StringVector views = multiView(file.header(0)); printf("OpenEXR-load: MultiView file\n"); printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str()); - for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) { - printf("OpenEXR-load: Found view %s\n", (*i).c_str()); + for (const std::string &view : views) { + printf("OpenEXR-load: Found view %s\n", view.c_str()); } } else if (numparts > 1) { @@ -1835,10 +1828,10 @@ static void imb_exr_type_by_channels(ChannelList &channels, * with non-empty ones in the file. */ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) { - for (std::set::iterator i = layerNames.begin(); i != layerNames.end(); i++) { + for (const std::string &layer_name : layerNames) { /* see if any layername differs from a viewname */ - if (imb_exr_get_multiView_id(views, *i) == -1) { - std::string layerName = *i; + if (imb_exr_get_multiView_id(views, layer_name) == -1) { + std::string layerName = layer_name; size_t pos = layerName.rfind('.'); if (pos == std::string::npos) { diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 14c3d756d56..0b9636ffb70 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -724,9 +724,7 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, int current_mat = 0; - for (int i = 0; i < face_sets.size(); i++) { - const std::string &grp_name = face_sets[i]; - + for (const std::string &grp_name : face_sets) { if (r_mat_map.find(grp_name) == r_mat_map.end()) { r_mat_map[grp_name] = ++current_mat; } diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 850b6a813ed..77ccdeae28d 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -272,9 +272,8 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain, AnimationImporter::~AnimationImporter() { /* free unused FCurves */ - for (std::vector::iterator it = unused_curves.begin(); it != unused_curves.end(); - it++) { - BKE_fcurve_free(*it); + for (FCurve *unused_curve : unused_curves) { + BKE_fcurve_free(unused_curve); } if (!unused_curves.empty()) { @@ -2035,8 +2034,8 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, COLLADABU::Math::Matrix4 matrix; int mi = 0, mj = 0; - for (std::vector::iterator it = curves.begin(); it != curves.end(); it++) { - matrix.setElement(mi, mj, evaluate_fcurve(*it, fra)); + for (FCurve *curve : curves) { + matrix.setElement(mi, mj, evaluate_fcurve(curve, fra)); mj++; if (mj == 4) { mi++; diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp index 8a3fbf3c92c..7d8e5825ac9 100644 --- a/source/blender/io/collada/BCMath.cpp +++ b/source/blender/io/collada/BCMath.cpp @@ -157,20 +157,20 @@ void BCMatrix::transpose(Matrix &mat) void BCMatrix::sanitize(Matrix &mat, int precision) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - double val = (double)mat[i][j]; + for (auto &row : mat) { + for (float &cell : row) { + double val = (double)cell; val = double_round(val, precision); - mat[i][j] = (float)val; + cell = (float)val; } } } void BCMatrix::sanitize(DMatrix &mat, int precision) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - mat[i][j] = double_round(mat[i][j], precision); + for (auto &row : mat) { + for (float &cell : row) { + cell = double_round(cell, precision); } } } diff --git a/source/blender/io/collada/BlenderContext.cpp b/source/blender/io/collada/BlenderContext.cpp index 8009f10aa03..ab420e79ba7 100644 --- a/source/blender/io/collada/BlenderContext.cpp +++ b/source/blender/io/collada/BlenderContext.cpp @@ -81,8 +81,8 @@ bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer std::vector children; bc_get_children(children, ob, view_layer); - for (int i = 0; i < children.size(); i++) { - if (bc_is_in_Export_set(export_set, children[i], view_layer)) { + for (Object *child : children) { + if (bc_is_in_Export_set(export_set, child, view_layer)) { to_export = true; break; } diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp index 52d4bbf122e..6f0d422dbe2 100644 --- a/source/blender/io/collada/ControllerExporter.cpp +++ b/source/blender/io/collada/ControllerExporter.cpp @@ -245,9 +245,9 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) if (sumw > 0.0f) { float invsumw = 1.0f / sumw; vcounts.push_back(jw.size()); - for (std::map::iterator m = jw.begin(); m != jw.end(); ++m) { - joints.push_back((*m).first); - weights.push_back(invsumw * (*m).second); + for (auto &index_and_weight : jw) { + joints.push_back(index_and_weight.first); + weights.push_back(invsumw * index_and_weight.second); } } else { @@ -596,8 +596,8 @@ std::string ControllerExporter::add_weights_source(Mesh *me, source.prepareToAppendValues(); - for (std::list::const_iterator i = weights.begin(); i != weights.end(); ++i) { - source.appendValues(*i); + for (float weight : weights) { + source.appendValues(weight); } source.finish(); @@ -638,8 +638,8 @@ void ControllerExporter::add_vertex_weights_element(const std::string &weights_s /* write deformer index - weight index pairs */ int weight_index = 0; - for (std::list::const_iterator i = joints.begin(); i != joints.end(); ++i) { - weightselem.appendValues(*i, weight_index++); + for (int joint_index : joints) { + weightselem.appendValues(joint_index, weight_index++); } weightselem.finish(); diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp index b85a96d89de..10c1a90576c 100644 --- a/source/blender/io/collada/DocumentImporter.cpp +++ b/source/blender/io/collada/DocumentImporter.cpp @@ -241,10 +241,8 @@ void DocumentImporter::finish() armature_importer.fix_animation(); #endif - for (std::vector::iterator vsit = vscenes.begin(); - vsit != vscenes.end(); - vsit++) { - const COLLADAFW::NodePointerArray &roots = (*vsit)->getRootNodes(); + for (const COLLADAFW::VisualScene *vscene : vscenes) { + const COLLADAFW::NodePointerArray &roots = vscene->getRootNodes(); for (unsigned int i = 0; i < roots.getCount(); i++) { translate_anim_recursive(roots[i], nullptr, nullptr); @@ -665,9 +663,7 @@ std::vector *DocumentImporter::write_node(COLLADAFW::Node *node, goto finally; } - for (std::vector::iterator it = objects_done->begin(); it != objects_done->end(); - ++it) { - ob = *it; + for (Object *ob : *objects_done) { std::string nodename = node->getName().empty() ? node->getOriginalId() : node->getName(); BKE_libblock_rename(bmain, &ob->id, (char *)nodename.c_str()); object_map.insert(std::pair(node->getUniqueId(), ob)); @@ -681,10 +677,7 @@ std::vector *DocumentImporter::write_node(COLLADAFW::Node *node, /* create_constraints(et,ob); */ } - for (std::vector::iterator it = objects_done->begin(); it != objects_done->end(); - ++it) { - ob = *it; - + for (Object *ob : *objects_done) { if (read_transform) { anim_importer.read_node_transform(node, ob); /* overwrites location set earlier */ } diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index bb2aabb0598..2934ea1caa6 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -973,9 +973,7 @@ static void bc_remove_materials_from_object(Object *ob, Mesh *me) std::vector MeshImporter::get_all_users_of(Mesh *reference_mesh) { std::vector mesh_users; - for (std::vector::iterator it = imported_objects.begin(); it != imported_objects.end(); - ++it) { - Object *ob = (*it); + for (Object *ob : imported_objects) { if (bc_is_marked(ob)) { bc_remove_mark(ob); Mesh *me = (Mesh *)ob->data; @@ -1007,9 +1005,7 @@ std::vector MeshImporter::get_all_users_of(Mesh *reference_mesh) */ void MeshImporter::optimize_material_assignements() { - for (std::vector::iterator it = imported_objects.begin(); it != imported_objects.end(); - ++it) { - Object *ob = (*it); + for (Object *ob : imported_objects) { Mesh *me = (Mesh *)ob->data; if (ID_REAL_USERS(&me->id) == 1) { bc_copy_materials_to_data(ob, me); @@ -1029,8 +1025,7 @@ void MeshImporter::optimize_material_assignements() } if (can_move) { bc_copy_materials_to_data(ref_ob, me); - for (int index = 0; index < mesh_users.size(); index++) { - Object *object = mesh_users[index]; + for (Object *object : mesh_users) { bc_remove_materials_from_object(object, me); bc_remove_mark(object); } diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp index 01c270518e9..5bbd22b8275 100644 --- a/source/blender/io/collada/SceneExporter.cpp +++ b/source/blender/io/collada/SceneExporter.cpp @@ -86,8 +86,7 @@ void SceneExporter::writeNodeList(std::vector &child_objects, Object * * I really prefer to enforce the export of hidden * elements in an object hierarchy. When the children of * the hidden elements are exported as well. */ - for (int i = 0; i < child_objects.size(); i++) { - Object *child = child_objects[i]; + for (auto *child : child_objects) { writeNode(child); if (bc_is_marked(child)) { bc_remove_mark(child); diff --git a/source/blender/io/collada/collada_internal.cpp b/source/blender/io/collada/collada_internal.cpp index 096f6a678ac..ed5cc62d05f 100644 --- a/source/blender/io/collada/collada_internal.cpp +++ b/source/blender/io/collada/collada_internal.cpp @@ -280,8 +280,7 @@ std::string encode_xml(std::string xml) std::map::const_iterator it; std::string encoded_xml; - for (unsigned int i = 0; i < xml.size(); i++) { - char c = xml.at(i); + for (char c : xml) { it = escape.find(c); if (it == escape.end()) { diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index c57952afcc8..25c10c717e2 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -379,11 +379,9 @@ void bc_match_scale(std::vector *objects_done, UnitConverter &bc_unit, bool scale_to_scene) { - for (std::vector::iterator it = objects_done->begin(); it != objects_done->end(); - ++it) { - Object *ob = *it; + for (Object *ob : *objects_done) { if (ob->parent == nullptr) { - bc_match_scale(*it, bc_unit, scale_to_scene); + bc_match_scale(ob, bc_unit, scale_to_scene); } } } @@ -524,10 +522,8 @@ BoneExtensionManager::~BoneExtensionManager() std::map::iterator map_it; for (map_it = extended_bone_maps.begin(); map_it != extended_bone_maps.end(); ++map_it) { BoneExtensionMap *extended_bones = map_it->second; - for (BoneExtensionMap::iterator ext_it = extended_bones->begin(); - ext_it != extended_bones->end(); - ++ext_it) { - delete ext_it->second; + for (auto &extended_bone : *extended_bones) { + delete extended_bone.second; } extended_bones->clear(); delete extended_bones; -- cgit v1.2.3 From d329a6a937eaeb5f8a683eedf3a79384eedf0e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 7 Dec 2020 12:54:46 +0100 Subject: Fix bug in cleanup commit Fix a copy-paste error in rB11c4066159e --- source/blender/io/collada/BCMath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp index 7d8e5825ac9..0521fda5fb1 100644 --- a/source/blender/io/collada/BCMath.cpp +++ b/source/blender/io/collada/BCMath.cpp @@ -169,7 +169,7 @@ void BCMatrix::sanitize(Matrix &mat, int precision) void BCMatrix::sanitize(DMatrix &mat, int precision) { for (auto &row : mat) { - for (float &cell : row) { + for (double &cell : row) { cell = double_round(cell, precision); } } -- cgit v1.2.3 From cf9275dd4e452717faffa0e502814af01d84d539 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 7 Dec 2020 13:11:17 +0100 Subject: Fix failing Cycles tests after Cryptomatte changes For old files without Cycles cryptomatte settings, must provide the defaults. --- intern/cycles/blender/addon/version_update.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 053603fa15c..5dae88d60c7 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -198,11 +198,11 @@ def do_versions(self): if scene.render.engine == 'CYCLES': for view_layer in scene.view_layers: cview_layer = view_layer.cycles - view_layer.use_pass_cryptomatte_object = cview_layer.get("use_pass_crypto_object") - view_layer.use_pass_cryptomatte_material = cview_layer.get("use_pass_crypto_material") - view_layer.use_pass_cryptomatte_asset = cview_layer.get("use_pass_crypto_asset") - view_layer.pass_cryptomatte_depth = cview_layer.get("pass_crypto_depth") - view_layer.use_pass_cryptomatte_accurate = cview_layer.get("pass_crypto_accurate") + view_layer.use_pass_cryptomatte_object = cview_layer.get("use_pass_crypto_object", False) + view_layer.use_pass_cryptomatte_material = cview_layer.get("use_pass_crypto_material", False) + view_layer.use_pass_cryptomatte_asset = cview_layer.get("use_pass_crypto_asset", False) + view_layer.pass_cryptomatte_depth = cview_layer.get("pass_crypto_depth", 6) + view_layer.use_pass_cryptomatte_accurate = cview_layer.get("pass_crypto_accurate", True) # Lamps for light in bpy.data.lights: -- cgit v1.2.3 From 0c0bc619181419a3005faf034706d77ef24457e6 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 7 Dec 2020 13:54:11 +0100 Subject: Fix access to invalid data in Outliner tree building Non-ID tree-elements would cast their data pointer to `ID *` and take the name and ID-Code from there. The name would actually be overridden a few lines later, so that didn't cause issues. But the ID-Code stored inside the tree element kept an undefined value. In practice that probably didn't cause many issues either, since it's just an undefined value that was very unlikely to take a valid 16-bit ID-code value, meaning ID-Code checks would simply fail as they should. Further there typically are other checks to see if the element actually represents an ID. However, in theory this may have caused a few random crashes or data-corruptions. --- source/blender/editors/space_outliner/outliner_tree.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 37f748692f9..811aaa1ba2e 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -965,7 +965,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { /* pass */ } - else if (type == TSE_ANIM_DATA) { + else if (ELEM(type, TSE_ANIM_DATA, TSE_NLA, TSE_NLA_TRACK, TSE_DRIVER_BASE)) { /* pass */ } else if (type == TSE_GP_LAYER) { @@ -977,7 +977,13 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, else if (type == TSE_ID_BASE) { /* pass */ } + else if (ELEM(type, TSE_KEYMAP, TSE_KEYMAP_ITEM)) { + /* pass */ + } else { + /* Other cases must be caught above. */ + BLI_assert(TSE_IS_REAL_ID(tselem)); + /* do here too, for blend file viewer, own ID_LI then shows file name */ if (GS(id->name) == ID_LI) { te->name = ((Library *)id)->filepath; -- cgit v1.2.3 From 95734e32bfb9d4309e05a69e41aa1b1676d42447 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 7 Dec 2020 14:06:40 +0100 Subject: Cleanup: Avoid setting (unsafe) Outliner tree element data that won't be used I carefully checked and am quite sure for `TSE_ANIMATION_DATA` and `TSE_NLA_ACTION` the direct-data isn't used at all. This data is stored and accessed in unsafe ways based on conventions anyway (`void *`). We should aim for a safer design but it will be difficult to get there. Any removed complexity will help. --- source/blender/editors/space_outliner/outliner_tree.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 811aaa1ba2e..a02a8441620 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1008,7 +1008,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* this element's info */ te->name = IFACE_("Animation"); - te->directdata = adt; /* Action */ outliner_add_element(space_outliner, &te->subtree, adt->action, te, 0, 0); @@ -1055,17 +1054,13 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, TreeElement *tenlt = outliner_add_element( space_outliner, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a); NlaStrip *strip; - TreeElement *ten; int b = 0; tenlt->name = nlt->name; for (strip = nlt->strips.first; strip; strip = strip->next, b++) { - ten = outliner_add_element( + outliner_add_element( space_outliner, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b); - if (ten) { - ten->directdata = strip; - } } } } -- cgit v1.2.3 From 634b10acbb6962f9901f0ad610d12b24f7d76c06 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 7 Dec 2020 14:14:31 +0100 Subject: Fix missing type check for Outliner eyedropper query Mistake in 35a5dee2ef73. Code would simply assume that the element under the cursor is an Object if it was an ID (but not a collection). This wouldn't cause any issues in current code, since the only other ID that set the direct-data were collections, which are special in that they don't have a `TreeStoreElem.type` of 0, which is already being checked for here. And if there was no direct-data set, the object lookup in the View-Layer would correctly fail too. --- source/blender/editors/space_outliner/outliner_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index fe4cc29b738..e0d63dfcf81 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -510,7 +510,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]); if (te) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0) { + if ((tselem->type == 0) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob); } -- cgit v1.2.3 From 2e221de4ceeedcaf6e322d9cd72b148cb04cdac4 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 7 Dec 2020 14:50:08 +0100 Subject: UI Code Quality: Start refactoring Outliner tree-element building (using C++) Continuation of the work started with 249e4df110e0. After all display modes were ported to this new design, this commit starts the (more complex) work on the individual tree-element types. More concretely it ports animation tree-elements (action data-blocks, drivers and NLA data). The commit above explains motivations. In short, we need a better design that's easier to reason about and better testable. Changes done here are pretty straight forward and introduce similar class hierarchy and building patterns as introduced for the display modes already. I.e. an abstract base class, `AbstractTreeElement` with derived classes for the concrete types, and a C-API with a switch to create the needed objects from a type enum. The latter should be replacable with something nicer later on (RAII based, and type-safer through meta-programming). Each tree-element type has its own class, with an own header and source file (okay some closely related types can share a header and source file, like the NLA ones). I added some further temporary bits for the transition to the new design, such as the `TreeElement.type`. It should entirely replace `TreeElement` eventually, just as `outliner_add_element()` should be quite small by then and easily replacable by a `TreeBuilder` helper. --- .../blender/editors/space_outliner/CMakeLists.txt | 9 +++ .../editors/space_outliner/outliner_intern.h | 8 ++ .../blender/editors/space_outliner/outliner_tree.c | 77 ++++--------------- .../editors/space_outliner/tree/tree_element.cc | 88 ++++++++++++++++++++++ .../editors/space_outliner/tree/tree_element.h | 45 +++++++++++ .../editors/space_outliner/tree/tree_element.hh | 53 +++++++++++++ .../space_outliner/tree/tree_element_anim_data.cc | 70 +++++++++++++++++ .../space_outliner/tree/tree_element_anim_data.hh | 42 +++++++++++ .../tree/tree_element_driver_base.cc | 68 +++++++++++++++++ .../tree/tree_element_driver_base.hh | 38 ++++++++++ .../space_outliner/tree/tree_element_nla.cc | 78 +++++++++++++++++++ .../space_outliner/tree/tree_element_nla.hh | 53 +++++++++++++ 12 files changed, 566 insertions(+), 63 deletions(-) create mode 100644 source/blender/editors/space_outliner/tree/tree_element.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element.h create mode 100644 source/blender/editors/space_outliner/tree/tree_element.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_anim_data.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_anim_data.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_driver_base.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_driver_base.hh create mode 100644 source/blender/editors/space_outliner/tree/tree_element_nla.cc create mode 100644 source/blender/editors/space_outliner/tree/tree_element_nla.hh diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index b21b969493a..74f99540bee 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -52,10 +52,19 @@ set(SRC tree/tree_display_orphaned.cc tree/tree_display_scenes.cc tree/tree_display_data.cc + tree/tree_element.cc + tree/tree_element_anim_data.cc + tree/tree_element_driver_base.cc + tree/tree_element_nla.cc outliner_intern.h tree/tree_display.h tree/tree_display.hh + tree/tree_element.h + tree/tree_element.hh + tree/tree_element_anim_data.hh + tree/tree_element_driver_base.hh + tree/tree_element_nla.hh ) set(LIB diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index ecf8cc0f800..0294b4836c8 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -75,6 +75,14 @@ typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *c typedef struct TreeElement { struct TreeElement *next, *prev, *parent; + + /** + * Handle to the new C++ object (a derived type of base #AbstractTreeElement) that should replace + * #TreeElement. Step by step, data should be moved to it and operations based on the type should + * become virtual methods of the class hierarchy. + */ + struct TreeElementType *type; + ListBase subtree; int xs, ys; /* Do selection. */ TreeStoreElem *store_elem; /* Element in tree store. */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index a02a8441620..7308b161d18 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -84,6 +84,7 @@ #include "outliner_intern.h" #include "tree/tree_display.h" +#include "tree/tree_element.h" #ifdef WIN32 # include "BLI_math_base.h" /* M_PI */ @@ -230,6 +231,7 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) if (element->flag & TE_FREE_NAME) { MEM_freeN((void *)element->name); } + outliner_tree_element_type_free(&element->type); MEM_freeN(element); } @@ -959,6 +961,11 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->parent = parent; te->index = index; /* For data arrays. */ + + /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some + * support this, eventually this should replace `TreeElement` entirely. */ + te->type = outliner_tree_element_type_create(type, te, idv); + if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { /* pass */ } @@ -994,7 +1001,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->idcode = GS(id->name); } - if (type == 0) { + if (te->type) { + outliner_tree_element_type_expand(te->type, space_outliner); + } + else if (type == 0) { TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID data-block. */ @@ -1002,68 +1012,9 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, outliner_add_id_contents(space_outliner, te, tselem, id); } } - else if (type == TSE_ANIM_DATA) { - IdAdtTemplate *iat = (IdAdtTemplate *)idv; - AnimData *adt = (AnimData *)iat->adt; - - /* this element's info */ - te->name = IFACE_("Animation"); - - /* Action */ - outliner_add_element(space_outliner, &te->subtree, adt->action, te, 0, 0); - - /* Drivers */ - if (adt->drivers.first) { - TreeElement *ted = outliner_add_element( - space_outliner, &te->subtree, adt, te, TSE_DRIVER_BASE, 0); - ID *lastadded = NULL; - FCurve *fcu; - - ted->name = IFACE_("Drivers"); - - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - if (fcu->driver && fcu->driver->variables.first) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* loop over all targets used here */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - if (lastadded != dtar->id) { - /* XXX this lastadded check is rather lame, and also fails quite badly... */ - outliner_add_element( - space_outliner, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0); - lastadded = dtar->id; - } - } - DRIVER_TARGETS_LOOPER_END; - } - } - } - } - - /* NLA Data */ - if (adt->nla_tracks.first) { - TreeElement *tenla = outliner_add_element(space_outliner, &te->subtree, adt, te, TSE_NLA, 0); - NlaTrack *nlt; - int a = 0; - - tenla->name = IFACE_("NLA Tracks"); - - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - TreeElement *tenlt = outliner_add_element( - space_outliner, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a); - NlaStrip *strip; - int b = 0; - - tenlt->name = nlt->name; - - for (strip = nlt->strips.first; strip; strip = strip->next, b++) { - outliner_add_element( - space_outliner, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b); - } - } - } + else if (ELEM(type, TSE_ANIM_DATA, TSE_DRIVER_BASE, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK)) { + /* Should already use new AbstractTreeElement design. */ + BLI_assert(0); } else if (type == TSE_GP_LAYER) { bGPDlayer *gpl = (bGPDlayer *)idv; diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc new file mode 100644 index 00000000000..ce2a8fa634d --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "../outliner_intern.h" + +#include "tree_element_anim_data.hh" +#include "tree_element_driver_base.hh" +#include "tree_element_nla.hh" + +#include "tree_element.h" +#include "tree_element.hh" + +namespace blender::ed::outliner { + +static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv) +{ + /* Would be nice to get rid of void * here, can we somehow expect the right type right away? + * Perfect forwarding maybe, once the API is C++ only? */ + ID &id = *static_cast(idv); + + switch (type) { + case TSE_ANIM_DATA: + return new TreeElementAnimData(legacy_te, id); + case TSE_DRIVER_BASE: + return new TreeElementDriverBase(legacy_te, *static_cast(idv)); + case TSE_NLA: + return new TreeElementNLA(legacy_te, *static_cast(idv)); + case TSE_NLA_TRACK: + return new TreeElementNLATrack(legacy_te, *static_cast(idv)); + case TSE_NLA_ACTION: + return new TreeElementNLAAction(legacy_te); + default: + break; + } + + return nullptr; +} + +static void tree_element_free(AbstractTreeElement **tree_element) +{ + delete *tree_element; + *tree_element = nullptr; +} + +static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner &space_outliner) +{ + tree_element.expand(space_outliner); +} + +} // namespace blender::ed::outliner + +namespace outliner = blender::ed::outliner; + +TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv) +{ + outliner::AbstractTreeElement *element = outliner::tree_element_create(type, *legacy_te, idv); + return reinterpret_cast(element); +} + +void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner) +{ + outliner::tree_element_expand(reinterpret_cast(*type), + *space_outliner); +} + +void outliner_tree_element_type_free(TreeElementType **type) +{ + outliner::tree_element_free(reinterpret_cast(type)); +} diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h new file mode 100644 index 00000000000..9012321a323 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + * + * C-API for the Tree-Element types. + * This API shouldn't stay for long. All tree building should eventually be done through C++ types, + * with more type safety and an easier to reason about design. + */ + +#pragma once + +#include "DNA_space_types.h" + +struct TreeElement; + +#ifdef __cplusplus +extern "C" { +#endif + +/** C alias for an #AbstractTreeElement handle. */ +typedef struct TreeElementType TreeElementType; + +TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv); +void outliner_tree_element_type_free(TreeElementType **element); + +void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh new file mode 100644 index 00000000000..8a1ebb51eae --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.h" + +namespace blender::ed::outliner { + +/* -------------------------------------------------------------------- */ +/* Tree-Display Interface */ + +class AbstractTreeElement { + protected: + /** + * Reference back to the owning legacy TreeElement. + * Most concrete types need access to this, so storing here. Eventually the type should be + * replaced by AbstractTreeElement and derived types. + */ + TreeElement &legacy_te_; + + public: + AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te) + { + } + virtual ~AbstractTreeElement() = default; + + /** + * Let the type add its own children. + */ + virtual void expand(SpaceOutliner &) const + { + } +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc new file mode 100644 index 00000000000..13a25800800 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase_wrapper.hh" + +#include "DNA_anim_types.h" +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_anim_data.hh" + +namespace blender::ed::outliner { + +TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id) + : AbstractTreeElement(legacy_te), anim_data_(*reinterpret_cast(id).adt) +{ + BLI_assert(legacy_te.store_elem->type == TSE_ANIM_DATA); + /* this element's info */ + legacy_te.name = IFACE_("Animation"); + legacy_te.directdata = &anim_data_; +} + +void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const +{ + /* Animation data-block itself. */ + outliner_add_element(&space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, 0, 0); + + expand_drivers(space_outliner); + expand_NLA_tracks(space_outliner); +} + +void TreeElementAnimData::expand_drivers(SpaceOutliner &space_outliner) const +{ + if (BLI_listbase_is_empty(&anim_data_.drivers)) { + return; + } + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &anim_data_, &legacy_te_, TSE_DRIVER_BASE, 0); +} + +void TreeElementAnimData::expand_NLA_tracks(SpaceOutliner &space_outliner) const +{ + if (BLI_listbase_is_empty(&anim_data_.nla_tracks)) { + return; + } + outliner_add_element(&space_outliner, &legacy_te_.subtree, &anim_data_, &legacy_te_, TSE_NLA, 0); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh new file mode 100644 index 00000000000..8114277b6d6 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.hh @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct TreeElement; + +namespace blender::ed::outliner { + +class TreeElementAnimData final : public AbstractTreeElement { + AnimData &anim_data_; + + public: + TreeElementAnimData(TreeElement &legacy_te, ID &id); + + void expand(SpaceOutliner &space_outliner) const override; + + private: + void expand_drivers(SpaceOutliner &space_outliner) const; + void expand_NLA_tracks(SpaceOutliner &space_outliner) const; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc b/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc new file mode 100644 index 00000000000..a01a3c42531 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc @@ -0,0 +1,68 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase_wrapper.hh" + +#include "BKE_fcurve_driver.h" + +#include "DNA_anim_types.h" +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_driver_base.hh" + +namespace blender::ed::outliner { + +TreeElementDriverBase::TreeElementDriverBase(TreeElement &legacy_te, AnimData &anim_data) + : AbstractTreeElement(legacy_te), anim_data_(anim_data) +{ + BLI_assert(legacy_te.store_elem->type == TSE_DRIVER_BASE); + legacy_te.name = IFACE_("Drivers"); +} + +void TreeElementDriverBase::expand(SpaceOutliner &space_outliner) const +{ + ID *lastadded = nullptr; + + for (FCurve *fcu : blender::ListBaseWrapper(anim_data_.drivers)) { + if (fcu->driver && fcu->driver->variables.first) { + ChannelDriver *driver = fcu->driver; + + for (DriverVar *dvar : blender::ListBaseWrapper(driver->variables)) { + /* loop over all targets used here */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (lastadded != dtar->id) { + /* XXX this lastadded check is rather lame, and also fails quite badly... */ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, dtar->id, &legacy_te_, TSE_LINKED_OB, 0); + lastadded = dtar->id; + } + } + DRIVER_TARGETS_LOOPER_END; + } + } + } +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh b/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh new file mode 100644 index 00000000000..1925e3570be --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct TreeElement; + +namespace blender::ed::outliner { + +class TreeElementDriverBase final : public AbstractTreeElement { + AnimData &anim_data_; + + public: + TreeElementDriverBase(TreeElement &legacy_te, AnimData &anim_data); + + void expand(SpaceOutliner &space_outliner) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc new file mode 100644 index 00000000000..5d4ec53e60c --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase_wrapper.hh" + +#include "DNA_anim_types.h" +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_nla.hh" + +namespace blender::ed::outliner { + +TreeElementNLA::TreeElementNLA(TreeElement &legacy_te, AnimData &anim_data) + : AbstractTreeElement(legacy_te), anim_data_(anim_data) +{ + BLI_assert(legacy_te.store_elem->type == TSE_NLA); + legacy_te.name = IFACE_("NLA Tracks"); + legacy_te.directdata = &anim_data; +} + +void TreeElementNLA::expand(SpaceOutliner &space_outliner) const +{ + int a = 0; + for (NlaTrack *nlt : ListBaseWrapper(anim_data_.nla_tracks)) { + outliner_add_element(&space_outliner, &legacy_te_.subtree, nlt, &legacy_te_, TSE_NLA_TRACK, a); + a++; + } +} + +/* -------------------------------------------------------------------- */ + +TreeElementNLATrack::TreeElementNLATrack(TreeElement &legacy_te, NlaTrack &track) + : AbstractTreeElement(legacy_te), track_(track) +{ + BLI_assert(legacy_te.store_elem->type == TSE_NLA_TRACK); + legacy_te.name = track.name; +} + +void TreeElementNLATrack::expand(SpaceOutliner &space_outliner) const +{ + int a = 0; + for (NlaStrip *strip : ListBaseWrapper(track_.strips)) { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, strip->act, &legacy_te_, TSE_NLA_ACTION, a); + a++; + } +} + +/* -------------------------------------------------------------------- */ + +TreeElementNLAAction::TreeElementNLAAction(TreeElement &legacy_te) : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te.store_elem->type == TSE_NLA_ACTION); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh new file mode 100644 index 00000000000..3ca62b13bd8 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct NlaTrack; +struct NlaStrip; + +namespace blender::ed::outliner { + +class TreeElementNLA final : public AbstractTreeElement { + AnimData &anim_data_; + + public: + TreeElementNLA(TreeElement &legacy_te, AnimData &anim_data); + + void expand(SpaceOutliner &space_outliner) const override; +}; + +class TreeElementNLATrack final : public AbstractTreeElement { + NlaTrack &track_; + + public: + TreeElementNLATrack(TreeElement &legacy_te, NlaTrack &track); + + void expand(SpaceOutliner &space_outliner) const override; +}; + +class TreeElementNLAAction final : public AbstractTreeElement { + public: + TreeElementNLAAction(TreeElement &legacy_te); +}; + +} // namespace blender::ed::outliner -- cgit v1.2.3 From c51a70537b12946bd8e7e66d29ef438a41a8801a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 7 Dec 2020 16:30:09 +0100 Subject: Fix T81745: Auto Weights fails with Mirror mod + Vertex Groups X Fix the Assign Automatic Weights operator in weight paint mode when the Vertex Groups X option is enabled. This issue was probably introduced in rB5502517c3c12 where `me->editflag & ME_EDIT_MIRROR_X` was replaced by either `me->editflag & ME_EDIT_VERTEX_GROUPS_X_SYMMETRY` or `me->symmetry & ME_SYMMETRY_X`. In this case, the former wasn't working, so I replaced it with the latter. --- source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index eea79bad789..8eb2ebd0f19 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -120,13 +120,8 @@ static int weight_from_bones_exec(bContext *C, wmOperator *op) Mesh *me = ob->data; int type = RNA_enum_get(op->ptr, "type"); - ED_object_vgroup_calc_from_armature(op->reports, - depsgraph, - scene, - ob, - armob, - type, - (me->editflag & ME_EDIT_VERTEX_GROUPS_X_SYMMETRY)); + ED_object_vgroup_calc_from_armature( + op->reports, depsgraph, scene, ob, armob, type, (me->symmetry & ME_SYMMETRY_X)); DEG_id_tag_update(&me->id, 0); DEG_relations_tag_update(CTX_data_main(C)); -- cgit v1.2.3 From 513578b182fd0c427b9da653b715f8bfb16faec1 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 7 Dec 2020 15:40:29 +0100 Subject: Fix (unreported) LibOverride: GPencil local Modifiers not fully editable. Missing case in `RNA_property_overridable_get` --- source/blender/makesrna/intern/rna_access_compare_override.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 4bbbf5f01da..2bf4de7af60 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -24,6 +24,7 @@ #include "DNA_ID.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_key_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -77,6 +78,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop) return true; } } + else if (RNA_struct_is_a(ptr->type, &RNA_GpencilModifier)) { + GpencilModifierData *gp_mod = ptr->data; + if (gp_mod->flag & eGpencilModifierFlag_OverrideLibrary_Local) { + return true; + } + } /* If this is a RNA-defined property (real or 'virtual' IDProp), * we want to use RNA prop flag. */ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && -- cgit v1.2.3 From bab57550b69b8429bb2f081fbc75f1d1ca035a34 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 7 Dec 2020 16:52:45 +0100 Subject: LibOverride: Abstract a bit handling of local items of RNA collections. RNA collections that support insertion of new items in liboverride data-block need a special way to distiguish between locale and orig-from-linked items (since some operations are allowed on the forer, but no the latter). In future we want a proper solution to abstract that at the `BKE_lib_override` level, but for now we need to add some code for each case. Note that this commit also fixes a few potential issues with GPencil modifiers, and constraints, regarding their handling of local overrides. --- source/blender/blenkernel/BKE_constraint.h | 3 ++ source/blender/blenkernel/BKE_gpencil_modifier.h | 3 ++ source/blender/blenkernel/BKE_modifier.h | 1 + source/blender/blenkernel/intern/constraint.c | 15 ++++++++++ .../blender/blenkernel/intern/gpencil_modifier.c | 13 +++++++++ source/blender/blenkernel/intern/modifier.c | 13 +++++++++ source/blender/editors/object/object_constraint.c | 8 ++--- .../editors/object/object_gpencil_modifier.c | 34 +++++++++++++--------- source/blender/editors/object/object_modifier.c | 8 ++--- 9 files changed, 74 insertions(+), 24 deletions(-) diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 4b9f480e091..1589bff7501 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -177,6 +177,9 @@ struct bConstraint *BKE_constraint_find_from_target(struct Object *ob, struct bConstraintTarget *tgt, struct bPoseChannel **r_pchan); +bool BKE_constraint_is_local_in_liboverride(const struct Object *ob, + const struct bConstraint *con); + struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type); struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob, struct bPoseChannel *pchan, diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 7729d2c53ab..bdc583048b8 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -278,6 +278,9 @@ void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); +bool BKE_gpencil_modifier_is_local_in_liboverride(const struct Object *ob, + const struct GpencilModifierData *gmd); + typedef struct GpencilVirtualModifierData { ArmatureGpencilModifierData amd; LatticeGpencilModifierData lmd; diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b0a7d89e3d8..37f566d6f8e 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -431,6 +431,7 @@ bool BKE_modifier_is_non_geometrical(ModifierData *md); bool BKE_modifier_is_enabled(const struct Scene *scene, struct ModifierData *md, int required_mode); +bool BKE_modifier_is_local_in_liboverride(const struct Object *ob, const struct ModifierData *md); void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format, diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 28121206a90..982e91dd1e0 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -5754,6 +5754,7 @@ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bConstraint *dst = MEM_dupallocN(src); constraint_copy_data_ex(dst, src, flag, do_extern); dst->next = dst->prev = NULL; + dst->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; return dst; } @@ -5788,6 +5789,7 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { constraint_copy_data_ex(con, srccon, flag, do_extern); + con->flag |= CONSTRAINT_OVERRIDE_LIBRARY_LOCAL; } } @@ -5954,6 +5956,19 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon return orig_con; } +/** + * Check whether given constraint is local when the object is a library override. + * + * \param con May be NULL, in which case we consider it as a non-local constraint case. + * + * \note This check is only valid for a liboverride data-block, it always return \a true otherwise. + */ +bool BKE_constraint_is_local_in_liboverride(const Object *ob, const bConstraint *con) +{ + return (!ID_IS_OVERRIDE_LIBRARY(ob) || + (con != NULL && (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) != 0)); +} + /* -------- Constraints and Proxies ------- */ /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 09f9e9e891c..7425a1a5f7a 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -530,6 +530,19 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format CLOG_STR_ERROR(&LOG, md->error); } +/** + * Check whether given modifier is local when the object is a library override. + * + * \param gmd May be NULL, in which case we consider it as a non-local modifier case. + * + * \note This check is only valid for a liboverride data-block, it always return \a true otherwise. + */ +bool BKE_gpencil_modifier_is_local_in_liboverride(const Object *ob, const GpencilModifierData *gmd) +{ + return (!ID_IS_OVERRIDE_LIBRARY(ob) || + (gmd != NULL && (gmd->flag & eGpencilModifierFlag_OverrideLibrary_Local) != 0)); +} + /** * Link grease pencil modifier related IDs. * \param ob: Grease pencil object diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index c9bdaecfa2a..7865d44c446 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -574,6 +574,19 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re return true; } +/** + * Check whether given modifier is local when the object is a library override. + * + * \param md May be NULL, in which case we consider it as a non-local modifier case. + * + * \note This check is only valid for a liboverride data-block, it always return \a true otherwise. + */ +bool BKE_modifier_is_local_in_liboverride(const Object *ob, const ModifierData *md) +{ + return (!ID_IS_OVERRIDE_LIBRARY(ob) || + (md != NULL && (md->flag & eModifierFlag_OverrideLibrary_Local) != 0)); +} + CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene, Object *ob, ModifierData *md, diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index fa8531dfb48..e684ad03f53 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -706,11 +706,9 @@ static bool edit_constraint_poll_generic(bContext *C, return false; } - if (ID_IS_OVERRIDE_LIBRARY(ob) && !is_liboverride_allowed) { - if ((con == NULL) || (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) == 0) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from library override"); - return false; - } + if (!is_liboverride_allowed && !BKE_constraint_is_local_in_liboverride(ob, con)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from library override"); + return false; } return true; diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index eed3c7f419d..d3f165678c3 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -319,6 +319,8 @@ int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModi BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd); BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd); + nmd->flag |= eGpencilModifierFlag_OverrideLibrary_Local; + return 1; } @@ -422,7 +424,10 @@ void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot) /********** generic functions for operators using mod names and data context *********************/ -static bool gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) +static bool gpencil_edit_modifier_poll_generic(bContext *C, + StructRNA *rna_type, + int obtype_flag, + const bool is_liboverride_allowed) { PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); @@ -438,11 +443,10 @@ static bool gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, return false; } - if (ID_IS_OVERRIDE_LIBRARY(ob)) { - if ((mod == NULL) || (mod->flag & eGpencilModifierFlag_OverrideLibrary_Local) == 0) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); - return false; - } + if (!is_liboverride_allowed && + (mod == NULL || !BKE_gpencil_modifier_is_local_in_liboverride(ob, mod))) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + return false; } return true; @@ -450,7 +454,14 @@ static bool gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, static bool gpencil_edit_modifier_poll(bContext *C) { - return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0); + return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0, false); +} + +/* Used by operators performing actions allowed also on modifiers from the overridden linked object + * (not only from added 'local' ones). */ +static bool gpencil_edit_modifier_liboverride_allowed_poll(bContext *C) +{ + return gpencil_edit_modifier_poll_generic(C, &RNA_Modifier, 0, true); } static void gpencil_edit_modifier_properties(wmOperatorType *ot) @@ -669,11 +680,6 @@ void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot) /* ************************* Move to Index Gpencil Modifier Operator ************************* */ -static bool gpencil_modifier_move_to_index_poll(bContext *C) -{ - return gpencil_edit_modifier_poll(C); -} - static int gpencil_modifier_move_to_index_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C); @@ -706,7 +712,7 @@ void OBJECT_OT_gpencil_modifier_move_to_index(wmOperatorType *ot) ot->invoke = gpencil_modifier_move_to_index_invoke; ot->exec = gpencil_modifier_move_to_index_exec; - ot->poll = gpencil_modifier_move_to_index_poll; + ot->poll = gpencil_edit_modifier_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -823,7 +829,7 @@ void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot) ot->invoke = gpencil_modifier_copy_invoke; ot->exec = gpencil_modifier_copy_exec; - ot->poll = gpencil_edit_modifier_poll; + ot->poll = gpencil_edit_modifier_liboverride_allowed_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 7d12fa1805b..bb4581b0ee8 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1052,11 +1052,9 @@ bool edit_modifier_poll_generic(bContext *C, return false; } - if (ID_IS_OVERRIDE_LIBRARY(ob) && !is_liboverride_allowed) { - if ((mod == NULL) || (mod->flag & eModifierFlag_OverrideLibrary_Local) == 0) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); - return false; - } + if (!is_liboverride_allowed && !BKE_modifier_is_local_in_liboverride(ob, mod)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + return false; } if (!is_editmode_allowed && CTX_data_edit_object(C) != NULL) { -- cgit v1.2.3 From fb82cfb539f4a33b6fa0a3b44f4833d27b9ef8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 7 Dec 2020 16:54:39 +0100 Subject: Animation: Show Channel Group Colors is now off by default Change the default for the Show Channel Group Colors preference to OFF. This option in the user preferences was introduced in rBad85256e7108. It moved a per-file-per-editor option to the user preferences. As this option would be frequently turned off by animators, this would now have to happen only once. This commit takes this one step further, and turns it off by default, as it can cause major readability issues of the animation channel list. --- source/blender/blenloader/intern/versioning_userdef.c | 4 ---- source/blender/makesrna/intern/rna_userdef.c | 1 - 2 files changed, 5 deletions(-) diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 1266a0c01f8..1d85109774c 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -817,10 +817,6 @@ void blo_do_versions_userdef(UserDef *userdef) userdef->uiflag &= ~USER_UIFLAG_UNUSED_3; } - if (!USER_VERSION_ATLEAST(292, 4)) { - userdef->animation_flag = USER_ANIM_SHOW_CHANNEL_GROUP_COLORS; - } - /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 23f3a04fd91..628eff54032 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5026,7 +5026,6 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop, "Channel Group Colors", "Use animation channel group colors; generally this is used to show bone group colors"); - RNA_def_property_boolean_default(prop, true); RNA_def_property_update(prop, 0, "rna_userdef_anim_update"); prop = RNA_def_property(srna, "fcurve_new_auto_smoothing", PROP_ENUM, PROP_NONE); -- cgit v1.2.3 From 3012446f02781e5208e55a8c997041b782955a74 Mon Sep 17 00:00:00 2001 From: Jim Eckerlein Date: Mon, 7 Dec 2020 15:23:55 +0100 Subject: glTF: update Draco library to new version To support decoding and enhanced encoding of Draco compressed glTF files. Differential Revision: https://developer.blender.org/D9642 --- extern/draco/CMakeLists.txt | 16 +- extern/draco/draco/AUTHORS | 7 + extern/draco/draco/CMakeLists.txt | 271 +++++ extern/draco/draco/LICENSE | 202 ++++ .../src/draco/animation/keyframe_animation.cc | 54 + .../draco/src/draco/animation/keyframe_animation.h | 107 ++ .../draco/animation/keyframe_animation_decoder.cc | 30 + .../draco/animation/keyframe_animation_decoder.h | 34 + .../draco/animation/keyframe_animation_encoder.cc | 28 + .../draco/animation/keyframe_animation_encoder.h | 39 + .../attributes/attribute_octahedron_transform.cc | 88 ++ .../attributes/attribute_octahedron_transform.h | 60 + .../attributes/attribute_quantization_transform.cc | 187 +++ .../attributes/attribute_quantization_transform.h | 78 ++ .../src/draco/attributes/attribute_transform.cc | 44 + .../src/draco/attributes/attribute_transform.h | 46 + .../draco/attributes/attribute_transform_data.h | 71 ++ .../draco/attributes/attribute_transform_type.h | 30 + .../src/draco/attributes/geometry_attribute.cc | 98 ++ .../src/draco/attributes/geometry_attribute.h | 333 ++++++ .../draco/src/draco/attributes/geometry_indices.h | 54 + .../draco/src/draco/attributes/point_attribute.cc | 225 ++++ .../draco/src/draco/attributes/point_attribute.h | 190 +++ .../compression/attributes/attributes_decoder.cc | 111 ++ .../compression/attributes/attributes_decoder.h | 97 ++ .../attributes/attributes_decoder_interface.h | 62 + .../compression/attributes/attributes_encoder.cc | 49 + .../compression/attributes/attributes_encoder.h | 154 +++ .../attributes/kd_tree_attributes_decoder.cc | 551 +++++++++ .../attributes/kd_tree_attributes_decoder.h | 46 + .../attributes/kd_tree_attributes_encoder.cc | 300 +++++ .../attributes/kd_tree_attributes_encoder.h | 51 + .../attributes/kd_tree_attributes_shared.h | 28 + .../compression/attributes/linear_sequencer.h | 51 + .../mesh_attribute_indices_encoding_data.h | 58 + .../attributes/normal_compression_utils.h | 343 ++++++ .../draco/compression/attributes/point_d_vector.h | 279 +++++ .../compression/attributes/points_sequencer.h | 63 + ...cheme_constrained_multi_parallelogram_decoder.h | 231 ++++ ...cheme_constrained_multi_parallelogram_encoder.h | 414 +++++++ ...scheme_constrained_multi_parallelogram_shared.h | 34 + .../mesh_prediction_scheme_data.h | 72 ++ .../mesh_prediction_scheme_decoder.h | 46 + .../mesh_prediction_scheme_encoder.h | 46 + ...sh_prediction_scheme_geometric_normal_decoder.h | 172 +++ ...sh_prediction_scheme_geometric_normal_encoder.h | 180 +++ ...iction_scheme_geometric_normal_predictor_area.h | 110 ++ ...iction_scheme_geometric_normal_predictor_base.h | 96 ++ ...prediction_scheme_multi_parallelogram_decoder.h | 126 ++ ...prediction_scheme_multi_parallelogram_encoder.h | 133 +++ .../mesh_prediction_scheme_parallelogram_decoder.h | 98 ++ .../mesh_prediction_scheme_parallelogram_encoder.h | 111 ++ .../mesh_prediction_scheme_parallelogram_shared.h | 73 ++ .../mesh_prediction_scheme_tex_coords_decoder.h | 344 ++++++ .../mesh_prediction_scheme_tex_coords_encoder.h | 318 +++++ ...prediction_scheme_tex_coords_portable_decoder.h | 143 +++ ...prediction_scheme_tex_coords_portable_encoder.h | 133 +++ ...ediction_scheme_tex_coords_portable_predictor.h | 256 +++++ .../prediction_schemes/prediction_scheme_decoder.h | 90 ++ .../prediction_scheme_decoder_factory.h | 194 ++++ .../prediction_scheme_decoder_interface.h | 53 + .../prediction_scheme_decoding_transform.h | 65 ++ .../prediction_scheme_delta_decoder.h | 65 ++ .../prediction_scheme_delta_encoder.h | 69 ++ .../prediction_schemes/prediction_scheme_encoder.h | 90 ++ .../prediction_scheme_encoder_factory.cc | 74 ++ .../prediction_scheme_encoder_factory.h | 129 +++ .../prediction_scheme_encoder_interface.h | 55 + .../prediction_scheme_encoding_transform.h | 77 ++ .../prediction_schemes/prediction_scheme_factory.h | 85 ++ .../prediction_scheme_interface.h | 60 + ...l_octahedron_canonicalized_decoding_transform.h | 118 ++ ...l_octahedron_canonicalized_encoding_transform.h | 116 ++ ...ormal_octahedron_canonicalized_transform_base.h | 102 ++ ...n_scheme_normal_octahedron_decoding_transform.h | 103 ++ ...n_scheme_normal_octahedron_encoding_transform.h | 105 ++ ...ction_scheme_normal_octahedron_transform_base.h | 90 ++ .../prediction_scheme_wrap_decoding_transform.h | 72 ++ .../prediction_scheme_wrap_encoding_transform.h | 81 ++ .../prediction_scheme_wrap_transform_base.h | 120 ++ .../attributes/sequential_attribute_decoder.cc | 118 ++ .../attributes/sequential_attribute_decoder.h | 86 ++ .../sequential_attribute_decoders_controller.cc | 149 +++ .../sequential_attribute_decoders_controller.h | 61 + .../attributes/sequential_attribute_encoder.cc | 108 ++ .../attributes/sequential_attribute_encoder.h | 134 +++ .../sequential_attribute_encoders_controller.cc | 159 +++ .../sequential_attribute_encoders_controller.h | 115 ++ .../sequential_integer_attribute_decoder.cc | 235 ++++ .../sequential_integer_attribute_decoder.h | 76 ++ .../sequential_integer_attribute_encoder.cc | 230 ++++ .../sequential_integer_attribute_encoder.h | 67 ++ .../sequential_normal_attribute_decoder.cc | 94 ++ .../sequential_normal_attribute_decoder.h | 82 ++ .../sequential_normal_attribute_encoder.cc | 53 + .../sequential_normal_attribute_encoder.h | 82 ++ .../sequential_quantization_attribute_decoder.cc | 120 ++ .../sequential_quantization_attribute_decoder.h | 56 + .../sequential_quantization_attribute_encoder.cc | 79 ++ .../sequential_quantization_attribute_encoder.h | 52 + .../bit_coders/adaptive_rans_bit_coding_shared.h | 43 + .../bit_coders/adaptive_rans_bit_decoder.cc | 70 ++ .../bit_coders/adaptive_rans_bit_decoder.h | 54 + .../bit_coders/adaptive_rans_bit_encoder.cc | 59 + .../bit_coders/adaptive_rans_bit_encoder.h | 61 + .../compression/bit_coders/direct_bit_decoder.cc | 54 + .../compression/bit_coders/direct_bit_decoder.h | 90 ++ .../compression/bit_coders/direct_bit_encoder.cc | 39 + .../compression/bit_coders/direct_bit_encoder.h | 89 ++ .../bit_coders/folded_integer_bit_decoder.h | 77 ++ .../bit_coders/folded_integer_bit_encoder.h | 82 ++ .../compression/bit_coders/rans_bit_decoder.cc | 82 ++ .../compression/bit_coders/rans_bit_decoder.h | 55 + .../compression/bit_coders/rans_bit_encoder.cc | 125 ++ .../compression/bit_coders/rans_bit_encoder.h | 57 + .../compression/bit_coders/symbol_bit_decoder.cc | 49 + .../compression/bit_coders/symbol_bit_decoder.h | 36 + .../compression/bit_coders/symbol_bit_encoder.cc | 30 + .../compression/bit_coders/symbol_bit_encoder.h | 36 + .../draco/compression/config/compression_shared.h | 152 +++ .../src/draco/compression/config/decoder_options.h | 34 + .../src/draco/compression/config/draco_options.h | 249 ++++ .../src/draco/compression/config/encoder_options.h | 97 ++ .../draco/compression/config/encoding_features.h | 39 + extern/draco/draco/src/draco/compression/decode.cc | 132 +++ extern/draco/draco/src/draco/compression/decode.h | 80 ++ extern/draco/draco/src/draco/compression/encode.cc | 96 ++ extern/draco/draco/src/draco/compression/encode.h | 140 +++ .../draco/src/draco/compression/encode_base.h | 131 +++ .../draco/src/draco/compression/entropy/ans.h | 527 +++++++++ .../draco/compression/entropy/rans_symbol_coding.h | 54 + .../compression/entropy/rans_symbol_decoder.h | 164 +++ .../compression/entropy/rans_symbol_encoder.h | 290 +++++ .../draco/compression/entropy/shannon_entropy.cc | 147 +++ .../draco/compression/entropy/shannon_entropy.h | 110 ++ .../draco/compression/entropy/symbol_decoding.cc | 181 +++ .../draco/compression/entropy/symbol_decoding.h | 29 + .../draco/compression/entropy/symbol_encoding.cc | 376 ++++++ .../draco/compression/entropy/symbol_encoding.h | 47 + .../draco/src/draco/compression/expert_encode.cc | 182 +++ .../draco/src/draco/compression/expert_encode.h | 147 +++ .../src/draco/compression/mesh/mesh_decoder.cc | 37 + .../src/draco/compression/mesh/mesh_decoder.h | 68 ++ .../compression/mesh/mesh_edgebreaker_decoder.cc | 70 ++ .../compression/mesh/mesh_edgebreaker_decoder.h | 54 + .../mesh/mesh_edgebreaker_decoder_impl.cc | 1216 ++++++++++++++++++++ .../mesh/mesh_edgebreaker_decoder_impl.h | 228 ++++ .../mesh/mesh_edgebreaker_decoder_impl_interface.h | 47 + .../compression/mesh/mesh_edgebreaker_encoder.cc | 195 ++++ .../compression/mesh/mesh_edgebreaker_encoder.h | 73 ++ .../mesh/mesh_edgebreaker_encoder_impl.cc | 854 ++++++++++++++ .../mesh/mesh_edgebreaker_encoder_impl.h | 210 ++++ .../mesh/mesh_edgebreaker_encoder_impl_interface.h | 57 + .../compression/mesh/mesh_edgebreaker_shared.h | 131 +++ .../mesh/mesh_edgebreaker_traversal_decoder.h | 201 ++++ .../mesh/mesh_edgebreaker_traversal_encoder.h | 139 +++ ...mesh_edgebreaker_traversal_predictive_decoder.h | 134 +++ ...mesh_edgebreaker_traversal_predictive_encoder.h | 172 +++ .../mesh_edgebreaker_traversal_valence_decoder.h | 210 ++++ .../mesh_edgebreaker_traversal_valence_encoder.h | 226 ++++ .../src/draco/compression/mesh/mesh_encoder.cc | 34 + .../src/draco/compression/mesh/mesh_encoder.h | 84 ++ .../compression/mesh/mesh_sequential_decoder.cc | 164 +++ .../compression/mesh/mesh_sequential_decoder.h | 39 + .../compression/mesh/mesh_sequential_encoder.cc | 132 +++ .../compression/mesh/mesh_sequential_encoder.h | 57 + .../mesh/traverser/depth_first_traverser.h | 172 +++ .../traverser/max_prediction_degree_traverser.h | 226 ++++ .../mesh_attribute_indices_encoding_observer.h | 76 ++ .../mesh/traverser/mesh_traversal_sequencer.h | 113 ++ .../compression/mesh/traverser/traverser_base.h | 87 ++ .../dynamic_integer_points_kd_tree_decoder.cc | 26 + .../dynamic_integer_points_kd_tree_decoder.h | 330 ++++++ .../dynamic_integer_points_kd_tree_encoder.cc | 26 + .../dynamic_integer_points_kd_tree_encoder.h | 371 ++++++ .../algorithms/float_points_tree_decoder.cc | 141 +++ .../algorithms/float_points_tree_decoder.h | 141 +++ .../algorithms/float_points_tree_encoder.cc | 94 ++ .../algorithms/float_points_tree_encoder.h | 126 ++ .../algorithms/integer_points_kd_tree_decoder.cc | 45 + .../algorithms/integer_points_kd_tree_decoder.h | 314 +++++ .../algorithms/integer_points_kd_tree_encoder.cc | 45 + .../algorithms/integer_points_kd_tree_encoder.h | 404 +++++++ .../algorithms/point_cloud_compression_method.h | 34 + .../point_cloud/algorithms/point_cloud_types.h | 76 ++ .../point_cloud/algorithms/quantize_points_3.h | 84 ++ .../point_cloud/algorithms/queuing_policy.h | 75 ++ .../compression/point_cloud/point_cloud_decoder.cc | 189 +++ .../compression/point_cloud/point_cloud_decoder.h | 118 ++ .../compression/point_cloud/point_cloud_encoder.cc | 304 +++++ .../compression/point_cloud/point_cloud_encoder.h | 158 +++ .../point_cloud/point_cloud_kd_tree_decoder.cc | 40 + .../point_cloud/point_cloud_kd_tree_decoder.h | 31 + .../point_cloud/point_cloud_kd_tree_encoder.cc | 43 + .../point_cloud/point_cloud_kd_tree_encoder.h | 45 + .../point_cloud/point_cloud_sequential_decoder.cc | 42 + .../point_cloud/point_cloud_sequential_decoder.h | 33 + .../point_cloud/point_cloud_sequential_encoder.cc | 49 + .../point_cloud/point_cloud_sequential_encoder.h | 43 + extern/draco/draco/src/draco/core/bit_utils.cc | 36 + extern/draco/draco/src/draco/core/bit_utils.h | 124 ++ extern/draco/draco/src/draco/core/bounding_box.cc | 23 + extern/draco/draco/src/draco/core/bounding_box.h | 54 + extern/draco/draco/src/draco/core/cycle_timer.cc | 49 + extern/draco/draco/src/draco/core/cycle_timer.h | 50 + extern/draco/draco/src/draco/core/data_buffer.cc | 61 + extern/draco/draco/src/draco/core/data_buffer.h | 82 ++ .../draco/draco/src/draco/core/decoder_buffer.cc | 72 ++ extern/draco/draco/src/draco/core/decoder_buffer.h | 216 ++++ extern/draco/draco/src/draco/core/divide.cc | 88 ++ extern/draco/draco/src/draco/core/divide.h | 42 + .../draco/draco/src/draco/core/draco_index_type.h | 183 +++ .../draco/src/draco/core/draco_index_type_vector.h | 83 ++ extern/draco/draco/src/draco/core/draco_types.cc | 61 + extern/draco/draco/src/draco/core/draco_types.h | 52 + extern/draco/draco/src/draco/core/draco_version.h | 27 + .../draco/draco/src/draco/core/encoder_buffer.cc | 93 ++ extern/draco/draco/src/draco/core/encoder_buffer.h | 152 +++ extern/draco/draco/src/draco/core/hash_utils.cc | 58 + extern/draco/draco/src/draco/core/hash_utils.h | 64 ++ extern/draco/draco/src/draco/core/macros.h | 110 ++ extern/draco/draco/src/draco/core/math_utils.h | 55 + extern/draco/draco/src/draco/core/options.cc | 94 ++ extern/draco/draco/src/draco/core/options.h | 150 +++ .../draco/src/draco/core/quantization_utils.cc | 42 + .../draco/src/draco/core/quantization_utils.h | 82 ++ extern/draco/draco/src/draco/core/status.h | 77 ++ extern/draco/draco/src/draco/core/status_or.h | 81 ++ .../draco/draco/src/draco/core/varint_decoding.h | 80 ++ .../draco/draco/src/draco/core/varint_encoding.h | 61 + extern/draco/draco/src/draco/core/vector_d.h | 349 ++++++ extern/draco/draco/src/draco/draco_features.h | 10 + extern/draco/draco/src/draco/mesh/corner_table.cc | 440 +++++++ extern/draco/draco/src/draco/mesh/corner_table.h | 396 +++++++ .../draco/src/draco/mesh/corner_table_iterators.h | 289 +++++ extern/draco/draco/src/draco/mesh/mesh.cc | 40 + extern/draco/draco/src/draco/mesh/mesh.h | 152 +++ .../draco/src/draco/mesh/mesh_are_equivalent.cc | 205 ++++ .../draco/src/draco/mesh/mesh_are_equivalent.h | 71 ++ .../src/draco/mesh/mesh_attribute_corner_table.cc | 211 ++++ .../src/draco/mesh/mesh_attribute_corner_table.h | 196 ++++ extern/draco/draco/src/draco/mesh/mesh_cleanup.cc | 188 +++ extern/draco/draco/src/draco/mesh/mesh_cleanup.h | 43 + .../draco/src/draco/mesh/mesh_misc_functions.cc | 63 + .../draco/src/draco/mesh/mesh_misc_functions.h | 98 ++ .../draco/draco/src/draco/mesh/mesh_stripifier.cc | 102 ++ .../draco/draco/src/draco/mesh/mesh_stripifier.h | 260 +++++ .../src/draco/mesh/triangle_soup_mesh_builder.cc | 89 ++ .../src/draco/mesh/triangle_soup_mesh_builder.h | 63 + extern/draco/draco/src/draco/mesh/valence_cache.h | 142 +++ .../draco/src/draco/metadata/geometry_metadata.cc | 44 + .../draco/src/draco/metadata/geometry_metadata.h | 140 +++ extern/draco/draco/src/draco/metadata/metadata.cc | 132 +++ extern/draco/draco/src/draco/metadata/metadata.h | 208 ++++ .../draco/src/draco/metadata/metadata_decoder.cc | 142 +++ .../draco/src/draco/metadata/metadata_decoder.h | 42 + .../draco/src/draco/metadata/metadata_encoder.cc | 97 ++ .../draco/src/draco/metadata/metadata_encoder.h | 41 + .../draco/src/draco/point_cloud/point_cloud.cc | 281 +++++ .../draco/src/draco/point_cloud/point_cloud.h | 244 ++++ .../src/draco/point_cloud/point_cloud_builder.cc | 76 ++ .../src/draco/point_cloud/point_cloud_builder.h | 80 ++ extern/draco/dracoenc/AUTHORS | 7 - extern/draco/dracoenc/CMakeLists.txt | 188 --- extern/draco/dracoenc/LICENSE | 202 ---- extern/draco/dracoenc/cmake/DracoConfig.cmake | 3 - extern/draco/dracoenc/cmake/FindDraco.cmake | 58 - extern/draco/dracoenc/cmake/compiler_flags.cmake | 216 ---- extern/draco/dracoenc/cmake/compiler_tests.cmake | 124 -- extern/draco/dracoenc/cmake/draco_features.cmake | 57 - .../draco/dracoenc/cmake/draco_test_config.h.cmake | 13 - extern/draco/dracoenc/cmake/draco_version.cc.cmake | 21 - extern/draco/dracoenc/cmake/draco_version.h.cmake | 21 - extern/draco/dracoenc/cmake/msvc_runtime.cmake | 14 - extern/draco/dracoenc/cmake/sanitizers.cmake | 19 - .../dracoenc/cmake/toolchains/arm-ios-common.cmake | 13 - .../toolchains/arm64-android-ndk-libcpp.cmake | 12 - .../dracoenc/cmake/toolchains/arm64-ios.cmake | 14 - .../cmake/toolchains/arm64-linux-gcc.cmake | 18 - .../toolchains/armv7-android-ndk-libcpp.cmake | 12 - .../dracoenc/cmake/toolchains/armv7-ios.cmake | 14 - .../cmake/toolchains/armv7-linux-gcc.cmake | 24 - .../dracoenc/cmake/toolchains/armv7s-ios.cmake | 14 - .../cmake/toolchains/x86-android-ndk-libcpp.cmake | 12 - .../toolchains/x86_64-android-ndk-libcpp.cmake | 12 - extern/draco/dracoenc/cmake/util.cmake | 73 -- .../src/draco/animation/keyframe_animation.cc | 55 - .../src/draco/animation/keyframe_animation.h | 108 -- .../draco/animation/keyframe_animation_decoder.cc | 29 - .../draco/animation/keyframe_animation_decoder.h | 34 - .../draco/animation/keyframe_animation_encoder.cc | 28 - .../draco/animation/keyframe_animation_encoder.h | 39 - .../animation/keyframe_animation_encoding_test.cc | 168 --- .../src/draco/animation/keyframe_animation_test.cc | 102 -- .../attributes/attribute_octahedron_transform.cc | 86 -- .../attributes/attribute_octahedron_transform.h | 60 - .../attributes/attribute_quantization_transform.cc | 178 --- .../attributes/attribute_quantization_transform.h | 78 -- .../src/draco/attributes/attribute_transform.cc | 44 - .../src/draco/attributes/attribute_transform.h | 46 - .../draco/attributes/attribute_transform_data.h | 71 -- .../draco/attributes/attribute_transform_type.h | 30 - .../src/draco/attributes/geometry_attribute.cc | 91 -- .../src/draco/attributes/geometry_attribute.h | 304 ----- .../src/draco/attributes/geometry_indices.h | 54 - .../src/draco/attributes/point_attribute.cc | 205 ---- .../src/draco/attributes/point_attribute.h | 186 --- .../src/draco/attributes/point_attribute_test.cc | 129 --- .../compression/attributes/attributes_decoder.cc | 97 -- .../compression/attributes/attributes_decoder.h | 94 -- .../attributes/attributes_decoder_interface.h | 62 - .../compression/attributes/attributes_encoder.cc | 49 - .../compression/attributes/attributes_encoder.h | 149 --- .../attributes/kd_tree_attributes_decoder.cc | 515 --------- .../attributes/kd_tree_attributes_decoder.h | 46 - .../attributes/kd_tree_attributes_encoder.cc | 289 ----- .../attributes/kd_tree_attributes_encoder.h | 51 - .../attributes/kd_tree_attributes_shared.h | 28 - .../compression/attributes/linear_sequencer.h | 50 - .../mesh_attribute_indices_encoding_data.h | 58 - .../attributes/normal_compression_utils.h | 335 ------ .../draco/compression/attributes/point_d_vector.h | 275 ----- .../compression/attributes/point_d_vector_test.cc | 359 ------ .../compression/attributes/points_sequencer.h | 63 - ...cheme_constrained_multi_parallelogram_decoder.h | 227 ---- ...cheme_constrained_multi_parallelogram_encoder.h | 410 ------- ...scheme_constrained_multi_parallelogram_shared.h | 34 - .../mesh_prediction_scheme_data.h | 72 -- .../mesh_prediction_scheme_decoder.h | 46 - .../mesh_prediction_scheme_encoder.h | 46 - ...sh_prediction_scheme_geometric_normal_decoder.h | 163 --- ...sh_prediction_scheme_geometric_normal_encoder.h | 175 --- ...iction_scheme_geometric_normal_predictor_area.h | 110 -- ...iction_scheme_geometric_normal_predictor_base.h | 94 -- ...prediction_scheme_multi_parallelogram_decoder.h | 127 -- ...prediction_scheme_multi_parallelogram_encoder.h | 133 --- .../mesh_prediction_scheme_parallelogram_decoder.h | 98 -- .../mesh_prediction_scheme_parallelogram_encoder.h | 111 -- .../mesh_prediction_scheme_parallelogram_shared.h | 72 -- .../mesh_prediction_scheme_tex_coords_decoder.h | 335 ------ .../mesh_prediction_scheme_tex_coords_encoder.h | 313 ----- ...prediction_scheme_tex_coords_portable_decoder.h | 131 --- ...prediction_scheme_tex_coords_portable_encoder.h | 129 --- ...ediction_scheme_tex_coords_portable_predictor.h | 252 ---- .../prediction_schemes/prediction_scheme_decoder.h | 89 -- .../prediction_scheme_decoder_factory.h | 193 ---- .../prediction_scheme_decoder_interface.h | 53 - .../prediction_scheme_decoding_transform.h | 65 -- .../prediction_scheme_delta_decoder.h | 65 -- .../prediction_scheme_delta_encoder.h | 69 -- .../prediction_schemes/prediction_scheme_encoder.h | 89 -- .../prediction_scheme_encoder_factory.cc | 72 -- .../prediction_scheme_encoder_factory.h | 127 -- .../prediction_scheme_encoder_interface.h | 55 - .../prediction_scheme_encoding_transform.h | 77 -- .../prediction_schemes/prediction_scheme_factory.h | 83 -- .../prediction_scheme_interface.h | 60 - ...l_octahedron_canonicalized_decoding_transform.h | 113 -- ...l_octahedron_canonicalized_encoding_transform.h | 116 -- ...ormal_octahedron_canonicalized_transform_base.h | 101 -- ...rmal_octahedron_canonicalized_transform_test.cc | 192 ---- ...n_scheme_normal_octahedron_decoding_transform.h | 102 -- ...n_scheme_normal_octahedron_encoding_transform.h | 105 -- ...ction_scheme_normal_octahedron_transform_base.h | 89 -- ...tion_scheme_normal_octahedron_transform_test.cc | 71 -- .../prediction_scheme_wrap_decoding_transform.h | 67 -- .../prediction_scheme_wrap_encoding_transform.h | 78 -- .../prediction_scheme_wrap_transform_base.h | 116 -- .../attributes/sequential_attribute_decoder.cc | 113 -- .../attributes/sequential_attribute_decoder.h | 87 -- .../sequential_attribute_decoders_controller.cc | 140 --- .../sequential_attribute_decoders_controller.h | 60 - .../attributes/sequential_attribute_encoder.cc | 104 -- .../attributes/sequential_attribute_encoder.h | 133 --- .../sequential_attribute_encoders_controller.cc | 149 --- .../sequential_attribute_encoders_controller.h | 110 -- .../sequential_integer_attribute_decoder.cc | 213 ---- .../sequential_integer_attribute_decoder.h | 76 -- .../sequential_integer_attribute_encoder.cc | 225 ---- .../sequential_integer_attribute_encoder.h | 67 -- .../sequential_integer_attribute_encoding_test.cc | 67 -- .../sequential_normal_attribute_decoder.cc | 89 -- .../sequential_normal_attribute_decoder.h | 83 -- .../sequential_normal_attribute_encoder.cc | 50 - .../sequential_normal_attribute_encoder.h | 82 -- .../sequential_quantization_attribute_decoder.cc | 112 -- .../sequential_quantization_attribute_decoder.h | 57 - .../sequential_quantization_attribute_encoder.cc | 74 -- .../sequential_quantization_attribute_encoder.h | 52 - .../bit_coders/adaptive_rans_bit_coding_shared.h | 43 - .../bit_coders/adaptive_rans_bit_decoder.cc | 67 -- .../bit_coders/adaptive_rans_bit_decoder.h | 54 - .../bit_coders/adaptive_rans_bit_encoder.cc | 59 - .../bit_coders/adaptive_rans_bit_encoder.h | 61 - .../compression/bit_coders/direct_bit_decoder.cc | 50 - .../compression/bit_coders/direct_bit_decoder.h | 90 -- .../compression/bit_coders/direct_bit_encoder.cc | 39 - .../compression/bit_coders/direct_bit_encoder.h | 89 -- .../bit_coders/folded_integer_bit_decoder.h | 76 -- .../bit_coders/folded_integer_bit_encoder.h | 82 -- .../compression/bit_coders/rans_bit_decoder.cc | 77 -- .../compression/bit_coders/rans_bit_decoder.h | 56 - .../compression/bit_coders/rans_bit_encoder.cc | 123 -- .../compression/bit_coders/rans_bit_encoder.h | 57 - .../compression/bit_coders/rans_coding_test.cc | 9 - .../compression/bit_coders/symbol_bit_decoder.cc | 47 - .../compression/bit_coders/symbol_bit_decoder.h | 36 - .../compression/bit_coders/symbol_bit_encoder.cc | 30 - .../compression/bit_coders/symbol_bit_encoder.h | 36 - .../draco/compression/config/compression_shared.h | 153 --- .../src/draco/compression/config/decoder_options.h | 34 - .../compression/config/decoder_options_test.cc | 67 -- .../src/draco/compression/config/draco_options.h | 244 ---- .../src/draco/compression/config/encoder_options.h | 97 -- .../draco/compression/config/encoding_features.h | 39 - .../draco/dracoenc/src/draco/compression/decode.cc | 132 --- .../draco/dracoenc/src/draco/compression/decode.h | 81 -- .../dracoenc/src/draco/compression/decode_test.cc | 196 ---- .../draco/dracoenc/src/draco/compression/encode.cc | 95 -- .../draco/dracoenc/src/draco/compression/encode.h | 140 --- .../dracoenc/src/draco/compression/encode_base.h | 126 -- .../dracoenc/src/draco/compression/encode_test.cc | 293 ----- .../dracoenc/src/draco/compression/entropy/ans.h | 517 --------- .../draco/compression/entropy/rans_symbol_coding.h | 54 - .../compression/entropy/rans_symbol_decoder.h | 153 --- .../compression/entropy/rans_symbol_encoder.h | 280 ----- .../draco/compression/entropy/shannon_entropy.cc | 143 --- .../draco/compression/entropy/shannon_entropy.h | 110 -- .../compression/entropy/shannon_entropy_test.cc | 56 - .../compression/entropy/symbol_coding_test.cc | 170 --- .../draco/compression/entropy/symbol_decoding.cc | 171 --- .../draco/compression/entropy/symbol_decoding.h | 29 - .../draco/compression/entropy/symbol_encoding.cc | 370 ------ .../draco/compression/entropy/symbol_encoding.h | 47 - .../src/draco/compression/expert_encode.cc | 177 --- .../dracoenc/src/draco/compression/expert_encode.h | 147 --- .../src/draco/compression/mesh/mesh_decoder.cc | 35 - .../src/draco/compression/mesh/mesh_decoder.h | 68 -- .../draco/compression/mesh/mesh_decoder_helpers.h | 84 -- .../compression/mesh/mesh_edgebreaker_decoder.cc | 67 -- .../compression/mesh/mesh_edgebreaker_decoder.h | 55 - .../mesh/mesh_edgebreaker_decoder_impl.cc | 1150 ------------------ .../mesh/mesh_edgebreaker_decoder_impl.h | 226 ---- .../mesh/mesh_edgebreaker_decoder_impl_interface.h | 47 - .../compression/mesh/mesh_edgebreaker_encoder.cc | 182 --- .../compression/mesh/mesh_edgebreaker_encoder.h | 73 -- .../mesh/mesh_edgebreaker_encoder_impl.cc | 830 ------------- .../mesh/mesh_edgebreaker_encoder_impl.h | 210 ---- .../mesh/mesh_edgebreaker_encoder_impl_interface.h | 57 - .../mesh/mesh_edgebreaker_encoding_test.cc | 247 ---- .../compression/mesh/mesh_edgebreaker_shared.h | 131 --- .../mesh/mesh_edgebreaker_traversal_decoder.h | 193 ---- .../mesh/mesh_edgebreaker_traversal_encoder.h | 139 --- ...mesh_edgebreaker_traversal_predictive_decoder.h | 132 --- ...mesh_edgebreaker_traversal_predictive_encoder.h | 171 --- .../mesh_edgebreaker_traversal_valence_decoder.h | 202 ---- .../mesh_edgebreaker_traversal_valence_encoder.h | 223 ---- .../src/draco/compression/mesh/mesh_encoder.cc | 33 - .../src/draco/compression/mesh/mesh_encoder.h | 84 -- .../draco/compression/mesh/mesh_encoder_helpers.h | 81 -- .../draco/compression/mesh/mesh_encoder_test.cc | 93 -- .../compression/mesh/mesh_sequential_decoder.cc | 150 --- .../compression/mesh/mesh_sequential_decoder.h | 39 - .../compression/mesh/mesh_sequential_encoder.cc | 131 --- .../compression/mesh/mesh_sequential_encoder.h | 57 - .../mesh/traverser/depth_first_traverser.h | 169 --- .../traverser/max_prediction_degree_traverser.h | 223 ---- .../mesh_attribute_indices_encoding_observer.h | 76 -- .../mesh/traverser/mesh_traversal_sequencer.h | 110 -- .../compression/mesh/traverser/traverser_base.h | 85 -- .../dynamic_integer_points_kd_tree_decoder.cc | 26 - .../dynamic_integer_points_kd_tree_decoder.h | 310 ----- .../dynamic_integer_points_kd_tree_encoder.cc | 26 - .../dynamic_integer_points_kd_tree_encoder.h | 365 ------ .../algorithms/float_points_tree_decoder.cc | 143 --- .../algorithms/float_points_tree_decoder.h | 127 -- .../algorithms/float_points_tree_encoder.cc | 94 -- .../algorithms/float_points_tree_encoder.h | 124 -- .../algorithms/integer_points_kd_tree_decoder.cc | 45 - .../algorithms/integer_points_kd_tree_decoder.h | 299 ----- .../algorithms/integer_points_kd_tree_encoder.cc | 45 - .../algorithms/integer_points_kd_tree_encoder.h | 397 ------- .../algorithms/point_cloud_compression_method.h | 34 - .../point_cloud/algorithms/point_cloud_types.h | 75 -- .../point_cloud/algorithms/quantize_points_3.h | 83 -- .../point_cloud/algorithms/queuing_policy.h | 75 -- .../compression/point_cloud/point_cloud_decoder.cc | 167 --- .../compression/point_cloud/point_cloud_decoder.h | 116 -- .../compression/point_cloud/point_cloud_encoder.cc | 283 ----- .../compression/point_cloud/point_cloud_encoder.h | 158 --- .../point_cloud/point_cloud_kd_tree_decoder.cc | 38 - .../point_cloud/point_cloud_kd_tree_decoder.h | 31 - .../point_cloud/point_cloud_kd_tree_encoder.cc | 42 - .../point_cloud/point_cloud_kd_tree_encoder.h | 45 - .../point_cloud_kd_tree_encoding_test.cc | 456 -------- .../point_cloud/point_cloud_sequential_decoder.cc | 41 - .../point_cloud/point_cloud_sequential_decoder.h | 33 - .../point_cloud/point_cloud_sequential_encoder.cc | 49 - .../point_cloud/point_cloud_sequential_encoder.h | 43 - .../point_cloud_sequential_encoding_test.cc | 90 -- extern/draco/dracoenc/src/draco/core/bit_utils.cc | 36 - extern/draco/dracoenc/src/draco/core/bit_utils.h | 123 -- .../draco/dracoenc/src/draco/core/bounding_box.cc | 23 - .../draco/dracoenc/src/draco/core/bounding_box.h | 52 - .../src/draco/core/buffer_bit_coding_test.cc | 116 -- .../draco/dracoenc/src/draco/core/cycle_timer.cc | 49 - extern/draco/dracoenc/src/draco/core/cycle_timer.h | 50 - .../draco/dracoenc/src/draco/core/data_buffer.cc | 56 - extern/draco/dracoenc/src/draco/core/data_buffer.h | 82 -- .../dracoenc/src/draco/core/decoder_buffer.cc | 70 -- .../draco/dracoenc/src/draco/core/decoder_buffer.h | 210 ---- extern/draco/dracoenc/src/draco/core/divide.cc | 88 -- extern/draco/dracoenc/src/draco/core/divide.h | 41 - .../dracoenc/src/draco/core/draco_index_type.h | 183 --- .../src/draco/core/draco_index_type_vector.h | 77 -- .../dracoenc/src/draco/core/draco_test_base.h | 11 - .../dracoenc/src/draco/core/draco_test_utils.cc | 83 -- .../dracoenc/src/draco/core/draco_test_utils.h | 70 -- .../draco/dracoenc/src/draco/core/draco_tests.cc | 6 - .../draco/dracoenc/src/draco/core/draco_types.cc | 61 - extern/draco/dracoenc/src/draco/core/draco_types.h | 51 - .../draco/dracoenc/src/draco/core/draco_version.h | 27 - .../dracoenc/src/draco/core/encoder_buffer.cc | 90 -- .../draco/dracoenc/src/draco/core/encoder_buffer.h | 148 --- extern/draco/dracoenc/src/draco/core/hash_utils.cc | 57 - extern/draco/dracoenc/src/draco/core/hash_utils.h | 64 -- extern/draco/dracoenc/src/draco/core/macros.h | 111 -- extern/draco/dracoenc/src/draco/core/math_utils.h | 54 - .../dracoenc/src/draco/core/math_utils_test.cc | 22 - extern/draco/dracoenc/src/draco/core/options.cc | 89 -- extern/draco/dracoenc/src/draco/core/options.h | 145 --- .../dracoenc/src/draco/core/quantization_utils.cc | 41 - .../dracoenc/src/draco/core/quantization_utils.h | 81 -- .../src/draco/core/quantization_utils_test.cc | 91 -- extern/draco/dracoenc/src/draco/core/status.h | 75 -- extern/draco/dracoenc/src/draco/core/status_or.h | 81 -- .../draco/dracoenc/src/draco/core/status_test.cc | 38 - extern/draco/dracoenc/src/draco/core/statusor.h | 81 -- .../dracoenc/src/draco/core/varint_decoding.h | 59 - .../dracoenc/src/draco/core/varint_encoding.h | 57 - extern/draco/dracoenc/src/draco/core/vector_d.h | 305 ----- .../draco/dracoenc/src/draco/core/vector_d_test.cc | 235 ---- extern/draco/dracoenc/src/draco/draco_features.h | 8 - extern/draco/dracoenc/src/draco/io/mesh_io.cc | 69 -- extern/draco/dracoenc/src/draco/io/mesh_io.h | 102 -- extern/draco/dracoenc/src/draco/io/obj_decoder.cc | 689 ----------- extern/draco/dracoenc/src/draco/io/obj_decoder.h | 130 --- .../dracoenc/src/draco/io/obj_decoder_test.cc | 190 --- extern/draco/dracoenc/src/draco/io/obj_encoder.cc | 314 ----- extern/draco/dracoenc/src/draco/io/obj_encoder.h | 92 -- .../dracoenc/src/draco/io/obj_encoder_test.cc | 106 -- extern/draco/dracoenc/src/draco/io/parser_utils.cc | 232 ---- extern/draco/dracoenc/src/draco/io/parser_utils.h | 64 -- extern/draco/dracoenc/src/draco/io/ply_decoder.cc | 295 ----- extern/draco/dracoenc/src/draco/io/ply_decoder.h | 69 -- .../dracoenc/src/draco/io/ply_decoder_test.cc | 90 -- extern/draco/dracoenc/src/draco/io/ply_encoder.cc | 201 ---- extern/draco/dracoenc/src/draco/io/ply_encoder.h | 54 - .../dracoenc/src/draco/io/ply_property_reader.h | 96 -- .../dracoenc/src/draco/io/ply_property_writer.h | 94 -- extern/draco/dracoenc/src/draco/io/ply_reader.cc | 295 ----- extern/draco/dracoenc/src/draco/io/ply_reader.h | 152 --- .../draco/dracoenc/src/draco/io/ply_reader_test.cc | 147 --- .../draco/dracoenc/src/draco/io/point_cloud_io.cc | 58 - .../draco/dracoenc/src/draco/io/point_cloud_io.h | 89 -- .../dracoenc/src/draco/io/point_cloud_io_test.cc | 115 -- .../draco/dracoenc/src/draco/mesh/corner_table.cc | 419 ------- .../draco/dracoenc/src/draco/mesh/corner_table.h | 367 ------ .../src/draco/mesh/corner_table_iterators.h | 281 ----- extern/draco/dracoenc/src/draco/mesh/mesh.cc | 43 - extern/draco/dracoenc/src/draco/mesh/mesh.h | 151 --- .../dracoenc/src/draco/mesh/mesh_are_equivalent.cc | 192 ---- .../dracoenc/src/draco/mesh/mesh_are_equivalent.h | 71 -- .../src/draco/mesh/mesh_are_equivalent_test.cc | 99 -- .../src/draco/mesh/mesh_attribute_corner_table.cc | 202 ---- .../src/draco/mesh/mesh_attribute_corner_table.h | 177 --- .../draco/dracoenc/src/draco/mesh/mesh_cleanup.cc | 185 --- .../draco/dracoenc/src/draco/mesh/mesh_cleanup.h | 43 - .../dracoenc/src/draco/mesh/mesh_cleanup_test.cc | 131 --- .../dracoenc/src/draco/mesh/mesh_misc_functions.cc | 58 - .../dracoenc/src/draco/mesh/mesh_misc_functions.h | 80 -- .../dracoenc/src/draco/mesh/mesh_stripifier.cc | 99 -- .../dracoenc/src/draco/mesh/mesh_stripifier.h | 252 ---- .../src/draco/mesh/triangle_soup_mesh_builder.cc | 87 -- .../src/draco/mesh/triangle_soup_mesh_builder.h | 64 -- .../draco/mesh/triangle_soup_mesh_builder_test.cc | 197 ---- .../draco/dracoenc/src/draco/mesh/valence_cache.h | 136 --- .../src/draco/metadata/geometry_metadata.cc | 40 - .../src/draco/metadata/geometry_metadata.h | 126 -- .../draco/dracoenc/src/draco/metadata/metadata.cc | 130 --- .../draco/dracoenc/src/draco/metadata/metadata.h | 208 ---- .../src/draco/metadata/metadata_decoder.cc | 103 -- .../dracoenc/src/draco/metadata/metadata_decoder.h | 42 - .../src/draco/metadata/metadata_encoder.cc | 92 -- .../dracoenc/src/draco/metadata/metadata_encoder.h | 41 - .../src/draco/metadata/metadata_encoder_test.cc | 165 --- .../dracoenc/src/draco/metadata/metadata_test.cc | 156 --- .../dracoenc/src/draco/point_cloud/point_cloud.cc | 266 ----- .../dracoenc/src/draco/point_cloud/point_cloud.h | 241 ---- .../src/draco/point_cloud/point_cloud_builder.cc | 75 -- .../src/draco/point_cloud/point_cloud_builder.h | 80 -- .../draco/point_cloud/point_cloud_builder_test.cc | 171 --- .../src/draco/point_cloud/point_cloud_test.cc | 131 --- .../dracoenc/src/draco/tools/draco_decoder.cc | 178 --- .../dracoenc/src/draco/tools/draco_encoder.cc | 373 ------ extern/draco/src/common.cpp | 77 ++ extern/draco/src/common.h | 50 + extern/draco/src/decoder.cpp | 222 ++++ extern/draco/src/decoder.h | 53 + extern/draco/src/draco-compressor.cpp | 277 ----- extern/draco/src/draco-compressor.h | 173 --- extern/draco/src/encoder.cpp | 247 ++++ extern/draco/src/encoder.h | 51 + 613 files changed, 33495 insertions(+), 41937 deletions(-) create mode 100644 extern/draco/draco/AUTHORS create mode 100644 extern/draco/draco/CMakeLists.txt create mode 100644 extern/draco/draco/LICENSE create mode 100644 extern/draco/draco/src/draco/animation/keyframe_animation.cc create mode 100644 extern/draco/draco/src/draco/animation/keyframe_animation.h create mode 100644 extern/draco/draco/src/draco/animation/keyframe_animation_decoder.cc create mode 100644 extern/draco/draco/src/draco/animation/keyframe_animation_decoder.h create mode 100644 extern/draco/draco/src/draco/animation/keyframe_animation_encoder.cc create mode 100644 extern/draco/draco/src/draco/animation/keyframe_animation_encoder.h create mode 100644 extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc create mode 100644 extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h create mode 100644 extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc create mode 100644 extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h create mode 100644 extern/draco/draco/src/draco/attributes/attribute_transform.cc create mode 100644 extern/draco/draco/src/draco/attributes/attribute_transform.h create mode 100644 extern/draco/draco/src/draco/attributes/attribute_transform_data.h create mode 100644 extern/draco/draco/src/draco/attributes/attribute_transform_type.h create mode 100644 extern/draco/draco/src/draco/attributes/geometry_attribute.cc create mode 100644 extern/draco/draco/src/draco/attributes/geometry_attribute.h create mode 100644 extern/draco/draco/src/draco/attributes/geometry_indices.h create mode 100644 extern/draco/draco/src/draco/attributes/point_attribute.cc create mode 100644 extern/draco/draco/src/draco/attributes/point_attribute.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/attributes_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/attributes_decoder_interface.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/attributes_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_shared.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/linear_sequencer.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/mesh_attribute_indices_encoding_data.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/point_d_vector.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/points_sequencer.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_encoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/config/compression_shared.h create mode 100644 extern/draco/draco/src/draco/compression/config/decoder_options.h create mode 100644 extern/draco/draco/src/draco/compression/config/draco_options.h create mode 100644 extern/draco/draco/src/draco/compression/config/encoder_options.h create mode 100644 extern/draco/draco/src/draco/compression/config/encoding_features.h create mode 100644 extern/draco/draco/src/draco/compression/decode.cc create mode 100644 extern/draco/draco/src/draco/compression/decode.h create mode 100644 extern/draco/draco/src/draco/compression/encode.cc create mode 100644 extern/draco/draco/src/draco/compression/encode.h create mode 100644 extern/draco/draco/src/draco/compression/encode_base.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/ans.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/rans_symbol_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/shannon_entropy.cc create mode 100644 extern/draco/draco/src/draco/compression/entropy/shannon_entropy.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc create mode 100644 extern/draco/draco/src/draco/compression/entropy/symbol_decoding.h create mode 100644 extern/draco/draco/src/draco/compression/entropy/symbol_encoding.cc create mode 100644 extern/draco/draco/src/draco/compression/entropy/symbol_encoding.h create mode 100644 extern/draco/draco/src/draco/compression/expert_encode.cc create mode 100644 extern/draco/draco/src/draco/compression/expert_encode.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl_interface.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_predictive_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_predictive_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/traverser/depth_first_traverser.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/traverser/max_prediction_degree_traverser.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h create mode 100644 extern/draco/draco/src/draco/compression/mesh/traverser/traverser_base.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/point_cloud_types.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/algorithms/queuing_policy.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_kd_tree_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_kd_tree_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_sequential_decoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_sequential_decoder.h create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc create mode 100644 extern/draco/draco/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h create mode 100644 extern/draco/draco/src/draco/core/bit_utils.cc create mode 100644 extern/draco/draco/src/draco/core/bit_utils.h create mode 100644 extern/draco/draco/src/draco/core/bounding_box.cc create mode 100644 extern/draco/draco/src/draco/core/bounding_box.h create mode 100644 extern/draco/draco/src/draco/core/cycle_timer.cc create mode 100644 extern/draco/draco/src/draco/core/cycle_timer.h create mode 100644 extern/draco/draco/src/draco/core/data_buffer.cc create mode 100644 extern/draco/draco/src/draco/core/data_buffer.h create mode 100644 extern/draco/draco/src/draco/core/decoder_buffer.cc create mode 100644 extern/draco/draco/src/draco/core/decoder_buffer.h create mode 100644 extern/draco/draco/src/draco/core/divide.cc create mode 100644 extern/draco/draco/src/draco/core/divide.h create mode 100644 extern/draco/draco/src/draco/core/draco_index_type.h create mode 100644 extern/draco/draco/src/draco/core/draco_index_type_vector.h create mode 100644 extern/draco/draco/src/draco/core/draco_types.cc create mode 100644 extern/draco/draco/src/draco/core/draco_types.h create mode 100644 extern/draco/draco/src/draco/core/draco_version.h create mode 100644 extern/draco/draco/src/draco/core/encoder_buffer.cc create mode 100644 extern/draco/draco/src/draco/core/encoder_buffer.h create mode 100644 extern/draco/draco/src/draco/core/hash_utils.cc create mode 100644 extern/draco/draco/src/draco/core/hash_utils.h create mode 100644 extern/draco/draco/src/draco/core/macros.h create mode 100644 extern/draco/draco/src/draco/core/math_utils.h create mode 100644 extern/draco/draco/src/draco/core/options.cc create mode 100644 extern/draco/draco/src/draco/core/options.h create mode 100644 extern/draco/draco/src/draco/core/quantization_utils.cc create mode 100644 extern/draco/draco/src/draco/core/quantization_utils.h create mode 100644 extern/draco/draco/src/draco/core/status.h create mode 100644 extern/draco/draco/src/draco/core/status_or.h create mode 100644 extern/draco/draco/src/draco/core/varint_decoding.h create mode 100644 extern/draco/draco/src/draco/core/varint_encoding.h create mode 100644 extern/draco/draco/src/draco/core/vector_d.h create mode 100644 extern/draco/draco/src/draco/draco_features.h create mode 100644 extern/draco/draco/src/draco/mesh/corner_table.cc create mode 100644 extern/draco/draco/src/draco/mesh/corner_table.h create mode 100644 extern/draco/draco/src/draco/mesh/corner_table_iterators.h create mode 100644 extern/draco/draco/src/draco/mesh/mesh.cc create mode 100644 extern/draco/draco/src/draco/mesh/mesh.h create mode 100644 extern/draco/draco/src/draco/mesh/mesh_are_equivalent.cc create mode 100644 extern/draco/draco/src/draco/mesh/mesh_are_equivalent.h create mode 100644 extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.cc create mode 100644 extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h create mode 100644 extern/draco/draco/src/draco/mesh/mesh_cleanup.cc create mode 100644 extern/draco/draco/src/draco/mesh/mesh_cleanup.h create mode 100644 extern/draco/draco/src/draco/mesh/mesh_misc_functions.cc create mode 100644 extern/draco/draco/src/draco/mesh/mesh_misc_functions.h create mode 100644 extern/draco/draco/src/draco/mesh/mesh_stripifier.cc create mode 100644 extern/draco/draco/src/draco/mesh/mesh_stripifier.h create mode 100644 extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc create mode 100644 extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.h create mode 100644 extern/draco/draco/src/draco/mesh/valence_cache.h create mode 100644 extern/draco/draco/src/draco/metadata/geometry_metadata.cc create mode 100644 extern/draco/draco/src/draco/metadata/geometry_metadata.h create mode 100644 extern/draco/draco/src/draco/metadata/metadata.cc create mode 100644 extern/draco/draco/src/draco/metadata/metadata.h create mode 100644 extern/draco/draco/src/draco/metadata/metadata_decoder.cc create mode 100644 extern/draco/draco/src/draco/metadata/metadata_decoder.h create mode 100644 extern/draco/draco/src/draco/metadata/metadata_encoder.cc create mode 100644 extern/draco/draco/src/draco/metadata/metadata_encoder.h create mode 100644 extern/draco/draco/src/draco/point_cloud/point_cloud.cc create mode 100644 extern/draco/draco/src/draco/point_cloud/point_cloud.h create mode 100644 extern/draco/draco/src/draco/point_cloud/point_cloud_builder.cc create mode 100644 extern/draco/draco/src/draco/point_cloud/point_cloud_builder.h delete mode 100644 extern/draco/dracoenc/AUTHORS delete mode 100644 extern/draco/dracoenc/CMakeLists.txt delete mode 100644 extern/draco/dracoenc/LICENSE delete mode 100644 extern/draco/dracoenc/cmake/DracoConfig.cmake delete mode 100644 extern/draco/dracoenc/cmake/FindDraco.cmake delete mode 100644 extern/draco/dracoenc/cmake/compiler_flags.cmake delete mode 100644 extern/draco/dracoenc/cmake/compiler_tests.cmake delete mode 100644 extern/draco/dracoenc/cmake/draco_features.cmake delete mode 100644 extern/draco/dracoenc/cmake/draco_test_config.h.cmake delete mode 100644 extern/draco/dracoenc/cmake/draco_version.cc.cmake delete mode 100644 extern/draco/dracoenc/cmake/draco_version.h.cmake delete mode 100644 extern/draco/dracoenc/cmake/msvc_runtime.cmake delete mode 100644 extern/draco/dracoenc/cmake/sanitizers.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/arm-ios-common.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/arm64-android-ndk-libcpp.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/arm64-ios.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/arm64-linux-gcc.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/armv7-android-ndk-libcpp.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/armv7-ios.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/armv7-linux-gcc.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/armv7s-ios.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/x86-android-ndk-libcpp.cmake delete mode 100644 extern/draco/dracoenc/cmake/toolchains/x86_64-android-ndk-libcpp.cmake delete mode 100644 extern/draco/dracoenc/cmake/util.cmake delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation.cc delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation.h delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation_encoding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/animation/keyframe_animation_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.cc delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_transform.cc delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_transform_data.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/attribute_transform_type.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/geometry_attribute.cc delete mode 100644 extern/draco/dracoenc/src/draco/attributes/geometry_attribute.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/geometry_indices.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/point_attribute.cc delete mode 100644 extern/draco/dracoenc/src/draco/attributes/point_attribute.h delete mode 100644 extern/draco/dracoenc/src/draco/attributes/point_attribute_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/attributes_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/attributes_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/attributes_decoder_interface.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/attributes_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/attributes_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/kd_tree_attributes_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/kd_tree_attributes_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/kd_tree_attributes_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/kd_tree_attributes_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/kd_tree_attributes_shared.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/linear_sequencer.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/mesh_attribute_indices_encoding_data.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/normal_compression_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/points_sequencer.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_encoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_integer_attribute_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_integer_attribute_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_integer_attribute_encoding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_normal_attribute_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_normal_attribute_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/attributes/sequential_quantization_attribute_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/direct_bit_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/direct_bit_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/direct_bit_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/direct_bit_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/folded_integer_bit_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/folded_integer_bit_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/rans_bit_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/rans_bit_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/rans_bit_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/rans_bit_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/rans_coding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/symbol_bit_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/symbol_bit_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/symbol_bit_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/bit_coders/symbol_bit_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/config/compression_shared.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/config/decoder_options.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/config/decoder_options_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/config/draco_options.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/config/encoder_options.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/config/encoding_features.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/decode.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/decode.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/decode_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/encode.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/encode.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/encode_base.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/encode_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/ans.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/shannon_entropy.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/shannon_entropy.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/shannon_entropy_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/symbol_coding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/symbol_decoding.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/symbol_decoding.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/symbol_encoding.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/entropy/symbol_encoding.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/expert_encode.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/expert_encode.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_decoder_helpers.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl_interface.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_shared.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_traversal_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_traversal_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_traversal_predictive_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_traversal_predictive_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_helpers.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/traverser/depth_first_traverser.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/traverser/max_prediction_degree_traverser.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/mesh/traverser/traverser_base.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_types.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/quantize_points_3.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/queuing_policy.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/bit_utils.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/bit_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/core/bounding_box.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/bounding_box.h delete mode 100644 extern/draco/dracoenc/src/draco/core/buffer_bit_coding_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/cycle_timer.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/cycle_timer.h delete mode 100644 extern/draco/dracoenc/src/draco/core/data_buffer.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/data_buffer.h delete mode 100644 extern/draco/dracoenc/src/draco/core/decoder_buffer.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/decoder_buffer.h delete mode 100644 extern/draco/dracoenc/src/draco/core/divide.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/divide.h delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_index_type.h delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_index_type_vector.h delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_test_base.h delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_test_utils.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_test_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_tests.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_types.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_types.h delete mode 100644 extern/draco/dracoenc/src/draco/core/draco_version.h delete mode 100644 extern/draco/dracoenc/src/draco/core/encoder_buffer.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/encoder_buffer.h delete mode 100644 extern/draco/dracoenc/src/draco/core/hash_utils.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/hash_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/core/macros.h delete mode 100644 extern/draco/dracoenc/src/draco/core/math_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/core/math_utils_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/options.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/options.h delete mode 100644 extern/draco/dracoenc/src/draco/core/quantization_utils.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/quantization_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/core/quantization_utils_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/status.h delete mode 100644 extern/draco/dracoenc/src/draco/core/status_or.h delete mode 100644 extern/draco/dracoenc/src/draco/core/status_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/core/statusor.h delete mode 100644 extern/draco/dracoenc/src/draco/core/varint_decoding.h delete mode 100644 extern/draco/dracoenc/src/draco/core/varint_encoding.h delete mode 100644 extern/draco/dracoenc/src/draco/core/vector_d.h delete mode 100644 extern/draco/dracoenc/src/draco/core/vector_d_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/draco_features.h delete mode 100644 extern/draco/dracoenc/src/draco/io/mesh_io.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/mesh_io.h delete mode 100644 extern/draco/dracoenc/src/draco/io/obj_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/obj_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/io/obj_decoder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/obj_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/obj_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/io/obj_encoder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/parser_utils.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/parser_utils.h delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_property_reader.h delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_property_writer.h delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_reader.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_reader.h delete mode 100644 extern/draco/dracoenc/src/draco/io/ply_reader_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/point_cloud_io.cc delete mode 100644 extern/draco/dracoenc/src/draco/io/point_cloud_io.h delete mode 100644 extern/draco/dracoenc/src/draco/io/point_cloud_io_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/corner_table.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/corner_table.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/corner_table_iterators.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_are_equivalent.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_are_equivalent.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_are_equivalent_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_attribute_corner_table.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_attribute_corner_table.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_cleanup.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_cleanup.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_cleanup_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_stripifier.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/mesh_stripifier.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.h delete mode 100644 extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/mesh/valence_cache.h delete mode 100644 extern/draco/dracoenc/src/draco/metadata/geometry_metadata.cc delete mode 100644 extern/draco/dracoenc/src/draco/metadata/geometry_metadata.h delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata.cc delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata.h delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata_decoder.h delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata_encoder.h delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/metadata/metadata_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc delete mode 100644 extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h delete mode 100644 extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc delete mode 100644 extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.h delete mode 100644 extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/point_cloud/point_cloud_test.cc delete mode 100644 extern/draco/dracoenc/src/draco/tools/draco_decoder.cc delete mode 100644 extern/draco/dracoenc/src/draco/tools/draco_encoder.cc create mode 100644 extern/draco/src/common.cpp create mode 100644 extern/draco/src/common.h create mode 100644 extern/draco/src/decoder.cpp create mode 100644 extern/draco/src/decoder.h delete mode 100644 extern/draco/src/draco-compressor.cpp delete mode 100644 extern/draco/src/draco-compressor.h create mode 100644 extern/draco/src/encoder.cpp create mode 100644 extern/draco/src/encoder.h diff --git a/extern/draco/CMakeLists.txt b/extern/draco/CMakeLists.txt index 6961fa8a769..d4cfeea4bee 100644 --- a/extern/draco/CMakeLists.txt +++ b/extern/draco/CMakeLists.txt @@ -19,20 +19,24 @@ # ***** END GPL LICENSE BLOCK ***** # Build Draco library. -add_subdirectory(dracoenc) +add_subdirectory(draco) -# Build blender-draco-exporter module. +# Build Draco-Blender bridging module. set(SRC - src/draco-compressor.cpp - src/draco-compressor.h + src/common.cpp + src/common.h + src/decoder.cpp + src/decoder.h + src/encoder.cpp + src/encoder.h ) set(INC - dracoenc/src + draco/src ) set(LIB - dracoenc + draco ) add_library(extern_draco SHARED "${SRC}") diff --git a/extern/draco/draco/AUTHORS b/extern/draco/draco/AUTHORS new file mode 100644 index 00000000000..67f63a67129 --- /dev/null +++ b/extern/draco/draco/AUTHORS @@ -0,0 +1,7 @@ +# This is the list of Draco authors for copyright purposes. +# +# This does not necessarily list everyone who has contributed code, since in +# some cases, their employer may be the copyright holder. To see the full list +# of contributors, see the revision history in source control. +Google Inc. +and other contributors diff --git a/extern/draco/draco/CMakeLists.txt b/extern/draco/draco/CMakeLists.txt new file mode 100644 index 00000000000..6f9ffce6b48 --- /dev/null +++ b/extern/draco/draco/CMakeLists.txt @@ -0,0 +1,271 @@ +remove_strict_flags() + +set(SRC + src/draco/animation/keyframe_animation.cc + src/draco/animation/keyframe_animation.h + src/draco/animation/keyframe_animation_decoder.cc + src/draco/animation/keyframe_animation_decoder.h + src/draco/animation/keyframe_animation_encoder.cc + src/draco/animation/keyframe_animation_encoder.h + src/draco/attributes/attribute_octahedron_transform.cc + src/draco/attributes/attribute_octahedron_transform.h + src/draco/attributes/attribute_quantization_transform.cc + src/draco/attributes/attribute_quantization_transform.h + src/draco/attributes/attribute_transform.cc + src/draco/attributes/attribute_transform.h + src/draco/attributes/attribute_transform_data.h + src/draco/attributes/attribute_transform_type.h + src/draco/attributes/geometry_attribute.cc + src/draco/attributes/geometry_attribute.h + src/draco/attributes/geometry_indices.h + src/draco/attributes/point_attribute.cc + src/draco/attributes/point_attribute.h + src/draco/compression/attributes/attributes_decoder.cc + src/draco/compression/attributes/attributes_decoder.h + src/draco/compression/attributes/attributes_decoder_interface.h + src/draco/compression/attributes/attributes_encoder.cc + src/draco/compression/attributes/attributes_encoder.h + src/draco/compression/attributes/kd_tree_attributes_decoder.cc + src/draco/compression/attributes/kd_tree_attributes_decoder.h + src/draco/compression/attributes/kd_tree_attributes_encoder.cc + src/draco/compression/attributes/kd_tree_attributes_encoder.h + src/draco/compression/attributes/kd_tree_attributes_shared.h + src/draco/compression/attributes/linear_sequencer.h + src/draco/compression/attributes/mesh_attribute_indices_encoding_data.h + src/draco/compression/attributes/normal_compression_utils.h + src/draco/compression/attributes/point_d_vector.h + src/draco/compression/attributes/points_sequencer.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h + src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc + src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_encoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h + src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h + src/draco/compression/attributes/sequential_attribute_decoder.cc + src/draco/compression/attributes/sequential_attribute_decoder.h + src/draco/compression/attributes/sequential_attribute_decoders_controller.cc + src/draco/compression/attributes/sequential_attribute_decoders_controller.h + src/draco/compression/attributes/sequential_attribute_encoder.cc + src/draco/compression/attributes/sequential_attribute_encoder.h + src/draco/compression/attributes/sequential_attribute_encoders_controller.cc + src/draco/compression/attributes/sequential_attribute_encoders_controller.h + src/draco/compression/attributes/sequential_integer_attribute_decoder.cc + src/draco/compression/attributes/sequential_integer_attribute_decoder.h + src/draco/compression/attributes/sequential_integer_attribute_encoder.cc + src/draco/compression/attributes/sequential_integer_attribute_encoder.h + src/draco/compression/attributes/sequential_normal_attribute_decoder.cc + src/draco/compression/attributes/sequential_normal_attribute_decoder.h + src/draco/compression/attributes/sequential_normal_attribute_encoder.cc + src/draco/compression/attributes/sequential_normal_attribute_encoder.h + src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc + src/draco/compression/attributes/sequential_quantization_attribute_decoder.h + src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc + src/draco/compression/attributes/sequential_quantization_attribute_encoder.h + src/draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h + src/draco/compression/bit_coders/adaptive_rans_bit_decoder.cc + src/draco/compression/bit_coders/adaptive_rans_bit_decoder.h + src/draco/compression/bit_coders/adaptive_rans_bit_encoder.cc + src/draco/compression/bit_coders/adaptive_rans_bit_encoder.h + src/draco/compression/bit_coders/direct_bit_decoder.cc + src/draco/compression/bit_coders/direct_bit_decoder.h + src/draco/compression/bit_coders/direct_bit_encoder.cc + src/draco/compression/bit_coders/direct_bit_encoder.h + src/draco/compression/bit_coders/folded_integer_bit_decoder.h + src/draco/compression/bit_coders/folded_integer_bit_encoder.h + src/draco/compression/bit_coders/rans_bit_decoder.cc + src/draco/compression/bit_coders/rans_bit_decoder.h + src/draco/compression/bit_coders/rans_bit_encoder.cc + src/draco/compression/bit_coders/rans_bit_encoder.h + src/draco/compression/bit_coders/symbol_bit_decoder.cc + src/draco/compression/bit_coders/symbol_bit_decoder.h + src/draco/compression/bit_coders/symbol_bit_encoder.cc + src/draco/compression/bit_coders/symbol_bit_encoder.h + src/draco/compression/config/compression_shared.h + src/draco/compression/config/decoder_options.h + src/draco/compression/config/draco_options.h + src/draco/compression/config/encoder_options.h + src/draco/compression/config/encoding_features.h + src/draco/compression/decode.cc + src/draco/compression/decode.h + src/draco/compression/encode.cc + src/draco/compression/encode.h + src/draco/compression/encode_base.h + src/draco/compression/entropy/ans.h + src/draco/compression/entropy/rans_symbol_coding.h + src/draco/compression/entropy/rans_symbol_decoder.h + src/draco/compression/entropy/rans_symbol_encoder.h + src/draco/compression/entropy/shannon_entropy.cc + src/draco/compression/entropy/shannon_entropy.h + src/draco/compression/entropy/symbol_decoding.cc + src/draco/compression/entropy/symbol_decoding.h + src/draco/compression/entropy/symbol_encoding.cc + src/draco/compression/entropy/symbol_encoding.h + src/draco/compression/expert_encode.cc + src/draco/compression/expert_encode.h + src/draco/compression/mesh/mesh_decoder.cc + src/draco/compression/mesh/mesh_decoder.h + src/draco/compression/mesh/mesh_edgebreaker_decoder.cc + src/draco/compression/mesh/mesh_edgebreaker_decoder.h + src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc + src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.h + src/draco/compression/mesh/mesh_edgebreaker_decoder_impl_interface.h + src/draco/compression/mesh/mesh_edgebreaker_encoder.cc + src/draco/compression/mesh/mesh_edgebreaker_encoder.h + src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc + src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h + src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h + src/draco/compression/mesh/mesh_edgebreaker_shared.h + src/draco/compression/mesh/mesh_edgebreaker_traversal_decoder.h + src/draco/compression/mesh/mesh_edgebreaker_traversal_encoder.h + src/draco/compression/mesh/mesh_edgebreaker_traversal_predictive_decoder.h + src/draco/compression/mesh/mesh_edgebreaker_traversal_predictive_encoder.h + src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h + src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_encoder.h + src/draco/compression/mesh/mesh_encoder.cc + src/draco/compression/mesh/mesh_encoder.h + src/draco/compression/mesh/mesh_sequential_decoder.cc + src/draco/compression/mesh/mesh_sequential_decoder.h + src/draco/compression/mesh/mesh_sequential_encoder.cc + src/draco/compression/mesh/mesh_sequential_encoder.h + src/draco/compression/mesh/traverser/depth_first_traverser.h + src/draco/compression/mesh/traverser/max_prediction_degree_traverser.h + src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h + src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h + src/draco/compression/mesh/traverser/traverser_base.h + src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.cc + src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h + src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.cc + src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h + src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc + src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h + src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.cc + src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h + src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.cc + src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h + src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.cc + src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h + src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h + src/draco/compression/point_cloud/algorithms/point_cloud_types.h + src/draco/compression/point_cloud/algorithms/quantize_points_3.h + src/draco/compression/point_cloud/algorithms/queuing_policy.h + src/draco/compression/point_cloud/point_cloud_decoder.cc + src/draco/compression/point_cloud/point_cloud_decoder.h + src/draco/compression/point_cloud/point_cloud_encoder.cc + src/draco/compression/point_cloud/point_cloud_encoder.h + src/draco/compression/point_cloud/point_cloud_kd_tree_decoder.cc + src/draco/compression/point_cloud/point_cloud_kd_tree_decoder.h + src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc + src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h + src/draco/compression/point_cloud/point_cloud_sequential_decoder.cc + src/draco/compression/point_cloud/point_cloud_sequential_decoder.h + src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc + src/draco/compression/point_cloud/point_cloud_sequential_encoder.h + src/draco/core/bit_utils.cc + src/draco/core/bit_utils.h + src/draco/core/bounding_box.cc + src/draco/core/bounding_box.h + src/draco/core/cycle_timer.cc + src/draco/core/cycle_timer.h + src/draco/core/data_buffer.cc + src/draco/core/data_buffer.h + src/draco/core/decoder_buffer.cc + src/draco/core/decoder_buffer.h + src/draco/core/divide.cc + src/draco/core/divide.h + src/draco/core/draco_index_type.h + src/draco/core/draco_index_type_vector.h + src/draco/core/draco_types.cc + src/draco/core/draco_types.h + src/draco/core/draco_version.h + src/draco/core/encoder_buffer.cc + src/draco/core/encoder_buffer.h + src/draco/core/hash_utils.cc + src/draco/core/hash_utils.h + src/draco/core/macros.h + src/draco/core/math_utils.h + src/draco/core/options.cc + src/draco/core/options.h + src/draco/core/quantization_utils.cc + src/draco/core/quantization_utils.h + src/draco/core/status.h + src/draco/core/status_or.h + src/draco/core/varint_decoding.h + src/draco/core/varint_encoding.h + src/draco/core/vector_d.h + src/draco/mesh/corner_table.cc + src/draco/mesh/corner_table.h + src/draco/mesh/corner_table_iterators.h + src/draco/mesh/mesh.cc + src/draco/mesh/mesh.h + src/draco/mesh/mesh_are_equivalent.cc + src/draco/mesh/mesh_are_equivalent.h + src/draco/mesh/mesh_attribute_corner_table.cc + src/draco/mesh/mesh_attribute_corner_table.h + src/draco/mesh/mesh_cleanup.cc + src/draco/mesh/mesh_cleanup.h + src/draco/mesh/mesh_misc_functions.cc + src/draco/mesh/mesh_misc_functions.h + src/draco/mesh/mesh_stripifier.cc + src/draco/mesh/mesh_stripifier.h + src/draco/mesh/triangle_soup_mesh_builder.cc + src/draco/mesh/triangle_soup_mesh_builder.h + src/draco/mesh/valence_cache.h + src/draco/metadata/geometry_metadata.cc + src/draco/metadata/geometry_metadata.h + src/draco/metadata/metadata.cc + src/draco/metadata/metadata.h + src/draco/metadata/metadata_decoder.cc + src/draco/metadata/metadata_decoder.h + src/draco/metadata/metadata_encoder.cc + src/draco/metadata/metadata_encoder.h + src/draco/point_cloud/point_cloud.cc + src/draco/point_cloud/point_cloud.h + src/draco/point_cloud/point_cloud_builder.cc + src/draco/point_cloud/point_cloud_builder.h +) + +set(LIB +) + +set(INC + src +) + +blender_add_lib(draco "${SRC}" "${INC}" "" "${LIB}") + diff --git a/extern/draco/draco/LICENSE b/extern/draco/draco/LICENSE new file mode 100644 index 00000000000..7a4a3ea2424 --- /dev/null +++ b/extern/draco/draco/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/extern/draco/draco/src/draco/animation/keyframe_animation.cc b/extern/draco/draco/src/draco/animation/keyframe_animation.cc new file mode 100644 index 00000000000..eaf94a3305d --- /dev/null +++ b/extern/draco/draco/src/draco/animation/keyframe_animation.cc @@ -0,0 +1,54 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/animation/keyframe_animation.h" + +namespace draco { + +KeyframeAnimation::KeyframeAnimation() {} + +bool KeyframeAnimation::SetTimestamps( + const std::vector ×tamp) { + // Already added attributes. + const int32_t num_frames = timestamp.size(); + if (num_attributes() > 0) { + // Timestamp attribute could be added only once. + if (timestamps()->size()) { + return false; + } else { + // Check if the number of frames is consistent with + // the existing keyframes. + if (num_frames != num_points()) { + return false; + } + } + } else { + // This is the first attribute. + set_num_frames(num_frames); + } + + // Add attribute for time stamp data. + std::unique_ptr timestamp_att = + std::unique_ptr(new PointAttribute()); + timestamp_att->Init(GeometryAttribute::GENERIC, 1, DT_FLOAT32, false, + num_frames); + for (PointIndex i(0); i < num_frames; ++i) { + timestamp_att->SetAttributeValue(timestamp_att->mapped_index(i), + ×tamp[i.value()]); + } + this->SetAttribute(kTimestampId, std::move(timestamp_att)); + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/animation/keyframe_animation.h b/extern/draco/draco/src/draco/animation/keyframe_animation.h new file mode 100644 index 00000000000..a7afb2b81be --- /dev/null +++ b/extern/draco/draco/src/draco/animation/keyframe_animation.h @@ -0,0 +1,107 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ANIMATION_KEYFRAME_ANIMATION_H_ +#define DRACO_ANIMATION_KEYFRAME_ANIMATION_H_ + +#include + +#include "draco/point_cloud/point_cloud.h" + +namespace draco { + +// Class for holding keyframe animation data. It will have two or more +// attributes as a point cloud. The first attribute is always the timestamp +// of the animation. Each KeyframeAnimation could have multiple animations with +// the same number of frames. Each animation will be treated as a point +// attribute. +class KeyframeAnimation : public PointCloud { + public: + // Force time stamp to be float type. + using TimestampType = float; + + KeyframeAnimation(); + + // Animation must have only one timestamp attribute. + // This function must be called before adding any animation data. + // Returns false if timestamp already exists. + bool SetTimestamps(const std::vector ×tamp); + + // Returns an id for the added animation data. This id will be used to + // identify this animation. + // Returns -1 if error, e.g. number of frames is not consistent. + // Type |T| should be consistent with |DataType|, e.g: + // float - DT_FLOAT32, + // int32_t - DT_INT32, ... + template + int32_t AddKeyframes(DataType data_type, uint32_t num_components, + const std::vector &data); + + const PointAttribute *timestamps() const { + return GetAttributeByUniqueId(kTimestampId); + } + const PointAttribute *keyframes(int32_t animation_id) const { + return GetAttributeByUniqueId(animation_id); + } + + // Number of frames should be equal to number points in the point cloud. + void set_num_frames(int32_t num_frames) { set_num_points(num_frames); } + int32_t num_frames() const { return static_cast(num_points()); } + + int32_t num_animations() const { return num_attributes() - 1; } + + private: + // Attribute id of timestamp is fixed to 0. + static constexpr int32_t kTimestampId = 0; +}; + +template +int32_t KeyframeAnimation::AddKeyframes(DataType data_type, + uint32_t num_components, + const std::vector &data) { + // TODO(draco-eng): Verify T is consistent with |data_type|. + if (num_components == 0) { + return -1; + } + // If timestamps is not added yet, then reserve attribute 0 for timestamps. + if (!num_attributes()) { + // Add a temporary attribute with 0 points to fill attribute id 0. + std::unique_ptr temp_att = + std::unique_ptr(new PointAttribute()); + temp_att->Init(GeometryAttribute::GENERIC, num_components, data_type, false, + 0); + this->AddAttribute(std::move(temp_att)); + + set_num_frames(data.size() / num_components); + } + + if (data.size() != num_components * num_frames()) { + return -1; + } + + std::unique_ptr keyframe_att = + std::unique_ptr(new PointAttribute()); + keyframe_att->Init(GeometryAttribute::GENERIC, num_components, data_type, + false, num_frames()); + const size_t stride = num_components; + for (PointIndex i(0); i < num_frames(); ++i) { + keyframe_att->SetAttributeValue(keyframe_att->mapped_index(i), + &data[i.value() * stride]); + } + return this->AddAttribute(std::move(keyframe_att)); +} + +} // namespace draco + +#endif // DRACO_ANIMATION_KEYFRAME_ANIMATION_H_ diff --git a/extern/draco/draco/src/draco/animation/keyframe_animation_decoder.cc b/extern/draco/draco/src/draco/animation/keyframe_animation_decoder.cc new file mode 100644 index 00000000000..20659468d94 --- /dev/null +++ b/extern/draco/draco/src/draco/animation/keyframe_animation_decoder.cc @@ -0,0 +1,30 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/animation/keyframe_animation_decoder.h" + +namespace draco { + +Status KeyframeAnimationDecoder::Decode(const DecoderOptions &options, + DecoderBuffer *in_buffer, + KeyframeAnimation *animation) { + const auto status = PointCloudSequentialDecoder::Decode( + options, in_buffer, static_cast(animation)); + if (!status.ok()) { + return status; + } + return OkStatus(); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/animation/keyframe_animation_decoder.h b/extern/draco/draco/src/draco/animation/keyframe_animation_decoder.h new file mode 100644 index 00000000000..fdf086b3a38 --- /dev/null +++ b/extern/draco/draco/src/draco/animation/keyframe_animation_decoder.h @@ -0,0 +1,34 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ANIMATION_KEYFRAME_ANIMATION_DECODER_H_ +#define DRACO_ANIMATION_KEYFRAME_ANIMATION_DECODER_H_ + +#include "draco/animation/keyframe_animation.h" +#include "draco/compression/point_cloud/point_cloud_sequential_decoder.h" + +namespace draco { + +// Class for decoding keyframe animation. +class KeyframeAnimationDecoder : private PointCloudSequentialDecoder { + public: + KeyframeAnimationDecoder(){}; + + Status Decode(const DecoderOptions &options, DecoderBuffer *in_buffer, + KeyframeAnimation *animation); +}; + +} // namespace draco + +#endif // DRACO_ANIMATION_KEYFRAME_ANIMATION_DECODER_H_ diff --git a/extern/draco/draco/src/draco/animation/keyframe_animation_encoder.cc b/extern/draco/draco/src/draco/animation/keyframe_animation_encoder.cc new file mode 100644 index 00000000000..f7d84f3106a --- /dev/null +++ b/extern/draco/draco/src/draco/animation/keyframe_animation_encoder.cc @@ -0,0 +1,28 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/animation/keyframe_animation_encoder.h" + +namespace draco { + +KeyframeAnimationEncoder::KeyframeAnimationEncoder() {} + +Status KeyframeAnimationEncoder::EncodeKeyframeAnimation( + const KeyframeAnimation &animation, const EncoderOptions &options, + EncoderBuffer *out_buffer) { + SetPointCloud(animation); + return Encode(options, out_buffer); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/animation/keyframe_animation_encoder.h b/extern/draco/draco/src/draco/animation/keyframe_animation_encoder.h new file mode 100644 index 00000000000..6096c79fa12 --- /dev/null +++ b/extern/draco/draco/src/draco/animation/keyframe_animation_encoder.h @@ -0,0 +1,39 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ANIMATION_KEYFRAME_ANIMATION_ENCODER_H_ +#define DRACO_ANIMATION_KEYFRAME_ANIMATION_ENCODER_H_ + +#include "draco/animation/keyframe_animation.h" +#include "draco/compression/point_cloud/point_cloud_sequential_encoder.h" + +namespace draco { + +// Class for encoding keyframe animation. It takes KeyframeAnimation as a +// PointCloud and compress it. It's mostly a wrapper around PointCloudEncoder so +// that the animation module could be separated from geometry compression when +// exposed to developers. +class KeyframeAnimationEncoder : private PointCloudSequentialEncoder { + public: + KeyframeAnimationEncoder(); + + // Encode an animation to a buffer. + Status EncodeKeyframeAnimation(const KeyframeAnimation &animation, + const EncoderOptions &options, + EncoderBuffer *out_buffer); +}; + +} // namespace draco + +#endif // DRACO_ANIMATION_KEYFRAME_ANIMATION_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc new file mode 100644 index 00000000000..283a21251f4 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc @@ -0,0 +1,88 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "draco/attributes/attribute_octahedron_transform.h" + +#include "draco/attributes/attribute_transform_type.h" +#include "draco/compression/attributes/normal_compression_utils.h" + +namespace draco { + +bool AttributeOctahedronTransform::InitFromAttribute( + const PointAttribute &attribute) { + const AttributeTransformData *const transform_data = + attribute.GetAttributeTransformData(); + if (!transform_data || + transform_data->transform_type() != ATTRIBUTE_OCTAHEDRON_TRANSFORM) { + return false; // Wrong transform type. + } + quantization_bits_ = transform_data->GetParameterValue(0); + return true; +} + +void AttributeOctahedronTransform::CopyToAttributeTransformData( + AttributeTransformData *out_data) const { + out_data->set_transform_type(ATTRIBUTE_OCTAHEDRON_TRANSFORM); + out_data->AppendParameterValue(quantization_bits_); +} + +void AttributeOctahedronTransform::SetParameters(int quantization_bits) { + quantization_bits_ = quantization_bits; +} + +bool AttributeOctahedronTransform::EncodeParameters( + EncoderBuffer *encoder_buffer) const { + if (is_initialized()) { + encoder_buffer->Encode(static_cast(quantization_bits_)); + return true; + } + return false; +} + +std::unique_ptr +AttributeOctahedronTransform::GeneratePortableAttribute( + const PointAttribute &attribute, const std::vector &point_ids, + int num_points) const { + DRACO_DCHECK(is_initialized()); + + // Allocate portable attribute. + const int num_entries = static_cast(point_ids.size()); + std::unique_ptr portable_attribute = + InitPortableAttribute(num_entries, 2, num_points, attribute, true); + + // Quantize all values in the order given by point_ids into portable + // attribute. + int32_t *const portable_attribute_data = reinterpret_cast( + portable_attribute->GetAddress(AttributeValueIndex(0))); + float att_val[3]; + int32_t dst_index = 0; + OctahedronToolBox converter; + if (!converter.SetQuantizationBits(quantization_bits_)) { + return nullptr; + } + for (uint32_t i = 0; i < point_ids.size(); ++i) { + const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]); + attribute.GetValue(att_val_id, att_val); + // Encode the vector into a s and t octahedral coordinates. + int32_t s, t; + converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t); + portable_attribute_data[dst_index++] = s; + portable_attribute_data[dst_index++] = t; + } + + return portable_attribute; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h new file mode 100644 index 00000000000..6e4e74284f0 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h @@ -0,0 +1,60 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_ +#define DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_ + +#include "draco/attributes/attribute_transform.h" +#include "draco/attributes/point_attribute.h" +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// Attribute transform for attributes transformed to octahedral coordinates. +class AttributeOctahedronTransform : public AttributeTransform { + public: + AttributeOctahedronTransform() : quantization_bits_(-1) {} + + // Return attribute transform type. + AttributeTransformType Type() const override { + return ATTRIBUTE_OCTAHEDRON_TRANSFORM; + } + // Try to init transform from attribute. + bool InitFromAttribute(const PointAttribute &attribute) override; + // Copy parameter values into the provided AttributeTransformData instance. + void CopyToAttributeTransformData( + AttributeTransformData *out_data) const override; + + // Set number of quantization bits. + void SetParameters(int quantization_bits); + + // Encode relevant parameters into buffer. + bool EncodeParameters(EncoderBuffer *encoder_buffer) const; + + bool is_initialized() const { return quantization_bits_ != -1; } + int32_t quantization_bits() const { return quantization_bits_; } + + // Create portable attribute. + std::unique_ptr GeneratePortableAttribute( + const PointAttribute &attribute, const std::vector &point_ids, + int num_points) const; + + private: + int32_t quantization_bits_; +}; + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc new file mode 100644 index 00000000000..daa634ed03f --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc @@ -0,0 +1,187 @@ + +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/attributes/attribute_quantization_transform.h" + +#include "draco/attributes/attribute_transform_type.h" +#include "draco/core/quantization_utils.h" + +namespace draco { + +bool AttributeQuantizationTransform::InitFromAttribute( + const PointAttribute &attribute) { + const AttributeTransformData *const transform_data = + attribute.GetAttributeTransformData(); + if (!transform_data || + transform_data->transform_type() != ATTRIBUTE_QUANTIZATION_TRANSFORM) { + return false; // Wrong transform type. + } + int32_t byte_offset = 0; + quantization_bits_ = transform_data->GetParameterValue(byte_offset); + byte_offset += 4; + min_values_.resize(attribute.num_components()); + for (int i = 0; i < attribute.num_components(); ++i) { + min_values_[i] = transform_data->GetParameterValue(byte_offset); + byte_offset += 4; + } + range_ = transform_data->GetParameterValue(byte_offset); + return true; +} + +// Copy parameter values into the provided AttributeTransformData instance. +void AttributeQuantizationTransform::CopyToAttributeTransformData( + AttributeTransformData *out_data) const { + out_data->set_transform_type(ATTRIBUTE_QUANTIZATION_TRANSFORM); + out_data->AppendParameterValue(quantization_bits_); + for (int i = 0; i < min_values_.size(); ++i) { + out_data->AppendParameterValue(min_values_[i]); + } + out_data->AppendParameterValue(range_); +} + +void AttributeQuantizationTransform::SetParameters(int quantization_bits, + const float *min_values, + int num_components, + float range) { + quantization_bits_ = quantization_bits; + min_values_.assign(min_values, min_values + num_components); + range_ = range; +} + +bool AttributeQuantizationTransform::ComputeParameters( + const PointAttribute &attribute, const int quantization_bits) { + if (quantization_bits_ != -1) { + return false; // already initialized. + } + quantization_bits_ = quantization_bits; + + const int num_components = attribute.num_components(); + range_ = 0.f; + min_values_ = std::vector(num_components, 0.f); + const std::unique_ptr max_values(new float[num_components]); + const std::unique_ptr att_val(new float[num_components]); + // Compute minimum values and max value difference. + attribute.GetValue(AttributeValueIndex(0), att_val.get()); + attribute.GetValue(AttributeValueIndex(0), min_values_.data()); + attribute.GetValue(AttributeValueIndex(0), max_values.get()); + + for (AttributeValueIndex i(1); i < static_cast(attribute.size()); + ++i) { + attribute.GetValue(i, att_val.get()); + for (int c = 0; c < num_components; ++c) { + if (min_values_[c] > att_val[c]) { + min_values_[c] = att_val[c]; + } + if (max_values[c] < att_val[c]) { + max_values[c] = att_val[c]; + } + } + } + for (int c = 0; c < num_components; ++c) { + if (std::isnan(min_values_[c]) || std::isinf(min_values_[c]) || + std::isnan(max_values[c]) || std::isinf(max_values[c])) { + return false; + } + const float dif = max_values[c] - min_values_[c]; + if (dif > range_) { + range_ = dif; + } + } + + // In case all values are the same, initialize the range to unit length. This + // will ensure that all values are quantized properly to the same value. + if (range_ == 0.f) { + range_ = 1.f; + } + + return true; +} + +bool AttributeQuantizationTransform::EncodeParameters( + EncoderBuffer *encoder_buffer) const { + if (is_initialized()) { + encoder_buffer->Encode(min_values_.data(), + sizeof(float) * min_values_.size()); + encoder_buffer->Encode(range_); + encoder_buffer->Encode(static_cast(quantization_bits_)); + return true; + } + return false; +} + +std::unique_ptr +AttributeQuantizationTransform::GeneratePortableAttribute( + const PointAttribute &attribute, int num_points) const { + DRACO_DCHECK(is_initialized()); + + // Allocate portable attribute. + const int num_entries = num_points; + const int num_components = attribute.num_components(); + std::unique_ptr portable_attribute = + InitPortableAttribute(num_entries, num_components, 0, attribute, true); + + // Quantize all values using the order given by point_ids. + int32_t *const portable_attribute_data = reinterpret_cast( + portable_attribute->GetAddress(AttributeValueIndex(0))); + const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1; + Quantizer quantizer; + quantizer.Init(range(), max_quantized_value); + int32_t dst_index = 0; + const std::unique_ptr att_val(new float[num_components]); + for (PointIndex i(0); i < num_points; ++i) { + const AttributeValueIndex att_val_id = attribute.mapped_index(i); + attribute.GetValue(att_val_id, att_val.get()); + for (int c = 0; c < num_components; ++c) { + const float value = (att_val[c] - min_values()[c]); + const int32_t q_val = quantizer.QuantizeFloat(value); + portable_attribute_data[dst_index++] = q_val; + } + } + return portable_attribute; +} + +std::unique_ptr +AttributeQuantizationTransform::GeneratePortableAttribute( + const PointAttribute &attribute, const std::vector &point_ids, + int num_points) const { + DRACO_DCHECK(is_initialized()); + + // Allocate portable attribute. + const int num_entries = static_cast(point_ids.size()); + const int num_components = attribute.num_components(); + std::unique_ptr portable_attribute = InitPortableAttribute( + num_entries, num_components, num_points, attribute, true); + + // Quantize all values using the order given by point_ids. + int32_t *const portable_attribute_data = reinterpret_cast( + portable_attribute->GetAddress(AttributeValueIndex(0))); + const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1; + Quantizer quantizer; + quantizer.Init(range(), max_quantized_value); + int32_t dst_index = 0; + const std::unique_ptr att_val(new float[num_components]); + for (uint32_t i = 0; i < point_ids.size(); ++i) { + const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]); + attribute.GetValue(att_val_id, att_val.get()); + for (int c = 0; c < num_components; ++c) { + const float value = (att_val[c] - min_values()[c]); + const int32_t q_val = quantizer.QuantizeFloat(value); + portable_attribute_data[dst_index++] = q_val; + } + } + return portable_attribute; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h new file mode 100644 index 00000000000..934856f2db7 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h @@ -0,0 +1,78 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_QUANTIZATION_TRANSFORM_H_ +#define DRACO_ATTRIBUTES_ATTRIBUTE_QUANTIZATION_TRANSFORM_H_ + +#include + +#include "draco/attributes/attribute_transform.h" +#include "draco/attributes/point_attribute.h" +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// Attribute transform for quantized attributes. +class AttributeQuantizationTransform : public AttributeTransform { + public: + AttributeQuantizationTransform() : quantization_bits_(-1), range_(0.f) {} + // Return attribute transform type. + AttributeTransformType Type() const override { + return ATTRIBUTE_QUANTIZATION_TRANSFORM; + } + // Try to init transform from attribute. + bool InitFromAttribute(const PointAttribute &attribute) override; + // Copy parameter values into the provided AttributeTransformData instance. + void CopyToAttributeTransformData( + AttributeTransformData *out_data) const override; + + void SetParameters(int quantization_bits, const float *min_values, + int num_components, float range); + + bool ComputeParameters(const PointAttribute &attribute, + const int quantization_bits); + + // Encode relevant parameters into buffer. + bool EncodeParameters(EncoderBuffer *encoder_buffer) const; + + int32_t quantization_bits() const { return quantization_bits_; } + float min_value(int axis) const { return min_values_[axis]; } + const std::vector &min_values() const { return min_values_; } + float range() const { return range_; } + bool is_initialized() const { return quantization_bits_ != -1; } + + // Create portable attribute using 1:1 mapping between points in the input and + // output attribute. + std::unique_ptr GeneratePortableAttribute( + const PointAttribute &attribute, int num_points) const; + + // Create portable attribute using custom mapping between input and output + // points. + std::unique_ptr GeneratePortableAttribute( + const PointAttribute &attribute, const std::vector &point_ids, + int num_points) const; + + private: + int32_t quantization_bits_; + + // Minimal dequantized value for each component of the attribute. + std::vector min_values_; + + // Bounds of the dequantized attribute (max delta over all components). + float range_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTE_DEQUANTIZATION_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_transform.cc new file mode 100644 index 00000000000..55af630ac07 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_transform.cc @@ -0,0 +1,44 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/attributes/attribute_transform.h" + +namespace draco { + +bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const { + std::unique_ptr transform_data( + new AttributeTransformData()); + this->CopyToAttributeTransformData(transform_data.get()); + attribute->SetAttributeTransformData(std::move(transform_data)); + return true; +} + +std::unique_ptr AttributeTransform::InitPortableAttribute( + int num_entries, int num_components, int num_points, + const PointAttribute &attribute, bool is_unsigned) const { + const DataType dt = is_unsigned ? DT_UINT32 : DT_INT32; + GeometryAttribute va; + va.Init(attribute.attribute_type(), nullptr, num_components, dt, false, + num_components * DataTypeLength(dt), 0); + std::unique_ptr portable_attribute(new PointAttribute(va)); + portable_attribute->Reset(num_entries); + if (num_points) { + portable_attribute->SetExplicitMapping(num_points); + } else { + portable_attribute->SetIdentityMapping(); + } + return portable_attribute; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.h b/extern/draco/draco/src/draco/attributes/attribute_transform.h new file mode 100644 index 00000000000..d746fbf6eea --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_transform.h @@ -0,0 +1,46 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_H_ +#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_H_ + +#include "draco/attributes/attribute_transform_data.h" +#include "draco/attributes/point_attribute.h" + +namespace draco { + +// Virtual base class for various attribute transforms, enforcing common +// interface where possible. +class AttributeTransform { + public: + virtual ~AttributeTransform() = default; + + // Return attribute transform type. + virtual AttributeTransformType Type() const = 0; + // Try to init transform from attribute. + virtual bool InitFromAttribute(const PointAttribute &attribute) = 0; + // Copy parameter values into the provided AttributeTransformData instance. + virtual void CopyToAttributeTransformData( + AttributeTransformData *out_data) const = 0; + bool TransferToAttribute(PointAttribute *attribute) const; + + protected: + std::unique_ptr InitPortableAttribute( + int num_entries, int num_components, int num_points, + const PointAttribute &attribute, bool is_unsigned) const; +}; + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform_data.h b/extern/draco/draco/src/draco/attributes/attribute_transform_data.h new file mode 100644 index 00000000000..96ed073200d --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_transform_data.h @@ -0,0 +1,71 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_ +#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_ + +#include + +#include "draco/attributes/attribute_transform_type.h" +#include "draco/core/data_buffer.h" + +namespace draco { + +// Class for holding parameter values for an attribute transform of a +// PointAttribute. This can be for example quantization data for an attribute +// that holds quantized values. This class provides only a basic storage for +// attribute transform parameters and it should be accessed only through wrapper +// classes for a specific transform (e.g. AttributeQuantizationTransform). +class AttributeTransformData { + public: + AttributeTransformData() : transform_type_(ATTRIBUTE_INVALID_TRANSFORM) {} + AttributeTransformData(const AttributeTransformData &data) = default; + + // Returns the type of the attribute transform that is described by the class. + AttributeTransformType transform_type() const { return transform_type_; } + void set_transform_type(AttributeTransformType type) { + transform_type_ = type; + } + + // Returns a parameter value on a given |byte_offset|. + template + DataTypeT GetParameterValue(int byte_offset) const { + DataTypeT out_data; + buffer_.Read(byte_offset, &out_data, sizeof(DataTypeT)); + return out_data; + } + + // Sets a parameter value on a given |byte_offset|. + template + void SetParameterValue(int byte_offset, const DataTypeT &in_data) { + if (byte_offset + sizeof(DataTypeT) > buffer_.data_size()) { + buffer_.Resize(byte_offset + sizeof(DataTypeT)); + } + buffer_.Write(byte_offset, &in_data, sizeof(DataTypeT)); + } + + // Sets a parameter value at the end of the |buffer_|. + template + void AppendParameterValue(const DataTypeT &in_data) { + SetParameterValue(static_cast(buffer_.data_size()), in_data); + } + + private: + AttributeTransformType transform_type_; + DataBuffer buffer_; +}; + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_ diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform_type.h b/extern/draco/draco/src/draco/attributes/attribute_transform_type.h new file mode 100644 index 00000000000..51ce6f333b4 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/attribute_transform_type.h @@ -0,0 +1,30 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_ +#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_ + +namespace draco { + +// List of all currently supported attribute transforms. +enum AttributeTransformType { + ATTRIBUTE_INVALID_TRANSFORM = -1, + ATTRIBUTE_NO_TRANSFORM = 0, + ATTRIBUTE_QUANTIZATION_TRANSFORM = 1, + ATTRIBUTE_OCTAHEDRON_TRANSFORM = 2, +}; + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_ diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc new file mode 100644 index 00000000000..f7ed6a86915 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc @@ -0,0 +1,98 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/attributes/geometry_attribute.h" + +namespace draco { + +GeometryAttribute::GeometryAttribute() + : buffer_(nullptr), + num_components_(1), + data_type_(DT_FLOAT32), + byte_stride_(0), + byte_offset_(0), + attribute_type_(INVALID), + unique_id_(0) {} + +void GeometryAttribute::Init(GeometryAttribute::Type attribute_type, + DataBuffer *buffer, int8_t num_components, + DataType data_type, bool normalized, + int64_t byte_stride, int64_t byte_offset) { + buffer_ = buffer; + if (buffer) { + buffer_descriptor_.buffer_id = buffer->buffer_id(); + buffer_descriptor_.buffer_update_count = buffer->update_count(); + } + num_components_ = num_components; + data_type_ = data_type; + normalized_ = normalized; + byte_stride_ = byte_stride; + byte_offset_ = byte_offset; + attribute_type_ = attribute_type; +} + +bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) { + if (buffer_ == nullptr || src_att.buffer_ == nullptr) { + return false; + } + buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size()); + num_components_ = src_att.num_components_; + data_type_ = src_att.data_type_; + normalized_ = src_att.normalized_; + byte_stride_ = src_att.byte_stride_; + byte_offset_ = src_att.byte_offset_; + attribute_type_ = src_att.attribute_type_; + buffer_descriptor_ = src_att.buffer_descriptor_; + unique_id_ = src_att.unique_id_; + return true; +} + +bool GeometryAttribute::operator==(const GeometryAttribute &va) const { + if (attribute_type_ != va.attribute_type_) { + return false; + } + // It's OK to compare just the buffer descriptors here. We don't need to + // compare the buffers themselves. + if (buffer_descriptor_.buffer_id != va.buffer_descriptor_.buffer_id) { + return false; + } + if (buffer_descriptor_.buffer_update_count != + va.buffer_descriptor_.buffer_update_count) { + return false; + } + if (num_components_ != va.num_components_) { + return false; + } + if (data_type_ != va.data_type_) { + return false; + } + if (byte_stride_ != va.byte_stride_) { + return false; + } + if (byte_offset_ != va.byte_offset_) { + return false; + } + return true; +} + +void GeometryAttribute::ResetBuffer(DataBuffer *buffer, int64_t byte_stride, + int64_t byte_offset) { + buffer_ = buffer; + buffer_descriptor_.buffer_id = buffer->buffer_id(); + buffer_descriptor_.buffer_update_count = buffer->update_count(); + byte_stride_ = byte_stride; + byte_offset_ = byte_offset; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.h b/extern/draco/draco/src/draco/attributes/geometry_attribute.h new file mode 100644 index 00000000000..b94ba8e22dd --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.h @@ -0,0 +1,333 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_ +#define DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_ + +#include +#include + +#include "draco/attributes/geometry_indices.h" +#include "draco/core/data_buffer.h" +#include "draco/core/hash_utils.h" + +namespace draco { + +// The class provides access to a specific attribute which is stored in a +// DataBuffer, such as normals or coordinates. However, the GeometryAttribute +// class does not own the buffer and the buffer itself may store other data +// unrelated to this attribute (such as data for other attributes in which case +// we can have multiple GeometryAttributes accessing one buffer). Typically, +// all attributes for a point (or corner, face) are stored in one block, which +// is advantageous in terms of memory access. The length of the entire block is +// given by the byte_stride, the position where the attribute starts is given by +// the byte_offset, the actual number of bytes that the attribute occupies is +// given by the data_type and the number of components. +class GeometryAttribute { + public: + // Supported attribute types. + enum Type { + INVALID = -1, + // Named attributes start here. The difference between named and generic + // attributes is that for named attributes we know their purpose and we + // can apply some special methods when dealing with them (e.g. during + // encoding). + POSITION = 0, + NORMAL, + COLOR, + TEX_COORD, + // A special id used to mark attributes that are not assigned to any known + // predefined use case. Such attributes are often used for a shader specific + // data. + GENERIC, + // Total number of different attribute types. + // Always keep behind all named attributes. + NAMED_ATTRIBUTES_COUNT, + }; + + GeometryAttribute(); + // Initializes and enables the attribute. + void Init(Type attribute_type, DataBuffer *buffer, int8_t num_components, + DataType data_type, bool normalized, int64_t byte_stride, + int64_t byte_offset); + bool IsValid() const { return buffer_ != nullptr; } + + // Copies data from the source attribute to the this attribute. + // This attribute must have a valid buffer allocated otherwise the operation + // is going to fail and return false. + bool CopyFrom(const GeometryAttribute &src_att); + + // Function for getting a attribute value with a specific format. + // Unsafe. Caller must ensure the accessed memory is valid. + // T is the attribute data type. + // att_components_t is the number of attribute components. + template + std::array GetValue( + AttributeValueIndex att_index) const { + // Byte address of the attribute index. + const int64_t byte_pos = byte_offset_ + byte_stride_ * att_index.value(); + std::array out; + buffer_->Read(byte_pos, &(out[0]), sizeof(out)); + return out; + } + + // Function for getting a attribute value with a specific format. + // T is the attribute data type. + // att_components_t is the number of attribute components. + template + bool GetValue(AttributeValueIndex att_index, + std::array *out) const { + // Byte address of the attribute index. + const int64_t byte_pos = byte_offset_ + byte_stride_ * att_index.value(); + // Check we are not reading past end of data. + if (byte_pos + sizeof(*out) > buffer_->data_size()) { + return false; + } + buffer_->Read(byte_pos, &((*out)[0]), sizeof(*out)); + return true; + } + + // Returns the byte position of the attribute entry in the data buffer. + inline int64_t GetBytePos(AttributeValueIndex att_index) const { + return byte_offset_ + byte_stride_ * att_index.value(); + } + + inline const uint8_t *GetAddress(AttributeValueIndex att_index) const { + const int64_t byte_pos = GetBytePos(att_index); + return buffer_->data() + byte_pos; + } + inline uint8_t *GetAddress(AttributeValueIndex att_index) { + const int64_t byte_pos = GetBytePos(att_index); + return buffer_->data() + byte_pos; + } + + // Fills out_data with the raw value of the requested attribute entry. + // out_data must be at least byte_stride_ long. + void GetValue(AttributeValueIndex att_index, void *out_data) const { + const int64_t byte_pos = byte_offset_ + byte_stride_ * att_index.value(); + buffer_->Read(byte_pos, out_data, byte_stride_); + } + + // Sets a value of an attribute entry. The input value must be allocated to + // cover all components of a single attribute entry. + void SetAttributeValue(AttributeValueIndex entry_index, const void *value) { + const int64_t byte_pos = entry_index.value() * byte_stride(); + buffer_->Write(byte_pos, value, byte_stride()); + } + + // DEPRECATED: Use + // ConvertValue(AttributeValueIndex att_id, + // int out_num_components, + // OutT *out_val); + // + // Function for conversion of a attribute to a specific output format. + // OutT is the desired data type of the attribute. + // out_att_components_t is the number of components of the output format. + // Returns false when the conversion failed. + template + bool ConvertValue(AttributeValueIndex att_id, OutT *out_val) const { + return ConvertValue(att_id, out_att_components_t, out_val); + } + + // Function for conversion of a attribute to a specific output format. + // |out_val| needs to be able to store |out_num_components| values. + // OutT is the desired data type of the attribute. + // Returns false when the conversion failed. + template + bool ConvertValue(AttributeValueIndex att_id, int8_t out_num_components, + OutT *out_val) const { + if (out_val == nullptr) { + return false; + } + switch (data_type_) { + case DT_INT8: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_UINT8: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_INT16: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_UINT16: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_INT32: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_UINT32: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_INT64: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_UINT64: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_FLOAT32: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_FLOAT64: + return ConvertTypedValue(att_id, out_num_components, + out_val); + case DT_BOOL: + return ConvertTypedValue(att_id, out_num_components, + out_val); + default: + // Wrong attribute type. + return false; + } + } + + // Function for conversion of a attribute to a specific output format. + // The |out_value| must be able to store all components of a single attribute + // entry. + // OutT is the desired data type of the attribute. + // Returns false when the conversion failed. + template + bool ConvertValue(AttributeValueIndex att_index, OutT *out_value) const { + return ConvertValue(att_index, num_components_, out_value); + } + + // Utility function. Returns |attribute_type| as std::string. + static std::string TypeToString(Type attribute_type) { + switch (attribute_type) { + case INVALID: + return "INVALID"; + case POSITION: + return "POSITION"; + case NORMAL: + return "NORMAL"; + case COLOR: + return "COLOR"; + case TEX_COORD: + return "TEX_COORD"; + case GENERIC: + return "GENERIC"; + default: + return "UNKNOWN"; + } + } + + bool operator==(const GeometryAttribute &va) const; + + // Returns the type of the attribute indicating the nature of the attribute. + Type attribute_type() const { return attribute_type_; } + void set_attribute_type(Type type) { attribute_type_ = type; } + // Returns the data type that is stored in the attribute. + DataType data_type() const { return data_type_; } + // Returns the number of components that are stored for each entry. + // For position attribute this is usually three (x,y,z), + // while texture coordinates have two components (u,v). + int8_t num_components() const { return num_components_; } + // Indicates whether the data type should be normalized before interpretation, + // that is, it should be divided by the max value of the data type. + bool normalized() const { return normalized_; } + // The buffer storing the entire data of the attribute. + const DataBuffer *buffer() const { return buffer_; } + // Returns the number of bytes between two attribute entries, this is, at + // least size of the data types times number of components. + int64_t byte_stride() const { return byte_stride_; } + // The offset where the attribute starts within the block of size byte_stride. + int64_t byte_offset() const { return byte_offset_; } + void set_byte_offset(int64_t byte_offset) { byte_offset_ = byte_offset; } + DataBufferDescriptor buffer_descriptor() const { return buffer_descriptor_; } + uint32_t unique_id() const { return unique_id_; } + void set_unique_id(uint32_t id) { unique_id_ = id; } + + protected: + // Sets a new internal storage for the attribute. + void ResetBuffer(DataBuffer *buffer, int64_t byte_stride, + int64_t byte_offset); + + private: + // Function for conversion of an attribute to a specific output format given a + // format of the stored attribute. + // T is the stored attribute data type. + // OutT is the desired data type of the attribute. + template + bool ConvertTypedValue(AttributeValueIndex att_id, int8_t out_num_components, + OutT *out_value) const { + const uint8_t *src_address = GetAddress(att_id); + + // Convert all components available in both the original and output formats. + for (int i = 0; i < std::min(num_components_, out_num_components); ++i) { + const T in_value = *reinterpret_cast(src_address); + out_value[i] = static_cast(in_value); + // When converting integer to floating point, normalize the value if + // necessary. + if (std::is_integral::value && std::is_floating_point::value && + normalized_) { + out_value[i] /= static_cast(std::numeric_limits::max()); + } + // TODO(ostava): Add handling of normalized attributes when converting + // between different integer representations. If the attribute is + // normalized, integer values should be converted as if they represent 0-1 + // range. E.g. when we convert uint16 to uint8, the range <0, 2^16 - 1> + // should be converted to range <0, 2^8 - 1>. + src_address += sizeof(T); + } + // Fill empty data for unused output components if needed. + for (int i = num_components_; i < out_num_components; ++i) { + out_value[i] = static_cast(0); + } + return true; + } + + DataBuffer *buffer_; + // The buffer descriptor is stored at the time the buffer is attached to this + // attribute. The purpose is to detect if any changes happened to the buffer + // since the time it was attached. + DataBufferDescriptor buffer_descriptor_; + int8_t num_components_; + DataType data_type_; + bool normalized_; + int64_t byte_stride_; + int64_t byte_offset_; + + Type attribute_type_; + + // Unique id of this attribute. No two attributes could have the same unique + // id. It is used to identify each attribute, especially when there are + // multiple attribute of the same type in a point cloud. + uint32_t unique_id_; + + friend struct GeometryAttributeHasher; +}; + +// Hashing support + +// Function object for using Attribute as a hash key. +struct GeometryAttributeHasher { + size_t operator()(const GeometryAttribute &va) const { + size_t hash = HashCombine(va.buffer_descriptor_.buffer_id, + va.buffer_descriptor_.buffer_update_count); + hash = HashCombine(va.num_components_, hash); + hash = HashCombine(static_cast(va.data_type_), hash); + hash = HashCombine(static_cast(va.attribute_type_), hash); + hash = HashCombine(va.byte_stride_, hash); + return HashCombine(va.byte_offset_, hash); + } +}; + +// Function object for using GeometryAttribute::Type as a hash key. +struct GeometryAttributeTypeHasher { + size_t operator()(const GeometryAttribute::Type &at) const { + return static_cast(at); + } +}; + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_ diff --git a/extern/draco/draco/src/draco/attributes/geometry_indices.h b/extern/draco/draco/src/draco/attributes/geometry_indices.h new file mode 100644 index 00000000000..80e43e30a13 --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/geometry_indices.h @@ -0,0 +1,54 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_GEOMETRY_INDICES_H_ +#define DRACO_ATTRIBUTES_GEOMETRY_INDICES_H_ + +#include + +#include + +#include "draco/core/draco_index_type.h" + +namespace draco { + +// Index of an attribute value entry stored in a GeometryAttribute. +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, AttributeValueIndex) +// Index of a point in a PointCloud. +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, PointIndex) +// Vertex index in a Mesh or CornerTable. +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, VertexIndex) +// Corner index that identifies a corner in a Mesh or CornerTable. +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, CornerIndex) +// Face index for Mesh and CornerTable. +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, FaceIndex) + +// Constants denoting invalid indices. +static constexpr AttributeValueIndex kInvalidAttributeValueIndex( + std::numeric_limits::max()); +static constexpr PointIndex kInvalidPointIndex( + std::numeric_limits::max()); +static constexpr VertexIndex kInvalidVertexIndex( + std::numeric_limits::max()); +static constexpr CornerIndex kInvalidCornerIndex( + std::numeric_limits::max()); +static constexpr FaceIndex kInvalidFaceIndex( + std::numeric_limits::max()); + +// TODO(ostava): Add strongly typed indices for attribute id and unique +// attribute id. + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_GEOMETRY_INDICES_H_ diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.cc b/extern/draco/draco/src/draco/attributes/point_attribute.cc new file mode 100644 index 00000000000..b28f860c15d --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/point_attribute.cc @@ -0,0 +1,225 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/attributes/point_attribute.h" + +#include + +using std::unordered_map; + +// Shortcut for typed conditionals. +template +using conditional_t = typename std::conditional::type; + +namespace draco { + +PointAttribute::PointAttribute() + : num_unique_entries_(0), identity_mapping_(false) {} + +PointAttribute::PointAttribute(const GeometryAttribute &att) + : GeometryAttribute(att), + num_unique_entries_(0), + identity_mapping_(false) {} + +void PointAttribute::Init(Type attribute_type, int8_t num_components, + DataType data_type, bool normalized, + size_t num_attribute_values) { + attribute_buffer_ = std::unique_ptr(new DataBuffer()); + GeometryAttribute::Init(attribute_type, attribute_buffer_.get(), + num_components, data_type, normalized, + DataTypeLength(data_type) * num_components, 0); + Reset(num_attribute_values); + SetIdentityMapping(); +} + +void PointAttribute::CopyFrom(const PointAttribute &src_att) { + if (buffer() == nullptr) { + // If the destination attribute doesn't have a valid buffer, create it. + attribute_buffer_ = std::unique_ptr(new DataBuffer()); + ResetBuffer(attribute_buffer_.get(), 0, 0); + } + if (!GeometryAttribute::CopyFrom(src_att)) { + return; + } + identity_mapping_ = src_att.identity_mapping_; + num_unique_entries_ = src_att.num_unique_entries_; + indices_map_ = src_att.indices_map_; + if (src_att.attribute_transform_data_) { + attribute_transform_data_ = std::unique_ptr( + new AttributeTransformData(*src_att.attribute_transform_data_)); + } else { + attribute_transform_data_ = nullptr; + } +} + +bool PointAttribute::Reset(size_t num_attribute_values) { + if (attribute_buffer_ == nullptr) { + attribute_buffer_ = std::unique_ptr(new DataBuffer()); + } + const int64_t entry_size = DataTypeLength(data_type()) * num_components(); + if (!attribute_buffer_->Update(nullptr, num_attribute_values * entry_size)) { + return false; + } + // Assign the new buffer to the parent attribute. + ResetBuffer(attribute_buffer_.get(), entry_size, 0); + num_unique_entries_ = static_cast(num_attribute_values); + return true; +} + +void PointAttribute::Resize(size_t new_num_unique_entries) { + num_unique_entries_ = static_cast(new_num_unique_entries); + attribute_buffer_->Resize(new_num_unique_entries * byte_stride()); +} + +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED +AttributeValueIndex::ValueType PointAttribute::DeduplicateValues( + const GeometryAttribute &in_att) { + return DeduplicateValues(in_att, AttributeValueIndex(0)); +} + +AttributeValueIndex::ValueType PointAttribute::DeduplicateValues( + const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) { + AttributeValueIndex::ValueType unique_vals = 0; + switch (in_att.data_type()) { + // Currently we support only float, uint8, and uint16 arguments. + case DT_FLOAT32: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + case DT_INT8: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + case DT_UINT8: + case DT_BOOL: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + case DT_UINT16: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + case DT_INT16: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + case DT_UINT32: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + case DT_INT32: + unique_vals = DeduplicateTypedValues(in_att, in_att_offset); + break; + default: + return -1; // Unsupported data type. + } + if (unique_vals == 0) { + return -1; // Unexpected error. + } + return unique_vals; +} + +// Helper function for calling UnifyDuplicateAttributes +// with the correct template arguments. +// Returns the number of unique attribute values. +template +AttributeValueIndex::ValueType PointAttribute::DeduplicateTypedValues( + const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) { + // Select the correct method to call based on the number of attribute + // components. + switch (in_att.num_components()) { + case 1: + return DeduplicateFormattedValues(in_att, in_att_offset); + case 2: + return DeduplicateFormattedValues(in_att, in_att_offset); + case 3: + return DeduplicateFormattedValues(in_att, in_att_offset); + case 4: + return DeduplicateFormattedValues(in_att, in_att_offset); + default: + return 0; + } +} + +template +AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues( + const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) { + // We want to detect duplicates using a hash map but we cannot hash floating + // point numbers directly so bit-copy floats to the same sized integers and + // hash them. + + // First we need to determine which int type to use (1, 2, 4 or 8 bytes). + // Note, this is done at compile time using std::conditional struct. + // Conditional is in form . If bool-expression + // is true the "true" branch is used and vice versa. All at compile time. + typedef conditional_t>> + HashType; + + AttributeValueIndex unique_vals(0); + typedef std::array AttributeValue; + typedef std::array AttributeHashableValue; + // Hash map storing index of the first attribute with a given value. + unordered_map> + value_to_index_map; + AttributeValue att_value; + AttributeHashableValue hashable_value; + IndexTypeVector value_map( + num_unique_entries_); + for (AttributeValueIndex i(0); i < num_unique_entries_; ++i) { + const AttributeValueIndex att_pos = i + in_att_offset; + att_value = in_att.GetValue(att_pos); + // Convert the value to hashable type. Bit-copy real attributes to integers. + memcpy(&(hashable_value[0]), &(att_value[0]), sizeof(att_value)); + + // Check if the given attribute value has been used before already. + auto it = value_to_index_map.find(hashable_value); + if (it != value_to_index_map.end()) { + // Duplicated value found. Update index mapping. + value_map[i] = it->second; + } else { + // New unique value. + // Update the hash map with a new entry pointing to the latest unique + // vertex index. + value_to_index_map.insert( + std::pair(hashable_value, + unique_vals)); + // Add the unique value to the mesh builder. + SetAttributeValue(unique_vals, &att_value); + // Update index mapping. + value_map[i] = unique_vals; + + ++unique_vals; + } + } + if (unique_vals == num_unique_entries_) { + return unique_vals.value(); // Nothing has changed. + } + if (is_mapping_identity()) { + // Change identity mapping to the explicit one. + // The number of points is equal to the number of old unique values. + SetExplicitMapping(num_unique_entries_); + // Update the explicit map. + for (uint32_t i = 0; i < num_unique_entries_; ++i) { + SetPointMapEntry(PointIndex(i), value_map[AttributeValueIndex(i)]); + } + } else { + // Update point to value map using the mapping between old and new values. + for (PointIndex i(0); i < static_cast(indices_map_.size()); ++i) { + SetPointMapEntry(i, value_map[indices_map_[i]]); + } + } + num_unique_entries_ = unique_vals.value(); + return num_unique_entries_; +} +#endif + +} // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.h b/extern/draco/draco/src/draco/attributes/point_attribute.h new file mode 100644 index 00000000000..ee36620313e --- /dev/null +++ b/extern/draco/draco/src/draco/attributes/point_attribute.h @@ -0,0 +1,190 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_ATTRIBUTES_POINT_ATTRIBUTE_H_ +#define DRACO_ATTRIBUTES_POINT_ATTRIBUTE_H_ + +#include + +#include "draco/attributes/attribute_transform_data.h" +#include "draco/attributes/geometry_attribute.h" +#include "draco/core/draco_index_type_vector.h" +#include "draco/core/hash_utils.h" +#include "draco/core/macros.h" +#include "draco/draco_features.h" + +namespace draco { + +// Class for storing point specific data about each attribute. In general, +// multiple points stored in a point cloud can share the same attribute value +// and this class provides the necessary mapping between point ids and attribute +// value ids. +class PointAttribute : public GeometryAttribute { + public: + PointAttribute(); + explicit PointAttribute(const GeometryAttribute &att); + + // Make sure the move constructor is defined (needed for better performance + // when new attributes are added to PointCloud). + PointAttribute(PointAttribute &&attribute) = default; + PointAttribute &operator=(PointAttribute &&attribute) = default; + + // Initializes a point attribute. By default the attribute will be set to + // identity mapping between point indices and attribute values. To set custom + // mapping use SetExplicitMapping() function. + void Init(Type attribute_type, int8_t num_components, DataType data_type, + bool normalized, size_t num_attribute_values); + + // Copies attribute data from the provided |src_att| attribute. + void CopyFrom(const PointAttribute &src_att); + + // Prepares the attribute storage for the specified number of entries. + bool Reset(size_t num_attribute_values); + + size_t size() const { return num_unique_entries_; } + AttributeValueIndex mapped_index(PointIndex point_index) const { + if (identity_mapping_) { + return AttributeValueIndex(point_index.value()); + } + return indices_map_[point_index]; + } + DataBuffer *buffer() const { return attribute_buffer_.get(); } + bool is_mapping_identity() const { return identity_mapping_; } + size_t indices_map_size() const { + if (is_mapping_identity()) { + return 0; + } + return indices_map_.size(); + } + + const uint8_t *GetAddressOfMappedIndex(PointIndex point_index) const { + return GetAddress(mapped_index(point_index)); + } + + // Sets the new number of unique attribute entries for the attribute. The + // function resizes the attribute storage to hold |num_attribute_values| + // entries. + // All previous entries with AttributeValueIndex < |num_attribute_values| + // are preserved. Caller needs to ensure that the PointAttribute is still + // valid after the resizing operation (that is, each point is mapped to a + // valid attribute value). + void Resize(size_t new_num_unique_entries); + + // Functions for setting the type of mapping between point indices and + // attribute entry ids. + // This function sets the mapping to implicit, where point indices are equal + // to attribute entry indices. + void SetIdentityMapping() { + identity_mapping_ = true; + indices_map_.clear(); + } + // This function sets the mapping to be explicitly using the indices_map_ + // array that needs to be initialized by the caller. + void SetExplicitMapping(size_t num_points) { + identity_mapping_ = false; + indices_map_.resize(num_points, kInvalidAttributeValueIndex); + } + + // Set an explicit map entry for a specific point index. + void SetPointMapEntry(PointIndex point_index, + AttributeValueIndex entry_index) { + DRACO_DCHECK(!identity_mapping_); + indices_map_[point_index] = entry_index; + } + + // Same as GeometryAttribute::GetValue(), but using point id as the input. + // Mapping to attribute value index is performed automatically. + void GetMappedValue(PointIndex point_index, void *out_data) const { + return GetValue(mapped_index(point_index), out_data); + } + +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED + // Deduplicate |in_att| values into |this| attribute. |in_att| can be equal + // to |this|. + // Returns -1 if the deduplication failed. + AttributeValueIndex::ValueType DeduplicateValues( + const GeometryAttribute &in_att); + + // Same as above but the values read from |in_att| are sampled with the + // provided offset |in_att_offset|. + AttributeValueIndex::ValueType DeduplicateValues( + const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); +#endif + + // Set attribute transform data for the attribute. The data is used to store + // the type and parameters of the transform that is applied on the attribute + // data (optional). + void SetAttributeTransformData( + std::unique_ptr transform_data) { + attribute_transform_data_ = std::move(transform_data); + } + const AttributeTransformData *GetAttributeTransformData() const { + return attribute_transform_data_.get(); + } + + private: +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED + template + AttributeValueIndex::ValueType DeduplicateTypedValues( + const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); + template + AttributeValueIndex::ValueType DeduplicateFormattedValues( + const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); +#endif + + // Data storage for attribute values. GeometryAttribute itself doesn't own its + // buffer so we need to allocate it here. + std::unique_ptr attribute_buffer_; + + // Mapping between point ids and attribute value ids. + IndexTypeVector indices_map_; + AttributeValueIndex::ValueType num_unique_entries_; + // Flag when the mapping between point ids and attribute values is identity. + bool identity_mapping_; + + // If an attribute contains transformed data (e.g. quantized), we can specify + // the attribute transform here and use it to transform the attribute back to + // its original format. + std::unique_ptr attribute_transform_data_; + + friend struct PointAttributeHasher; +}; + +// Hash functor for the PointAttribute class. +struct PointAttributeHasher { + size_t operator()(const PointAttribute &attribute) const { + GeometryAttributeHasher base_hasher; + size_t hash = base_hasher(attribute); + hash = HashCombine(attribute.identity_mapping_, hash); + hash = HashCombine(attribute.num_unique_entries_, hash); + hash = HashCombine(attribute.indices_map_.size(), hash); + if (!attribute.indices_map_.empty()) { + const uint64_t indices_hash = FingerprintString( + reinterpret_cast(attribute.indices_map_.data()), + attribute.indices_map_.size()); + hash = HashCombine(indices_hash, hash); + } + if (attribute.attribute_buffer_ != nullptr) { + const uint64_t buffer_hash = FingerprintString( + reinterpret_cast(attribute.attribute_buffer_->data()), + attribute.attribute_buffer_->data_size()); + hash = HashCombine(buffer_hash, hash); + } + return hash; + } +}; + +} // namespace draco + +#endif // DRACO_ATTRIBUTES_POINT_ATTRIBUTE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc new file mode 100644 index 00000000000..ce5b8b9c756 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc @@ -0,0 +1,111 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/attributes_decoder.h" + +#include "draco/core/varint_decoding.h" + +namespace draco { + +AttributesDecoder::AttributesDecoder() + : point_cloud_decoder_(nullptr), point_cloud_(nullptr) {} + +bool AttributesDecoder::Init(PointCloudDecoder *decoder, PointCloud *pc) { + point_cloud_decoder_ = decoder; + point_cloud_ = pc; + return true; +} + +bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { + // Decode and create attributes. + uint32_t num_attributes; +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (point_cloud_decoder_->bitstream_version() < + DRACO_BITSTREAM_VERSION(2, 0)) { + if (!in_buffer->Decode(&num_attributes)) { + return false; + } + } else +#endif + { + if (!DecodeVarint(&num_attributes, in_buffer)) { + return false; + } + } + if (num_attributes == 0) { + return false; + } + point_attribute_ids_.resize(num_attributes); + PointCloud *pc = point_cloud_; + for (uint32_t i = 0; i < num_attributes; ++i) { + // Decode attribute descriptor data. + uint8_t att_type, data_type, num_components, normalized; + if (!in_buffer->Decode(&att_type)) { + return false; + } + if (!in_buffer->Decode(&data_type)) { + return false; + } + if (!in_buffer->Decode(&num_components)) { + return false; + } + if (!in_buffer->Decode(&normalized)) { + return false; + } + if (att_type >= GeometryAttribute::NAMED_ATTRIBUTES_COUNT) { + return false; + } + if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) { + return false; + } + const DataType draco_dt = static_cast(data_type); + + // Add the attribute to the point cloud + GeometryAttribute ga; + ga.Init(static_cast(att_type), nullptr, + num_components, draco_dt, normalized > 0, + DataTypeLength(draco_dt) * num_components, 0); + uint32_t unique_id; +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (point_cloud_decoder_->bitstream_version() < + DRACO_BITSTREAM_VERSION(1, 3)) { + uint16_t custom_id; + if (!in_buffer->Decode(&custom_id)) { + return false; + } + // TODO(draco-eng): Add "custom_id" to attribute metadata. + unique_id = static_cast(custom_id); + ga.set_unique_id(unique_id); + } else +#endif + { + DecodeVarint(&unique_id, in_buffer); + ga.set_unique_id(unique_id); + } + const int att_id = pc->AddAttribute( + std::unique_ptr(new PointAttribute(ga))); + pc->attribute(att_id)->set_unique_id(unique_id); + point_attribute_ids_[i] = att_id; + + // Update the inverse map. + if (att_id >= + static_cast(point_attribute_to_local_id_map_.size())) { + point_attribute_to_local_id_map_.resize(att_id + 1, -1); + } + point_attribute_to_local_id_map_[att_id] = i; + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.h b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.h new file mode 100644 index 00000000000..5b2bb2cfeb2 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.h @@ -0,0 +1,97 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_DECODER_H_ + +#include + +#include "draco/compression/attributes/attributes_decoder_interface.h" +#include "draco/compression/point_cloud/point_cloud_decoder.h" +#include "draco/core/decoder_buffer.h" +#include "draco/draco_features.h" +#include "draco/point_cloud/point_cloud.h" + +namespace draco { + +// Base class for decoding one or more attributes that were encoded with a +// matching AttributesEncoder. It is a basic implementation of +// AttributesDecoderInterface that provides functionality that is shared between +// all AttributesDecoders. +class AttributesDecoder : public AttributesDecoderInterface { + public: + AttributesDecoder(); + virtual ~AttributesDecoder() = default; + + // Called after all attribute decoders are created. It can be used to perform + // any custom initialization. + bool Init(PointCloudDecoder *decoder, PointCloud *pc) override; + + // Decodes any attribute decoder specific data from the |in_buffer|. + bool DecodeAttributesDecoderData(DecoderBuffer *in_buffer) override; + + int32_t GetAttributeId(int i) const override { + return point_attribute_ids_[i]; + } + int32_t GetNumAttributes() const override { + return static_cast(point_attribute_ids_.size()); + } + PointCloudDecoder *GetDecoder() const override { + return point_cloud_decoder_; + } + + // Decodes attribute data from the source buffer. + bool DecodeAttributes(DecoderBuffer *in_buffer) override { + if (!DecodePortableAttributes(in_buffer)) { + return false; + } + if (!DecodeDataNeededByPortableTransforms(in_buffer)) { + return false; + } + if (!TransformAttributesToOriginalFormat()) { + return false; + } + return true; + } + + protected: + int32_t GetLocalIdForPointAttribute(int32_t point_attribute_id) const { + const int id_map_size = + static_cast(point_attribute_to_local_id_map_.size()); + if (point_attribute_id >= id_map_size) { + return -1; + } + return point_attribute_to_local_id_map_[point_attribute_id]; + } + virtual bool DecodePortableAttributes(DecoderBuffer *in_buffer) = 0; + virtual bool DecodeDataNeededByPortableTransforms(DecoderBuffer *in_buffer) { + return true; + } + virtual bool TransformAttributesToOriginalFormat() { return true; } + + private: + // List of attribute ids that need to be decoded with this decoder. + std::vector point_attribute_ids_; + + // Map between point attribute id and the local id (i.e., the inverse of the + // |point_attribute_ids_|. + std::vector point_attribute_to_local_id_map_; + + PointCloudDecoder *point_cloud_decoder_; + PointCloud *point_cloud_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder_interface.h new file mode 100644 index 00000000000..8e5cf52ac3b --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder_interface.h @@ -0,0 +1,62 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_DECODER_INTERFACE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_DECODER_INTERFACE_H_ + +#include + +#include "draco/core/decoder_buffer.h" +#include "draco/point_cloud/point_cloud.h" + +namespace draco { + +class PointCloudDecoder; + +// Interface class for decoding one or more attributes that were encoded with a +// matching AttributesEncoder. It provides only the basic interface +// that is used by the PointCloudDecoder. The actual decoding must be +// implemented in derived classes using the DecodeAttributes() method. +class AttributesDecoderInterface { + public: + AttributesDecoderInterface() = default; + virtual ~AttributesDecoderInterface() = default; + + // Called after all attribute decoders are created. It can be used to perform + // any custom initialization. + virtual bool Init(PointCloudDecoder *decoder, PointCloud *pc) = 0; + + // Decodes any attribute decoder specific data from the |in_buffer|. + virtual bool DecodeAttributesDecoderData(DecoderBuffer *in_buffer) = 0; + + // Decode attribute data from the source buffer. Needs to be implemented by + // the derived classes. + virtual bool DecodeAttributes(DecoderBuffer *in_buffer) = 0; + + virtual int32_t GetAttributeId(int i) const = 0; + virtual int32_t GetNumAttributes() const = 0; + virtual PointCloudDecoder *GetDecoder() const = 0; + + // Returns an attribute containing data processed by the attribute transform. + // (see TransformToPortableFormat() method). This data is guaranteed to be + // same for encoder and decoder and it can be used by predictors. + virtual const PointAttribute *GetPortableAttribute( + int32_t /* point_attribute_id */) { + return nullptr; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_DECODER_INTERFACE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc new file mode 100644 index 00000000000..797c62f30aa --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc @@ -0,0 +1,49 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/attributes_encoder.h" + +#include "draco/core/varint_encoding.h" + +namespace draco { + +AttributesEncoder::AttributesEncoder() + : point_cloud_encoder_(nullptr), point_cloud_(nullptr) {} + +AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() { + AddAttributeId(att_id); +} + +bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) { + point_cloud_encoder_ = encoder; + point_cloud_ = pc; + return true; +} + +bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) { + // Encode data about all attributes. + EncodeVarint(num_attributes(), out_buffer); + for (uint32_t i = 0; i < num_attributes(); ++i) { + const int32_t att_id = point_attribute_ids_[i]; + const PointAttribute *const pa = point_cloud_->attribute(att_id); + out_buffer->Encode(static_cast(pa->attribute_type())); + out_buffer->Encode(static_cast(pa->data_type())); + out_buffer->Encode(static_cast(pa->num_components())); + out_buffer->Encode(static_cast(pa->normalized())); + EncodeVarint(pa->unique_id(), out_buffer); + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.h b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.h new file mode 100644 index 00000000000..9de846ae6d4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.h @@ -0,0 +1,154 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_ENCODER_H_ + +#include "draco/attributes/point_attribute.h" +#include "draco/core/encoder_buffer.h" +#include "draco/point_cloud/point_cloud.h" + +namespace draco { + +class PointCloudEncoder; + +// Base class for encoding one or more attributes of a PointCloud (or other +// geometry). This base class provides only the basic interface that is used +// by the PointCloudEncoder. +class AttributesEncoder { + public: + AttributesEncoder(); + // Constructs an attribute encoder associated with a given point attribute. + explicit AttributesEncoder(int point_attrib_id); + virtual ~AttributesEncoder() = default; + + // Called after all attribute encoders are created. It can be used to perform + // any custom initialization, including setting up attribute dependencies. + // Note: no data should be encoded in this function, because the decoder may + // process encoders in a different order from the decoder. + virtual bool Init(PointCloudEncoder *encoder, const PointCloud *pc); + + // Encodes data needed by the target attribute decoder. + virtual bool EncodeAttributesEncoderData(EncoderBuffer *out_buffer); + + // Returns a unique identifier of the given encoder type, that is used during + // decoding to construct the corresponding attribute decoder. + virtual uint8_t GetUniqueId() const = 0; + + // Encode attribute data to the target buffer. + virtual bool EncodeAttributes(EncoderBuffer *out_buffer) { + if (!TransformAttributesToPortableFormat()) { + return false; + } + if (!EncodePortableAttributes(out_buffer)) { + return false; + } + // Encode data needed by portable transforms after the attribute is encoded. + // This corresponds to the order in which the data is going to be decoded by + // the decoder. + if (!EncodeDataNeededByPortableTransforms(out_buffer)) { + return false; + } + return true; + } + + // Returns the number of attributes that need to be encoded before the + // specified attribute is encoded. + // Note that the attribute is specified by its point attribute id. + virtual int NumParentAttributes(int32_t /* point_attribute_id */) const { + return 0; + } + + virtual int GetParentAttributeId(int32_t /* point_attribute_id */, + int32_t /* parent_i */) const { + return -1; + } + + // Marks a given attribute as a parent of another attribute. + virtual bool MarkParentAttribute(int32_t /* point_attribute_id */) { + return false; + } + + // Returns an attribute containing data processed by the attribute transform. + // (see TransformToPortableFormat() method). This data is guaranteed to be + // encoded losslessly and it can be safely used for predictors. + virtual const PointAttribute *GetPortableAttribute( + int32_t /* point_attribute_id */) { + return nullptr; + } + + void AddAttributeId(int32_t id) { + point_attribute_ids_.push_back(id); + if (id >= static_cast(point_attribute_to_local_id_map_.size())) { + point_attribute_to_local_id_map_.resize(id + 1, -1); + } + point_attribute_to_local_id_map_[id] = + static_cast(point_attribute_ids_.size()) - 1; + } + + // Sets new attribute point ids (replacing the existing ones). + void SetAttributeIds(const std::vector &point_attribute_ids) { + point_attribute_ids_.clear(); + point_attribute_to_local_id_map_.clear(); + for (int32_t att_id : point_attribute_ids) { + AddAttributeId(att_id); + } + } + + int32_t GetAttributeId(int i) const { return point_attribute_ids_[i]; } + uint32_t num_attributes() const { + return static_cast(point_attribute_ids_.size()); + } + PointCloudEncoder *encoder() const { return point_cloud_encoder_; } + + protected: + // Transforms the input attribute data into a form that should be losslessly + // encoded (transform itself can be lossy). + virtual bool TransformAttributesToPortableFormat() { return true; } + + // Losslessly encodes data of all portable attributes. + // Precondition: All attributes must have been transformed into portable + // format at this point (see TransformAttributesToPortableFormat() method). + virtual bool EncodePortableAttributes(EncoderBuffer *out_buffer) = 0; + + // Encodes any data needed to revert the transform to portable format for each + // attribute (e.g. data needed for dequantization of quantized values). + virtual bool EncodeDataNeededByPortableTransforms(EncoderBuffer *out_buffer) { + return true; + } + + int32_t GetLocalIdForPointAttribute(int32_t point_attribute_id) const { + const int id_map_size = + static_cast(point_attribute_to_local_id_map_.size()); + if (point_attribute_id >= id_map_size) { + return -1; + } + return point_attribute_to_local_id_map_[point_attribute_id]; + } + + private: + // List of attribute ids that need to be encoded with this encoder. + std::vector point_attribute_ids_; + + // Map between point attribute id and the local id (i.e., the inverse of the + // |point_attribute_ids_|. + std::vector point_attribute_to_local_id_map_; + + PointCloudEncoder *point_cloud_encoder_; + const PointCloud *point_cloud_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTES_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc new file mode 100644 index 00000000000..99469f94590 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc @@ -0,0 +1,551 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/kd_tree_attributes_decoder.h" + +#include "draco/compression/attributes/kd_tree_attributes_shared.h" +#include "draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h" +#include "draco/compression/point_cloud/algorithms/float_points_tree_decoder.h" +#include "draco/compression/point_cloud/point_cloud_decoder.h" +#include "draco/core/draco_types.h" +#include "draco/core/varint_decoding.h" + +namespace draco { + +// attribute, offset_dimensionality, data_type, data_size, num_components +using AttributeTuple = + std::tuple; + +// Output iterator that is used to decode values directly into the data buffer +// of the modified PointAttribute. +// The extension of this iterator beyond the DT_UINT32 concerns itself only with +// the size of the data for efficiency, not the type. DataType is conveyed in +// but is an unused field populated for any future logic/special casing. +// DT_UINT32 and all other 4-byte types are naturally supported from the size of +// data in the kd tree encoder. DT_UINT16 and DT_UINT8 are supported by way +// of byte copies into a temporary memory buffer. +template +class PointAttributeVectorOutputIterator { + typedef PointAttributeVectorOutputIterator Self; + + public: + PointAttributeVectorOutputIterator( + PointAttributeVectorOutputIterator &&that) = default; + + explicit PointAttributeVectorOutputIterator( + const std::vector &atts) + : attributes_(atts), point_id_(0) { + DRACO_DCHECK_GE(atts.size(), 1); + uint32_t required_decode_bytes = 0; + for (auto index = 0; index < attributes_.size(); index++) { + const AttributeTuple &att = attributes_[index]; + required_decode_bytes = (std::max)(required_decode_bytes, + std::get<3>(att) * std::get<4>(att)); + } + memory_.resize(required_decode_bytes); + data_ = memory_.data(); + } + + const Self &operator++() { + ++point_id_; + return *this; + } + + // We do not want to do ANY copying of this constructor so this particular + // operator is disabled for performance reasons. + // Self operator++(int) { + // Self copy = *this; + // ++point_id_; + // return copy; + // } + + Self &operator*() { return *this; } + // Still needed in some cases. + // TODO(hemmer): remove. + // hardcoded to 3 based on legacy usage. + const Self &operator=(const VectorD &val) { + DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute. + AttributeTuple &att = attributes_[0]; + PointAttribute *attribute = std::get<0>(att); + const uint32_t &offset = std::get<1>(att); + DRACO_DCHECK_EQ(offset, 0); // expected to be zero + attribute->SetAttributeValue(attribute->mapped_index(point_id_), + &val[0] + offset); + return *this; + } + // Additional operator taking std::vector as argument. + const Self &operator=(const std::vector &val) { + for (auto index = 0; index < attributes_.size(); index++) { + AttributeTuple &att = attributes_[index]; + PointAttribute *attribute = std::get<0>(att); + const uint32_t &offset = std::get<1>(att); + const uint32_t &data_size = std::get<3>(att); + const uint32_t &num_components = std::get<4>(att); + const uint32_t *data_source = val.data() + offset; + if (data_size < 4) { // handle uint16_t, uint8_t + // selectively copy data bytes + uint8_t *data_counter = data_; + for (uint32_t index = 0; index < num_components; + index += 1, data_counter += data_size) { + std::memcpy(data_counter, data_source + index, data_size); + } + // redirect to copied data + data_source = reinterpret_cast(data_); + } + const AttributeValueIndex avi = attribute->mapped_index(point_id_); + if (avi >= static_cast(attribute->size())) { + return *this; + } + attribute->SetAttributeValue(avi, data_source); + } + return *this; + } + + private: + // preallocated memory for buffering different data sizes. Never reallocated. + std::vector memory_; + uint8_t *data_; + std::vector attributes_; + PointIndex point_id_; + + // NO COPY + PointAttributeVectorOutputIterator( + const PointAttributeVectorOutputIterator &that) = delete; + PointAttributeVectorOutputIterator &operator=( + PointAttributeVectorOutputIterator const &) = delete; +}; + +KdTreeAttributesDecoder::KdTreeAttributesDecoder() {} + +bool KdTreeAttributesDecoder::DecodePortableAttributes( + DecoderBuffer *in_buffer) { + if (in_buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 3)) { + // Old bitstream does everything in the + // DecodeDataNeededByPortableTransforms() method. + return true; + } + uint8_t compression_level = 0; + if (!in_buffer->Decode(&compression_level)) { + return false; + } + const int32_t num_points = GetDecoder()->point_cloud()->num_points(); + + // Decode data using the kd tree decoding into integer (portable) attributes. + // We first need to go over all attributes and create a new portable storage + // for those attributes that need it (floating point attributes that have to + // be dequantized after decoding). + + const int num_attributes = GetNumAttributes(); + uint32_t total_dimensionality = 0; // position is a required dimension + std::vector atts(num_attributes); + + for (int i = 0; i < GetNumAttributes(); ++i) { + const int att_id = GetAttributeId(i); + PointAttribute *const att = GetDecoder()->point_cloud()->attribute(att_id); + // All attributes have the same number of values and identity mapping + // between PointIndex and AttributeValueIndex. + att->Reset(num_points); + att->SetIdentityMapping(); + + PointAttribute *target_att = nullptr; + if (att->data_type() == DT_UINT32 || att->data_type() == DT_UINT16 || + att->data_type() == DT_UINT8) { + // We can decode to these attributes directly. + target_att = att; + } else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 || + att->data_type() == DT_INT8) { + // Prepare storage for data that is used to convert unsigned values back + // to the signed ones. + for (int c = 0; c < att->num_components(); ++c) { + min_signed_values_.push_back(0); + } + target_att = att; + } else if (att->data_type() == DT_FLOAT32) { + // Create a portable attribute that will hold the decoded data. We will + // dequantize the decoded data to the final attribute later on. + const int num_components = att->num_components(); + GeometryAttribute va; + va.Init(att->attribute_type(), nullptr, num_components, DT_UINT32, false, + num_components * DataTypeLength(DT_UINT32), 0); + std::unique_ptr port_att(new PointAttribute(va)); + port_att->SetIdentityMapping(); + port_att->Reset(num_points); + quantized_portable_attributes_.push_back(std::move(port_att)); + target_att = quantized_portable_attributes_.back().get(); + } else { + // Unsupported type. + return false; + } + // Add attribute to the output iterator used by the core algorithm. + const DataType data_type = target_att->data_type(); + const uint32_t data_size = (std::max)(0, DataTypeLength(data_type)); + const uint32_t num_components = target_att->num_components(); + atts[i] = std::make_tuple(target_att, total_dimensionality, data_type, + data_size, num_components); + total_dimensionality += num_components; + } + PointAttributeVectorOutputIterator out_it(atts); + + switch (compression_level) { + case 0: { + DynamicIntegerPointsKdTreeDecoder<0> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 1: { + DynamicIntegerPointsKdTreeDecoder<1> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 2: { + DynamicIntegerPointsKdTreeDecoder<2> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 3: { + DynamicIntegerPointsKdTreeDecoder<3> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 4: { + DynamicIntegerPointsKdTreeDecoder<4> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 5: { + DynamicIntegerPointsKdTreeDecoder<5> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 6: { + DynamicIntegerPointsKdTreeDecoder<6> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + default: + return false; + } + return true; +} + +bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( + DecoderBuffer *in_buffer) { + if (in_buffer->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 3)) { + // Decode quantization data for each attribute that need it. + // TODO(ostava): This should be moved to AttributeQuantizationTransform. + std::vector min_value; + for (int i = 0; i < GetNumAttributes(); ++i) { + const int att_id = GetAttributeId(i); + const PointAttribute *const att = + GetDecoder()->point_cloud()->attribute(att_id); + if (att->data_type() == DT_FLOAT32) { + const int num_components = att->num_components(); + min_value.resize(num_components); + if (!in_buffer->Decode(&min_value[0], sizeof(float) * num_components)) { + return false; + } + float max_value_dif; + if (!in_buffer->Decode(&max_value_dif)) { + return false; + } + uint8_t quantization_bits; + if (!in_buffer->Decode(&quantization_bits) || quantization_bits > 31) { + return false; + } + AttributeQuantizationTransform transform; + transform.SetParameters(quantization_bits, min_value.data(), + num_components, max_value_dif); + const int num_transforms = + static_cast(attribute_quantization_transforms_.size()); + if (!transform.TransferToAttribute( + quantized_portable_attributes_[num_transforms].get())) { + return false; + } + attribute_quantization_transforms_.push_back(transform); + } + } + + // Decode transform data for signed integer attributes. + for (int i = 0; i < min_signed_values_.size(); ++i) { + int32_t val; + DecodeVarint(&val, in_buffer); + min_signed_values_[i] = val; + } + return true; + } +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + // Handle old bitstream + // Figure out the total dimensionality of the point cloud + const uint32_t attribute_count = GetNumAttributes(); + uint32_t total_dimensionality = 0; // position is a required dimension + std::vector atts(attribute_count); + for (auto attribute_index = 0; + static_cast(attribute_index) < attribute_count; + attribute_index += 1) // increment the dimensionality as needed... + { + const int att_id = GetAttributeId(attribute_index); + PointAttribute *const att = GetDecoder()->point_cloud()->attribute(att_id); + const DataType data_type = att->data_type(); + const uint32_t data_size = (std::max)(0, DataTypeLength(data_type)); + const uint32_t num_components = att->num_components(); + if (data_size > 4) { + return false; + } + + atts[attribute_index] = std::make_tuple( + att, total_dimensionality, data_type, data_size, num_components); + // everything is treated as 32bit in the encoder. + total_dimensionality += num_components; + } + + const int att_id = GetAttributeId(0); + PointAttribute *const att = GetDecoder()->point_cloud()->attribute(att_id); + att->SetIdentityMapping(); + // Decode method + uint8_t method; + if (!in_buffer->Decode(&method)) { + return false; + } + if (method == KdTreeAttributesEncodingMethod::kKdTreeQuantizationEncoding) { + uint8_t compression_level = 0; + if (!in_buffer->Decode(&compression_level)) { + return false; + } + uint32_t num_points = 0; + if (!in_buffer->Decode(&num_points)) { + return false; + } + att->Reset(num_points); + FloatPointsTreeDecoder decoder; + decoder.set_num_points_from_header(num_points); + PointAttributeVectorOutputIterator out_it(atts); + if (!decoder.DecodePointCloud(in_buffer, out_it)) { + return false; + } + } else if (method == KdTreeAttributesEncodingMethod::kKdTreeIntegerEncoding) { + uint8_t compression_level = 0; + if (!in_buffer->Decode(&compression_level)) { + return false; + } + if (6 < compression_level) { + LOGE("KdTreeAttributesDecoder: compression level %i not supported.\n", + compression_level); + return false; + } + + uint32_t num_points; + if (!in_buffer->Decode(&num_points)) { + return false; + } + + for (auto attribute_index = 0; + static_cast(attribute_index) < attribute_count; + attribute_index += 1) { + const int att_id = GetAttributeId(attribute_index); + PointAttribute *const attr = + GetDecoder()->point_cloud()->attribute(att_id); + attr->Reset(num_points); + attr->SetIdentityMapping(); + }; + + PointAttributeVectorOutputIterator out_it(atts); + + switch (compression_level) { + case 0: { + DynamicIntegerPointsKdTreeDecoder<0> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 1: { + DynamicIntegerPointsKdTreeDecoder<1> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 2: { + DynamicIntegerPointsKdTreeDecoder<2> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 3: { + DynamicIntegerPointsKdTreeDecoder<3> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 4: { + DynamicIntegerPointsKdTreeDecoder<4> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 5: { + DynamicIntegerPointsKdTreeDecoder<5> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + case 6: { + DynamicIntegerPointsKdTreeDecoder<6> decoder(total_dimensionality); + if (!decoder.DecodePoints(in_buffer, out_it)) { + return false; + } + break; + } + default: + return false; + } + } else { + // Invalid method. + return false; + } + return true; +#else + return false; +#endif +} + +template +bool KdTreeAttributesDecoder::TransformAttributeBackToSignedType( + PointAttribute *att, int num_processed_signed_components) { + typedef typename std::make_unsigned::type UnsignedType; + std::vector unsigned_val(att->num_components()); + std::vector signed_val(att->num_components()); + + for (AttributeValueIndex avi(0); avi < static_cast(att->size()); + ++avi) { + att->GetValue(avi, &unsigned_val[0]); + for (int c = 0; c < att->num_components(); ++c) { + // Up-cast |unsigned_val| to int32_t to ensure we don't overflow it for + // smaller data types. + signed_val[c] = static_cast( + static_cast(unsigned_val[c]) + + min_signed_values_[num_processed_signed_components + c]); + } + att->SetAttributeValue(avi, &signed_val[0]); + } + return true; +} + +bool KdTreeAttributesDecoder::TransformAttributesToOriginalFormat() { + if (quantized_portable_attributes_.empty() && min_signed_values_.empty()) { + return true; + } + int num_processed_quantized_attributes = 0; + int num_processed_signed_components = 0; + // Dequantize attributes that needed it. + for (int i = 0; i < GetNumAttributes(); ++i) { + const int att_id = GetAttributeId(i); + PointAttribute *const att = GetDecoder()->point_cloud()->attribute(att_id); + if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 || + att->data_type() == DT_INT8) { + std::vector unsigned_val(att->num_components()); + std::vector signed_val(att->num_components()); + // Values are stored as unsigned in the attribute, make them signed again. + if (att->data_type() == DT_INT32) { + if (!TransformAttributeBackToSignedType( + att, num_processed_signed_components)) { + return false; + } + } else if (att->data_type() == DT_INT16) { + if (!TransformAttributeBackToSignedType( + att, num_processed_signed_components)) { + return false; + } + } else if (att->data_type() == DT_INT8) { + if (!TransformAttributeBackToSignedType( + att, num_processed_signed_components)) { + return false; + } + } + num_processed_signed_components += att->num_components(); + } else if (att->data_type() == DT_FLOAT32) { + // TODO(ostava): This code should be probably moved out to attribute + // transform and shared with the SequentialQuantizationAttributeDecoder. + + const PointAttribute *const src_att = + quantized_portable_attributes_[num_processed_quantized_attributes] + .get(); + + const AttributeQuantizationTransform &transform = + attribute_quantization_transforms_ + [num_processed_quantized_attributes]; + + num_processed_quantized_attributes++; + + if (GetDecoder()->options()->GetAttributeBool( + att->attribute_type(), "skip_attribute_transform", false)) { + // Attribute transform should not be performed. In this case, we replace + // the output geometry attribute with the portable attribute. + // TODO(ostava): We can potentially avoid this copy by introducing a new + // mechanism that would allow to use the final attributes as portable + // attributes for predictors that may need them. + att->CopyFrom(*src_att); + continue; + } + + // Convert all quantized values back to floats. + const int32_t max_quantized_value = + (1u << static_cast(transform.quantization_bits())) - 1; + const int num_components = att->num_components(); + const int entry_size = sizeof(float) * num_components; + const std::unique_ptr att_val(new float[num_components]); + int quant_val_id = 0; + int out_byte_pos = 0; + Dequantizer dequantizer; + if (!dequantizer.Init(transform.range(), max_quantized_value)) { + return false; + } + const uint32_t *const portable_attribute_data = + reinterpret_cast( + src_att->GetAddress(AttributeValueIndex(0))); + for (uint32_t i = 0; i < src_att->size(); ++i) { + for (int c = 0; c < num_components; ++c) { + float value = dequantizer.DequantizeFloat( + portable_attribute_data[quant_val_id++]); + value = value + transform.min_value(c); + att_val[c] = value; + } + // Store the floating point value into the attribute buffer. + att->buffer()->Write(out_byte_pos, att_val.get(), entry_size); + out_byte_pos += entry_size; + } + } + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.h new file mode 100644 index 00000000000..87338d6b0d4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_DECODER_H_ + +#include "draco/attributes/attribute_quantization_transform.h" +#include "draco/compression/attributes/attributes_decoder.h" + +namespace draco { + +// Decodes attributes encoded with the KdTreeAttributesEncoder. +class KdTreeAttributesDecoder : public AttributesDecoder { + public: + KdTreeAttributesDecoder(); + + protected: + bool DecodePortableAttributes(DecoderBuffer *in_buffer) override; + bool DecodeDataNeededByPortableTransforms(DecoderBuffer *in_buffer) override; + bool TransformAttributesToOriginalFormat() override; + + private: + template + bool TransformAttributeBackToSignedType(PointAttribute *att, + int num_processed_signed_components); + + std::vector + attribute_quantization_transforms_; + std::vector min_signed_values_; + std::vector> quantized_portable_attributes_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc new file mode 100644 index 00000000000..0f9c31565e5 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc @@ -0,0 +1,300 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/kd_tree_attributes_encoder.h" + +#include "draco/compression/attributes/kd_tree_attributes_shared.h" +#include "draco/compression/attributes/point_d_vector.h" +#include "draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h" +#include "draco/compression/point_cloud/algorithms/float_points_tree_encoder.h" +#include "draco/compression/point_cloud/point_cloud_encoder.h" +#include "draco/core/varint_encoding.h" + +namespace draco { + +KdTreeAttributesEncoder::KdTreeAttributesEncoder() : num_components_(0) {} + +KdTreeAttributesEncoder::KdTreeAttributesEncoder(int att_id) + : AttributesEncoder(att_id), num_components_(0) {} + +bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() { + // Convert any of the input attributes into a format that can be processed by + // the kd tree encoder (quantization of floating attributes for now). + const size_t num_points = encoder()->point_cloud()->num_points(); + int num_components = 0; + for (uint32_t i = 0; i < num_attributes(); ++i) { + const int att_id = GetAttributeId(i); + const PointAttribute *const att = + encoder()->point_cloud()->attribute(att_id); + num_components += att->num_components(); + } + num_components_ = num_components; + + // Go over all attributes and quantize them if needed. + for (uint32_t i = 0; i < num_attributes(); ++i) { + const int att_id = GetAttributeId(i); + const PointAttribute *const att = + encoder()->point_cloud()->attribute(att_id); + if (att->data_type() == DT_FLOAT32) { + // Quantization path. + AttributeQuantizationTransform attribute_quantization_transform; + const int quantization_bits = encoder()->options()->GetAttributeInt( + att_id, "quantization_bits", -1); + if (quantization_bits < 1) { + return false; + } + if (encoder()->options()->IsAttributeOptionSet(att_id, + "quantization_origin") && + encoder()->options()->IsAttributeOptionSet(att_id, + "quantization_range")) { + // Quantization settings are explicitly specified in the provided + // options. + std::vector quantization_origin(att->num_components()); + encoder()->options()->GetAttributeVector(att_id, "quantization_origin", + att->num_components(), + &quantization_origin[0]); + const float range = encoder()->options()->GetAttributeFloat( + att_id, "quantization_range", 1.f); + attribute_quantization_transform.SetParameters( + quantization_bits, quantization_origin.data(), + att->num_components(), range); + } else { + // Compute quantization settings from the attribute values. + attribute_quantization_transform.ComputeParameters(*att, + quantization_bits); + } + attribute_quantization_transforms_.push_back( + attribute_quantization_transform); + // Store the quantized attribute in an array that will be used when we do + // the actual encoding of the data. + quantized_portable_attributes_.push_back( + attribute_quantization_transform.GeneratePortableAttribute( + *att, static_cast(num_points))); + } else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 || + att->data_type() == DT_INT8) { + // For signed types, find the minimum value for each component. These + // values are going to be used to transform the attribute values to + // unsigned integers that can be processed by the core kd tree algorithm. + std::vector min_value(att->num_components(), + std::numeric_limits::max()); + std::vector act_value(att->num_components()); + for (AttributeValueIndex avi(0); avi < static_cast(att->size()); + ++avi) { + att->ConvertValue(avi, &act_value[0]); + for (int c = 0; c < att->num_components(); ++c) { + if (min_value[c] > act_value[c]) { + min_value[c] = act_value[c]; + } + } + } + for (int c = 0; c < att->num_components(); ++c) { + min_signed_values_.push_back(min_value[c]); + } + } + } + return true; +} + +bool KdTreeAttributesEncoder::EncodeDataNeededByPortableTransforms( + EncoderBuffer *out_buffer) { + // Store quantization settings for all attributes that need it. + for (int i = 0; i < attribute_quantization_transforms_.size(); ++i) { + attribute_quantization_transforms_[i].EncodeParameters(out_buffer); + } + + // Encode data needed for transforming signed integers to unsigned ones. + for (int i = 0; i < min_signed_values_.size(); ++i) { + EncodeVarint(min_signed_values_[i], out_buffer); + } + return true; +} + +bool KdTreeAttributesEncoder::EncodePortableAttributes( + EncoderBuffer *out_buffer) { + // Encode the data using the kd tree encoder algorithm. The data is first + // copied to a PointDVector that provides all the API expected by the core + // encoding algorithm. + + // We limit the maximum value of compression_level to 6 as we don't currently + // have viable algorithms for higher compression levels. + uint8_t compression_level = + std::min(10 - encoder()->options()->GetSpeed(), 6); + DRACO_DCHECK_LE(compression_level, 6); + + if (compression_level == 6 && num_components_ > 15) { + // Don't use compression level for CL >= 6. Axis selection is currently + // encoded using 4 bits. + compression_level = 5; + } + + out_buffer->Encode(compression_level); + + // Init PointDVector. The number of dimensions is equal to the total number + // of dimensions across all attributes. + const int num_points = encoder()->point_cloud()->num_points(); + PointDVector point_vector(num_points, num_components_); + + int num_processed_components = 0; + int num_processed_quantized_attributes = 0; + int num_processed_signed_components = 0; + // Copy data to the point vector. + for (uint32_t i = 0; i < num_attributes(); ++i) { + const int att_id = GetAttributeId(i); + const PointAttribute *const att = + encoder()->point_cloud()->attribute(att_id); + const PointAttribute *source_att = nullptr; + if (att->data_type() == DT_UINT32 || att->data_type() == DT_UINT16 || + att->data_type() == DT_UINT8 || att->data_type() == DT_INT32 || + att->data_type() == DT_INT16 || att->data_type() == DT_INT8) { + // Use the original attribute. + source_att = att; + } else if (att->data_type() == DT_FLOAT32) { + // Use the portable (quantized) attribute instead. + source_att = + quantized_portable_attributes_[num_processed_quantized_attributes] + .get(); + num_processed_quantized_attributes++; + } else { + // Unsupported data type. + return false; + } + + if (source_att == nullptr) { + return false; + } + + // Copy source_att to the vector. + if (source_att->data_type() == DT_UINT32) { + // If the data type is the same as the one used by the point vector, we + // can directly copy individual elements. + for (PointIndex pi(0); pi < num_points; ++pi) { + const AttributeValueIndex avi = source_att->mapped_index(pi); + const uint8_t *const att_value_address = source_att->GetAddress(avi); + point_vector.CopyAttribute(source_att->num_components(), + num_processed_components, pi.value(), + att_value_address); + } + } else if (source_att->data_type() == DT_INT32 || + source_att->data_type() == DT_INT16 || + source_att->data_type() == DT_INT8) { + // Signed values need to be converted to unsigned before they are stored + // in the point vector. + std::vector signed_point(source_att->num_components()); + std::vector unsigned_point(source_att->num_components()); + for (PointIndex pi(0); pi < num_points; ++pi) { + const AttributeValueIndex avi = source_att->mapped_index(pi); + source_att->ConvertValue(avi, &signed_point[0]); + for (int c = 0; c < source_att->num_components(); ++c) { + unsigned_point[c] = + signed_point[c] - + min_signed_values_[num_processed_signed_components + c]; + } + + point_vector.CopyAttribute(source_att->num_components(), + num_processed_components, pi.value(), + &unsigned_point[0]); + } + num_processed_signed_components += source_att->num_components(); + } else { + // If the data type of the attribute is different, we have to convert the + // value before we put it to the point vector. + std::vector point(source_att->num_components()); + for (PointIndex pi(0); pi < num_points; ++pi) { + const AttributeValueIndex avi = source_att->mapped_index(pi); + source_att->ConvertValue(avi, &point[0]); + point_vector.CopyAttribute(source_att->num_components(), + num_processed_components, pi.value(), + point.data()); + } + } + num_processed_components += source_att->num_components(); + } + + // Compute the maximum bit length needed for the kd tree encoding. + int num_bits = 0; + const uint32_t *data = point_vector[0]; + for (int i = 0; i < num_points * num_components_; ++i) { + if (data[i] > 0) { + const int msb = MostSignificantBit(data[i]) + 1; + if (msb > num_bits) { + num_bits = msb; + } + } + } + + switch (compression_level) { + case 6: { + DynamicIntegerPointsKdTreeEncoder<6> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + case 5: { + DynamicIntegerPointsKdTreeEncoder<5> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + case 4: { + DynamicIntegerPointsKdTreeEncoder<4> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + case 3: { + DynamicIntegerPointsKdTreeEncoder<3> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + case 2: { + DynamicIntegerPointsKdTreeEncoder<2> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + case 1: { + DynamicIntegerPointsKdTreeEncoder<1> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + case 0: { + DynamicIntegerPointsKdTreeEncoder<0> points_encoder(num_components_); + if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(), + num_bits, out_buffer)) { + return false; + } + break; + } + // Compression level and/or encoding speed seem wrong. + default: + return false; + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h new file mode 100644 index 00000000000..8b4c4e2faab --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ + +#include "draco/attributes/attribute_quantization_transform.h" +#include "draco/compression/attributes/attributes_encoder.h" +#include "draco/compression/config/compression_shared.h" + +namespace draco { + +// Encodes all attributes of a given PointCloud using one of the available +// Kd-tree compression methods. +// See compression/point_cloud/point_cloud_kd_tree_encoder.h for more details. +class KdTreeAttributesEncoder : public AttributesEncoder { + public: + KdTreeAttributesEncoder(); + explicit KdTreeAttributesEncoder(int att_id); + + uint8_t GetUniqueId() const override { return KD_TREE_ATTRIBUTE_ENCODER; } + + protected: + bool TransformAttributesToPortableFormat() override; + bool EncodePortableAttributes(EncoderBuffer *out_buffer) override; + bool EncodeDataNeededByPortableTransforms(EncoderBuffer *out_buffer) override; + + private: + std::vector + attribute_quantization_transforms_; + // Min signed values are used to transform signed integers into unsigned ones + // (by subtracting the min signed value for each component). + std::vector min_signed_values_; + std::vector> quantized_portable_attributes_; + int num_components_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_shared.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_shared.h new file mode 100644 index 00000000000..94841a91d99 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_shared.h @@ -0,0 +1,28 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_SHARED_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_SHARED_H_ + +namespace draco { + +// Defines types of kD-tree compression +enum KdTreeAttributesEncodingMethod { + kKdTreeQuantizationEncoding = 0, + kKdTreeIntegerEncoding +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_SHARED_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/linear_sequencer.h b/extern/draco/draco/src/draco/compression/attributes/linear_sequencer.h new file mode 100644 index 00000000000..7d9b5264199 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/linear_sequencer.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_LINEAR_SEQUENCER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_LINEAR_SEQUENCER_H_ + +#include "draco/compression/attributes/points_sequencer.h" + +namespace draco { + +// A simple sequencer that generates a linear sequence [0, num_points - 1]. +// I.e., the order of the points is preserved for the input data. +class LinearSequencer : public PointsSequencer { + public: + explicit LinearSequencer(int32_t num_points) : num_points_(num_points) {} + + bool UpdatePointToAttributeIndexMapping(PointAttribute *attribute) override { + attribute->SetIdentityMapping(); + return true; + } + + protected: + bool GenerateSequenceInternal() override { + if (num_points_ < 0) { + return false; + } + out_point_ids()->resize(num_points_); + for (int i = 0; i < num_points_; ++i) { + out_point_ids()->at(i) = PointIndex(i); + } + return true; + } + + private: + int32_t num_points_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_LINEAR_SEQUENCER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/mesh_attribute_indices_encoding_data.h b/extern/draco/draco/src/draco/compression/attributes/mesh_attribute_indices_encoding_data.h new file mode 100644 index 00000000000..9a358e44733 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/mesh_attribute_indices_encoding_data.h @@ -0,0 +1,58 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_ATTRIBUTE_INDICES_ENCODING_DATA_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_MESH_ATTRIBUTE_INDICES_ENCODING_DATA_H_ + +#include + +#include + +#include "draco/attributes/geometry_indices.h" + +namespace draco { + +// Data used for encoding and decoding of mesh attributes. +struct MeshAttributeIndicesEncodingData { + MeshAttributeIndicesEncodingData() : num_values(0) {} + + void Init(int num_vertices) { + vertex_to_encoded_attribute_value_index_map.resize(num_vertices); + + // We expect to store one value for each vertex. + encoded_attribute_value_index_to_corner_map.reserve(num_vertices); + } + + // Array for storing the corner ids in the order their associated attribute + // entries were encoded/decoded. For every encoded attribute value entry we + // store exactly one corner. I.e., this is the mapping between an encoded + // attribute entry ids and corner ids. This map is needed for example by + // prediction schemes. Note that not all corners are included in this map, + // e.g., if multiple corners share the same attribute value, only one of these + // corners will be usually included. + std::vector encoded_attribute_value_index_to_corner_map; + + // Map for storing encoding order of attribute entries for each vertex. + // i.e. Mapping between vertices and their corresponding attribute entry ids + // that are going to be used by the decoder. + // -1 if an attribute entry hasn't been encoded/decoded yet. + std::vector vertex_to_encoded_attribute_value_index_map; + + // Total number of encoded/decoded attribute entries. + int num_values; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_MESH_ATTRIBUTE_INDICES_ENCODING_DATA_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h new file mode 100644 index 00000000000..32e27c711e3 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h @@ -0,0 +1,343 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Utilities for converting unit vectors to octahedral coordinates and back. +// For more details about octahedral coordinates, see for example Cigolle +// et al.'14 “A Survey of Efficient Representations for Independent Unit +// Vectors”. +// +// In short this is motivated by an octahedron inscribed into a sphere. The +// direction of the normal vector can be defined by a point on the octahedron. +// On the right hemisphere (x > 0) this point is projected onto the x = 0 plane, +// that is, the right side of the octahedron forms a diamond like shape. The +// left side of the octahedron is also projected onto the x = 0 plane, however, +// in this case we flap the triangles of the diamond outward. Afterwards we +// shift the resulting square such that all values are positive. +// +// Important values in this file: +// * q: number of quantization bits +// * max_quantized_value: the max value representable with q bits (odd) +// * max_value: max value of the diamond = max_quantized_value - 1 (even) +// * center_value: center of the diamond after shift +// +// Note that the parameter space is somewhat periodic, e.g. (0, 0) == +// (max_value, max_value), which is also why the diamond is one smaller than the +// maximal representable value in order to have an odd range of values. + +#ifndef DRACO_COMPRESSION_ATTRIBUTES_NORMAL_COMPRESSION_UTILS_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_NORMAL_COMPRESSION_UTILS_H_ + +#include + +#include +#include + +#include "draco/core/macros.h" + +namespace draco { + +class OctahedronToolBox { + public: + OctahedronToolBox() + : quantization_bits_(-1), + max_quantized_value_(-1), + max_value_(-1), + center_value_(-1) {} + + bool SetQuantizationBits(int32_t q) { + if (q < 2 || q > 30) { + return false; + } + quantization_bits_ = q; + max_quantized_value_ = (1 << quantization_bits_) - 1; + max_value_ = max_quantized_value_ - 1; + center_value_ = max_value_ / 2; + return true; + } + bool IsInitialized() const { return quantization_bits_ != -1; } + + // Convert all edge points in the top left and bottom right quadrants to + // their corresponding position in the bottom left and top right quadrants. + // Convert all corner edge points to the top right corner. + inline void CanonicalizeOctahedralCoords(int32_t s, int32_t t, int32_t *out_s, + int32_t *out_t) const { + if ((s == 0 && t == 0) || (s == 0 && t == max_value_) || + (s == max_value_ && t == 0)) { + s = max_value_; + t = max_value_; + } else if (s == 0 && t > center_value_) { + t = center_value_ - (t - center_value_); + } else if (s == max_value_ && t < center_value_) { + t = center_value_ + (center_value_ - t); + } else if (t == max_value_ && s < center_value_) { + s = center_value_ + (center_value_ - s); + } else if (t == 0 && s > center_value_) { + s = center_value_ - (s - center_value_); + } + + *out_s = s; + *out_t = t; + } + + // Converts an integer vector to octahedral coordinates. + // Precondition: |int_vec| abs sum must equal center value. + inline void IntegerVectorToQuantizedOctahedralCoords(const int32_t *int_vec, + int32_t *out_s, + int32_t *out_t) const { + DRACO_DCHECK_EQ( + std::abs(int_vec[0]) + std::abs(int_vec[1]) + std::abs(int_vec[2]), + center_value_); + int32_t s, t; + if (int_vec[0] >= 0) { + // Right hemisphere. + s = (int_vec[1] + center_value_); + t = (int_vec[2] + center_value_); + } else { + // Left hemisphere. + if (int_vec[1] < 0) { + s = std::abs(int_vec[2]); + } else { + s = (max_value_ - std::abs(int_vec[2])); + } + if (int_vec[2] < 0) { + t = std::abs(int_vec[1]); + } else { + t = (max_value_ - std::abs(int_vec[1])); + } + } + CanonicalizeOctahedralCoords(s, t, out_s, out_t); + } + + template + void FloatVectorToQuantizedOctahedralCoords(const T *vector, int32_t *out_s, + int32_t *out_t) const { + const double abs_sum = std::abs(static_cast(vector[0])) + + std::abs(static_cast(vector[1])) + + std::abs(static_cast(vector[2])); + + // Adjust values such that abs sum equals 1. + double scaled_vector[3]; + if (abs_sum > 1e-6) { + // Scale needed to project the vector to the surface of an octahedron. + const double scale = 1.0 / abs_sum; + scaled_vector[0] = vector[0] * scale; + scaled_vector[1] = vector[1] * scale; + scaled_vector[2] = vector[2] * scale; + } else { + scaled_vector[0] = 1.0; + scaled_vector[1] = 0; + scaled_vector[2] = 0; + } + + // Scale vector such that the sum equals the center value. + int32_t int_vec[3]; + int_vec[0] = + static_cast(floor(scaled_vector[0] * center_value_ + 0.5)); + int_vec[1] = + static_cast(floor(scaled_vector[1] * center_value_ + 0.5)); + // Make sure the sum is exactly the center value. + int_vec[2] = center_value_ - std::abs(int_vec[0]) - std::abs(int_vec[1]); + if (int_vec[2] < 0) { + // If the sum of first two coordinates is too large, we need to decrease + // the length of one of the coordinates. + if (int_vec[1] > 0) { + int_vec[1] += int_vec[2]; + } else { + int_vec[1] -= int_vec[2]; + } + int_vec[2] = 0; + } + // Take care of the sign. + if (scaled_vector[2] < 0) { + int_vec[2] *= -1; + } + + IntegerVectorToQuantizedOctahedralCoords(int_vec, out_s, out_t); + } + + // Normalize |vec| such that its abs sum is equal to the center value; + template + void CanonicalizeIntegerVector(T *vec) const { + static_assert(std::is_integral::value, "T must be an integral type."); + static_assert(std::is_signed::value, "T must be a signed type."); + const int64_t abs_sum = static_cast(std::abs(vec[0])) + + static_cast(std::abs(vec[1])) + + static_cast(std::abs(vec[2])); + + if (abs_sum == 0) { + vec[0] = center_value_; // vec[1] == v[2] == 0 + } else { + vec[0] = + (static_cast(vec[0]) * static_cast(center_value_)) / + abs_sum; + vec[1] = + (static_cast(vec[1]) * static_cast(center_value_)) / + abs_sum; + if (vec[2] >= 0) { + vec[2] = center_value_ - std::abs(vec[0]) - std::abs(vec[1]); + } else { + vec[2] = -(center_value_ - std::abs(vec[0]) - std::abs(vec[1])); + } + } + } + + // TODO(b/149328891): Change function to not use templates as |T| is only + // float. + template + void OctaherdalCoordsToUnitVector(T in_s, T in_t, T *out_vector) const { + DRACO_DCHECK_GE(in_s, 0); + DRACO_DCHECK_GE(in_t, 0); + DRACO_DCHECK_LE(in_s, 1); + DRACO_DCHECK_LE(in_t, 1); + T s = in_s; + T t = in_t; + T spt = s + t; + T smt = s - t; + T x_sign = 1.0; + if (spt >= 0.5 && spt <= 1.5 && smt >= -0.5 && smt <= 0.5) { + // Right hemisphere. Don't do anything. + } else { + // Left hemisphere. + x_sign = -1.0; + if (spt <= 0.5) { + s = 0.5 - in_t; + t = 0.5 - in_s; + } else if (spt >= 1.5) { + s = 1.5 - in_t; + t = 1.5 - in_s; + } else if (smt <= -0.5) { + s = in_t - 0.5; + t = in_s + 0.5; + } else { + s = in_t + 0.5; + t = in_s - 0.5; + } + spt = s + t; + smt = s - t; + } + const T y = 2.0 * s - 1.0; + const T z = 2.0 * t - 1.0; + const T x = std::min(std::min(2.0 * spt - 1.0, 3.0 - 2.0 * spt), + std::min(2.0 * smt + 1.0, 1.0 - 2.0 * smt)) * + x_sign; + // Normalize the computed vector. + const T normSquared = x * x + y * y + z * z; + if (normSquared < 1e-6) { + out_vector[0] = 0; + out_vector[1] = 0; + out_vector[2] = 0; + } else { + const T d = 1.0 / std::sqrt(normSquared); + out_vector[0] = x * d; + out_vector[1] = y * d; + out_vector[2] = z * d; + } + } + + template + void QuantizedOctaherdalCoordsToUnitVector(int32_t in_s, int32_t in_t, + T *out_vector) const { + T scale = 1.0 / static_cast(max_value_); + OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector); + } + + // |s| and |t| are expected to be signed values. + inline bool IsInDiamond(const int32_t &s, const int32_t &t) const { + // Expect center already at origin. + DRACO_DCHECK_LE(s, center_value_); + DRACO_DCHECK_LE(t, center_value_); + DRACO_DCHECK_GE(s, -center_value_); + DRACO_DCHECK_GE(t, -center_value_); + return std::abs(s) + std::abs(t) <= center_value_; + } + + void InvertDiamond(int32_t *s, int32_t *t) const { + // Expect center already at origin. + DRACO_DCHECK_LE(*s, center_value_); + DRACO_DCHECK_LE(*t, center_value_); + DRACO_DCHECK_GE(*s, -center_value_); + DRACO_DCHECK_GE(*t, -center_value_); + int32_t sign_s = 0; + int32_t sign_t = 0; + if (*s >= 0 && *t >= 0) { + sign_s = 1; + sign_t = 1; + } else if (*s <= 0 && *t <= 0) { + sign_s = -1; + sign_t = -1; + } else { + sign_s = (*s > 0) ? 1 : -1; + sign_t = (*t > 0) ? 1 : -1; + } + + const int32_t corner_point_s = sign_s * center_value_; + const int32_t corner_point_t = sign_t * center_value_; + *s = 2 * *s - corner_point_s; + *t = 2 * *t - corner_point_t; + if (sign_s * sign_t >= 0) { + int32_t temp = *s; + *s = -*t; + *t = -temp; + } else { + std::swap(*s, *t); + } + *s = (*s + corner_point_s) / 2; + *t = (*t + corner_point_t) / 2; + } + + void InvertDirection(int32_t *s, int32_t *t) const { + // Expect center already at origin. + DRACO_DCHECK_LE(*s, center_value_); + DRACO_DCHECK_LE(*t, center_value_); + DRACO_DCHECK_GE(*s, -center_value_); + DRACO_DCHECK_GE(*t, -center_value_); + *s *= -1; + *t *= -1; + this->InvertDiamond(s, t); + } + + // For correction values. + int32_t ModMax(int32_t x) const { + if (x > this->center_value()) { + return x - this->max_quantized_value(); + } + if (x < -this->center_value()) { + return x + this->max_quantized_value(); + } + return x; + } + + // For correction values. + int32_t MakePositive(int32_t x) const { + DRACO_DCHECK_LE(x, this->center_value() * 2); + if (x < 0) { + return x + this->max_quantized_value(); + } + return x; + } + + int32_t quantization_bits() const { return quantization_bits_; } + int32_t max_quantized_value() const { return max_quantized_value_; } + int32_t max_value() const { return max_value_; } + int32_t center_value() const { return center_value_; } + + private: + int32_t quantization_bits_; + int32_t max_quantized_value_; + int32_t max_value_; + int32_t center_value_; +}; +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_NORMAL_COMPRESSION_UTILS_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/point_d_vector.h b/extern/draco/draco/src/draco/compression/attributes/point_d_vector.h new file mode 100644 index 00000000000..3b115d500cd --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/point_d_vector.h @@ -0,0 +1,279 @@ +// Copyright 2018 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_ + +#include +#include +#include + +#include "draco/core/macros.h" + +namespace draco { + +// The main class of this file is PointDVector providing an interface similar to +// std::vector for arbitrary number of dimensions (without a template +// argument). PointDVectorIterator is a random access iterator, which allows for +// compatibility with existing algorithms. PseudoPointD provides for a view on +// the individual items in a contiguous block of memory, which is compatible +// with the swap function and is returned by a dereference of +// PointDVectorIterator. Swap functions provide for compatibility/specialization +// that allows these classes to work with currently utilized STL functions. + +// This class allows for swap functionality from the RandomIterator +// It seems problematic to bring this inside PointDVector due to templating. +template +class PseudoPointD { + public: + PseudoPointD(internal_t *mem, internal_t dimension) + : mem_(mem), dimension_(dimension) {} + + // Specifically copies referenced memory + void swap(PseudoPointD &other) noexcept { + for (internal_t dim = 0; dim < dimension_; dim += 1) { + std::swap(mem_[dim], other.mem_[dim]); + } + } + + PseudoPointD(const PseudoPointD &other) + : mem_(other.mem_), dimension_(other.dimension_) {} + + const internal_t &operator[](const size_t &n) const { + DRACO_DCHECK_LT(n, dimension_); + return mem_[n]; + } + internal_t &operator[](const size_t &n) { + DRACO_DCHECK_LT(n, dimension_); + return mem_[n]; + } + + bool operator==(const PseudoPointD &other) const { + for (auto dim = 0; dim < dimension_; dim += 1) { + if (mem_[dim] != other.mem_[dim]) { + return false; + } + } + return true; + } + bool operator!=(const PseudoPointD &other) const { + return !this->operator==(other); + } + + private: + internal_t *const mem_; + const internal_t dimension_; +}; + +// It seems problematic to bring this inside PointDVector due to templating. +template +void swap(draco::PseudoPointD &&a, + draco::PseudoPointD &&b) noexcept { + a.swap(b); +}; +template +void swap(draco::PseudoPointD &a, + draco::PseudoPointD &b) noexcept { + a.swap(b); +}; + +template +class PointDVector { + public: + PointDVector(const uint32_t n_items, const uint32_t dimensionality) + : n_items_(n_items), + dimensionality_(dimensionality), + item_size_bytes_(dimensionality * sizeof(internal_t)), + data_(n_items * dimensionality), + data0_(data_.data()) {} + // random access iterator + class PointDVectorIterator + : public std::iterator { + friend class PointDVector; + + public: + // std::iter_swap is called inside of std::partition and needs this + // specialized support + PseudoPointD operator*() const { + return PseudoPointD(vec_->data0_ + item_ * dimensionality_, + dimensionality_); + } + const PointDVectorIterator &operator++() { + item_ += 1; + return *this; + } + const PointDVectorIterator &operator--() { + item_ -= 1; + return *this; + } + PointDVectorIterator operator++(int32_t) { + PointDVectorIterator copy(*this); + item_ += 1; + return copy; + } + PointDVectorIterator operator--(int32_t) { + PointDVectorIterator copy(*this); + item_ -= 1; + return copy; + } + PointDVectorIterator &operator=(const PointDVectorIterator &other) { + this->item_ = other.item_; + return *this; + } + + bool operator==(const PointDVectorIterator &ref) const { + return item_ == ref.item_; + } + bool operator!=(const PointDVectorIterator &ref) const { + return item_ != ref.item_; + } + bool operator<(const PointDVectorIterator &ref) const { + return item_ < ref.item_; + } + bool operator>(const PointDVectorIterator &ref) const { + return item_ > ref.item_; + } + bool operator<=(const PointDVectorIterator &ref) const { + return item_ <= ref.item_; + } + bool operator>=(const PointDVectorIterator &ref) const { + return item_ >= ref.item_; + } + + PointDVectorIterator operator+(const int32_t &add) const { + PointDVectorIterator copy(vec_, item_ + add); + return copy; + } + PointDVectorIterator &operator+=(const int32_t &add) { + item_ += add; + return *this; + } + PointDVectorIterator operator-(const int32_t &sub) const { + PointDVectorIterator copy(vec_, item_ - sub); + return copy; + } + size_t operator-(const PointDVectorIterator &sub) const { + return (item_ - sub.item_); + } + + PointDVectorIterator &operator-=(const int32_t &sub) { + item_ -= sub; + return *this; + } + + internal_t *operator[](const size_t &n) const { + return vec_->data0_ + (item_ + n) * dimensionality_; + } + + protected: + explicit PointDVectorIterator(PointDVector *vec, size_t start_item) + : item_(start_item), vec_(vec), dimensionality_(vec->dimensionality_) {} + + private: + size_t item_; // this counts the item that should be referenced. + PointDVector *const vec_; // the thing that we're iterating on + const uint32_t dimensionality_; // local copy from vec_ + }; + + PointDVectorIterator begin() { return PointDVectorIterator(this, 0); } + PointDVectorIterator end() { return PointDVectorIterator(this, n_items_); } + + // operator[] allows for unprotected user-side usage of operator[] on the + // return value AS IF it were a natively indexable type like Point3* + internal_t *operator[](const uint32_t index) { + DRACO_DCHECK_LT(index, n_items_); + return data0_ + index * dimensionality_; + } + const internal_t *operator[](const uint32_t index) const { + DRACO_DCHECK_LT(index, n_items_); + return data0_ + index * dimensionality_; + } + + uint32_t size() const { return n_items_; } + size_t GetBufferSize() const { return data_.size(); } + + // copy a single contiguous 'item' from one PointDVector into this one. + void CopyItem(const PointDVector &source, const internal_t source_index, + const internal_t destination_index) { + DRACO_DCHECK(&source != this || + (&source == this && source_index != destination_index)); + DRACO_DCHECK_LT(destination_index, n_items_); + DRACO_DCHECK_LT(source_index, source.n_items_); + + // DRACO_DCHECK_EQ(source.n_items_, n_items_); // not technically necessary + DRACO_DCHECK_EQ(source.dimensionality_, dimensionality_); + + const internal_t *ref = source[source_index]; + internal_t *const dest = this->operator[](destination_index); + std::memcpy(dest, ref, item_size_bytes_); + } + + // Copy data directly off of an attribute buffer interleaved into internal + // memory. + void CopyAttribute( + // The dimensionality of the attribute being integrated + const internal_t attribute_dimensionality, + // The offset in dimensions to insert this attribute. + const internal_t offset_dimensionality, const internal_t index, + // The direct pointer to the data + const void *const attribute_item_data) { + // chunk copy + const size_t copy_size = sizeof(internal_t) * attribute_dimensionality; + + // a multiply and add can be optimized away with an iterator + std::memcpy(data0_ + index * dimensionality_ + offset_dimensionality, + attribute_item_data, copy_size); + } + // Copy data off of a contiguous buffer interleaved into internal memory + void CopyAttribute( + // The dimensionality of the attribute being integrated + const internal_t attribute_dimensionality, + // The offset in dimensions to insert this attribute. + const internal_t offset_dimensionality, + const internal_t *const attribute_mem) { + DRACO_DCHECK_LT(offset_dimensionality, + dimensionality_ - attribute_dimensionality); + // degenerate case block copy the whole buffer. + if (dimensionality_ == attribute_dimensionality) { + DRACO_DCHECK_EQ(offset_dimensionality, 0); + const size_t copy_size = + sizeof(internal_t) * attribute_dimensionality * n_items_; + std::memcpy(data0_, attribute_mem, copy_size); + } else { // chunk copy + const size_t copy_size = sizeof(internal_t) * attribute_dimensionality; + internal_t *internal_data; + const internal_t *attribute_data; + internal_t item; + for (internal_data = data0_ + offset_dimensionality, + attribute_data = attribute_mem, item = 0; + item < n_items_; internal_data += dimensionality_, + attribute_data += attribute_dimensionality, item += 1) { + std::memcpy(internal_data, attribute_data, copy_size); + } + } + } + + private: + // internal parameters. + const uint32_t n_items_; + const uint32_t dimensionality_; // The dimension of the points in the buffer + const uint32_t item_size_bytes_; + std::vector data_; // contiguously stored data. Never resized. + internal_t *const data0_; // raw pointer to base data. +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/points_sequencer.h b/extern/draco/draco/src/draco/compression/attributes/points_sequencer.h new file mode 100644 index 00000000000..2f4f7e16d11 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/points_sequencer.h @@ -0,0 +1,63 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINTS_SEQUENCER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_POINTS_SEQUENCER_H_ + +#include + +#include "draco/attributes/point_attribute.h" + +namespace draco { + +// Class for generating a sequence of point ids that can be used to encode +// or decode attribute values in a specific order. +// See sequential_attribute_encoders/decoders_controller.h for more details. +class PointsSequencer { + public: + PointsSequencer() : out_point_ids_(nullptr) {} + virtual ~PointsSequencer() = default; + + // Fills the |out_point_ids| with the generated sequence of point ids. + bool GenerateSequence(std::vector *out_point_ids) { + out_point_ids_ = out_point_ids; + return GenerateSequenceInternal(); + } + + // Appends a point to the sequence. + void AddPointId(PointIndex point_id) { out_point_ids_->push_back(point_id); } + + // Sets the correct mapping between point ids and value ids. I.e., the inverse + // of the |out_point_ids|. In general, |out_point_ids_| does not contain + // sufficient information to compute the inverse map, because not all point + // ids are necessarily contained within the map. + // Must be implemented for sequencers that are used by attribute decoders. + virtual bool UpdatePointToAttributeIndexMapping(PointAttribute * /* attr */) { + return false; + } + + protected: + // Method that needs to be implemented by the derived classes. The + // implementation is responsible for filling |out_point_ids_| with the valid + // sequence of point ids. + virtual bool GenerateSequenceInternal() = 0; + std::vector *out_point_ids() const { return out_point_ids_; } + + private: + std::vector *out_point_ids_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_POINTS_SEQUENCER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h new file mode 100644 index 00000000000..36c124baa83 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h @@ -0,0 +1,231 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_DECODER_H_ + +#include +#include + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h" +#include "draco/compression/bit_coders/rans_bit_decoder.h" +#include "draco/core/varint_decoding.h" +#include "draco/draco_features.h" + +namespace draco { + +// Decoder for predictions encoded with the constrained multi-parallelogram +// encoder. See the corresponding encoder for more details about the prediction +// method. +template +class MeshPredictionSchemeConstrainedMultiParallelogramDecoder + : public MeshPredictionSchemeDecoder { + public: + using CorrType = + typename PredictionSchemeDecoder::CorrType; + using CornerTable = typename MeshDataT::CornerTable; + + explicit MeshPredictionSchemeConstrainedMultiParallelogramDecoder( + const PointAttribute *attribute) + : MeshPredictionSchemeDecoder( + attribute), + selected_mode_(Mode::OPTIMAL_MULTI_PARALLELOGRAM) {} + MeshPredictionSchemeConstrainedMultiParallelogramDecoder( + const PointAttribute *attribute, const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeDecoder( + attribute, transform, mesh_data), + selected_mode_(Mode::OPTIMAL_MULTI_PARALLELOGRAM) {} + + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + + bool DecodePredictionData(DecoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM; + } + + bool IsInitialized() const override { + return this->mesh_data().IsInitialized(); + } + + private: + typedef constrained_multi_parallelogram::Mode Mode; + static constexpr int kMaxNumParallelograms = + constrained_multi_parallelogram::kMaxNumParallelograms; + // Crease edges are used to store whether any given edge should be used for + // parallelogram prediction or not. New values are added in the order in which + // the edges are processed. For better compression, the flags are stored in + // in separate contexts based on the number of available parallelograms at a + // given vertex. + std::vector is_crease_edge_[kMaxNumParallelograms]; + Mode selected_mode_; +}; + +template +bool MeshPredictionSchemeConstrainedMultiParallelogramDecoder< + DataTypeT, TransformT, MeshDataT>:: + ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int /* size */, int num_components, + const PointIndex * /* entry_to_point_id_map */) { + this->transform().Init(num_components); + + // Predicted values for all simple parallelograms encountered at any given + // vertex. + std::vector pred_vals[kMaxNumParallelograms]; + for (int i = 0; i < kMaxNumParallelograms; ++i) { + pred_vals[i].resize(num_components, 0); + } + this->transform().ComputeOriginalValue(pred_vals[0].data(), in_corr, + out_data); + + const CornerTable *const table = this->mesh_data().corner_table(); + const std::vector *const vertex_to_data_map = + this->mesh_data().vertex_to_data_map(); + + // Current position in the |is_crease_edge_| array for each context. + std::vector is_crease_edge_pos(kMaxNumParallelograms, 0); + + // Used to store predicted value for multi-parallelogram prediction. + std::vector multi_pred_vals(num_components); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + for (int p = 1; p < corner_map_size; ++p) { + const CornerIndex start_corner_id = + this->mesh_data().data_to_corner_map()->at(p); + + CornerIndex corner_id(start_corner_id); + int num_parallelograms = 0; + bool first_pass = true; + while (corner_id != kInvalidCornerIndex) { + if (ComputeParallelogramPrediction( + p, corner_id, table, *vertex_to_data_map, out_data, + num_components, &(pred_vals[num_parallelograms][0]))) { + // Parallelogram prediction applied and stored in + // |pred_vals[num_parallelograms]| + ++num_parallelograms; + // Stop processing when we reach the maximum number of allowed + // parallelograms. + if (num_parallelograms == kMaxNumParallelograms) { + break; + } + } + + // Proceed to the next corner attached to the vertex. First swing left + // and if we reach a boundary, swing right from the start corner. + if (first_pass) { + corner_id = table->SwingLeft(corner_id); + } else { + corner_id = table->SwingRight(corner_id); + } + if (corner_id == start_corner_id) { + break; + } + if (corner_id == kInvalidCornerIndex && first_pass) { + first_pass = false; + corner_id = table->SwingRight(start_corner_id); + } + } + + // Check which of the available parallelograms are actually used and compute + // the final predicted value. + int num_used_parallelograms = 0; + if (num_parallelograms > 0) { + for (int i = 0; i < num_components; ++i) { + multi_pred_vals[i] = 0; + } + // Check which parallelograms are actually used. + for (int i = 0; i < num_parallelograms; ++i) { + const int context = num_parallelograms - 1; + const int pos = is_crease_edge_pos[context]++; + if (is_crease_edge_[context].size() <= pos) { + return false; + } + const bool is_crease = is_crease_edge_[context][pos]; + if (!is_crease) { + ++num_used_parallelograms; + for (int j = 0; j < num_components; ++j) { + multi_pred_vals[j] += pred_vals[i][j]; + } + } + } + } + const int dst_offset = p * num_components; + if (num_used_parallelograms == 0) { + // No parallelogram was valid. + // We use the last decoded point as a reference. + const int src_offset = (p - 1) * num_components; + this->transform().ComputeOriginalValue( + out_data + src_offset, in_corr + dst_offset, out_data + dst_offset); + } else { + // Compute the correction from the predicted value. + for (int c = 0; c < num_components; ++c) { + multi_pred_vals[c] /= num_used_parallelograms; + } + this->transform().ComputeOriginalValue( + multi_pred_vals.data(), in_corr + dst_offset, out_data + dst_offset); + } + } + return true; +} + +template +bool MeshPredictionSchemeConstrainedMultiParallelogramDecoder< + DataTypeT, TransformT, MeshDataT>::DecodePredictionData(DecoderBuffer + *buffer) { +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 2)) { + // Decode prediction mode. + uint8_t mode; + if (!buffer->Decode(&mode)) { + return false; + } + + if (mode != Mode::OPTIMAL_MULTI_PARALLELOGRAM) { + // Unsupported mode. + return false; + } + } +#endif + + // Encode selected edges using separate rans bit coder for each context. + for (int i = 0; i < kMaxNumParallelograms; ++i) { + uint32_t num_flags; + if (!DecodeVarint(&num_flags, buffer)) { + return false; + } + if (num_flags > 0) { + is_crease_edge_[i].resize(num_flags); + RAnsBitDecoder decoder; + if (!decoder.StartDecoding(buffer)) { + return false; + } + for (uint32_t j = 0; j < num_flags; ++j) { + is_crease_edge_[i][j] = decoder.DecodeNextBit(); + } + decoder.EndDecoding(); + } + } + return MeshPredictionSchemeDecoder::DecodePredictionData(buffer); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h new file mode 100644 index 00000000000..77df8ee24f1 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h @@ -0,0 +1,414 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_ENCODER_H_ + +#include +#include + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h" +#include "draco/compression/bit_coders/rans_bit_encoder.h" +#include "draco/compression/entropy/shannon_entropy.h" +#include "draco/core/varint_encoding.h" + +namespace draco { + +// Compared to standard multi-parallelogram, constrained multi-parallelogram can +// explicitly select which of the available parallelograms are going to be used +// for the prediction by marking crease edges between two triangles. This +// requires storing extra data, but it allows the predictor to avoid using +// parallelograms that would lead to poor predictions. For improved efficiency, +// our current implementation limits the maximum number of used parallelograms +// to four, which covers >95% of the cases (on average, there are only two +// parallelograms available for any given vertex). +// All bits of the explicitly chosen configuration are stored together in a +// single context chosen by the total number of parallelograms available to +// choose from. +template +class MeshPredictionSchemeConstrainedMultiParallelogramEncoder + : public MeshPredictionSchemeEncoder { + public: + using CorrType = + typename PredictionSchemeEncoder::CorrType; + using CornerTable = typename MeshDataT::CornerTable; + + explicit MeshPredictionSchemeConstrainedMultiParallelogramEncoder( + const PointAttribute *attribute) + : MeshPredictionSchemeEncoder( + attribute), + selected_mode_(Mode::OPTIMAL_MULTI_PARALLELOGRAM) {} + MeshPredictionSchemeConstrainedMultiParallelogramEncoder( + const PointAttribute *attribute, const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeEncoder( + attribute, transform, mesh_data), + selected_mode_(Mode::OPTIMAL_MULTI_PARALLELOGRAM) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + + bool EncodePredictionData(EncoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM; + } + + bool IsInitialized() const override { + return this->mesh_data().IsInitialized(); + } + + private: + // Function used to compute number of bits needed to store overhead of the + // predictor. In this case, we consider overhead to be all bits that mark + // whether a parallelogram should be used for prediction or not. The input + // to this method is the total number of parallelograms that were evaluated so + // far(total_parallelogram), and the number of parallelograms we decided to + // use for prediction (total_used_parallelograms). + // Returns number of bits required to store the overhead. + int64_t ComputeOverheadBits(int64_t total_used_parallelograms, + int64_t total_parallelogram) const { + // For now we assume RAns coding for the bits where the total required size + // is directly correlated to the binary entropy of the input stream. + // TODO(ostava): This should be generalized in case we use other binary + // coding scheme. + const double entropy = ComputeBinaryShannonEntropy( + static_cast(total_parallelogram), + static_cast(total_used_parallelograms)); + + // Round up to the nearest full bit. + return static_cast( + ceil(static_cast(total_parallelogram) * entropy)); + } + + // Struct that contains data used for measuring the error of each available + // parallelogram configuration. + struct Error { + Error() : num_bits(0), residual_error(0) {} + + // Primary metric: number of bits required to store the data as a result of + // the selected prediction configuration. + int num_bits; + // Secondary metric: absolute difference of residuals for the given + // configuration. + int residual_error; + + bool operator<(const Error &e) const { + if (num_bits < e.num_bits) { + return true; + } + if (num_bits > e.num_bits) { + return false; + } + return residual_error < e.residual_error; + } + }; + + // Computes error for predicting |predicted_val| instead of |actual_val|. + // Error is computed as the number of bits needed to encode the difference + // between the values. + Error ComputeError(const DataTypeT *predicted_val, + const DataTypeT *actual_val, int *out_residuals, + int num_components) { + Error error; + + for (int i = 0; i < num_components; ++i) { + const int dif = (predicted_val[i] - actual_val[i]); + error.residual_error += std::abs(dif); + out_residuals[i] = dif; + // Entropy needs unsigned symbols, so convert the signed difference to an + // unsigned symbol. + entropy_symbols_[i] = ConvertSignedIntToSymbol(dif); + } + + // Generate entropy data for case that this configuration was used. + // Note that the entropy stream is NOT updated in this case. + const auto entropy_data = + entropy_tracker_.Peek(entropy_symbols_.data(), num_components); + + error.num_bits = entropy_tracker_.GetNumberOfDataBits(entropy_data) + + entropy_tracker_.GetNumberOfRAnsTableBits(entropy_data); + return error; + } + + typedef constrained_multi_parallelogram::Mode Mode; + static constexpr int kMaxNumParallelograms = + constrained_multi_parallelogram::kMaxNumParallelograms; + // Crease edges are used to store whether any given edge should be used for + // parallelogram prediction or not. New values are added in the order in which + // the edges are processed. For better compression, the flags are stored in + // in separate contexts based on the number of available parallelograms at a + // given vertex. + // TODO(draco-eng) reconsider std::vector (performance/space). + std::vector is_crease_edge_[kMaxNumParallelograms]; + Mode selected_mode_; + + ShannonEntropyTracker entropy_tracker_; + + // Temporary storage for symbols that are fed into the |entropy_stream|. + // Always contains only |num_components| entries. + std::vector entropy_symbols_; +}; + +template +bool MeshPredictionSchemeConstrainedMultiParallelogramEncoder< + DataTypeT, TransformT, MeshDataT>:: + ComputeCorrectionValues(const DataTypeT *in_data, CorrType *out_corr, + int size, int num_components, + const PointIndex * /* entry_to_point_id_map */) { + this->transform().Init(in_data, size, num_components); + const CornerTable *const table = this->mesh_data().corner_table(); + const std::vector *const vertex_to_data_map = + this->mesh_data().vertex_to_data_map(); + + // Predicted values for all simple parallelograms encountered at any given + // vertex. + std::vector pred_vals[kMaxNumParallelograms]; + for (int i = 0; i < kMaxNumParallelograms; ++i) { + pred_vals[i].resize(num_components); + } + // Used to store predicted value for various multi-parallelogram predictions + // (combinations of simple parallelogram predictions). + std::vector multi_pred_vals(num_components); + entropy_symbols_.resize(num_components); + + // Struct for holding data about prediction configuration for different sets + // of used parallelograms. + struct PredictionConfiguration { + PredictionConfiguration() + : error(), configuration(0), num_used_parallelograms(0) {} + Error error; + uint8_t configuration; // Bitfield, 1 use parallelogram, 0 don't use it. + int num_used_parallelograms; + std::vector predicted_value; + std::vector residuals; + }; + + // Bit-field used for computing permutations of excluded edges + // (parallelograms). + bool exluded_parallelograms[kMaxNumParallelograms]; + + // Data about the number of used parallelogram and total number of available + // parallelogram for each context. Used to compute overhead needed for storing + // the parallelogram choices made by the encoder. + int64_t total_used_parallelograms[kMaxNumParallelograms] = {0}; + int64_t total_parallelograms[kMaxNumParallelograms] = {0}; + + std::vector current_residuals(num_components); + + // We start processing the vertices from the end because this prediction uses + // data from previous entries that could be overwritten when an entry is + // processed. + for (int p = + static_cast(this->mesh_data().data_to_corner_map()->size()) - 1; + p > 0; --p) { + const CornerIndex start_corner_id = + this->mesh_data().data_to_corner_map()->at(p); + + // Go over all corners attached to the vertex and compute the predicted + // value from the parallelograms defined by their opposite faces. + CornerIndex corner_id(start_corner_id); + int num_parallelograms = 0; + bool first_pass = true; + while (corner_id != kInvalidCornerIndex) { + if (ComputeParallelogramPrediction( + p, corner_id, table, *vertex_to_data_map, in_data, num_components, + &(pred_vals[num_parallelograms][0]))) { + // Parallelogram prediction applied and stored in + // |pred_vals[num_parallelograms]| + ++num_parallelograms; + // Stop processing when we reach the maximum number of allowed + // parallelograms. + if (num_parallelograms == kMaxNumParallelograms) { + break; + } + } + + // Proceed to the next corner attached to the vertex. First swing left + // and if we reach a boundary, swing right from the start corner. + if (first_pass) { + corner_id = table->SwingLeft(corner_id); + } else { + corner_id = table->SwingRight(corner_id); + } + if (corner_id == start_corner_id) { + break; + } + if (corner_id == kInvalidCornerIndex && first_pass) { + first_pass = false; + corner_id = table->SwingRight(start_corner_id); + } + } + + // Offset to the target (destination) vertex. + const int dst_offset = p * num_components; + Error error; + + // Compute all prediction errors for all possible configurations of + // available parallelograms. + + // Variable for holding the best configuration that has been found so far. + PredictionConfiguration best_prediction; + + // Compute delta coding error (configuration when no parallelogram is + // selected). + const int src_offset = (p - 1) * num_components; + error = ComputeError(in_data + src_offset, in_data + dst_offset, + ¤t_residuals[0], num_components); + + if (num_parallelograms > 0) { + total_parallelograms[num_parallelograms - 1] += num_parallelograms; + const int64_t new_overhead_bits = + ComputeOverheadBits(total_used_parallelograms[num_parallelograms - 1], + total_parallelograms[num_parallelograms - 1]); + error.num_bits += new_overhead_bits; + } + + best_prediction.error = error; + best_prediction.configuration = 0; + best_prediction.num_used_parallelograms = 0; + best_prediction.predicted_value.assign( + in_data + src_offset, in_data + src_offset + num_components); + best_prediction.residuals.assign(current_residuals.begin(), + current_residuals.end()); + + // Compute prediction error for different cases of used parallelograms. + for (int num_used_parallelograms = 1; + num_used_parallelograms <= num_parallelograms; + ++num_used_parallelograms) { + // Mark all parallelograms as excluded. + std::fill(exluded_parallelograms, + exluded_parallelograms + num_parallelograms, true); + // TODO(draco-eng) maybe this should be another std::fill. + // Mark the first |num_used_parallelograms| as not excluded. + for (int j = 0; j < num_used_parallelograms; ++j) { + exluded_parallelograms[j] = false; + } + // Permute over the excluded edges and compute error for each + // configuration (permutation of excluded parallelograms). + do { + // Reset the multi-parallelogram predicted values. + for (int j = 0; j < num_components; ++j) { + multi_pred_vals[j] = 0; + } + uint8_t configuration = 0; + for (int j = 0; j < num_parallelograms; ++j) { + if (exluded_parallelograms[j]) { + continue; + } + for (int c = 0; c < num_components; ++c) { + multi_pred_vals[c] += pred_vals[j][c]; + } + // Set jth bit of the configuration. + configuration |= (1 << j); + } + + for (int j = 0; j < num_components; ++j) { + multi_pred_vals[j] /= num_used_parallelograms; + } + error = ComputeError(multi_pred_vals.data(), in_data + dst_offset, + ¤t_residuals[0], num_components); + if (num_parallelograms > 0) { + const int64_t new_overhead_bits = ComputeOverheadBits( + total_used_parallelograms[num_parallelograms - 1] + + num_used_parallelograms, + total_parallelograms[num_parallelograms - 1]); + + // Add overhead bits to the total error. + error.num_bits += new_overhead_bits; + } + if (error < best_prediction.error) { + best_prediction.error = error; + best_prediction.configuration = configuration; + best_prediction.num_used_parallelograms = num_used_parallelograms; + best_prediction.predicted_value.assign(multi_pred_vals.begin(), + multi_pred_vals.end()); + best_prediction.residuals.assign(current_residuals.begin(), + current_residuals.end()); + } + } while (std::next_permutation( + exluded_parallelograms, exluded_parallelograms + num_parallelograms)); + } + if (num_parallelograms > 0) { + total_used_parallelograms[num_parallelograms - 1] += + best_prediction.num_used_parallelograms; + } + + // Update the entropy stream by adding selected residuals as symbols to the + // stream. + for (int i = 0; i < num_components; ++i) { + entropy_symbols_[i] = + ConvertSignedIntToSymbol(best_prediction.residuals[i]); + } + entropy_tracker_.Push(entropy_symbols_.data(), num_components); + + for (int i = 0; i < num_parallelograms; ++i) { + if ((best_prediction.configuration & (1 << i)) == 0) { + // Parallelogram not used, mark the edge as crease. + is_crease_edge_[num_parallelograms - 1].push_back(true); + } else { + // Parallelogram used. Add it to the predicted value and mark the + // edge as not a crease. + is_crease_edge_[num_parallelograms - 1].push_back(false); + } + } + this->transform().ComputeCorrection(in_data + dst_offset, + best_prediction.predicted_value.data(), + out_corr + dst_offset); + } + // First element is always fixed because it cannot be predicted. + for (int i = 0; i < num_components; ++i) { + pred_vals[0][i] = static_cast(0); + } + this->transform().ComputeCorrection(in_data, pred_vals[0].data(), out_corr); + return true; +} + +template +bool MeshPredictionSchemeConstrainedMultiParallelogramEncoder< + DataTypeT, TransformT, MeshDataT>::EncodePredictionData(EncoderBuffer + *buffer) { + // Encode selected edges using separate rans bit coder for each context. + for (int i = 0; i < kMaxNumParallelograms; ++i) { + // |i| is the context based on the number of available parallelograms, which + // is always equal to |i + 1|. + const int num_used_parallelograms = i + 1; + EncodeVarint(is_crease_edge_[i].size(), buffer); + if (is_crease_edge_[i].size()) { + RAnsBitEncoder encoder; + encoder.StartEncoding(); + // Encode the crease edge flags in the reverse vertex order that is needed + // be the decoder. Note that for the currently supported mode, each vertex + // has exactly |num_used_parallelograms| edges that need to be encoded. + for (int j = static_cast(is_crease_edge_[i].size()) - + num_used_parallelograms; + j >= 0; j -= num_used_parallelograms) { + // Go over all edges of the current vertex. + for (int k = 0; k < num_used_parallelograms; ++k) { + encoder.EncodeBit(is_crease_edge_[i][j + k]); + } + } + encoder.EndEncoding(buffer); + } + } + return MeshPredictionSchemeEncoder::EncodePredictionData(buffer); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h new file mode 100644 index 00000000000..c7a4e351aeb --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_shared.h @@ -0,0 +1,34 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_SHARED_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_SHARED_H_ + +namespace draco { + +// Data shared between constrained multi-parallelogram encoder and decoder. +namespace constrained_multi_parallelogram { + +enum Mode { + // Selects the optimal multi-parallelogram from up to 4 available + // parallelograms. + OPTIMAL_MULTI_PARALLELOGRAM = 0, +}; + +static constexpr int kMaxNumParallelograms = 4; + +} // namespace constrained_multi_parallelogram +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_CONSTRAINED_MULTI_PARALLELOGRAM_SHARED_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h new file mode 100644 index 00000000000..f712952556a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h @@ -0,0 +1,72 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_ + +#include "draco/mesh/corner_table.h" +#include "draco/mesh/mesh.h" + +namespace draco { + +// Class stores data about the connectivity data of the mesh and information +// about how the connectivity was encoded/decoded. +template +class MeshPredictionSchemeData { + public: + typedef CornerTableT CornerTable; + MeshPredictionSchemeData() + : mesh_(nullptr), + corner_table_(nullptr), + vertex_to_data_map_(nullptr), + data_to_corner_map_(nullptr) {} + + void Set(const Mesh *mesh, const CornerTable *table, + const std::vector *data_to_corner_map, + const std::vector *vertex_to_data_map) { + mesh_ = mesh; + corner_table_ = table; + data_to_corner_map_ = data_to_corner_map; + vertex_to_data_map_ = vertex_to_data_map; + } + + const Mesh *mesh() const { return mesh_; } + const CornerTable *corner_table() const { return corner_table_; } + const std::vector *vertex_to_data_map() const { + return vertex_to_data_map_; + } + const std::vector *data_to_corner_map() const { + return data_to_corner_map_; + } + bool IsInitialized() const { + return mesh_ != nullptr && corner_table_ != nullptr && + vertex_to_data_map_ != nullptr && data_to_corner_map_ != nullptr; + } + + private: + const Mesh *mesh_; + const CornerTable *corner_table_; + + // Mapping between vertices and their encoding order. I.e. when an attribute + // entry on a given vertex was encoded. + const std::vector *vertex_to_data_map_; + + // Array that stores which corner was processed when a given attribute entry + // was encoded or decoded. + const std::vector *data_to_corner_map_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h new file mode 100644 index 00000000000..6694a981c10 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h" + +namespace draco { + +// Base class for all mesh prediction scheme decoders that use the mesh +// connectivity data. |MeshDataT| can be any class that provides the same +// interface as the PredictionSchemeMeshData class. +template +class MeshPredictionSchemeDecoder + : public PredictionSchemeDecoder { + public: + typedef MeshDataT MeshData; + MeshPredictionSchemeDecoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : PredictionSchemeDecoder(attribute, transform), + mesh_data_(mesh_data) {} + + protected: + const MeshData &mesh_data() const { return mesh_data_; } + + private: + MeshData mesh_data_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h new file mode 100644 index 00000000000..ab3c81a3901 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h @@ -0,0 +1,46 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h" + +namespace draco { + +// Base class for all mesh prediction scheme encoders that use the mesh +// connectivity data. |MeshDataT| can be any class that provides the same +// interface as the PredictionSchemeMeshData class. +template +class MeshPredictionSchemeEncoder + : public PredictionSchemeEncoder { + public: + typedef MeshDataT MeshData; + MeshPredictionSchemeEncoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : PredictionSchemeEncoder(attribute, transform), + mesh_data_(mesh_data) {} + + protected: + const MeshData &mesh_data() const { return mesh_data_; } + + private: + MeshData mesh_data_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h new file mode 100644 index 00000000000..da1387a3075 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h @@ -0,0 +1,172 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h" +#include "draco/compression/bit_coders/rans_bit_decoder.h" +#include "draco/draco_features.h" + +namespace draco { + +// See MeshPredictionSchemeGeometricNormalEncoder for documentation. +template +class MeshPredictionSchemeGeometricNormalDecoder + : public MeshPredictionSchemeDecoder { + public: + using CorrType = typename MeshPredictionSchemeDecoder::CorrType; + MeshPredictionSchemeGeometricNormalDecoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeDecoder( + attribute, transform, mesh_data), + predictor_(mesh_data) {} + + private: + MeshPredictionSchemeGeometricNormalDecoder() {} + + public: + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + + bool DecodePredictionData(DecoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_GEOMETRIC_NORMAL; + } + + bool IsInitialized() const override { + if (!predictor_.IsInitialized()) { + return false; + } + if (!this->mesh_data().IsInitialized()) { + return false; + } + if (!octahedron_tool_box_.IsInitialized()) { + return false; + } + return true; + } + + int GetNumParentAttributes() const override { return 1; } + + GeometryAttribute::Type GetParentAttributeType(int i) const override { + DRACO_DCHECK_EQ(i, 0); + (void)i; + return GeometryAttribute::POSITION; + } + + bool SetParentAttribute(const PointAttribute *att) override { + if (att->attribute_type() != GeometryAttribute::POSITION) { + return false; // Invalid attribute type. + } + if (att->num_components() != 3) { + return false; // Currently works only for 3 component positions. + } + predictor_.SetPositionAttribute(*att); + return true; + } + void SetQuantizationBits(int q) { + octahedron_tool_box_.SetQuantizationBits(q); + } + + private: + MeshPredictionSchemeGeometricNormalPredictorArea + predictor_; + OctahedronToolBox octahedron_tool_box_; + RAnsBitDecoder flip_normal_bit_decoder_; +}; + +template +bool MeshPredictionSchemeGeometricNormalDecoder< + DataTypeT, TransformT, + MeshDataT>::ComputeOriginalValues(const CorrType *in_corr, + DataTypeT *out_data, int /* size */, + int num_components, + const PointIndex *entry_to_point_id_map) { + this->SetQuantizationBits(this->transform().quantization_bits()); + predictor_.SetEntryToPointIdMap(entry_to_point_id_map); + DRACO_DCHECK(this->IsInitialized()); + + // Expecting in_data in octahedral coordinates, i.e., portable attribute. + DRACO_DCHECK_EQ(num_components, 2); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + + VectorD pred_normal_3d; + int32_t pred_normal_oct[2]; + + for (int data_id = 0; data_id < corner_map_size; ++data_id) { + const CornerIndex corner_id = + this->mesh_data().data_to_corner_map()->at(data_id); + predictor_.ComputePredictedValue(corner_id, pred_normal_3d.data()); + + // Compute predicted octahedral coordinates. + octahedron_tool_box_.CanonicalizeIntegerVector(pred_normal_3d.data()); + DRACO_DCHECK_EQ(pred_normal_3d.AbsSum(), + octahedron_tool_box_.center_value()); + if (flip_normal_bit_decoder_.DecodeNextBit()) { + pred_normal_3d = -pred_normal_3d; + } + octahedron_tool_box_.IntegerVectorToQuantizedOctahedralCoords( + pred_normal_3d.data(), pred_normal_oct, pred_normal_oct + 1); + + const int data_offset = data_id * 2; + this->transform().ComputeOriginalValue( + pred_normal_oct, in_corr + data_offset, out_data + data_offset); + } + flip_normal_bit_decoder_.EndDecoding(); + return true; +} + +template +bool MeshPredictionSchemeGeometricNormalDecoder< + DataTypeT, TransformT, MeshDataT>::DecodePredictionData(DecoderBuffer + *buffer) { + // Get data needed for transform + if (!this->transform().DecodeTransformData(buffer)) { + return false; + } + +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 2)) { + uint8_t prediction_mode; + if (!buffer->Decode(&prediction_mode)) { + return false; + } + + if (!predictor_.SetNormalPredictionMode( + NormalPredictionMode(prediction_mode))) { + return false; + } + } +#endif + + // Init normal flips. + if (!flip_normal_bit_decoder_.StartDecoding(buffer)) { + return false; + } + + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h new file mode 100644 index 00000000000..cf146f83ac9 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h @@ -0,0 +1,180 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h" +#include "draco/compression/bit_coders/rans_bit_encoder.h" +#include "draco/compression/config/compression_shared.h" + +namespace draco { + +// Prediction scheme for normals based on the underlying geometry. +// At a smooth vertices normals are computed by weighting the normals of +// adjacent faces with the area of these faces. At seams, the same approach +// applies for seam corners. +template +class MeshPredictionSchemeGeometricNormalEncoder + : public MeshPredictionSchemeEncoder { + public: + using CorrType = typename MeshPredictionSchemeEncoder::CorrType; + MeshPredictionSchemeGeometricNormalEncoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeEncoder( + attribute, transform, mesh_data), + predictor_(mesh_data) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + + bool EncodePredictionData(EncoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_GEOMETRIC_NORMAL; + } + + bool IsInitialized() const override { + if (!predictor_.IsInitialized()) { + return false; + } + if (!this->mesh_data().IsInitialized()) { + return false; + } + return true; + } + + int GetNumParentAttributes() const override { return 1; } + + GeometryAttribute::Type GetParentAttributeType(int i) const override { + DRACO_DCHECK_EQ(i, 0); + (void)i; + return GeometryAttribute::POSITION; + } + + bool SetParentAttribute(const PointAttribute *att) override { + if (att->attribute_type() != GeometryAttribute::POSITION) { + return false; // Invalid attribute type. + } + if (att->num_components() != 3) { + return false; // Currently works only for 3 component positions. + } + predictor_.SetPositionAttribute(*att); + return true; + } + + private: + void SetQuantizationBits(int q) { + DRACO_DCHECK_GE(q, 2); + DRACO_DCHECK_LE(q, 30); + octahedron_tool_box_.SetQuantizationBits(q); + } + MeshPredictionSchemeGeometricNormalPredictorArea + predictor_; + + OctahedronToolBox octahedron_tool_box_; + RAnsBitEncoder flip_normal_bit_encoder_; +}; + +template +bool MeshPredictionSchemeGeometricNormalEncoder:: + ComputeCorrectionValues(const DataTypeT *in_data, CorrType *out_corr, + int size, int num_components, + const PointIndex *entry_to_point_id_map) { + this->SetQuantizationBits(this->transform().quantization_bits()); + predictor_.SetEntryToPointIdMap(entry_to_point_id_map); + DRACO_DCHECK(this->IsInitialized()); + // Expecting in_data in octahedral coordinates, i.e., portable attribute. + DRACO_DCHECK_EQ(num_components, 2); + + flip_normal_bit_encoder_.StartEncoding(); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + + VectorD pred_normal_3d; + VectorD pos_pred_normal_oct; + VectorD neg_pred_normal_oct; + VectorD pos_correction; + VectorD neg_correction; + for (int data_id = 0; data_id < corner_map_size; ++data_id) { + const CornerIndex corner_id = + this->mesh_data().data_to_corner_map()->at(data_id); + predictor_.ComputePredictedValue(corner_id, pred_normal_3d.data()); + + // Compute predicted octahedral coordinates. + octahedron_tool_box_.CanonicalizeIntegerVector(pred_normal_3d.data()); + DRACO_DCHECK_EQ(pred_normal_3d.AbsSum(), + octahedron_tool_box_.center_value()); + + // Compute octahedral coordinates for both possible directions. + octahedron_tool_box_.IntegerVectorToQuantizedOctahedralCoords( + pred_normal_3d.data(), pos_pred_normal_oct.data(), + pos_pred_normal_oct.data() + 1); + pred_normal_3d = -pred_normal_3d; + octahedron_tool_box_.IntegerVectorToQuantizedOctahedralCoords( + pred_normal_3d.data(), neg_pred_normal_oct.data(), + neg_pred_normal_oct.data() + 1); + + // Choose the one with the best correction value. + const int data_offset = data_id * 2; + this->transform().ComputeCorrection(in_data + data_offset, + pos_pred_normal_oct.data(), + pos_correction.data()); + this->transform().ComputeCorrection(in_data + data_offset, + neg_pred_normal_oct.data(), + neg_correction.data()); + pos_correction[0] = octahedron_tool_box_.ModMax(pos_correction[0]); + pos_correction[1] = octahedron_tool_box_.ModMax(pos_correction[1]); + neg_correction[0] = octahedron_tool_box_.ModMax(neg_correction[0]); + neg_correction[1] = octahedron_tool_box_.ModMax(neg_correction[1]); + if (pos_correction.AbsSum() < neg_correction.AbsSum()) { + flip_normal_bit_encoder_.EncodeBit(false); + (out_corr + data_offset)[0] = + octahedron_tool_box_.MakePositive(pos_correction[0]); + (out_corr + data_offset)[1] = + octahedron_tool_box_.MakePositive(pos_correction[1]); + } else { + flip_normal_bit_encoder_.EncodeBit(true); + (out_corr + data_offset)[0] = + octahedron_tool_box_.MakePositive(neg_correction[0]); + (out_corr + data_offset)[1] = + octahedron_tool_box_.MakePositive(neg_correction[1]); + } + } + return true; +} + +template +bool MeshPredictionSchemeGeometricNormalEncoder< + DataTypeT, TransformT, MeshDataT>::EncodePredictionData(EncoderBuffer + *buffer) { + if (!this->transform().EncodeTransformData(buffer)) { + return false; + } + + // Encode normal flips. + flip_normal_bit_encoder_.EndEncoding(buffer); + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h new file mode 100644 index 00000000000..bf1a6146111 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h @@ -0,0 +1,110 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_PREDICTOR_AREA_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_PREDICTOR_AREA_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h" + +namespace draco { + +// This predictor estimates the normal via the surrounding triangles of the +// given corner. Triangles are weighted according to their area. +template +class MeshPredictionSchemeGeometricNormalPredictorArea + : public MeshPredictionSchemeGeometricNormalPredictorBase< + DataTypeT, TransformT, MeshDataT> { + typedef MeshPredictionSchemeGeometricNormalPredictorBase< + DataTypeT, TransformT, MeshDataT> + Base; + + public: + explicit MeshPredictionSchemeGeometricNormalPredictorArea(const MeshDataT &md) + : Base(md) { + this->SetNormalPredictionMode(TRIANGLE_AREA); + }; + virtual ~MeshPredictionSchemeGeometricNormalPredictorArea() {} + + // Computes predicted octahedral coordinates on a given corner. + void ComputePredictedValue(CornerIndex corner_id, + DataTypeT *prediction) override { + DRACO_DCHECK(this->IsInitialized()); + typedef typename MeshDataT::CornerTable CornerTable; + const CornerTable *const corner_table = this->mesh_data_.corner_table(); + // Going to compute the predicted normal from the surrounding triangles + // according to the connectivity of the given corner table. + VertexCornersIterator cit(corner_table, corner_id); + // Position of central vertex does not change in loop. + const VectorD pos_cent = this->GetPositionForCorner(corner_id); + // Computing normals for triangles and adding them up. + + VectorD normal; + CornerIndex c_next, c_prev; + while (!cit.End()) { + // Getting corners. + if (this->normal_prediction_mode_ == ONE_TRIANGLE) { + c_next = corner_table->Next(corner_id); + c_prev = corner_table->Previous(corner_id); + } else { + c_next = corner_table->Next(cit.Corner()); + c_prev = corner_table->Previous(cit.Corner()); + } + const VectorD pos_next = this->GetPositionForCorner(c_next); + const VectorD pos_prev = this->GetPositionForCorner(c_prev); + + // Computing delta vectors to next and prev. + const VectorD delta_next = pos_next - pos_cent; + const VectorD delta_prev = pos_prev - pos_cent; + + // Computing cross product. + const VectorD cross = CrossProduct(delta_next, delta_prev); + normal = normal + cross; + cit.Next(); + } + + // Convert to int32_t, make sure entries are not too large. + constexpr int64_t upper_bound = 1 << 29; + if (this->normal_prediction_mode_ == ONE_TRIANGLE) { + const int32_t abs_sum = static_cast(normal.AbsSum()); + if (abs_sum > upper_bound) { + const int64_t quotient = abs_sum / upper_bound; + normal = normal / quotient; + } + } else { + const int64_t abs_sum = normal.AbsSum(); + if (abs_sum > upper_bound) { + const int64_t quotient = abs_sum / upper_bound; + normal = normal / quotient; + } + } + DRACO_DCHECK_LE(normal.AbsSum(), upper_bound); + prediction[0] = static_cast(normal[0]); + prediction[1] = static_cast(normal[1]); + prediction[2] = static_cast(normal[2]); + } + bool SetNormalPredictionMode(NormalPredictionMode mode) override { + if (mode == ONE_TRIANGLE) { + this->normal_prediction_mode_ = mode; + return true; + } else if (mode == TRIANGLE_AREA) { + this->normal_prediction_mode_ = mode; + return true; + } + return false; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_PREDICTOR_AREA_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h new file mode 100644 index 00000000000..a554dda9676 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_base.h @@ -0,0 +1,96 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_PREDICTOR_BASE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_PREDICTOR_BASE_H_ + +#include + +#include "draco/attributes/point_attribute.h" +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/config/compression_shared.h" +#include "draco/core/math_utils.h" +#include "draco/core/vector_d.h" +#include "draco/mesh/corner_table.h" +#include "draco/mesh/corner_table_iterators.h" + +namespace draco { + +// Base class for geometric normal predictors using position attribute. +template +class MeshPredictionSchemeGeometricNormalPredictorBase { + protected: + explicit MeshPredictionSchemeGeometricNormalPredictorBase(const MeshDataT &md) + : pos_attribute_(nullptr), + entry_to_point_id_map_(nullptr), + mesh_data_(md) {} + virtual ~MeshPredictionSchemeGeometricNormalPredictorBase() {} + + public: + void SetPositionAttribute(const PointAttribute &position_attribute) { + pos_attribute_ = &position_attribute; + } + void SetEntryToPointIdMap(const PointIndex *map) { + entry_to_point_id_map_ = map; + } + bool IsInitialized() const { + if (pos_attribute_ == nullptr) { + return false; + } + if (entry_to_point_id_map_ == nullptr) { + return false; + } + return true; + } + + virtual bool SetNormalPredictionMode(NormalPredictionMode mode) = 0; + virtual NormalPredictionMode GetNormalPredictionMode() const { + return normal_prediction_mode_; + } + + protected: + VectorD GetPositionForDataId(int data_id) const { + DRACO_DCHECK(this->IsInitialized()); + const auto point_id = entry_to_point_id_map_[data_id]; + const auto pos_val_id = pos_attribute_->mapped_index(point_id); + VectorD pos; + pos_attribute_->ConvertValue(pos_val_id, &pos[0]); + return pos; + } + VectorD GetPositionForCorner(CornerIndex ci) const { + DRACO_DCHECK(this->IsInitialized()); + const auto corner_table = mesh_data_.corner_table(); + const auto vert_id = corner_table->Vertex(ci).value(); + const auto data_id = mesh_data_.vertex_to_data_map()->at(vert_id); + return GetPositionForDataId(data_id); + } + VectorD GetOctahedralCoordForDataId(int data_id, + const DataTypeT *data) const { + DRACO_DCHECK(this->IsInitialized()); + const int data_offset = data_id * 2; + return VectorD(data[data_offset], data[data_offset + 1]); + } + // Computes predicted octahedral coordinates on a given corner. + virtual void ComputePredictedValue(CornerIndex corner_id, + DataTypeT *prediction) = 0; + + const PointAttribute *pos_attribute_; + const PointIndex *entry_to_point_id_map_; + MeshDataT mesh_data_; + NormalPredictionMode normal_prediction_mode_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_GEOMETRIC_NORMAL_PREDICTOR_BASE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h new file mode 100644 index 00000000000..fc82e0a8f76 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h @@ -0,0 +1,126 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_MULTI_PARALLELOGRAM_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_MULTI_PARALLELOGRAM_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h" +#include "draco/draco_features.h" + +namespace draco { + +// Decoder for predictions encoded by multi-parallelogram encoding scheme. +// See the corresponding encoder for method description. +template +class MeshPredictionSchemeMultiParallelogramDecoder + : public MeshPredictionSchemeDecoder { + public: + using CorrType = + typename PredictionSchemeDecoder::CorrType; + using CornerTable = typename MeshDataT::CornerTable; + + explicit MeshPredictionSchemeMultiParallelogramDecoder( + const PointAttribute *attribute) + : MeshPredictionSchemeDecoder( + attribute) {} + MeshPredictionSchemeMultiParallelogramDecoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeDecoder( + attribute, transform, mesh_data) {} + + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_MULTI_PARALLELOGRAM; + } + + bool IsInitialized() const override { + return this->mesh_data().IsInitialized(); + } +}; + +template +bool MeshPredictionSchemeMultiParallelogramDecoder:: + ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int /* size */, int num_components, + const PointIndex * /* entry_to_point_id_map */) { + this->transform().Init(num_components); + + // For storage of prediction values (already initialized to zero). + std::unique_ptr pred_vals(new DataTypeT[num_components]()); + std::unique_ptr parallelogram_pred_vals( + new DataTypeT[num_components]()); + + this->transform().ComputeOriginalValue(pred_vals.get(), in_corr, out_data); + + const CornerTable *const table = this->mesh_data().corner_table(); + const std::vector *const vertex_to_data_map = + this->mesh_data().vertex_to_data_map(); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + for (int p = 1; p < corner_map_size; ++p) { + const CornerIndex start_corner_id = + this->mesh_data().data_to_corner_map()->at(p); + + CornerIndex corner_id(start_corner_id); + int num_parallelograms = 0; + for (int i = 0; i < num_components; ++i) { + pred_vals[i] = static_cast(0); + } + while (corner_id != kInvalidCornerIndex) { + if (ComputeParallelogramPrediction( + p, corner_id, table, *vertex_to_data_map, out_data, + num_components, parallelogram_pred_vals.get())) { + for (int c = 0; c < num_components; ++c) { + pred_vals[c] += parallelogram_pred_vals[c]; + } + ++num_parallelograms; + } + + // Proceed to the next corner attached to the vertex. + corner_id = table->SwingRight(corner_id); + if (corner_id == start_corner_id) { + corner_id = kInvalidCornerIndex; + } + } + + const int dst_offset = p * num_components; + if (num_parallelograms == 0) { + // No parallelogram was valid. + // We use the last decoded point as a reference. + const int src_offset = (p - 1) * num_components; + this->transform().ComputeOriginalValue( + out_data + src_offset, in_corr + dst_offset, out_data + dst_offset); + } else { + // Compute the correction from the predicted value. + for (int c = 0; c < num_components; ++c) { + pred_vals[c] /= num_parallelograms; + } + this->transform().ComputeOriginalValue( + pred_vals.get(), in_corr + dst_offset, out_data + dst_offset); + } + } + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_MULTI_PARALLELOGRAM_DECODER_H_ +#endif diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h new file mode 100644 index 00000000000..301b357d411 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h @@ -0,0 +1,133 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_MULTI_PARALLELOGRAM_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_MULTI_PARALLELOGRAM_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h" + +namespace draco { + +// Multi parallelogram prediction predicts attribute values using information +// from all opposite faces to the predicted vertex, compared to the standard +// prediction scheme, where only one opposite face is used (see +// prediction_scheme_parallelogram.h). This approach is generally slower than +// the standard parallelogram prediction, but it usually results in better +// prediction (5 - 20% based on the quantization level. Better gains can be +// achieved when more aggressive quantization is used). +template +class MeshPredictionSchemeMultiParallelogramEncoder + : public MeshPredictionSchemeEncoder { + public: + using CorrType = + typename PredictionSchemeEncoder::CorrType; + using CornerTable = typename MeshDataT::CornerTable; + + explicit MeshPredictionSchemeMultiParallelogramEncoder( + const PointAttribute *attribute) + : MeshPredictionSchemeEncoder( + attribute) {} + MeshPredictionSchemeMultiParallelogramEncoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeEncoder( + attribute, transform, mesh_data) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_MULTI_PARALLELOGRAM; + } + + bool IsInitialized() const override { + return this->mesh_data().IsInitialized(); + } +}; + +template +bool MeshPredictionSchemeMultiParallelogramEncoder:: + ComputeCorrectionValues(const DataTypeT *in_data, CorrType *out_corr, + int size, int num_components, + const PointIndex * /* entry_to_point_id_map */) { + this->transform().Init(in_data, size, num_components); + const CornerTable *const table = this->mesh_data().corner_table(); + const std::vector *const vertex_to_data_map = + this->mesh_data().vertex_to_data_map(); + + // For storage of prediction values (already initialized to zero). + std::unique_ptr pred_vals(new DataTypeT[num_components]()); + std::unique_ptr parallelogram_pred_vals( + new DataTypeT[num_components]()); + + // We start processing from the end because this prediction uses data from + // previous entries that could be overwritten when an entry is processed. + for (int p = + static_cast(this->mesh_data().data_to_corner_map()->size() - 1); + p > 0; --p) { + const CornerIndex start_corner_id = + this->mesh_data().data_to_corner_map()->at(p); + + // Go over all corners attached to the vertex and compute the predicted + // value from the parallelograms defined by their opposite faces. + CornerIndex corner_id(start_corner_id); + int num_parallelograms = 0; + for (int i = 0; i < num_components; ++i) { + pred_vals[i] = static_cast(0); + } + while (corner_id != kInvalidCornerIndex) { + if (ComputeParallelogramPrediction( + p, corner_id, table, *vertex_to_data_map, in_data, num_components, + parallelogram_pred_vals.get())) { + for (int c = 0; c < num_components; ++c) { + pred_vals[c] += parallelogram_pred_vals[c]; + } + ++num_parallelograms; + } + + // Proceed to the next corner attached to the vertex. + corner_id = table->SwingRight(corner_id); + if (corner_id == start_corner_id) { + corner_id = kInvalidCornerIndex; + } + } + const int dst_offset = p * num_components; + if (num_parallelograms == 0) { + // No parallelogram was valid. + // We use the last encoded point as a reference. + const int src_offset = (p - 1) * num_components; + this->transform().ComputeCorrection( + in_data + dst_offset, in_data + src_offset, out_corr + dst_offset); + } else { + // Compute the correction from the predicted value. + for (int c = 0; c < num_components; ++c) { + pred_vals[c] /= num_parallelograms; + } + this->transform().ComputeCorrection(in_data + dst_offset, pred_vals.get(), + out_corr + dst_offset); + } + } + // First element is always fixed because it cannot be predicted. + for (int i = 0; i < num_components; ++i) { + pred_vals[i] = static_cast(0); + } + this->transform().ComputeCorrection(in_data, pred_vals.get(), out_corr); + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_MULTI_PARALLELOGRAM_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h new file mode 100644 index 00000000000..4d47ddf306e --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h @@ -0,0 +1,98 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h" + +namespace draco { + +// Decoder for attribute values encoded with the standard parallelogram +// prediction. See the description of the corresponding encoder for more +// details. +template +class MeshPredictionSchemeParallelogramDecoder + : public MeshPredictionSchemeDecoder { + public: + using CorrType = + typename PredictionSchemeDecoder::CorrType; + using CornerTable = typename MeshDataT::CornerTable; + explicit MeshPredictionSchemeParallelogramDecoder( + const PointAttribute *attribute) + : MeshPredictionSchemeDecoder( + attribute) {} + MeshPredictionSchemeParallelogramDecoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeDecoder( + attribute, transform, mesh_data) {} + + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_PARALLELOGRAM; + } + + bool IsInitialized() const override { + return this->mesh_data().IsInitialized(); + } +}; + +template +bool MeshPredictionSchemeParallelogramDecoder:: + ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int /* size */, int num_components, + const PointIndex * /* entry_to_point_id_map */) { + this->transform().Init(num_components); + + const CornerTable *const table = this->mesh_data().corner_table(); + const std::vector *const vertex_to_data_map = + this->mesh_data().vertex_to_data_map(); + + // For storage of prediction values (already initialized to zero). + std::unique_ptr pred_vals(new DataTypeT[num_components]()); + + // Restore the first value. + this->transform().ComputeOriginalValue(pred_vals.get(), in_corr, out_data); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + for (int p = 1; p < corner_map_size; ++p) { + const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p); + const int dst_offset = p * num_components; + if (!ComputeParallelogramPrediction(p, corner_id, table, + *vertex_to_data_map, out_data, + num_components, pred_vals.get())) { + // Parallelogram could not be computed, Possible because some of the + // vertices are not valid (not encoded yet). + // We use the last encoded point as a reference (delta coding). + const int src_offset = (p - 1) * num_components; + this->transform().ComputeOriginalValue( + out_data + src_offset, in_corr + dst_offset, out_data + dst_offset); + } else { + // Apply the parallelogram prediction. + this->transform().ComputeOriginalValue( + pred_vals.get(), in_corr + dst_offset, out_data + dst_offset); + } + } + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h new file mode 100644 index 00000000000..f00801932c2 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h @@ -0,0 +1,111 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h" + +namespace draco { + +// Parallelogram prediction predicts an attribute value V from three vertices +// on the opposite face to the predicted vertex. The values on the three +// vertices are used to construct a parallelogram V' = O - A - B, where O is the +// value on the opposite vertex, and A, B are values on the shared vertices: +// V +// / \ +// / \ +// / \ +// A-------B +// \ / +// \ / +// \ / +// O +// +template +class MeshPredictionSchemeParallelogramEncoder + : public MeshPredictionSchemeEncoder { + public: + using CorrType = + typename PredictionSchemeEncoder::CorrType; + using CornerTable = typename MeshDataT::CornerTable; + explicit MeshPredictionSchemeParallelogramEncoder( + const PointAttribute *attribute) + : MeshPredictionSchemeEncoder( + attribute) {} + MeshPredictionSchemeParallelogramEncoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeEncoder( + attribute, transform, mesh_data) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_PARALLELOGRAM; + } + + bool IsInitialized() const override { + return this->mesh_data().IsInitialized(); + } +}; + +template +bool MeshPredictionSchemeParallelogramEncoder:: + ComputeCorrectionValues(const DataTypeT *in_data, CorrType *out_corr, + int size, int num_components, + const PointIndex * /* entry_to_point_id_map */) { + this->transform().Init(in_data, size, num_components); + // For storage of prediction values (already initialized to zero). + std::unique_ptr pred_vals(new DataTypeT[num_components]()); + + // We start processing from the end because this prediction uses data from + // previous entries that could be overwritten when an entry is processed. + const CornerTable *const table = this->mesh_data().corner_table(); + const std::vector *const vertex_to_data_map = + this->mesh_data().vertex_to_data_map(); + for (int p = + static_cast(this->mesh_data().data_to_corner_map()->size() - 1); + p > 0; --p) { + const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p); + const int dst_offset = p * num_components; + if (!ComputeParallelogramPrediction(p, corner_id, table, + *vertex_to_data_map, in_data, + num_components, pred_vals.get())) { + // Parallelogram could not be computed, Possible because some of the + // vertices are not valid (not encoded yet). + // We use the last encoded point as a reference (delta coding). + const int src_offset = (p - 1) * num_components; + this->transform().ComputeCorrection( + in_data + dst_offset, in_data + src_offset, out_corr + dst_offset); + } else { + // Apply the parallelogram prediction. + this->transform().ComputeCorrection(in_data + dst_offset, pred_vals.get(), + out_corr + dst_offset); + } + } + // First element is always fixed because it cannot be predicted. + for (int i = 0; i < num_components; ++i) { + pred_vals[i] = static_cast(0); + } + this->transform().ComputeCorrection(in_data, pred_vals.get(), out_corr); + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h new file mode 100644 index 00000000000..485d457ccf6 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h @@ -0,0 +1,73 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Shared functionality for different parallelogram prediction schemes. + +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_SHARED_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_SHARED_H_ + +#include "draco/mesh/corner_table.h" +#include "draco/mesh/mesh.h" + +namespace draco { + +// TODO(draco-eng) consolidate Vertex/next/previous queries to one call +// (performance). +template +inline void GetParallelogramEntries( + const CornerIndex ci, const CornerTableT *table, + const std::vector &vertex_to_data_map, int *opp_entry, + int *next_entry, int *prev_entry) { + // One vertex of the input |table| correspond to exactly one attribute value + // entry. The |table| can be either CornerTable for per-vertex attributes, + // or MeshAttributeCornerTable for attributes with interior seams. + *opp_entry = vertex_to_data_map[table->Vertex(ci).value()]; + *next_entry = vertex_to_data_map[table->Vertex(table->Next(ci)).value()]; + *prev_entry = vertex_to_data_map[table->Vertex(table->Previous(ci)).value()]; +} + +// Computes parallelogram prediction for a given corner and data entry id. +// The prediction is stored in |out_prediction|. +// Function returns false when the prediction couldn't be computed, e.g. because +// not all entry points were available. +template +inline bool ComputeParallelogramPrediction( + int data_entry_id, const CornerIndex ci, const CornerTableT *table, + const std::vector &vertex_to_data_map, const DataTypeT *in_data, + int num_components, DataTypeT *out_prediction) { + const CornerIndex oci = table->Opposite(ci); + if (oci == kInvalidCornerIndex) { + return false; + } + int vert_opp, vert_next, vert_prev; + GetParallelogramEntries(oci, table, vertex_to_data_map, + &vert_opp, &vert_next, &vert_prev); + if (vert_opp < data_entry_id && vert_next < data_entry_id && + vert_prev < data_entry_id) { + // Apply the parallelogram prediction. + const int v_opp_off = vert_opp * num_components; + const int v_next_off = vert_next * num_components; + const int v_prev_off = vert_prev * num_components; + for (int c = 0; c < num_components; ++c) { + out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) - + in_data[v_opp_off + c]; + } + return true; + } + return false; // Not all data is available for prediction +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_PARALLELOGRAM_SHARED_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h new file mode 100644 index 00000000000..02cf7e60f26 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h @@ -0,0 +1,344 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_DECODER_H_ + +#include + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h" +#include "draco/compression/bit_coders/rans_bit_decoder.h" +#include "draco/core/varint_decoding.h" +#include "draco/core/vector_d.h" +#include "draco/draco_features.h" +#include "draco/mesh/corner_table.h" + +namespace draco { + +// Decoder for predictions of UV coordinates encoded by our specialized texture +// coordinate predictor. See the corresponding encoder for more details. Note +// that this predictor is not portable and should not be used anymore. See +// MeshPredictionSchemeTexCoordsPortableEncoder/Decoder for a portable version +// of this prediction scheme. +template +class MeshPredictionSchemeTexCoordsDecoder + : public MeshPredictionSchemeDecoder { + public: + using CorrType = typename MeshPredictionSchemeDecoder::CorrType; + MeshPredictionSchemeTexCoordsDecoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data, int version) + : MeshPredictionSchemeDecoder( + attribute, transform, mesh_data), + pos_attribute_(nullptr), + entry_to_point_id_map_(nullptr), + num_components_(0), + version_(version) {} + + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + + bool DecodePredictionData(DecoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_TEX_COORDS_DEPRECATED; + } + + bool IsInitialized() const override { + if (pos_attribute_ == nullptr) { + return false; + } + if (!this->mesh_data().IsInitialized()) { + return false; + } + return true; + } + + int GetNumParentAttributes() const override { return 1; } + + GeometryAttribute::Type GetParentAttributeType(int i) const override { + DRACO_DCHECK_EQ(i, 0); + (void)i; + return GeometryAttribute::POSITION; + } + + bool SetParentAttribute(const PointAttribute *att) override { + if (att == nullptr) { + return false; + } + if (att->attribute_type() != GeometryAttribute::POSITION) { + return false; // Invalid attribute type. + } + if (att->num_components() != 3) { + return false; // Currently works only for 3 component positions. + } + pos_attribute_ = att; + return true; + } + + protected: + Vector3f GetPositionForEntryId(int entry_id) const { + const PointIndex point_id = entry_to_point_id_map_[entry_id]; + Vector3f pos; + pos_attribute_->ConvertValue(pos_attribute_->mapped_index(point_id), + &pos[0]); + return pos; + } + + Vector2f GetTexCoordForEntryId(int entry_id, const DataTypeT *data) const { + const int data_offset = entry_id * num_components_; + return Vector2f(static_cast(data[data_offset]), + static_cast(data[data_offset + 1])); + } + + void ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data, + int data_id); + + private: + const PointAttribute *pos_attribute_; + const PointIndex *entry_to_point_id_map_; + std::unique_ptr predicted_value_; + int num_components_; + // Encoded / decoded array of UV flips. + std::vector orientations_; + int version_; +}; + +template +bool MeshPredictionSchemeTexCoordsDecoder:: + ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int /* size */, int num_components, + const PointIndex *entry_to_point_id_map) { + num_components_ = num_components; + entry_to_point_id_map_ = entry_to_point_id_map; + predicted_value_ = + std::unique_ptr(new DataTypeT[num_components]); + this->transform().Init(num_components); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + for (int p = 0; p < corner_map_size; ++p) { + const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p); + ComputePredictedValue(corner_id, out_data, p); + + const int dst_offset = p * num_components; + this->transform().ComputeOriginalValue( + predicted_value_.get(), in_corr + dst_offset, out_data + dst_offset); + } + return true; +} + +template +bool MeshPredictionSchemeTexCoordsDecoder:: + DecodePredictionData(DecoderBuffer *buffer) { + // Decode the delta coded orientations. + uint32_t num_orientations = 0; + if (buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 2)) { + if (!buffer->Decode(&num_orientations)) { + return false; + } + } else { + if (!DecodeVarint(&num_orientations, buffer)) { + return false; + } + } + if (num_orientations == 0) { + return false; + } + orientations_.resize(num_orientations); + bool last_orientation = true; + RAnsBitDecoder decoder; + if (!decoder.StartDecoding(buffer)) { + return false; + } + for (uint32_t i = 0; i < num_orientations; ++i) { + if (!decoder.DecodeNextBit()) { + last_orientation = !last_orientation; + } + orientations_[i] = last_orientation; + } + decoder.EndDecoding(); + return MeshPredictionSchemeDecoder::DecodePredictionData(buffer); +} + +template +void MeshPredictionSchemeTexCoordsDecoder:: + ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data, + int data_id) { + // Compute the predicted UV coordinate from the positions on all corners + // of the processed triangle. For the best prediction, the UV coordinates + // on the next/previous corners need to be already encoded/decoded. + const CornerIndex next_corner_id = + this->mesh_data().corner_table()->Next(corner_id); + const CornerIndex prev_corner_id = + this->mesh_data().corner_table()->Previous(corner_id); + // Get the encoded data ids from the next and previous corners. + // The data id is the encoding order of the UV coordinates. + int next_data_id, prev_data_id; + + int next_vert_id, prev_vert_id; + next_vert_id = + this->mesh_data().corner_table()->Vertex(next_corner_id).value(); + prev_vert_id = + this->mesh_data().corner_table()->Vertex(prev_corner_id).value(); + + next_data_id = this->mesh_data().vertex_to_data_map()->at(next_vert_id); + prev_data_id = this->mesh_data().vertex_to_data_map()->at(prev_vert_id); + + if (prev_data_id < data_id && next_data_id < data_id) { + // Both other corners have available UV coordinates for prediction. + const Vector2f n_uv = GetTexCoordForEntryId(next_data_id, data); + const Vector2f p_uv = GetTexCoordForEntryId(prev_data_id, data); + if (p_uv == n_uv) { + // We cannot do a reliable prediction on degenerated UV triangles. + predicted_value_[0] = static_cast(p_uv[0]); + predicted_value_[1] = static_cast(p_uv[1]); + return; + } + + // Get positions at all corners. + const Vector3f tip_pos = GetPositionForEntryId(data_id); + const Vector3f next_pos = GetPositionForEntryId(next_data_id); + const Vector3f prev_pos = GetPositionForEntryId(prev_data_id); + // Use the positions of the above triangle to predict the texture coordinate + // on the tip corner C. + // Convert the triangle into a new coordinate system defined by orthogonal + // bases vectors S, T, where S is vector prev_pos - next_pos and T is an + // perpendicular vector to S in the same plane as vector the + // tip_pos - next_pos. + // The transformed triangle in the new coordinate system is then going to + // be represented as: + // + // 1 ^ + // | + // | + // | C + // | / \ + // | / \ + // |/ \ + // N--------------P + // 0 1 + // + // Where next_pos point (N) is at position (0, 0), prev_pos point (P) is + // at (1, 0). Our goal is to compute the position of the tip_pos point (C) + // in this new coordinate space (s, t). + // + const Vector3f pn = prev_pos - next_pos; + const Vector3f cn = tip_pos - next_pos; + const float pn_norm2_squared = pn.SquaredNorm(); + // Coordinate s of the tip corner C is simply the dot product of the + // normalized vectors |pn| and |cn| (normalized by the length of |pn|). + // Since both of these vectors are normalized, we don't need to perform the + // normalization explicitly and instead we can just use the squared norm + // of |pn| as a denominator of the resulting dot product of non normalized + // vectors. + float s, t; + // |pn_norm2_squared| can be exactly 0 when the next_pos and prev_pos are + // the same positions (e.g. because they were quantized to the same + // location). + if (version_ < DRACO_BITSTREAM_VERSION(1, 2) || pn_norm2_squared > 0) { + s = pn.Dot(cn) / pn_norm2_squared; + // To get the coordinate t, we can use formula: + // t = |C-N - (P-N) * s| / |P-N| + // Do not use std::sqrt to avoid changes in the bitstream. + t = sqrt((cn - pn * s).SquaredNorm() / pn_norm2_squared); + } else { + s = 0; + t = 0; + } + + // Now we need to transform the point (s, t) to the texture coordinate space + // UV. We know the UV coordinates on points N and P (N_UV and P_UV). Lets + // denote P_UV - N_UV = PN_UV. PN_UV is then 2 dimensional vector that can + // be used to define transformation from the normalized coordinate system + // to the texture coordinate system using a 3x3 affine matrix M: + // + // M = | PN_UV[0] -PN_UV[1] N_UV[0] | + // | PN_UV[1] PN_UV[0] N_UV[1] | + // | 0 0 1 | + // + // The predicted point C_UV in the texture space is then equal to + // C_UV = M * (s, t, 1). Because the triangle in UV space may be flipped + // around the PN_UV axis, we also need to consider point C_UV' = M * (s, -t) + // as the prediction. + const Vector2f pn_uv = p_uv - n_uv; + const float pnus = pn_uv[0] * s + n_uv[0]; + const float pnut = pn_uv[0] * t; + const float pnvs = pn_uv[1] * s + n_uv[1]; + const float pnvt = pn_uv[1] * t; + Vector2f predicted_uv; + + // When decoding the data, we already know which orientation to use. + const bool orientation = orientations_.back(); + orientations_.pop_back(); + if (orientation) + predicted_uv = Vector2f(pnus - pnvt, pnvs + pnut); + else + predicted_uv = Vector2f(pnus + pnvt, pnvs - pnut); + + if (std::is_integral::value) { + // Round the predicted value for integer types. + if (std::isnan(predicted_uv[0])) { + predicted_value_[0] = INT_MIN; + } else { + predicted_value_[0] = static_cast(floor(predicted_uv[0] + 0.5)); + } + if (std::isnan(predicted_uv[1])) { + predicted_value_[1] = INT_MIN; + } else { + predicted_value_[1] = static_cast(floor(predicted_uv[1] + 0.5)); + } + } else { + predicted_value_[0] = static_cast(predicted_uv[0]); + predicted_value_[1] = static_cast(predicted_uv[1]); + } + return; + } + // Else we don't have available textures on both corners. For such case we + // can't use positions for predicting the uv value and we resort to delta + // coding. + int data_offset = 0; + if (prev_data_id < data_id) { + // Use the value on the previous corner as the prediction. + data_offset = prev_data_id * num_components_; + } + if (next_data_id < data_id) { + // Use the value on the next corner as the prediction. + data_offset = next_data_id * num_components_; + } else { + // None of the other corners have a valid value. Use the last encoded value + // as the prediction if possible. + if (data_id > 0) { + data_offset = (data_id - 1) * num_components_; + } else { + // We are encoding the first value. Predict 0. + for (int i = 0; i < num_components_; ++i) { + predicted_value_[i] = 0; + } + return; + } + } + for (int i = 0; i < num_components_; ++i) { + predicted_value_[i] = data[data_offset + i]; + } +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_DECODER_H_ +#endif diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h new file mode 100644 index 00000000000..813b72ae35f --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h @@ -0,0 +1,318 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_ENCODER_H_ + +#include + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h" +#include "draco/compression/bit_coders/rans_bit_encoder.h" +#include "draco/core/varint_encoding.h" +#include "draco/core/vector_d.h" +#include "draco/mesh/corner_table.h" + +namespace draco { + +// Prediction scheme designed for predicting texture coordinates from known +// spatial position of vertices. For good parametrization, the ratios between +// triangle edge lengths should be about the same in both the spatial and UV +// coordinate spaces, which makes the positions a good predictor for the UV +// coordinates. +template +class MeshPredictionSchemeTexCoordsEncoder + : public MeshPredictionSchemeEncoder { + public: + using CorrType = typename MeshPredictionSchemeEncoder::CorrType; + MeshPredictionSchemeTexCoordsEncoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeEncoder( + attribute, transform, mesh_data), + pos_attribute_(nullptr), + entry_to_point_id_map_(nullptr), + num_components_(0) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + + bool EncodePredictionData(EncoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_TEX_COORDS_DEPRECATED; + } + + bool IsInitialized() const override { + if (pos_attribute_ == nullptr) { + return false; + } + if (!this->mesh_data().IsInitialized()) { + return false; + } + return true; + } + + int GetNumParentAttributes() const override { return 1; } + + GeometryAttribute::Type GetParentAttributeType(int i) const override { + DRACO_DCHECK_EQ(i, 0); + (void)i; + return GeometryAttribute::POSITION; + } + + bool SetParentAttribute(const PointAttribute *att) override { + if (att->attribute_type() != GeometryAttribute::POSITION) { + return false; // Invalid attribute type. + } + if (att->num_components() != 3) { + return false; // Currently works only for 3 component positions. + } + pos_attribute_ = att; + return true; + } + + protected: + Vector3f GetPositionForEntryId(int entry_id) const { + const PointIndex point_id = entry_to_point_id_map_[entry_id]; + Vector3f pos; + pos_attribute_->ConvertValue(pos_attribute_->mapped_index(point_id), + &pos[0]); + return pos; + } + + Vector2f GetTexCoordForEntryId(int entry_id, const DataTypeT *data) const { + const int data_offset = entry_id * num_components_; + return Vector2f(static_cast(data[data_offset]), + static_cast(data[data_offset + 1])); + } + + void ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data, + int data_id); + + private: + const PointAttribute *pos_attribute_; + const PointIndex *entry_to_point_id_map_; + std::unique_ptr predicted_value_; + int num_components_; + // Encoded / decoded array of UV flips. + std::vector orientations_; +}; + +template +bool MeshPredictionSchemeTexCoordsEncoder:: + ComputeCorrectionValues(const DataTypeT *in_data, CorrType *out_corr, + int size, int num_components, + const PointIndex *entry_to_point_id_map) { + num_components_ = num_components; + entry_to_point_id_map_ = entry_to_point_id_map; + predicted_value_ = + std::unique_ptr(new DataTypeT[num_components]); + this->transform().Init(in_data, size, num_components); + // We start processing from the end because this prediction uses data from + // previous entries that could be overwritten when an entry is processed. + for (int p = + static_cast(this->mesh_data().data_to_corner_map()->size()) - 1; + p >= 0; --p) { + const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p); + ComputePredictedValue(corner_id, in_data, p); + + const int dst_offset = p * num_components; + this->transform().ComputeCorrection( + in_data + dst_offset, predicted_value_.get(), out_corr + dst_offset); + } + return true; +} + +template +bool MeshPredictionSchemeTexCoordsEncoder:: + EncodePredictionData(EncoderBuffer *buffer) { + // Encode the delta-coded orientations using arithmetic coding. + const uint32_t num_orientations = static_cast(orientations_.size()); + EncodeVarint(num_orientations, buffer); + bool last_orientation = true; + RAnsBitEncoder encoder; + encoder.StartEncoding(); + for (bool orientation : orientations_) { + encoder.EncodeBit(orientation == last_orientation); + last_orientation = orientation; + } + encoder.EndEncoding(buffer); + return MeshPredictionSchemeEncoder::EncodePredictionData(buffer); +} + +template +void MeshPredictionSchemeTexCoordsEncoder:: + ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data, + int data_id) { + // Compute the predicted UV coordinate from the positions on all corners + // of the processed triangle. For the best prediction, the UV coordinates + // on the next/previous corners need to be already encoded/decoded. + const CornerIndex next_corner_id = + this->mesh_data().corner_table()->Next(corner_id); + const CornerIndex prev_corner_id = + this->mesh_data().corner_table()->Previous(corner_id); + // Get the encoded data ids from the next and previous corners. + // The data id is the encoding order of the UV coordinates. + int next_data_id, prev_data_id; + + int next_vert_id, prev_vert_id; + next_vert_id = + this->mesh_data().corner_table()->Vertex(next_corner_id).value(); + prev_vert_id = + this->mesh_data().corner_table()->Vertex(prev_corner_id).value(); + + next_data_id = this->mesh_data().vertex_to_data_map()->at(next_vert_id); + prev_data_id = this->mesh_data().vertex_to_data_map()->at(prev_vert_id); + + if (prev_data_id < data_id && next_data_id < data_id) { + // Both other corners have available UV coordinates for prediction. + const Vector2f n_uv = GetTexCoordForEntryId(next_data_id, data); + const Vector2f p_uv = GetTexCoordForEntryId(prev_data_id, data); + if (p_uv == n_uv) { + // We cannot do a reliable prediction on degenerated UV triangles. + predicted_value_[0] = static_cast(p_uv[0]); + predicted_value_[1] = static_cast(p_uv[1]); + return; + } + + // Get positions at all corners. + const Vector3f tip_pos = GetPositionForEntryId(data_id); + const Vector3f next_pos = GetPositionForEntryId(next_data_id); + const Vector3f prev_pos = GetPositionForEntryId(prev_data_id); + // Use the positions of the above triangle to predict the texture coordinate + // on the tip corner C. + // Convert the triangle into a new coordinate system defined by orthogonal + // bases vectors S, T, where S is vector prev_pos - next_pos and T is an + // perpendicular vector to S in the same plane as vector the + // tip_pos - next_pos. + // The transformed triangle in the new coordinate system is then going to + // be represented as: + // + // 1 ^ + // | + // | + // | C + // | / \ + // | / \ + // |/ \ + // N--------------P + // 0 1 + // + // Where next_pos point (N) is at position (0, 0), prev_pos point (P) is + // at (1, 0). Our goal is to compute the position of the tip_pos point (C) + // in this new coordinate space (s, t). + // + const Vector3f pn = prev_pos - next_pos; + const Vector3f cn = tip_pos - next_pos; + const float pn_norm2_squared = pn.SquaredNorm(); + // Coordinate s of the tip corner C is simply the dot product of the + // normalized vectors |pn| and |cn| (normalized by the length of |pn|). + // Since both of these vectors are normalized, we don't need to perform the + // normalization explicitly and instead we can just use the squared norm + // of |pn| as a denominator of the resulting dot product of non normalized + // vectors. + float s, t; + // |pn_norm2_squared| can be exactly 0 when the next_pos and prev_pos are + // the same positions (e.g. because they were quantized to the same + // location). + if (pn_norm2_squared > 0) { + s = pn.Dot(cn) / pn_norm2_squared; + // To get the coordinate t, we can use formula: + // t = |C-N - (P-N) * s| / |P-N| + // Do not use std::sqrt to avoid changes in the bitstream. + t = sqrt((cn - pn * s).SquaredNorm() / pn_norm2_squared); + } else { + s = 0; + t = 0; + } + + // Now we need to transform the point (s, t) to the texture coordinate space + // UV. We know the UV coordinates on points N and P (N_UV and P_UV). Lets + // denote P_UV - N_UV = PN_UV. PN_UV is then 2 dimensional vector that can + // be used to define transformation from the normalized coordinate system + // to the texture coordinate system using a 3x3 affine matrix M: + // + // M = | PN_UV[0] -PN_UV[1] N_UV[0] | + // | PN_UV[1] PN_UV[0] N_UV[1] | + // | 0 0 1 | + // + // The predicted point C_UV in the texture space is then equal to + // C_UV = M * (s, t, 1). Because the triangle in UV space may be flipped + // around the PN_UV axis, we also need to consider point C_UV' = M * (s, -t) + // as the prediction. + const Vector2f pn_uv = p_uv - n_uv; + const float pnus = pn_uv[0] * s + n_uv[0]; + const float pnut = pn_uv[0] * t; + const float pnvs = pn_uv[1] * s + n_uv[1]; + const float pnvt = pn_uv[1] * t; + Vector2f predicted_uv; + + // When encoding compute both possible vectors and determine which one + // results in a better prediction. + const Vector2f predicted_uv_0(pnus - pnvt, pnvs + pnut); + const Vector2f predicted_uv_1(pnus + pnvt, pnvs - pnut); + const Vector2f c_uv = GetTexCoordForEntryId(data_id, data); + if ((c_uv - predicted_uv_0).SquaredNorm() < + (c_uv - predicted_uv_1).SquaredNorm()) { + predicted_uv = predicted_uv_0; + orientations_.push_back(true); + } else { + predicted_uv = predicted_uv_1; + orientations_.push_back(false); + } + if (std::is_integral::value) { + // Round the predicted value for integer types. + predicted_value_[0] = static_cast(floor(predicted_uv[0] + 0.5)); + predicted_value_[1] = static_cast(floor(predicted_uv[1] + 0.5)); + } else { + predicted_value_[0] = static_cast(predicted_uv[0]); + predicted_value_[1] = static_cast(predicted_uv[1]); + } + return; + } + // Else we don't have available textures on both corners. For such case we + // can't use positions for predicting the uv value and we resort to delta + // coding. + int data_offset = 0; + if (prev_data_id < data_id) { + // Use the value on the previous corner as the prediction. + data_offset = prev_data_id * num_components_; + } + if (next_data_id < data_id) { + // Use the value on the next corner as the prediction. + data_offset = next_data_id * num_components_; + } else { + // None of the other corners have a valid value. Use the last encoded value + // as the prediction if possible. + if (data_id > 0) { + data_offset = (data_id - 1) * num_components_; + } else { + // We are encoding the first value. Predict 0. + for (int i = 0; i < num_components_; ++i) { + predicted_value_[i] = 0; + } + return; + } + } + for (int i = 0; i < num_components_; ++i) { + predicted_value_[i] = data[data_offset + i]; + } +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h new file mode 100644 index 00000000000..83d4966393f --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h @@ -0,0 +1,143 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h" +#include "draco/compression/bit_coders/rans_bit_decoder.h" + +namespace draco { + +// Decoder for predictions of UV coordinates encoded by our specialized and +// portable texture coordinate predictor. See the corresponding encoder for more +// details. +template +class MeshPredictionSchemeTexCoordsPortableDecoder + : public MeshPredictionSchemeDecoder { + public: + using CorrType = typename MeshPredictionSchemeDecoder::CorrType; + MeshPredictionSchemeTexCoordsPortableDecoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeDecoder( + attribute, transform, mesh_data), + predictor_(mesh_data) {} + + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + + bool DecodePredictionData(DecoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_TEX_COORDS_PORTABLE; + } + + bool IsInitialized() const override { + if (!predictor_.IsInitialized()) { + return false; + } + if (!this->mesh_data().IsInitialized()) { + return false; + } + return true; + } + + int GetNumParentAttributes() const override { return 1; } + + GeometryAttribute::Type GetParentAttributeType(int i) const override { + DRACO_DCHECK_EQ(i, 0); + (void)i; + return GeometryAttribute::POSITION; + } + + bool SetParentAttribute(const PointAttribute *att) override { + if (!att || att->attribute_type() != GeometryAttribute::POSITION) { + return false; // Invalid attribute type. + } + if (att->num_components() != 3) { + return false; // Currently works only for 3 component positions. + } + predictor_.SetPositionAttribute(*att); + return true; + } + + private: + MeshPredictionSchemeTexCoordsPortablePredictor + predictor_; +}; + +template +bool MeshPredictionSchemeTexCoordsPortableDecoder< + DataTypeT, TransformT, + MeshDataT>::ComputeOriginalValues(const CorrType *in_corr, + DataTypeT *out_data, int /* size */, + int num_components, + const PointIndex *entry_to_point_id_map) { + if (num_components != MeshPredictionSchemeTexCoordsPortablePredictor< + DataTypeT, MeshDataT>::kNumComponents) { + return false; + } + predictor_.SetEntryToPointIdMap(entry_to_point_id_map); + this->transform().Init(num_components); + + const int corner_map_size = + static_cast(this->mesh_data().data_to_corner_map()->size()); + for (int p = 0; p < corner_map_size; ++p) { + const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p); + if (!predictor_.template ComputePredictedValue(corner_id, out_data, + p)) { + return false; + } + + const int dst_offset = p * num_components; + this->transform().ComputeOriginalValue(predictor_.predicted_value(), + in_corr + dst_offset, + out_data + dst_offset); + } + return true; +} + +template +bool MeshPredictionSchemeTexCoordsPortableDecoder< + DataTypeT, TransformT, MeshDataT>::DecodePredictionData(DecoderBuffer + *buffer) { + // Decode the delta coded orientations. + int32_t num_orientations = 0; + if (!buffer->Decode(&num_orientations) || num_orientations < 0) { + return false; + } + predictor_.ResizeOrientations(num_orientations); + bool last_orientation = true; + RAnsBitDecoder decoder; + if (!decoder.StartDecoding(buffer)) { + return false; + } + for (int i = 0; i < num_orientations; ++i) { + if (!decoder.DecodeNextBit()) { + last_orientation = !last_orientation; + } + predictor_.set_orientation(i, last_orientation); + } + decoder.EndDecoding(); + return MeshPredictionSchemeDecoder::DecodePredictionData(buffer); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h new file mode 100644 index 00000000000..741ec66dc2a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h @@ -0,0 +1,133 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h" +#include "draco/compression/bit_coders/rans_bit_encoder.h" + +namespace draco { + +// Prediction scheme designed for predicting texture coordinates from known +// spatial position of vertices. For isometric parametrizations, the ratios +// between triangle edge lengths should be about the same in both the spatial +// and UV coordinate spaces, which makes the positions a good predictor for the +// UV coordinates. Note that this may not be the optimal approach for other +// parametrizations such as projective ones. +template +class MeshPredictionSchemeTexCoordsPortableEncoder + : public MeshPredictionSchemeEncoder { + public: + using CorrType = typename MeshPredictionSchemeEncoder::CorrType; + MeshPredictionSchemeTexCoordsPortableEncoder(const PointAttribute *attribute, + const TransformT &transform, + const MeshDataT &mesh_data) + : MeshPredictionSchemeEncoder( + attribute, transform, mesh_data), + predictor_(mesh_data) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + + bool EncodePredictionData(EncoderBuffer *buffer) override; + + PredictionSchemeMethod GetPredictionMethod() const override { + return MESH_PREDICTION_TEX_COORDS_PORTABLE; + } + + bool IsInitialized() const override { + if (!predictor_.IsInitialized()) { + return false; + } + if (!this->mesh_data().IsInitialized()) { + return false; + } + return true; + } + + int GetNumParentAttributes() const override { return 1; } + + GeometryAttribute::Type GetParentAttributeType(int i) const override { + DRACO_DCHECK_EQ(i, 0); + (void)i; + return GeometryAttribute::POSITION; + } + + bool SetParentAttribute(const PointAttribute *att) override { + if (att->attribute_type() != GeometryAttribute::POSITION) { + return false; // Invalid attribute type. + } + if (att->num_components() != 3) { + return false; // Currently works only for 3 component positions. + } + predictor_.SetPositionAttribute(*att); + return true; + } + + private: + MeshPredictionSchemeTexCoordsPortablePredictor + predictor_; +}; + +template +bool MeshPredictionSchemeTexCoordsPortableEncoder:: + ComputeCorrectionValues(const DataTypeT *in_data, CorrType *out_corr, + int size, int num_components, + const PointIndex *entry_to_point_id_map) { + predictor_.SetEntryToPointIdMap(entry_to_point_id_map); + this->transform().Init(in_data, size, num_components); + // We start processing from the end because this prediction uses data from + // previous entries that could be overwritten when an entry is processed. + for (int p = + static_cast(this->mesh_data().data_to_corner_map()->size() - 1); + p >= 0; --p) { + const CornerIndex corner_id = this->mesh_data().data_to_corner_map()->at(p); + predictor_.template ComputePredictedValue(corner_id, in_data, p); + + const int dst_offset = p * num_components; + this->transform().ComputeCorrection(in_data + dst_offset, + predictor_.predicted_value(), + out_corr + dst_offset); + } + return true; +} + +template +bool MeshPredictionSchemeTexCoordsPortableEncoder< + DataTypeT, TransformT, MeshDataT>::EncodePredictionData(EncoderBuffer + *buffer) { + // Encode the delta-coded orientations using arithmetic coding. + const int32_t num_orientations = predictor_.num_orientations(); + buffer->Encode(num_orientations); + bool last_orientation = true; + RAnsBitEncoder encoder; + encoder.StartEncoding(); + for (int i = 0; i < num_orientations; ++i) { + const bool orientation = predictor_.orientation(i); + encoder.EncodeBit(orientation == last_orientation); + last_orientation = orientation; + } + encoder.EndEncoding(buffer); + return MeshPredictionSchemeEncoder::EncodePredictionData(buffer); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h new file mode 100644 index 00000000000..5d8a5060133 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h @@ -0,0 +1,256 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_PREDICTOR_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_PREDICTOR_H_ + +#include + +#include "draco/attributes/point_attribute.h" +#include "draco/core/math_utils.h" +#include "draco/core/vector_d.h" +#include "draco/mesh/corner_table.h" + +namespace draco { + +// Predictor functionality used for portable UV prediction by both encoder and +// decoder. +template +class MeshPredictionSchemeTexCoordsPortablePredictor { + public: + static constexpr int kNumComponents = 2; + + explicit MeshPredictionSchemeTexCoordsPortablePredictor(const MeshDataT &md) + : pos_attribute_(nullptr), + entry_to_point_id_map_(nullptr), + mesh_data_(md) {} + void SetPositionAttribute(const PointAttribute &position_attribute) { + pos_attribute_ = &position_attribute; + } + void SetEntryToPointIdMap(const PointIndex *map) { + entry_to_point_id_map_ = map; + } + bool IsInitialized() const { return pos_attribute_ != nullptr; } + + VectorD GetPositionForEntryId(int entry_id) const { + const PointIndex point_id = entry_to_point_id_map_[entry_id]; + VectorD pos; + pos_attribute_->ConvertValue(pos_attribute_->mapped_index(point_id), + &pos[0]); + return pos; + } + + VectorD GetTexCoordForEntryId(int entry_id, + const DataTypeT *data) const { + const int data_offset = entry_id * kNumComponents; + return VectorD(data[data_offset], data[data_offset + 1]); + } + + // Computes predicted UV coordinates on a given corner. The coordinates are + // stored in |predicted_value_| member. + template + bool ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data, + int data_id); + + const DataTypeT *predicted_value() const { return predicted_value_; } + bool orientation(int i) const { return orientations_[i]; } + void set_orientation(int i, bool v) { orientations_[i] = v; } + size_t num_orientations() const { return orientations_.size(); } + void ResizeOrientations(int num_orientations) { + orientations_.resize(num_orientations); + } + + private: + const PointAttribute *pos_attribute_; + const PointIndex *entry_to_point_id_map_; + DataTypeT predicted_value_[kNumComponents]; + // Encoded / decoded array of UV flips. + // TODO(ostava): We should remove this and replace this with in-place encoding + // and decoding to avoid unnecessary copy. + std::vector orientations_; + MeshDataT mesh_data_; +}; + +template +template +bool MeshPredictionSchemeTexCoordsPortablePredictor< + DataTypeT, MeshDataT>::ComputePredictedValue(CornerIndex corner_id, + const DataTypeT *data, + int data_id) { + // Compute the predicted UV coordinate from the positions on all corners + // of the processed triangle. For the best prediction, the UV coordinates + // on the next/previous corners need to be already encoded/decoded. + const CornerIndex next_corner_id = mesh_data_.corner_table()->Next(corner_id); + const CornerIndex prev_corner_id = + mesh_data_.corner_table()->Previous(corner_id); + // Get the encoded data ids from the next and previous corners. + // The data id is the encoding order of the UV coordinates. + int next_data_id, prev_data_id; + + int next_vert_id, prev_vert_id; + next_vert_id = mesh_data_.corner_table()->Vertex(next_corner_id).value(); + prev_vert_id = mesh_data_.corner_table()->Vertex(prev_corner_id).value(); + + next_data_id = mesh_data_.vertex_to_data_map()->at(next_vert_id); + prev_data_id = mesh_data_.vertex_to_data_map()->at(prev_vert_id); + + if (prev_data_id < data_id && next_data_id < data_id) { + // Both other corners have available UV coordinates for prediction. + const VectorD n_uv = GetTexCoordForEntryId(next_data_id, data); + const VectorD p_uv = GetTexCoordForEntryId(prev_data_id, data); + if (p_uv == n_uv) { + // We cannot do a reliable prediction on degenerated UV triangles. + predicted_value_[0] = p_uv[0]; + predicted_value_[1] = p_uv[1]; + return true; + } + + // Get positions at all corners. + const VectorD tip_pos = GetPositionForEntryId(data_id); + const VectorD next_pos = GetPositionForEntryId(next_data_id); + const VectorD prev_pos = GetPositionForEntryId(prev_data_id); + // We use the positions of the above triangle to predict the texture + // coordinate on the tip corner C. + // To convert the triangle into the UV coordinate system we first compute + // position X on the vector |prev_pos - next_pos| that is the projection of + // point C onto vector |prev_pos - next_pos|: + // + // C + // /. \ + // / . \ + // / . \ + // N---X----------P + // + // Where next_pos is point (N), prev_pos is point (P) and tip_pos is the + // position of predicted coordinate (C). + // + const VectorD pn = prev_pos - next_pos; + const uint64_t pn_norm2_squared = pn.SquaredNorm(); + if (pn_norm2_squared != 0) { + // Compute the projection of C onto PN by computing dot product of CN with + // PN and normalizing it by length of PN. This gives us a factor |s| where + // |s = PN.Dot(CN) / PN.SquaredNorm2()|. This factor can be used to + // compute X in UV space |X_UV| as |X_UV = N_UV + s * PN_UV|. + const VectorD cn = tip_pos - next_pos; + const int64_t cn_dot_pn = pn.Dot(cn); + + const VectorD pn_uv = p_uv - n_uv; + // Because we perform all computations with integers, we don't explicitly + // compute the normalized factor |s|, but rather we perform all operations + // over UV vectors in a non-normalized coordinate system scaled with a + // scaling factor |pn_norm2_squared|: + // + // x_uv = X_UV * PN.Norm2Squared() + // + const VectorD x_uv = + n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv); + + // Compute squared length of vector CX in position coordinate system: + const VectorD x_pos = + next_pos + (cn_dot_pn * pn) / pn_norm2_squared; + const uint64_t cx_norm2_squared = (tip_pos - x_pos).SquaredNorm(); + + // Compute vector CX_UV in the uv space by rotating vector PN_UV by 90 + // degrees and scaling it with factor CX.Norm2() / PN.Norm2(): + // + // CX_UV = (CX.Norm2() / PN.Norm2()) * Rot(PN_UV) + // + // To preserve precision, we perform all operations in scaled space as + // explained above, so we want the final vector to be: + // + // cx_uv = CX_UV * PN.Norm2Squared() + // + // We can then rewrite the formula as: + // + // cx_uv = CX.Norm2() * PN.Norm2() * Rot(PN_UV) + // + VectorD cx_uv(pn_uv[1], -pn_uv[0]); // Rotated PN_UV. + // Compute CX.Norm2() * PN.Norm2() + const uint64_t norm_squared = + IntSqrt(cx_norm2_squared * pn_norm2_squared); + // Final cx_uv in the scaled coordinate space. + cx_uv = cx_uv * norm_squared; + + // Predicted uv coordinate is then computed by either adding or + // subtracting CX_UV to/from X_UV. + VectorD predicted_uv; + if (is_encoder_t) { + // When encoding, compute both possible vectors and determine which one + // results in a better prediction. + // Both vectors need to be transformed back from the scaled space to + // the real UV coordinate space. + const VectorD predicted_uv_0((x_uv + cx_uv) / + pn_norm2_squared); + const VectorD predicted_uv_1((x_uv - cx_uv) / + pn_norm2_squared); + const VectorD c_uv = GetTexCoordForEntryId(data_id, data); + if ((c_uv - predicted_uv_0).SquaredNorm() < + (c_uv - predicted_uv_1).SquaredNorm()) { + predicted_uv = predicted_uv_0; + orientations_.push_back(true); + } else { + predicted_uv = predicted_uv_1; + orientations_.push_back(false); + } + } else { + // When decoding the data, we already know which orientation to use. + if (orientations_.empty()) { + return false; + } + const bool orientation = orientations_.back(); + orientations_.pop_back(); + if (orientation) { + predicted_uv = (x_uv + cx_uv) / pn_norm2_squared; + } else { + predicted_uv = (x_uv - cx_uv) / pn_norm2_squared; + } + } + predicted_value_[0] = static_cast(predicted_uv[0]); + predicted_value_[1] = static_cast(predicted_uv[1]); + return true; + } + } + // Else we don't have available textures on both corners or the position data + // is invalid. For such cases we can't use positions for predicting the uv + // value and we resort to delta coding. + int data_offset = 0; + if (prev_data_id < data_id) { + // Use the value on the previous corner as the prediction. + data_offset = prev_data_id * kNumComponents; + } + if (next_data_id < data_id) { + // Use the value on the next corner as the prediction. + data_offset = next_data_id * kNumComponents; + } else { + // None of the other corners have a valid value. Use the last encoded value + // as the prediction if possible. + if (data_id > 0) { + data_offset = (data_id - 1) * kNumComponents; + } else { + // We are encoding the first value. Predict 0. + for (int i = 0; i < kNumComponents; ++i) { + predicted_value_[i] = 0; + } + return true; + } + } + for (int i = 0; i < kNumComponents; ++i) { + predicted_value_[i] = data[data_offset + i]; + } + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_PREDICTOR_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h new file mode 100644 index 00000000000..064e1b44fe1 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h @@ -0,0 +1,90 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_H_ + +#include + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h" + +// Prediction schemes can be used during encoding and decoding of vertex +// attributes to predict attribute values based on the previously +// encoded/decoded data. The differences between the original and predicted +// attribute values are used to compute correction values that can be usually +// encoded with fewer bits compared to the original data. +namespace draco { + +// Abstract base class for typed prediction schemes. It provides basic access +// to the encoded attribute and to the supplied prediction transform. +template > +class PredictionSchemeDecoder : public PredictionSchemeTypedDecoderInterface< + DataTypeT, typename TransformT::CorrType> { + public: + typedef DataTypeT DataType; + typedef TransformT Transform; + // Correction type needs to be defined in the prediction transform class. + typedef typename Transform::CorrType CorrType; + explicit PredictionSchemeDecoder(const PointAttribute *attribute) + : PredictionSchemeDecoder(attribute, Transform()) {} + PredictionSchemeDecoder(const PointAttribute *attribute, + const Transform &transform) + : attribute_(attribute), transform_(transform) {} + + bool DecodePredictionData(DecoderBuffer *buffer) override { + if (!transform_.DecodeTransformData(buffer)) { + return false; + } + return true; + } + + const PointAttribute *GetAttribute() const override { return attribute(); } + + // Returns the number of parent attributes that are needed for the prediction. + int GetNumParentAttributes() const override { return 0; } + + // Returns the type of each of the parent attribute. + GeometryAttribute::Type GetParentAttributeType(int /* i */) const override { + return GeometryAttribute::INVALID; + } + + // Sets the required parent attribute. + bool SetParentAttribute(const PointAttribute * /* att */) override { + return false; + } + + bool AreCorrectionsPositive() override { + return transform_.AreCorrectionsPositive(); + } + + PredictionSchemeTransformType GetTransformType() const override { + return transform_.GetType(); + } + + protected: + inline const PointAttribute *attribute() const { return attribute_; } + inline const Transform &transform() const { return transform_; } + inline Transform &transform() { return transform_; } + + private: + const PointAttribute *attribute_; + Transform transform_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h new file mode 100644 index 00000000000..cf2a6ba6b3b --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h @@ -0,0 +1,194 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Functions for creating prediction schemes for decoders using the provided +// prediction method id. + +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_FACTORY_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_FACTORY_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h" +#include "draco/draco_features.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h" +#endif +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_decoder.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h" +#include "draco/compression/mesh/mesh_decoder.h" + +namespace draco { + +// Factory class for creating mesh prediction schemes. The factory implements +// operator() that is used to create an appropriate mesh prediction scheme in +// CreateMeshPredictionScheme() function in prediction_scheme_factory.h +template +struct MeshPredictionSchemeDecoderFactory { + // Operator () specialized for the wrap transform. Wrap transform can be used + // for all mesh prediction schemes. The specialization is done in compile time + // to prevent instantiations of unneeded combinations of prediction schemes + + // prediction transforms. + template + struct DispatchFunctor { + std::unique_ptr> operator()( + PredictionSchemeMethod method, const PointAttribute *attribute, + const TransformT &transform, const MeshDataT &mesh_data, + uint16_t bitstream_version) { + if (method == MESH_PREDICTION_PARALLELOGRAM) { + return std::unique_ptr>( + new MeshPredictionSchemeParallelogramDecoder( + attribute, transform, mesh_data)); + } +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + else if (method == MESH_PREDICTION_MULTI_PARALLELOGRAM) { + return std::unique_ptr>( + new MeshPredictionSchemeMultiParallelogramDecoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } +#endif + else if (method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM) { + return std::unique_ptr>( + new MeshPredictionSchemeConstrainedMultiParallelogramDecoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + else if (method == MESH_PREDICTION_TEX_COORDS_DEPRECATED) { + return std::unique_ptr>( + new MeshPredictionSchemeTexCoordsDecoder( + attribute, transform, mesh_data, bitstream_version)); + } +#endif + else if (method == MESH_PREDICTION_TEX_COORDS_PORTABLE) { + return std::unique_ptr>( + new MeshPredictionSchemeTexCoordsPortableDecoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + return std::unique_ptr>( + new MeshPredictionSchemeGeometricNormalDecoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } +#endif + return nullptr; + } + }; + +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + // Operator () specialized for normal octahedron transforms. These transforms + // are currently used only by the geometric normal prediction scheme (the + // transform is also used by delta coding, but delta predictor is not + // constructed in this function). + template + struct DispatchFunctor { + std::unique_ptr> operator()( + PredictionSchemeMethod method, const PointAttribute *attribute, + const TransformT &transform, const MeshDataT &mesh_data, + uint16_t bitstream_version) { + if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + return std::unique_ptr>( + new MeshPredictionSchemeGeometricNormalDecoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } + return nullptr; + } + }; + template + struct DispatchFunctor { + std::unique_ptr> operator()( + PredictionSchemeMethod method, const PointAttribute *attribute, + const TransformT &transform, const MeshDataT &mesh_data, + uint16_t bitstream_version) { + if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + return std::unique_ptr>( + new MeshPredictionSchemeGeometricNormalDecoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } + return nullptr; + } + }; +#endif + + template + std::unique_ptr> operator()( + PredictionSchemeMethod method, const PointAttribute *attribute, + const TransformT &transform, const MeshDataT &mesh_data, + uint16_t bitstream_version) { + return DispatchFunctor()( + method, attribute, transform, mesh_data, bitstream_version); + } +}; + +// Creates a prediction scheme for a given decoder and given prediction method. +// The prediction schemes are automatically initialized with decoder specific +// data if needed. +template +std::unique_ptr> +CreatePredictionSchemeForDecoder(PredictionSchemeMethod method, int att_id, + const PointCloudDecoder *decoder, + const TransformT &transform) { + if (method == PREDICTION_NONE) { + return nullptr; + } + const PointAttribute *const att = decoder->point_cloud()->attribute(att_id); + if (decoder->GetGeometryType() == TRIANGULAR_MESH) { + // Cast the decoder to mesh decoder. This is not necessarily safe if there + // is some other decoder decides to use TRIANGULAR_MESH as the return type, + // but unfortunately there is not nice work around for this without using + // RTTI (double dispatch and similar concepts will not work because of the + // template nature of the prediction schemes). + const MeshDecoder *const mesh_decoder = + static_cast(decoder); + + auto ret = CreateMeshPredictionScheme< + MeshDecoder, PredictionSchemeDecoder, + MeshPredictionSchemeDecoderFactory>( + mesh_decoder, method, att_id, transform, decoder->bitstream_version()); + if (ret) { + return ret; + } + // Otherwise try to create another prediction scheme. + } + // Create delta decoder. + return std::unique_ptr>( + new PredictionSchemeDeltaDecoder(att, transform)); +} + +// Create a prediction scheme using a default transform constructor. +template +std::unique_ptr> +CreatePredictionSchemeForDecoder(PredictionSchemeMethod method, int att_id, + const PointCloudDecoder *decoder) { + return CreatePredictionSchemeForDecoder( + method, att_id, decoder, TransformT()); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_FACTORY_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h new file mode 100644 index 00000000000..6f19f7fdb99 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_interface.h @@ -0,0 +1,53 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_INTERFACE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_INTERFACE_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h" +#include "draco/core/decoder_buffer.h" + +// Prediction schemes can be used during encoding and decoding of attributes +// to predict attribute values based on the previously encoded/decoded data. +// See prediction_scheme.h for more details. +namespace draco { + +// Abstract interface for all prediction schemes used during attribute encoding. +class PredictionSchemeDecoderInterface : public PredictionSchemeInterface { + public: + // Method that can be used to decode any prediction scheme specific data + // from the input buffer. + virtual bool DecodePredictionData(DecoderBuffer *buffer) = 0; +}; + +// A specialized version of the prediction scheme interface for specific +// input and output data types. +// |entry_to_point_id_map| is the mapping between value entries to point ids +// of the associated point cloud, where one entry is defined as |num_components| +// values of the |in_data|. +// DataTypeT is the data type of input and predicted values. +// CorrTypeT is the data type used for storing corrected values. +template +class PredictionSchemeTypedDecoderInterface + : public PredictionSchemeDecoderInterface { + public: + // Reverts changes made by the prediction scheme during encoding. + virtual bool ComputeOriginalValues( + const CorrTypeT *in_corr, DataTypeT *out_data, int size, + int num_components, const PointIndex *entry_to_point_id_map) = 0; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODER_INTERFACE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h new file mode 100644 index 00000000000..47c1532ad98 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoding_transform.h @@ -0,0 +1,65 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODING_TRANSFORM_H_ + +#include "draco/compression/config/compression_shared.h" +#include "draco/core/decoder_buffer.h" + +namespace draco { + +// PredictionSchemeDecodingTransform is used to transform predicted values and +// correction values into the final original attribute values. +// DataTypeT is the data type of predicted values. +// CorrTypeT is the data type used for storing corrected values. It allows +// transforms to store corrections into a different type or format compared to +// the predicted data. +template +class PredictionSchemeDecodingTransform { + public: + typedef CorrTypeT CorrType; + PredictionSchemeDecodingTransform() : num_components_(0) {} + + void Init(int num_components) { num_components_ = num_components; } + + // Computes the original value from the input predicted value and the decoded + // corrections. The default implementation is equal to std:plus. + inline void ComputeOriginalValue(const DataTypeT *predicted_vals, + const CorrTypeT *corr_vals, + DataTypeT *out_original_vals) const { + static_assert(std::is_same::value, + "For the default prediction transform, correction and input " + "data must be of the same type."); + for (int i = 0; i < num_components_; ++i) { + out_original_vals[i] = predicted_vals[i] + corr_vals[i]; + } + } + + // Decodes any transform specific data. Called before Init() method. + bool DecodeTransformData(DecoderBuffer * /* buffer */) { return true; } + + // Should return true if all corrected values are guaranteed to be positive. + bool AreCorrectionsPositive() const { return false; } + + protected: + int num_components() const { return num_components_; } + + private: + int num_components_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DECODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h new file mode 100644 index 00000000000..ae72c71208a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_decoder.h @@ -0,0 +1,65 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DELTA_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DELTA_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h" + +namespace draco { + +// Decoder for values encoded with delta coding. See the corresponding encoder +// for more details. +template +class PredictionSchemeDeltaDecoder + : public PredictionSchemeDecoder { + public: + using CorrType = + typename PredictionSchemeDecoder::CorrType; + // Initialized the prediction scheme. + explicit PredictionSchemeDeltaDecoder(const PointAttribute *attribute) + : PredictionSchemeDecoder(attribute) {} + PredictionSchemeDeltaDecoder(const PointAttribute *attribute, + const TransformT &transform) + : PredictionSchemeDecoder(attribute, transform) {} + + bool ComputeOriginalValues(const CorrType *in_corr, DataTypeT *out_data, + int size, int num_components, + const PointIndex *entry_to_point_id_map) override; + PredictionSchemeMethod GetPredictionMethod() const override { + return PREDICTION_DIFFERENCE; + } + bool IsInitialized() const override { return true; } +}; + +template +bool PredictionSchemeDeltaDecoder::ComputeOriginalValues( + const CorrType *in_corr, DataTypeT *out_data, int size, int num_components, + const PointIndex *) { + this->transform().Init(num_components); + // Decode the original value for the first element. + std::unique_ptr zero_vals(new DataTypeT[num_components]()); + this->transform().ComputeOriginalValue(zero_vals.get(), in_corr, out_data); + + // Decode data from the front using D(i) = D(i) + D(i - 1). + for (int i = num_components; i < size; i += num_components) { + this->transform().ComputeOriginalValue(out_data + i - num_components, + in_corr + i, out_data + i); + } + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DELTA_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h new file mode 100644 index 00000000000..324afafa637 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h @@ -0,0 +1,69 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DELTA_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DELTA_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h" + +namespace draco { + +// Basic prediction scheme based on computing backward differences between +// stored attribute values (also known as delta-coding). Usually works better +// than the reference point prediction scheme, because nearby values are often +// encoded next to each other. +template +class PredictionSchemeDeltaEncoder + : public PredictionSchemeEncoder { + public: + using CorrType = + typename PredictionSchemeEncoder::CorrType; + // Initialized the prediction scheme. + explicit PredictionSchemeDeltaEncoder(const PointAttribute *attribute) + : PredictionSchemeEncoder(attribute) {} + PredictionSchemeDeltaEncoder(const PointAttribute *attribute, + const TransformT &transform) + : PredictionSchemeEncoder(attribute, transform) {} + + bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrType *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) override; + PredictionSchemeMethod GetPredictionMethod() const override { + return PREDICTION_DIFFERENCE; + } + bool IsInitialized() const override { return true; } +}; + +template +bool PredictionSchemeDeltaEncoder< + DataTypeT, TransformT>::ComputeCorrectionValues(const DataTypeT *in_data, + CorrType *out_corr, + int size, + int num_components, + const PointIndex *) { + this->transform().Init(in_data, size, num_components); + // Encode data from the back using D(i) = D(i) - D(i - 1). + for (int i = size - num_components; i > 0; i -= num_components) { + this->transform().ComputeCorrection( + in_data + i, in_data + i - num_components, out_corr + i); + } + // Encode correction for the first element. + std::unique_ptr zero_vals(new DataTypeT[num_components]()); + this->transform().ComputeCorrection(in_data, zero_vals.get(), out_corr); + return true; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_DELTA_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h new file mode 100644 index 00000000000..2a211a9fc20 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h @@ -0,0 +1,90 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_H_ + +#include + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h" + +// Prediction schemes can be used during encoding and decoding of vertex +// attributes to predict attribute values based on the previously +// encoded/decoded data. The differences between the original and predicted +// attribute values are used to compute correction values that can be usually +// encoded with fewer bits compared to the original data. +namespace draco { + +// Abstract base class for typed prediction schemes. It provides basic access +// to the encoded attribute and to the supplied prediction transform. +template > +class PredictionSchemeEncoder : public PredictionSchemeTypedEncoderInterface< + DataTypeT, typename TransformT::CorrType> { + public: + typedef DataTypeT DataType; + typedef TransformT Transform; + // Correction type needs to be defined in the prediction transform class. + typedef typename Transform::CorrType CorrType; + explicit PredictionSchemeEncoder(const PointAttribute *attribute) + : PredictionSchemeEncoder(attribute, Transform()) {} + PredictionSchemeEncoder(const PointAttribute *attribute, + const Transform &transform) + : attribute_(attribute), transform_(transform) {} + + bool EncodePredictionData(EncoderBuffer *buffer) override { + if (!transform_.EncodeTransformData(buffer)) { + return false; + } + return true; + } + + const PointAttribute *GetAttribute() const override { return attribute(); } + + // Returns the number of parent attributes that are needed for the prediction. + int GetNumParentAttributes() const override { return 0; } + + // Returns the type of each of the parent attribute. + GeometryAttribute::Type GetParentAttributeType(int /* i */) const override { + return GeometryAttribute::INVALID; + } + + // Sets the required parent attribute. + bool SetParentAttribute(const PointAttribute * /* att */) override { + return false; + } + + bool AreCorrectionsPositive() override { + return transform_.AreCorrectionsPositive(); + } + + PredictionSchemeTransformType GetTransformType() const override { + return transform_.GetType(); + } + + protected: + inline const PointAttribute *attribute() const { return attribute_; } + inline const Transform &transform() const { return transform_; } + inline Transform &transform() { return transform_; } + + private: + const PointAttribute *attribute_; + Transform transform_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc new file mode 100644 index 00000000000..428340da013 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc @@ -0,0 +1,74 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h" + +namespace draco { + +PredictionSchemeMethod SelectPredictionMethod( + int att_id, const PointCloudEncoder *encoder) { + if (encoder->options()->GetSpeed() >= 10) { + // Selected fastest, though still doing some compression. + return PREDICTION_DIFFERENCE; + } + if (encoder->GetGeometryType() == TRIANGULAR_MESH) { + // Use speed setting to select the best encoding method. + const PointAttribute *const att = encoder->point_cloud()->attribute(att_id); + if (att->attribute_type() == GeometryAttribute::TEX_COORD) { + if (encoder->options()->GetSpeed() < 4) { + // Use texture coordinate prediction for speeds 0, 1, 2, 3. + return MESH_PREDICTION_TEX_COORDS_PORTABLE; + } + } + if (att->attribute_type() == GeometryAttribute::NORMAL) { +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + if (encoder->options()->GetSpeed() < 4) { + // Use geometric normal prediction for speeds 0, 1, 2, 3. + return MESH_PREDICTION_GEOMETRIC_NORMAL; + } +#endif + return PREDICTION_DIFFERENCE; // default + } + // Handle other attribute types. + if (encoder->options()->GetSpeed() >= 8) { + return PREDICTION_DIFFERENCE; + } + if (encoder->options()->GetSpeed() >= 2 || + encoder->point_cloud()->num_points() < 40) { + // Parallelogram prediction is used for speeds 2 - 7 or when the overhead + // of using constrained multi-parallelogram would be too high. + return MESH_PREDICTION_PARALLELOGRAM; + } + // Multi-parallelogram is used for speeds 0, 1. + return MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM; + } + // Default option is delta coding. + return PREDICTION_DIFFERENCE; +} + +// Returns the preferred prediction scheme based on the encoder options. +PredictionSchemeMethod GetPredictionMethodFromOptions( + int att_id, const EncoderOptions &options) { + const int pred_type = + options.GetAttributeInt(att_id, "prediction_scheme", -1); + if (pred_type == -1) { + return PREDICTION_UNDEFINED; + } + if (pred_type < 0 || pred_type >= NUM_PREDICTION_SCHEMES) { + return PREDICTION_NONE; + } + return static_cast(pred_type); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h new file mode 100644 index 00000000000..40a7683aa0d --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h @@ -0,0 +1,129 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Functions for creating prediction schemes for encoders using the provided +// prediction method id. + +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_FACTORY_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_FACTORY_H_ + +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h" +#endif +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_encoder.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_delta_encoder.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h" +#include "draco/compression/mesh/mesh_encoder.h" + +namespace draco { + +// Selects a prediction method based on the input geometry type and based on the +// encoder options. +PredictionSchemeMethod SelectPredictionMethod(int att_id, + const PointCloudEncoder *encoder); + +// Factory class for creating mesh prediction schemes. +template +struct MeshPredictionSchemeEncoderFactory { + template + std::unique_ptr> operator()( + PredictionSchemeMethod method, const PointAttribute *attribute, + const TransformT &transform, const MeshDataT &mesh_data, + uint16_t bitstream_version) { + if (method == MESH_PREDICTION_PARALLELOGRAM) { + return std::unique_ptr>( + new MeshPredictionSchemeParallelogramEncoder( + attribute, transform, mesh_data)); + } else if (method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM) { + return std::unique_ptr>( + new MeshPredictionSchemeConstrainedMultiParallelogramEncoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } else if (method == MESH_PREDICTION_TEX_COORDS_PORTABLE) { + return std::unique_ptr>( + new MeshPredictionSchemeTexCoordsPortableEncoder< + DataTypeT, TransformT, MeshDataT>(attribute, transform, + mesh_data)); + } +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + return std::unique_ptr>( + new MeshPredictionSchemeGeometricNormalEncoder( + attribute, transform, mesh_data)); + } +#endif + return nullptr; + } +}; + +// Creates a prediction scheme for a given encoder and given prediction method. +// The prediction schemes are automatically initialized with encoder specific +// data if needed. +template +std::unique_ptr> +CreatePredictionSchemeForEncoder(PredictionSchemeMethod method, int att_id, + const PointCloudEncoder *encoder, + const TransformT &transform) { + const PointAttribute *const att = encoder->point_cloud()->attribute(att_id); + if (method == PREDICTION_UNDEFINED) { + method = SelectPredictionMethod(att_id, encoder); + } + if (method == PREDICTION_NONE) { + return nullptr; // No prediction is used. + } + if (encoder->GetGeometryType() == TRIANGULAR_MESH) { + // Cast the encoder to mesh encoder. This is not necessarily safe if there + // is some other encoder decides to use TRIANGULAR_MESH as the return type, + // but unfortunately there is not nice work around for this without using + // RTTI (double dispatch and similar concepts will not work because of the + // template nature of the prediction schemes). + const MeshEncoder *const mesh_encoder = + static_cast(encoder); + auto ret = CreateMeshPredictionScheme< + MeshEncoder, PredictionSchemeEncoder, + MeshPredictionSchemeEncoderFactory>( + mesh_encoder, method, att_id, transform, kDracoMeshBitstreamVersion); + if (ret) { + return ret; + } + // Otherwise try to create another prediction scheme. + } + // Create delta encoder. + return std::unique_ptr>( + new PredictionSchemeDeltaEncoder(att, transform)); +} + +// Create a prediction scheme using a default transform constructor. +template +std::unique_ptr> +CreatePredictionSchemeForEncoder(PredictionSchemeMethod method, int att_id, + const PointCloudEncoder *encoder) { + return CreatePredictionSchemeForEncoder( + method, att_id, encoder, TransformT()); +} + +// Returns the preferred prediction scheme based on the encoder options. +PredictionSchemeMethod GetPredictionMethodFromOptions( + int att_id, const EncoderOptions &options); + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_FACTORY_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h new file mode 100644 index 00000000000..ab64bce7114 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h @@ -0,0 +1,55 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h" +#include "draco/core/encoder_buffer.h" + +// Prediction schemes can be used during encoding and decoding of attributes +// to predict attribute values based on the previously encoded/decoded data. +// See prediction_scheme.h for more details. +namespace draco { + +// Abstract interface for all prediction schemes used during attribute encoding. +class PredictionSchemeEncoderInterface : public PredictionSchemeInterface { + public: + // Method that can be used to encode any prediction scheme specific data + // into the output buffer. + virtual bool EncodePredictionData(EncoderBuffer *buffer) = 0; +}; + +// A specialized version of the prediction scheme interface for specific +// input and output data types. +// |entry_to_point_id_map| is the mapping between value entries to point ids +// of the associated point cloud, where one entry is defined as |num_components| +// values of the |in_data|. +// DataTypeT is the data type of input and predicted values. +// CorrTypeT is the data type used for storing corrected values. +template +class PredictionSchemeTypedEncoderInterface + : public PredictionSchemeEncoderInterface { + public: + // Applies the prediction scheme when encoding the attribute. + // |in_data| contains value entries to be encoded. + // |out_corr| is an output array containing the to be encoded corrections. + virtual bool ComputeCorrectionValues( + const DataTypeT *in_data, CorrTypeT *out_corr, int size, + int num_components, const PointIndex *entry_to_point_id_map) = 0; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h new file mode 100644 index 00000000000..0929492aaec --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoding_transform.h @@ -0,0 +1,77 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_TRANSFORM_H_ + +#include "draco/compression/config/compression_shared.h" +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// PredictionSchemeEncodingTransform is used to transform predicted values into +// correction values. +// CorrTypeT is the data type used for storing corrected values. It allows +// transforms to store corrections into a different type or format compared to +// the predicted data. +template +class PredictionSchemeEncodingTransform { + public: + typedef CorrTypeT CorrType; + PredictionSchemeEncodingTransform() : num_components_(0) {} + + PredictionSchemeTransformType GetType() const { + return PREDICTION_TRANSFORM_DELTA; + } + + // Performs any custom initialization of the transform for the encoder. + // |size| = total number of values in |orig_data| (i.e., number of entries * + // number of components). + void Init(const DataTypeT * /* orig_data */, int /* size */, + int num_components) { + num_components_ = num_components; + } + + // Computes the corrections based on the input original values and the + // predicted values. The correction is always computed for all components + // of the input element. |val_id| is the id of the input value + // (i.e., element_id * num_components). The default implementation is equal to + // std::minus. + inline void ComputeCorrection(const DataTypeT *original_vals, + const DataTypeT *predicted_vals, + CorrTypeT *out_corr_vals) { + static_assert(std::is_same::value, + "For the default prediction transform, correction and input " + "data must be of the same type."); + for (int i = 0; i < num_components_; ++i) { + out_corr_vals[i] = original_vals[i] - predicted_vals[i]; + } + } + + // Encode any transform specific data. + bool EncodeTransformData(EncoderBuffer * /* buffer */) { return true; } + + // Should return true if all corrected values are guaranteed to be positive. + bool AreCorrectionsPositive() const { return false; } + + protected: + int num_components() const { return num_components_; } + + private: + int num_components_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h new file mode 100644 index 00000000000..b36c4c8a273 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_factory.h @@ -0,0 +1,85 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Functions for creating prediction schemes from a provided prediction method +// name. The functions in this file can create only basic prediction schemes +// that don't require any encoder or decoder specific data. To create more +// sophisticated prediction schemes, use functions from either +// prediction_scheme_encoder_factory.h or, +// prediction_scheme_decoder_factory.h. + +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_FACTORY_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_FACTORY_H_ + +#include "draco/compression/attributes/mesh_attribute_indices_encoding_data.h" +#include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h" +#include "draco/compression/config/compression_shared.h" +#include "draco/mesh/mesh_attribute_corner_table.h" + +namespace draco { + +template +std::unique_ptr CreateMeshPredictionScheme( + const EncodingDataSourceT *source, PredictionSchemeMethod method, + int att_id, const typename PredictionSchemeT::Transform &transform, + uint16_t bitstream_version) { + const PointAttribute *const att = source->point_cloud()->attribute(att_id); + if (source->GetGeometryType() == TRIANGULAR_MESH && + (method == MESH_PREDICTION_PARALLELOGRAM || + method == MESH_PREDICTION_MULTI_PARALLELOGRAM || + method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM || + method == MESH_PREDICTION_TEX_COORDS_PORTABLE || + method == MESH_PREDICTION_GEOMETRIC_NORMAL || + method == MESH_PREDICTION_TEX_COORDS_DEPRECATED)) { + const CornerTable *const ct = source->GetCornerTable(); + const MeshAttributeIndicesEncodingData *const encoding_data = + source->GetAttributeEncodingData(att_id); + if (ct == nullptr || encoding_data == nullptr) { + // No connectivity data found. + return nullptr; + } + // Connectivity data exists. + const MeshAttributeCornerTable *const att_ct = + source->GetAttributeCornerTable(att_id); + if (att_ct != nullptr) { + typedef MeshPredictionSchemeData MeshData; + MeshData md; + md.Set(source->mesh(), att_ct, + &encoding_data->encoded_attribute_value_index_to_corner_map, + &encoding_data->vertex_to_encoded_attribute_value_index_map); + MeshPredictionSchemeFactoryT factory; + auto ret = factory(method, att, transform, md, bitstream_version); + if (ret) { + return ret; + } + } else { + typedef MeshPredictionSchemeData MeshData; + MeshData md; + md.Set(source->mesh(), ct, + &encoding_data->encoded_attribute_value_index_to_corner_map, + &encoding_data->vertex_to_encoded_attribute_value_index_map); + MeshPredictionSchemeFactoryT factory; + auto ret = factory(method, att, transform, md, bitstream_version); + if (ret) { + return ret; + } + } + } + return nullptr; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_FACTORY_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h new file mode 100644 index 00000000000..c9b3706930f --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_INTERFACE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_INTERFACE_H_ + +#include "draco/attributes/point_attribute.h" +#include "draco/compression/config/compression_shared.h" + +// Prediction schemes can be used during encoding and decoding of attributes +// to predict attribute values based on the previously encoded/decoded data. +// See prediction_scheme.h for more details. +namespace draco { + +// Abstract interface for all prediction schemes used during attribute encoding. +class PredictionSchemeInterface { + public: + virtual ~PredictionSchemeInterface() = default; + virtual PredictionSchemeMethod GetPredictionMethod() const = 0; + + // Returns the encoded attribute. + virtual const PointAttribute *GetAttribute() const = 0; + + // Returns true when the prediction scheme is initialized with all data it + // needs. + virtual bool IsInitialized() const = 0; + + // Returns the number of parent attributes that are needed for the prediction. + virtual int GetNumParentAttributes() const = 0; + + // Returns the type of each of the parent attribute. + virtual GeometryAttribute::Type GetParentAttributeType(int i) const = 0; + + // Sets the required parent attribute. + // Returns false if the attribute doesn't meet the requirements of the + // prediction scheme. + virtual bool SetParentAttribute(const PointAttribute *att) = 0; + + // Method should return true if the prediction scheme guarantees that all + // correction values are always positive (or at least non-negative). + virtual bool AreCorrectionsPositive() = 0; + + // Returns the transform type used by the prediction scheme. + virtual PredictionSchemeTransformType GetTransformType() const = 0; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_INTERFACE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h new file mode 100644 index 00000000000..5a6c7c2dd45 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h @@ -0,0 +1,118 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_DECODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_DECODING_TRANSFORM_H_ + +#include + +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h" +#include "draco/core/decoder_buffer.h" +#include "draco/core/macros.h" +#include "draco/core/vector_d.h" + +namespace draco { + +// Class for converting correction values transformed by the canonicalized +// normal octahedron transform back to the original values. See the +// corresponding encoder for more details. +template +class PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform + : public PredictionSchemeNormalOctahedronCanonicalizedTransformBase< + DataTypeT> { + public: + typedef VectorD Point2; + typedef DataTypeT CorrType; + typedef DataTypeT DataType; + + PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform() {} + + // Dummy to fulfill concept. + void Init(int num_components) {} + + bool DecodeTransformData(DecoderBuffer *buffer) { + DataTypeT max_quantized_value, center_value; + if (!buffer->Decode(&max_quantized_value)) { + return false; + } + if (!buffer->Decode(¢er_value)) { + return false; + } + (void)center_value; + if (!this->set_max_quantized_value(max_quantized_value)) { + return false; + } + // Account for reading wrong values, e.g., due to fuzzing. + if (this->quantization_bits() < 2) { + return false; + } + if (this->quantization_bits() > 30) { + return false; + } + return true; + } + + inline void ComputeOriginalValue(const DataType *pred_vals, + const CorrType *corr_vals, + DataType *out_orig_vals) const { + DRACO_DCHECK_LE(pred_vals[0], 2 * this->center_value()); + DRACO_DCHECK_LE(pred_vals[1], 2 * this->center_value()); + DRACO_DCHECK_LE(corr_vals[0], 2 * this->center_value()); + DRACO_DCHECK_LE(corr_vals[1], 2 * this->center_value()); + + DRACO_DCHECK_LE(0, pred_vals[0]); + DRACO_DCHECK_LE(0, pred_vals[1]); + DRACO_DCHECK_LE(0, corr_vals[0]); + DRACO_DCHECK_LE(0, corr_vals[1]); + + const Point2 pred = Point2(pred_vals[0], pred_vals[1]); + const Point2 corr = Point2(corr_vals[0], corr_vals[1]); + const Point2 orig = ComputeOriginalValue(pred, corr); + + out_orig_vals[0] = orig[0]; + out_orig_vals[1] = orig[1]; + } + + private: + Point2 ComputeOriginalValue(Point2 pred, Point2 corr) const { + const Point2 t(this->center_value(), this->center_value()); + pred = pred - t; + const bool pred_is_in_diamond = this->IsInDiamond(pred[0], pred[1]); + if (!pred_is_in_diamond) { + this->InvertDiamond(&pred[0], &pred[1]); + } + const bool pred_is_in_bottom_left = this->IsInBottomLeft(pred); + const int32_t rotation_count = this->GetRotationCount(pred); + if (!pred_is_in_bottom_left) { + pred = this->RotatePoint(pred, rotation_count); + } + Point2 orig = pred + corr; + orig[0] = this->ModMax(orig[0]); + orig[1] = this->ModMax(orig[1]); + if (!pred_is_in_bottom_left) { + const int32_t reverse_rotation_count = (4 - rotation_count) % 4; + orig = this->RotatePoint(orig, reverse_rotation_count); + } + if (!pred_is_in_diamond) { + this->InvertDiamond(&orig[0], &orig[1]); + } + orig = orig + t; + return orig; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_DECODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h new file mode 100644 index 00000000000..0dc96967b10 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h @@ -0,0 +1,116 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_ENCODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_ENCODING_TRANSFORM_H_ + +#include + +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h" +#include "draco/core/encoder_buffer.h" +#include "draco/core/macros.h" +#include "draco/core/vector_d.h" + +namespace draco { + +// The transform works on octahedral coordinates for normals. The square is +// subdivided into four inner triangles (diamond) and four outer triangles. The +// inner triangles are associated with the upper part of the octahedron and the +// outer triangles are associated with the lower part. +// Given a prediction value P and the actual value Q that should be encoded, +// this transform first checks if P is outside the diamond. If so, the outer +// triangles are flipped towards the inside and vice versa. Then it checks if p +// is in the bottom left quadrant. If it is not, it rotates p and q accordingly. +// The actual correction value is then based on the mapped and rotated P and Q +// values. The inversion tends to result in shorter correction vectors and the +// rotation makes it so that all long correction values are positive, reducing +// the possible value range of the correction values and increasing the +// occurrences of positive large correction values, which helps the entropy +// encoder. This is possible since P is also known by the decoder, see also +// ComputeCorrection and ComputeOriginalValue functions. +// Note that the tile is not periodic, which implies that the outer edges can +// not be identified, which requires us to use an odd number of values on each +// axis. +// DataTypeT is expected to be some integral type. +// +template +class PredictionSchemeNormalOctahedronCanonicalizedEncodingTransform + : public PredictionSchemeNormalOctahedronCanonicalizedTransformBase< + DataTypeT> { + public: + typedef PredictionSchemeNormalOctahedronCanonicalizedTransformBase + Base; + typedef VectorD Point2; + typedef DataTypeT CorrType; + typedef DataTypeT DataType; + + // We expect the mod value to be of the form 2^b-1. + explicit PredictionSchemeNormalOctahedronCanonicalizedEncodingTransform( + DataType max_quantized_value) + : Base(max_quantized_value) {} + + // Dummy function to fulfill concept. + void Init(const DataTypeT *orig_data, int size, int num_components) {} + + bool EncodeTransformData(EncoderBuffer *buffer) { + buffer->Encode(this->max_quantized_value()); + buffer->Encode(this->center_value()); + return true; + } + + inline void ComputeCorrection(const DataType *orig_vals, + const DataType *pred_vals, + CorrType *out_corr_vals) const { + DRACO_DCHECK_LE(pred_vals[0], this->center_value() * 2); + DRACO_DCHECK_LE(pred_vals[1], this->center_value() * 2); + DRACO_DCHECK_LE(orig_vals[0], this->center_value() * 2); + DRACO_DCHECK_LE(orig_vals[1], this->center_value() * 2); + DRACO_DCHECK_LE(0, pred_vals[0]); + DRACO_DCHECK_LE(0, pred_vals[1]); + DRACO_DCHECK_LE(0, orig_vals[0]); + DRACO_DCHECK_LE(0, orig_vals[1]); + + const Point2 orig = Point2(orig_vals[0], orig_vals[1]); + const Point2 pred = Point2(pred_vals[0], pred_vals[1]); + const Point2 corr = ComputeCorrection(orig, pred); + + out_corr_vals[0] = corr[0]; + out_corr_vals[1] = corr[1]; + } + + private: + Point2 ComputeCorrection(Point2 orig, Point2 pred) const { + const Point2 t(this->center_value(), this->center_value()); + orig = orig - t; + pred = pred - t; + if (!this->IsInDiamond(pred[0], pred[1])) { + this->InvertDiamond(&orig[0], &orig[1]); + this->InvertDiamond(&pred[0], &pred[1]); + } + if (!this->IsInBottomLeft(pred)) { + const int32_t rotation_count = this->GetRotationCount(pred); + orig = this->RotatePoint(orig, rotation_count); + pred = this->RotatePoint(pred, rotation_count); + } + Point2 corr = orig - pred; + corr[0] = this->MakePositive(corr[0]); + corr[1] = this->MakePositive(corr[1]); + return corr; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_ENCODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h new file mode 100644 index 00000000000..4a1e3a67b83 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_base.h @@ -0,0 +1,102 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_TRANSFORM_BASE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_TRANSFORM_BASE_H_ + +#include + +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h" +#include "draco/compression/config/compression_shared.h" +#include "draco/core/bit_utils.h" +#include "draco/core/macros.h" +#include "draco/core/vector_d.h" + +namespace draco { + +// Base class containing shared functionality used by both encoding and decoding +// canonicalized normal octahedron prediction scheme transforms. See the +// encoding transform for more details about the method. +template +class PredictionSchemeNormalOctahedronCanonicalizedTransformBase + : public PredictionSchemeNormalOctahedronTransformBase { + public: + typedef PredictionSchemeNormalOctahedronTransformBase Base; + typedef VectorD Point2; + typedef DataTypeT DataType; + + PredictionSchemeNormalOctahedronCanonicalizedTransformBase() : Base() {} + // We expect the mod value to be of the form 2^b-1. + explicit PredictionSchemeNormalOctahedronCanonicalizedTransformBase( + DataType mod_value) + : Base(mod_value) {} + + static constexpr PredictionSchemeTransformType GetType() { + return PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED; + } + + int32_t GetRotationCount(Point2 pred) const { + const DataType sign_x = pred[0]; + const DataType sign_y = pred[1]; + + int32_t rotation_count = 0; + if (sign_x == 0) { + if (sign_y == 0) { + rotation_count = 0; + } else if (sign_y > 0) { + rotation_count = 3; + } else { + rotation_count = 1; + } + } else if (sign_x > 0) { + if (sign_y >= 0) { + rotation_count = 2; + } else { + rotation_count = 1; + } + } else { + if (sign_y <= 0) { + rotation_count = 0; + } else { + rotation_count = 3; + } + } + return rotation_count; + } + + Point2 RotatePoint(Point2 p, int32_t rotation_count) const { + switch (rotation_count) { + case 1: + return Point2(p[1], -p[0]); + case 2: + return Point2(-p[0], -p[1]); + case 3: + return Point2(-p[1], p[0]); + default: + return p; + } + } + + bool IsInBottomLeft(const Point2 &p) const { + if (p[0] == 0 && p[1] == 0) { + return true; + } + return (p[0] < 0 && p[1] <= 0); + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_CANONICALIZED_TRANSFORM_BASE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h new file mode 100644 index 00000000000..a1bc4a327ac --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h @@ -0,0 +1,103 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_DECODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_DECODING_TRANSFORM_H_ + +#include + +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h" +#include "draco/core/decoder_buffer.h" +#include "draco/core/macros.h" +#include "draco/core/vector_d.h" +#include "draco/draco_features.h" + +namespace draco { + +// Class for converting correction values transformed by the octahedral normal +// transform back to the original values. See the corresponding encoder for more +// details. +template +class PredictionSchemeNormalOctahedronDecodingTransform + : public PredictionSchemeNormalOctahedronTransformBase { + public: + typedef VectorD Point2; + typedef DataTypeT CorrType; + typedef DataTypeT DataType; + + PredictionSchemeNormalOctahedronDecodingTransform() {} + + // Dummy function to fulfill concept. + void Init(int num_components) {} + bool DecodeTransformData(DecoderBuffer *buffer) { + DataTypeT max_quantized_value, center_value; + if (!buffer->Decode(&max_quantized_value)) { + return false; + } + if (buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 2)) { + if (!buffer->Decode(¢er_value)) { + return false; + } + } + (void)center_value; + return this->set_max_quantized_value(max_quantized_value); + } + + inline void ComputeOriginalValue(const DataType *pred_vals, + const CorrType *corr_vals, + DataType *out_orig_vals) const { + DRACO_DCHECK_LE(pred_vals[0], 2 * this->center_value()); + DRACO_DCHECK_LE(pred_vals[1], 2 * this->center_value()); + DRACO_DCHECK_LE(corr_vals[0], 2 * this->center_value()); + DRACO_DCHECK_LE(corr_vals[1], 2 * this->center_value()); + + DRACO_DCHECK_LE(0, pred_vals[0]); + DRACO_DCHECK_LE(0, pred_vals[1]); + DRACO_DCHECK_LE(0, corr_vals[0]); + DRACO_DCHECK_LE(0, corr_vals[1]); + + const Point2 pred = Point2(pred_vals[0], pred_vals[1]); + const Point2 corr = Point2(corr_vals[0], corr_vals[1]); + const Point2 orig = ComputeOriginalValue(pred, corr); + + out_orig_vals[0] = orig[0]; + out_orig_vals[1] = orig[1]; + } + + private: + Point2 ComputeOriginalValue(Point2 pred, const Point2 &corr) const { + const Point2 t(this->center_value(), this->center_value()); + pred = pred - t; + + const bool pred_is_in_diamond = this->IsInDiamond(pred[0], pred[1]); + if (!pred_is_in_diamond) { + this->InvertDiamond(&pred[0], &pred[1]); + } + Point2 orig = pred + corr; + orig[0] = this->ModMax(orig[0]); + orig[1] = this->ModMax(orig[1]); + if (!pred_is_in_diamond) { + this->InvertDiamond(&orig[0], &orig[1]); + } + orig = orig + t; + return orig; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_DECODING_TRANSFORM_H_ +#endif diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_encoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_encoding_transform.h new file mode 100644 index 00000000000..4abfef66903 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_encoding_transform.h @@ -0,0 +1,105 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_ENCODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_ENCODING_TRANSFORM_H_ + +#include + +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h" +#include "draco/core/encoder_buffer.h" +#include "draco/core/macros.h" +#include "draco/core/vector_d.h" + +namespace draco { + +// The transform works on octahedral coordinates for normals. The square is +// subdivided into four inner triangles (diamond) and four outer triangles. The +// inner triangles are associated with the upper part of the octahedron and the +// outer triangles are associated with the lower part. +// Given a prediction value P and the actual value Q that should be encoded, +// this transform first checks if P is outside the diamond. If so, the outer +// triangles are flipped towards the inside and vice versa. The actual +// correction value is then based on the mapped P and Q values. This tends to +// result in shorter correction vectors. +// This is possible since the P value is also known by the decoder, see also +// ComputeCorrection and ComputeOriginalValue functions. +// Note that the tile is not periodic, which implies that the outer edges can +// not be identified, which requires us to use an odd number of values on each +// axis. +// DataTypeT is expected to be some integral type. +// +template +class PredictionSchemeNormalOctahedronEncodingTransform + : public PredictionSchemeNormalOctahedronTransformBase { + public: + typedef PredictionSchemeNormalOctahedronTransformBase Base; + typedef VectorD Point2; + typedef DataTypeT CorrType; + typedef DataTypeT DataType; + + // We expect the mod value to be of the form 2^b-1. + explicit PredictionSchemeNormalOctahedronEncodingTransform( + DataType max_quantized_value) + : Base(max_quantized_value) {} + + void Init(const DataTypeT *orig_data, int size, int num_components) {} + + bool EncodeTransformData(EncoderBuffer *buffer) { + buffer->Encode(this->max_quantized_value()); + return true; + } + + inline void ComputeCorrection(const DataType *orig_vals, + const DataType *pred_vals, + CorrType *out_corr_vals) const { + DRACO_DCHECK_LE(pred_vals[0], this->center_value() * 2); + DRACO_DCHECK_LE(pred_vals[1], this->center_value() * 2); + DRACO_DCHECK_LE(orig_vals[0], this->center_value() * 2); + DRACO_DCHECK_LE(orig_vals[1], this->center_value() * 2); + DRACO_DCHECK_LE(0, pred_vals[0]); + DRACO_DCHECK_LE(0, pred_vals[1]); + DRACO_DCHECK_LE(0, orig_vals[0]); + DRACO_DCHECK_LE(0, orig_vals[1]); + + const Point2 orig = Point2(orig_vals[0], orig_vals[1]); + const Point2 pred = Point2(pred_vals[0], pred_vals[1]); + const Point2 corr = ComputeCorrection(orig, pred); + + out_corr_vals[0] = corr[0]; + out_corr_vals[1] = corr[1]; + } + + private: + Point2 ComputeCorrection(Point2 orig, Point2 pred) const { + const Point2 t(this->center_value(), this->center_value()); + orig = orig - t; + pred = pred - t; + + if (!this->IsInDiamond(pred[0], pred[1])) { + this->InvertDiamond(&orig[0], &orig[1]); + this->InvertDiamond(&pred[0], &pred[1]); + } + + Point2 corr = orig - pred; + corr[0] = this->MakePositive(corr[0]); + corr[1] = this->MakePositive(corr[1]); + return corr; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_ENCODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h new file mode 100644 index 00000000000..c9dd7d67bf4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_base.h @@ -0,0 +1,90 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_TRANSFORM_BASE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_TRANSFORM_BASE_H_ + +#include + +#include "draco/compression/attributes/normal_compression_utils.h" +#include "draco/compression/config/compression_shared.h" +#include "draco/core/bit_utils.h" +#include "draco/core/macros.h" +#include "draco/core/vector_d.h" + +namespace draco { + +// Base class containing shared functionality used by both encoding and decoding +// octahedral normal prediction scheme transforms. See the encoding transform +// for more details about the method. +template +class PredictionSchemeNormalOctahedronTransformBase { + public: + typedef VectorD Point2; + typedef DataTypeT DataType; + + PredictionSchemeNormalOctahedronTransformBase() {} + // We expect the mod value to be of the form 2^b-1. + explicit PredictionSchemeNormalOctahedronTransformBase( + DataType max_quantized_value) { + this->set_max_quantized_value(max_quantized_value); + } + + static constexpr PredictionSchemeTransformType GetType() { + return PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON; + } + + // We can return true as we keep correction values positive. + bool AreCorrectionsPositive() const { return true; } + + inline DataTypeT max_quantized_value() const { + return octahedron_tool_box_.max_quantized_value(); + } + inline DataTypeT center_value() const { + return octahedron_tool_box_.center_value(); + } + inline int32_t quantization_bits() const { + return octahedron_tool_box_.quantization_bits(); + } + + protected: + inline bool set_max_quantized_value(DataTypeT max_quantized_value) { + if (max_quantized_value % 2 == 0) { + return false; + } + int q = MostSignificantBit(max_quantized_value) + 1; + return octahedron_tool_box_.SetQuantizationBits(q); + } + + bool IsInDiamond(DataTypeT s, DataTypeT t) const { + return octahedron_tool_box_.IsInDiamond(s, t); + } + void InvertDiamond(DataTypeT *s, DataTypeT *t) const { + return octahedron_tool_box_.InvertDiamond(s, t); + } + + int32_t ModMax(int32_t x) const { return octahedron_tool_box_.ModMax(x); } + + // For correction values. + int32_t MakePositive(int32_t x) const { + return octahedron_tool_box_.MakePositive(x); + } + + private: + OctahedronToolBox octahedron_tool_box_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_NORMAL_OCTAHEDRON_TRANSFORM_BASE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h new file mode 100644 index 00000000000..0a14d0d9ba4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h @@ -0,0 +1,72 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_DECODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_DECODING_TRANSFORM_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h" +#include "draco/core/decoder_buffer.h" + +namespace draco { + +// PredictionSchemeWrapDecodingTransform unwraps values encoded with the +// PredictionSchemeWrapEncodingTransform. +// See prediction_scheme_wrap_transform_base.h for more details about the +// method. +template +class PredictionSchemeWrapDecodingTransform + : public PredictionSchemeWrapTransformBase { + public: + typedef CorrTypeT CorrType; + PredictionSchemeWrapDecodingTransform() {} + + // Computes the original value from the input predicted value and the decoded + // corrections. Values out of the bounds of the input values are unwrapped. + inline void ComputeOriginalValue(const DataTypeT *predicted_vals, + const CorrTypeT *corr_vals, + DataTypeT *out_original_vals) const { + predicted_vals = this->ClampPredictedValue(predicted_vals); + for (int i = 0; i < this->num_components(); ++i) { + out_original_vals[i] = predicted_vals[i] + corr_vals[i]; + if (out_original_vals[i] > this->max_value()) { + out_original_vals[i] -= this->max_dif(); + } else if (out_original_vals[i] < this->min_value()) { + out_original_vals[i] += this->max_dif(); + } + } + } + + bool DecodeTransformData(DecoderBuffer *buffer) { + DataTypeT min_value, max_value; + if (!buffer->Decode(&min_value)) { + return false; + } + if (!buffer->Decode(&max_value)) { + return false; + } + if (min_value > max_value) { + return false; + } + this->set_min_value(min_value); + this->set_max_value(max_value); + if (!this->InitCorrectionBounds()) { + return false; + } + return true; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_DECODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h new file mode 100644 index 00000000000..1f5e8b13584 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h @@ -0,0 +1,81 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_ENCODING_TRANSFORM_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_ENCODING_TRANSFORM_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h" +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// PredictionSchemeWrapEncodingTransform wraps input values using the wrapping +// scheme described in: prediction_scheme_wrap_transform_base.h . +template +class PredictionSchemeWrapEncodingTransform + : public PredictionSchemeWrapTransformBase { + public: + typedef CorrTypeT CorrType; + PredictionSchemeWrapEncodingTransform() {} + + void Init(const DataTypeT *orig_data, int size, int num_components) { + PredictionSchemeWrapTransformBase::Init(num_components); + // Go over the original values and compute the bounds. + if (size == 0) { + return; + } + DataTypeT min_value = orig_data[0]; + DataTypeT max_value = min_value; + for (int i = 1; i < size; ++i) { + if (orig_data[i] < min_value) { + min_value = orig_data[i]; + } else if (orig_data[i] > max_value) { + max_value = orig_data[i]; + } + } + this->set_min_value(min_value); + this->set_max_value(max_value); + this->InitCorrectionBounds(); + } + + // Computes the corrections based on the input original value and the + // predicted value. Out of bound correction values are wrapped around the max + // range of input values. + inline void ComputeCorrection(const DataTypeT *original_vals, + const DataTypeT *predicted_vals, + CorrTypeT *out_corr_vals) const { + for (int i = 0; i < this->num_components(); ++i) { + predicted_vals = this->ClampPredictedValue(predicted_vals); + out_corr_vals[i] = original_vals[i] - predicted_vals[i]; + // Wrap around if needed. + DataTypeT &corr_val = out_corr_vals[i]; + if (corr_val < this->min_correction()) { + corr_val += this->max_dif(); + } else if (corr_val > this->max_correction()) { + corr_val -= this->max_dif(); + } + } + } + + bool EncodeTransformData(EncoderBuffer *buffer) { + // Store the input value range as it is needed by the decoder. + buffer->Encode(this->min_value()); + buffer->Encode(this->max_value()); + return true; + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_ENCODING_TRANSFORM_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h new file mode 100644 index 00000000000..26f61fbaf6a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h @@ -0,0 +1,120 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_TRANSFORM_BASE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_TRANSFORM_BASE_H_ + +#include +#include + +#include "draco/compression/config/compression_shared.h" +#include "draco/core/macros.h" + +namespace draco { + +// PredictionSchemeWrapTransform uses the min and max bounds of the original +// data to wrap stored correction values around these bounds centered at 0, +// i.e., when the range of the original values O is between and +// N = MAX-MIN, we can then store any correction X = O - P, as: +// X + N, if X < -N / 2 +// X - N, if X > N / 2 +// X otherwise +// To unwrap this value, the decoder then simply checks whether the final +// corrected value F = P + X is out of the bounds of the input values. +// All out of bounds values are unwrapped using +// F + N, if F < MIN +// F - N, if F > MAX +// This wrapping can reduce the number of unique values, which translates to a +// better entropy of the stored values and better compression rates. +template +class PredictionSchemeWrapTransformBase { + public: + PredictionSchemeWrapTransformBase() + : num_components_(0), + min_value_(0), + max_value_(0), + max_dif_(0), + max_correction_(0), + min_correction_(0) {} + + static constexpr PredictionSchemeTransformType GetType() { + return PREDICTION_TRANSFORM_WRAP; + } + + void Init(int num_components) { + num_components_ = num_components; + clamped_value_.resize(num_components); + } + + bool AreCorrectionsPositive() const { return false; } + + inline const DataTypeT *ClampPredictedValue( + const DataTypeT *predicted_val) const { + for (int i = 0; i < this->num_components(); ++i) { + if (predicted_val[i] > max_value_) { + clamped_value_[i] = max_value_; + } else if (predicted_val[i] < min_value_) { + clamped_value_[i] = min_value_; + } else { + clamped_value_[i] = predicted_val[i]; + } + } + return &clamped_value_[0]; + } + + // TODO(hemmer): Consider refactoring to avoid this dummy. + int quantization_bits() const { + DRACO_DCHECK(false); + return -1; + } + + protected: + bool InitCorrectionBounds() { + const int64_t dif = + static_cast(max_value_) - static_cast(min_value_); + if (dif < 0 || dif >= std::numeric_limits::max()) { + return false; + } + max_dif_ = 1 + static_cast(dif); + max_correction_ = max_dif_ / 2; + min_correction_ = -max_correction_; + if ((max_dif_ & 1) == 0) { + max_correction_ -= 1; + } + return true; + } + + inline int num_components() const { return num_components_; } + inline DataTypeT min_value() const { return min_value_; } + inline void set_min_value(const DataTypeT &v) { min_value_ = v; } + inline DataTypeT max_value() const { return max_value_; } + inline void set_max_value(const DataTypeT &v) { max_value_ = v; } + inline DataTypeT max_dif() const { return max_dif_; } + inline DataTypeT min_correction() const { return min_correction_; } + inline DataTypeT max_correction() const { return max_correction_; } + + private: + int num_components_; + DataTypeT min_value_; + DataTypeT max_value_; + DataTypeT max_dif_; + DataTypeT max_correction_; + DataTypeT min_correction_; + // This is in fact just a tmp variable to avoid reallocation. + mutable std::vector clamped_value_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_TRANSFORM_BASE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.cc new file mode 100644 index 00000000000..b4ba24f2d31 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.cc @@ -0,0 +1,118 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_attribute_decoder.h" + +namespace draco { + +SequentialAttributeDecoder::SequentialAttributeDecoder() + : decoder_(nullptr), attribute_(nullptr), attribute_id_(-1) {} + +bool SequentialAttributeDecoder::Init(PointCloudDecoder *decoder, + int attribute_id) { + decoder_ = decoder; + attribute_ = decoder->point_cloud()->attribute(attribute_id); + attribute_id_ = attribute_id; + return true; +} + +bool SequentialAttributeDecoder::InitializeStandalone( + PointAttribute *attribute) { + attribute_ = attribute; + attribute_id_ = -1; + return true; +} + +bool SequentialAttributeDecoder::DecodePortableAttribute( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + if (attribute_->num_components() <= 0 || + !attribute_->Reset(point_ids.size())) { + return false; + } + if (!DecodeValues(point_ids, in_buffer)) { + return false; + } + return true; +} + +bool SequentialAttributeDecoder::DecodeDataNeededByPortableTransform( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + // Default implementation does not apply any transform. + return true; +} + +bool SequentialAttributeDecoder::TransformAttributeToOriginalFormat( + const std::vector &point_ids) { + // Default implementation does not apply any transform. + return true; +} + +const PointAttribute *SequentialAttributeDecoder::GetPortableAttribute() { + // If needed, copy point to attribute value index mapping from the final + // attribute to the portable attribute. + if (!attribute_->is_mapping_identity() && portable_attribute_ && + portable_attribute_->is_mapping_identity()) { + portable_attribute_->SetExplicitMapping(attribute_->indices_map_size()); + for (PointIndex i(0); + i < static_cast(attribute_->indices_map_size()); ++i) { + portable_attribute_->SetPointMapEntry(i, attribute_->mapped_index(i)); + } + } + return portable_attribute_.get(); +} + +bool SequentialAttributeDecoder::InitPredictionScheme( + PredictionSchemeInterface *ps) { + for (int i = 0; i < ps->GetNumParentAttributes(); ++i) { + const int att_id = decoder_->point_cloud()->GetNamedAttributeId( + ps->GetParentAttributeType(i)); + if (att_id == -1) { + return false; // Requested attribute does not exist. + } +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { + if (!ps->SetParentAttribute(decoder_->point_cloud()->attribute(att_id))) { + return false; + } + } else +#endif + { + const PointAttribute *const pa = decoder_->GetPortableAttribute(att_id); + if (pa == nullptr || !ps->SetParentAttribute(pa)) { + return false; + } + } + } + return true; +} + +bool SequentialAttributeDecoder::DecodeValues( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + const int32_t num_values = static_cast(point_ids.size()); + const int entry_size = static_cast(attribute_->byte_stride()); + std::unique_ptr value_data_ptr(new uint8_t[entry_size]); + uint8_t *const value_data = value_data_ptr.get(); + int out_byte_pos = 0; + // Decode raw attribute values in their original format. + for (int i = 0; i < num_values; ++i) { + if (!in_buffer->Decode(value_data, entry_size)) { + return false; + } + attribute_->buffer()->Write(out_byte_pos, value_data, entry_size); + out_byte_pos += entry_size; + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.h new file mode 100644 index 00000000000..d48119465a9 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoder.h @@ -0,0 +1,86 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h" +#include "draco/compression/point_cloud/point_cloud_decoder.h" +#include "draco/draco_features.h" + +namespace draco { + +// A base class for decoding attribute values encoded by the +// SequentialAttributeEncoder. +class SequentialAttributeDecoder { + public: + SequentialAttributeDecoder(); + virtual ~SequentialAttributeDecoder() = default; + + virtual bool Init(PointCloudDecoder *decoder, int attribute_id); + + // Initialization for a specific attribute. This can be used mostly for + // standalone decoding of an attribute without an PointCloudDecoder. + virtual bool InitializeStandalone(PointAttribute *attribute); + + // Performs lossless decoding of the portable attribute data. + virtual bool DecodePortableAttribute(const std::vector &point_ids, + DecoderBuffer *in_buffer); + + // Decodes any data needed to revert portable transform of the decoded + // attribute. + virtual bool DecodeDataNeededByPortableTransform( + const std::vector &point_ids, DecoderBuffer *in_buffer); + + // Reverts transformation performed by encoder in + // SequentialAttributeEncoder::TransformAttributeToPortableFormat() method. + virtual bool TransformAttributeToOriginalFormat( + const std::vector &point_ids); + + const PointAttribute *GetPortableAttribute(); + + const PointAttribute *attribute() const { return attribute_; } + PointAttribute *attribute() { return attribute_; } + int attribute_id() const { return attribute_id_; } + PointCloudDecoder *decoder() const { return decoder_; } + + protected: + // Should be used to initialize newly created prediction scheme. + // Returns false when the initialization failed (in which case the scheme + // cannot be used). + virtual bool InitPredictionScheme(PredictionSchemeInterface *ps); + + // The actual implementation of the attribute decoding. Should be overridden + // for specialized decoders. + virtual bool DecodeValues(const std::vector &point_ids, + DecoderBuffer *in_buffer); + + void SetPortableAttribute(std::unique_ptr att) { + portable_attribute_ = std::move(att); + } + + PointAttribute *portable_attribute() { return portable_attribute_.get(); } + + private: + PointCloudDecoder *decoder_; + PointAttribute *attribute_; + int attribute_id_; + + // Storage for decoded portable attribute (after lossless decoding). + std::unique_ptr portable_attribute_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc new file mode 100644 index 00000000000..0e5e26bcaa2 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc @@ -0,0 +1,149 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_attribute_decoders_controller.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED +#include "draco/compression/attributes/sequential_normal_attribute_decoder.h" +#endif +#include "draco/compression/attributes/sequential_quantization_attribute_decoder.h" +#include "draco/compression/config/compression_shared.h" + +namespace draco { + +SequentialAttributeDecodersController::SequentialAttributeDecodersController( + std::unique_ptr sequencer) + : sequencer_(std::move(sequencer)) {} + +bool SequentialAttributeDecodersController::DecodeAttributesDecoderData( + DecoderBuffer *buffer) { + if (!AttributesDecoder::DecodeAttributesDecoderData(buffer)) { + return false; + } + // Decode unique ids of all sequential encoders and create them. + const int32_t num_attributes = GetNumAttributes(); + sequential_decoders_.resize(num_attributes); + for (int i = 0; i < num_attributes; ++i) { + uint8_t decoder_type; + if (!buffer->Decode(&decoder_type)) { + return false; + } + // Create the decoder from the id. + sequential_decoders_[i] = CreateSequentialDecoder(decoder_type); + if (!sequential_decoders_[i]) { + return false; + } + if (!sequential_decoders_[i]->Init(GetDecoder(), GetAttributeId(i))) { + return false; + } + } + return true; +} + +bool SequentialAttributeDecodersController::DecodeAttributes( + DecoderBuffer *buffer) { + if (!sequencer_ || !sequencer_->GenerateSequence(&point_ids_)) { + return false; + } + // Initialize point to attribute value mapping for all decoded attributes. + const int32_t num_attributes = GetNumAttributes(); + for (int i = 0; i < num_attributes; ++i) { + PointAttribute *const pa = + GetDecoder()->point_cloud()->attribute(GetAttributeId(i)); + if (!sequencer_->UpdatePointToAttributeIndexMapping(pa)) { + return false; + } + } + return AttributesDecoder::DecodeAttributes(buffer); +} + +bool SequentialAttributeDecodersController::DecodePortableAttributes( + DecoderBuffer *in_buffer) { + const int32_t num_attributes = GetNumAttributes(); + for (int i = 0; i < num_attributes; ++i) { + if (!sequential_decoders_[i]->DecodePortableAttribute(point_ids_, + in_buffer)) { + return false; + } + } + return true; +} + +bool SequentialAttributeDecodersController:: + DecodeDataNeededByPortableTransforms(DecoderBuffer *in_buffer) { + const int32_t num_attributes = GetNumAttributes(); + for (int i = 0; i < num_attributes; ++i) { + if (!sequential_decoders_[i]->DecodeDataNeededByPortableTransform( + point_ids_, in_buffer)) { + return false; + } + } + return true; +} + +bool SequentialAttributeDecodersController:: + TransformAttributesToOriginalFormat() { + const int32_t num_attributes = GetNumAttributes(); + for (int i = 0; i < num_attributes; ++i) { + // Check whether the attribute transform should be skipped. + if (GetDecoder()->options()) { + const PointAttribute *const attribute = + sequential_decoders_[i]->attribute(); + const PointAttribute *const portable_attribute = + sequential_decoders_[i]->GetPortableAttribute(); + if (portable_attribute && + GetDecoder()->options()->GetAttributeBool( + attribute->attribute_type(), "skip_attribute_transform", false)) { + // Attribute transform should not be performed. In this case, we replace + // the output geometry attribute with the portable attribute. + // TODO(ostava): We can potentially avoid this copy by introducing a new + // mechanism that would allow to use the final attributes as portable + // attributes for predictors that may need them. + sequential_decoders_[i]->attribute()->CopyFrom(*portable_attribute); + continue; + } + } + if (!sequential_decoders_[i]->TransformAttributeToOriginalFormat( + point_ids_)) { + return false; + } + } + return true; +} + +std::unique_ptr +SequentialAttributeDecodersController::CreateSequentialDecoder( + uint8_t decoder_type) { + switch (decoder_type) { + case SEQUENTIAL_ATTRIBUTE_ENCODER_GENERIC: + return std::unique_ptr( + new SequentialAttributeDecoder()); + case SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER: + return std::unique_ptr( + new SequentialIntegerAttributeDecoder()); + case SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION: + return std::unique_ptr( + new SequentialQuantizationAttributeDecoder()); +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + case SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS: + return std::unique_ptr( + new SequentialNormalAttributeDecoder()); +#endif + default: + break; + } + // Unknown or unsupported decoder type. + return nullptr; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.h b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.h new file mode 100644 index 00000000000..abc1f368523 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_decoders_controller.h @@ -0,0 +1,61 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_DECODERS_CONTROLLER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_DECODERS_CONTROLLER_H_ + +#include "draco/compression/attributes/attributes_decoder.h" +#include "draco/compression/attributes/points_sequencer.h" +#include "draco/compression/attributes/sequential_attribute_decoder.h" + +namespace draco { + +// A basic implementation of an attribute decoder that decodes data encoded by +// the SequentialAttributeEncodersController class. The +// SequentialAttributeDecodersController creates a single +// AttributeIndexedValuesDecoder for each of the decoded attribute, where the +// type of the values decoder is determined by the unique identifier that was +// encoded by the encoder. +class SequentialAttributeDecodersController : public AttributesDecoder { + public: + explicit SequentialAttributeDecodersController( + std::unique_ptr sequencer); + + bool DecodeAttributesDecoderData(DecoderBuffer *buffer) override; + bool DecodeAttributes(DecoderBuffer *buffer) override; + const PointAttribute *GetPortableAttribute( + int32_t point_attribute_id) override { + const int32_t loc_id = GetLocalIdForPointAttribute(point_attribute_id); + if (loc_id < 0) { + return nullptr; + } + return sequential_decoders_[loc_id]->GetPortableAttribute(); + } + + protected: + bool DecodePortableAttributes(DecoderBuffer *in_buffer) override; + bool DecodeDataNeededByPortableTransforms(DecoderBuffer *in_buffer) override; + bool TransformAttributesToOriginalFormat() override; + virtual std::unique_ptr CreateSequentialDecoder( + uint8_t decoder_type); + + private: + std::vector> sequential_decoders_; + std::vector point_ids_; + std::unique_ptr sequencer_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_DECODERS_CONTROLLER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.cc new file mode 100644 index 00000000000..6bde3eeb3ba --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.cc @@ -0,0 +1,108 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_attribute_encoder.h" + +namespace draco { + +SequentialAttributeEncoder::SequentialAttributeEncoder() + : encoder_(nullptr), + attribute_(nullptr), + attribute_id_(-1), + is_parent_encoder_(false) {} + +bool SequentialAttributeEncoder::Init(PointCloudEncoder *encoder, + int attribute_id) { + encoder_ = encoder; + attribute_ = encoder_->point_cloud()->attribute(attribute_id); + attribute_id_ = attribute_id; + return true; +} + +bool SequentialAttributeEncoder::InitializeStandalone( + PointAttribute *attribute) { + attribute_ = attribute; + attribute_id_ = -1; + return true; +} + +bool SequentialAttributeEncoder::TransformAttributeToPortableFormat( + const std::vector &point_ids) { + // Default implementation doesn't transform the input data. + return true; +} + +bool SequentialAttributeEncoder::EncodePortableAttribute( + const std::vector &point_ids, EncoderBuffer *out_buffer) { + // Lossless encoding of the input values. + if (!EncodeValues(point_ids, out_buffer)) { + return false; + } + return true; +} + +bool SequentialAttributeEncoder::EncodeDataNeededByPortableTransform( + EncoderBuffer *out_buffer) { + // Default implementation doesn't transform the input data. + return true; +} + +bool SequentialAttributeEncoder::EncodeValues( + const std::vector &point_ids, EncoderBuffer *out_buffer) { + const int entry_size = static_cast(attribute_->byte_stride()); + const std::unique_ptr value_data_ptr(new uint8_t[entry_size]); + uint8_t *const value_data = value_data_ptr.get(); + // Encode all attribute values in their native raw format. + for (uint32_t i = 0; i < point_ids.size(); ++i) { + const AttributeValueIndex entry_id = attribute_->mapped_index(point_ids[i]); + attribute_->GetValue(entry_id, value_data); + out_buffer->Encode(value_data, entry_size); + } + return true; +} + +void SequentialAttributeEncoder::MarkParentAttribute() { + is_parent_encoder_ = true; +} + +bool SequentialAttributeEncoder::InitPredictionScheme( + PredictionSchemeInterface *ps) { + for (int i = 0; i < ps->GetNumParentAttributes(); ++i) { + const int att_id = encoder_->point_cloud()->GetNamedAttributeId( + ps->GetParentAttributeType(i)); + if (att_id == -1) { + return false; // Requested attribute does not exist. + } + parent_attributes_.push_back(att_id); + encoder_->MarkParentAttribute(att_id); + } + return true; +} + +bool SequentialAttributeEncoder::SetPredictionSchemeParentAttributes( + PredictionSchemeInterface *ps) { + for (int i = 0; i < ps->GetNumParentAttributes(); ++i) { + const int att_id = encoder_->point_cloud()->GetNamedAttributeId( + ps->GetParentAttributeType(i)); + if (att_id == -1) { + return false; // Requested attribute does not exist. + } + if (!ps->SetParentAttribute(encoder_->GetPortableAttribute(att_id))) { + return false; + } + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.h new file mode 100644 index 00000000000..00f62db8959 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoder.h @@ -0,0 +1,134 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h" +#include "draco/compression/point_cloud/point_cloud_encoder.h" + +namespace draco { + +// A base class for encoding attribute values of a single attribute using a +// given sequence of point ids. The default implementation encodes all attribute +// values directly to the buffer but derived classes can perform any custom +// encoding (such as quantization) by overriding the EncodeValues() method. +class SequentialAttributeEncoder { + public: + SequentialAttributeEncoder(); + virtual ~SequentialAttributeEncoder() = default; + + // Method that can be used for custom initialization of an attribute encoder, + // such as creation of prediction schemes and initialization of attribute + // encoder dependencies. + // |encoder| is the parent PointCloudEncoder, + // |attribute_id| is the id of the attribute that is being encoded by this + // encoder. + // This method is automatically called by the PointCloudEncoder after all + // attribute encoders are created and it should not be called explicitly from + // other places. + virtual bool Init(PointCloudEncoder *encoder, int attribute_id); + + // Initialization for a specific attribute. This can be used mostly for + // standalone encoding of an attribute without an PointCloudEncoder. + virtual bool InitializeStandalone(PointAttribute *attribute); + + // Transforms attribute data into format that is going to be encoded + // losslessly. The transform itself can be lossy. + virtual bool TransformAttributeToPortableFormat( + const std::vector &point_ids); + + // Performs lossless encoding of the transformed attribute data. + virtual bool EncodePortableAttribute(const std::vector &point_ids, + EncoderBuffer *out_buffer); + + // Encodes any data related to the portable attribute transform. + virtual bool EncodeDataNeededByPortableTransform(EncoderBuffer *out_buffer); + + virtual bool IsLossyEncoder() const { return false; } + + int NumParentAttributes() const { + return static_cast(parent_attributes_.size()); + } + int GetParentAttributeId(int i) const { return parent_attributes_[i]; } + + const PointAttribute *GetPortableAttribute() const { + if (portable_attribute_ != nullptr) { + return portable_attribute_.get(); + } + return attribute(); + } + + // Called when this attribute encoder becomes a parent encoder of another + // encoder. + void MarkParentAttribute(); + + virtual uint8_t GetUniqueId() const { + return SEQUENTIAL_ATTRIBUTE_ENCODER_GENERIC; + } + + const PointAttribute *attribute() const { return attribute_; } + int attribute_id() const { return attribute_id_; } + PointCloudEncoder *encoder() const { return encoder_; } + + protected: + // Should be used to initialize newly created prediction scheme. + // Returns false when the initialization failed (in which case the scheme + // cannot be used). + virtual bool InitPredictionScheme(PredictionSchemeInterface *ps); + + // Sets parent attributes for a given prediction scheme. Must be called + // after all prediction schemes are initialized, but before the prediction + // scheme is used. + virtual bool SetPredictionSchemeParentAttributes( + PredictionSchemeInterface *ps); + + // Encodes all attribute values in the specified order. Should be overridden + // for specialized encoders. + virtual bool EncodeValues(const std::vector &point_ids, + EncoderBuffer *out_buffer); + + bool is_parent_encoder() const { return is_parent_encoder_; } + + void SetPortableAttribute(std::unique_ptr att) { + portable_attribute_ = std::move(att); + } + + // Returns a mutable attribute that should be filled by derived encoders with + // the transformed version of the attribute data. To get a public const + // version, use the GetPortableAttribute() method. + PointAttribute *portable_attribute() { return portable_attribute_.get(); } + + private: + PointCloudEncoder *encoder_; + const PointAttribute *attribute_; + int attribute_id_; + + // List of attribute encoders that need to be encoded before this attribute. + // E.g. The parent attributes may be used to predict values used by this + // attribute encoder. + std::vector parent_attributes_; + + bool is_parent_encoder_; + + // Attribute that stores transformed data from the source attribute after it + // is processed through the ApplyTransform() method. Attribute data stored + // within this attribute is guaranteed to be encoded losslessly and it can be + // safely used for prediction of other attributes. + std::unique_ptr portable_attribute_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc new file mode 100644 index 00000000000..521935c1e99 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc @@ -0,0 +1,159 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_attribute_encoders_controller.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED +#include "draco/compression/attributes/sequential_normal_attribute_encoder.h" +#endif +#include "draco/compression/attributes/sequential_quantization_attribute_encoder.h" +#include "draco/compression/point_cloud/point_cloud_encoder.h" + +namespace draco { + +SequentialAttributeEncodersController::SequentialAttributeEncodersController( + std::unique_ptr sequencer) + : sequencer_(std::move(sequencer)) {} + +SequentialAttributeEncodersController::SequentialAttributeEncodersController( + std::unique_ptr sequencer, int att_id) + : AttributesEncoder(att_id), sequencer_(std::move(sequencer)) {} + +bool SequentialAttributeEncodersController::Init(PointCloudEncoder *encoder, + const PointCloud *pc) { + if (!AttributesEncoder::Init(encoder, pc)) { + return false; + } + if (!CreateSequentialEncoders()) { + return false; + } + // Initialize all value encoders. + for (uint32_t i = 0; i < num_attributes(); ++i) { + const int32_t att_id = GetAttributeId(i); + if (!sequential_encoders_[i]->Init(encoder, att_id)) { + return false; + } + } + return true; +} + +bool SequentialAttributeEncodersController::EncodeAttributesEncoderData( + EncoderBuffer *out_buffer) { + if (!AttributesEncoder::EncodeAttributesEncoderData(out_buffer)) { + return false; + } + // Encode a unique id of every sequential encoder. + for (uint32_t i = 0; i < sequential_encoders_.size(); ++i) { + out_buffer->Encode(sequential_encoders_[i]->GetUniqueId()); + } + return true; +} + +bool SequentialAttributeEncodersController::EncodeAttributes( + EncoderBuffer *buffer) { + if (!sequencer_ || !sequencer_->GenerateSequence(&point_ids_)) { + return false; + } + return AttributesEncoder::EncodeAttributes(buffer); +} + +bool SequentialAttributeEncodersController:: + TransformAttributesToPortableFormat() { + for (uint32_t i = 0; i < sequential_encoders_.size(); ++i) { + if (!sequential_encoders_[i]->TransformAttributeToPortableFormat( + point_ids_)) { + return false; + } + } + return true; +} + +bool SequentialAttributeEncodersController::EncodePortableAttributes( + EncoderBuffer *out_buffer) { + for (uint32_t i = 0; i < sequential_encoders_.size(); ++i) { + if (!sequential_encoders_[i]->EncodePortableAttribute(point_ids_, + out_buffer)) { + return false; + } + } + return true; +} + +bool SequentialAttributeEncodersController:: + EncodeDataNeededByPortableTransforms(EncoderBuffer *out_buffer) { + for (uint32_t i = 0; i < sequential_encoders_.size(); ++i) { + if (!sequential_encoders_[i]->EncodeDataNeededByPortableTransform( + out_buffer)) { + return false; + } + } + return true; +} + +bool SequentialAttributeEncodersController::CreateSequentialEncoders() { + sequential_encoders_.resize(num_attributes()); + for (uint32_t i = 0; i < num_attributes(); ++i) { + sequential_encoders_[i] = CreateSequentialEncoder(i); + if (sequential_encoders_[i] == nullptr) { + return false; + } + if (i < sequential_encoder_marked_as_parent_.size()) { + if (sequential_encoder_marked_as_parent_[i]) { + sequential_encoders_[i]->MarkParentAttribute(); + } + } + } + return true; +} + +std::unique_ptr +SequentialAttributeEncodersController::CreateSequentialEncoder(int i) { + const int32_t att_id = GetAttributeId(i); + const PointAttribute *const att = encoder()->point_cloud()->attribute(att_id); + + switch (att->data_type()) { + case DT_UINT8: + case DT_INT8: + case DT_UINT16: + case DT_INT16: + case DT_UINT32: + case DT_INT32: + return std::unique_ptr( + new SequentialIntegerAttributeEncoder()); + case DT_FLOAT32: + if (encoder()->options()->GetAttributeInt(att_id, "quantization_bits", + -1) > 0) { +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + if (att->attribute_type() == GeometryAttribute::NORMAL) { + // We currently only support normals with float coordinates + // and must be quantized. + return std::unique_ptr( + new SequentialNormalAttributeEncoder()); + } else { +#endif + return std::unique_ptr( + new SequentialQuantizationAttributeEncoder()); +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + } +#endif + } + break; + default: + break; + } + // Return the default attribute encoder. + return std::unique_ptr( + new SequentialAttributeEncoder()); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.h b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.h new file mode 100644 index 00000000000..13c2704ec0a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.h @@ -0,0 +1,115 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_ENCODERS_CONTROLLER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_ENCODERS_CONTROLLER_H_ + +#include "draco/compression/attributes/attributes_encoder.h" +#include "draco/compression/attributes/points_sequencer.h" +#include "draco/compression/attributes/sequential_attribute_encoder.h" + +namespace draco { + +// A basic implementation of an attribute encoder that can be used to encode +// an arbitrary set of attributes. The encoder creates a sequential attribute +// encoder for each encoded attribute (see sequential_attribute_encoder.h) and +// then it encodes all attribute values in an order defined by a point sequence +// generated in the GeneratePointSequence() method. The default implementation +// generates a linear sequence of all points, but derived classes can generate +// any custom sequence. +class SequentialAttributeEncodersController : public AttributesEncoder { + public: + explicit SequentialAttributeEncodersController( + std::unique_ptr sequencer); + SequentialAttributeEncodersController( + std::unique_ptr sequencer, int point_attrib_id); + + bool Init(PointCloudEncoder *encoder, const PointCloud *pc) override; + bool EncodeAttributesEncoderData(EncoderBuffer *out_buffer) override; + bool EncodeAttributes(EncoderBuffer *buffer) override; + uint8_t GetUniqueId() const override { return BASIC_ATTRIBUTE_ENCODER; } + + int NumParentAttributes(int32_t point_attribute_id) const override { + const int32_t loc_id = GetLocalIdForPointAttribute(point_attribute_id); + if (loc_id < 0) { + return 0; + } + return sequential_encoders_[loc_id]->NumParentAttributes(); + } + + int GetParentAttributeId(int32_t point_attribute_id, + int32_t parent_i) const override { + const int32_t loc_id = GetLocalIdForPointAttribute(point_attribute_id); + if (loc_id < 0) { + return -1; + } + return sequential_encoders_[loc_id]->GetParentAttributeId(parent_i); + } + + bool MarkParentAttribute(int32_t point_attribute_id) override { + const int32_t loc_id = GetLocalIdForPointAttribute(point_attribute_id); + if (loc_id < 0) { + return false; + } + // Mark the attribute encoder as parent (even when if it is not created + // yet). + if (sequential_encoder_marked_as_parent_.size() <= loc_id) { + sequential_encoder_marked_as_parent_.resize(loc_id + 1, false); + } + sequential_encoder_marked_as_parent_[loc_id] = true; + + if (sequential_encoders_.size() <= loc_id) { + return true; // Sequential encoders not generated yet. + } + sequential_encoders_[loc_id]->MarkParentAttribute(); + return true; + } + + const PointAttribute *GetPortableAttribute( + int32_t point_attribute_id) override { + const int32_t loc_id = GetLocalIdForPointAttribute(point_attribute_id); + if (loc_id < 0) { + return nullptr; + } + return sequential_encoders_[loc_id]->GetPortableAttribute(); + } + + protected: + bool TransformAttributesToPortableFormat() override; + bool EncodePortableAttributes(EncoderBuffer *out_buffer) override; + bool EncodeDataNeededByPortableTransforms(EncoderBuffer *out_buffer) override; + + // Creates all sequential encoders (one for each attribute associated with the + // encoder). + virtual bool CreateSequentialEncoders(); + + // Create a sequential encoder for a given attribute based on the attribute + // type + // and the provided encoder options. + virtual std::unique_ptr CreateSequentialEncoder( + int i); + + private: + std::vector> sequential_encoders_; + + // Flag for each sequential attribute encoder indicating whether it was marked + // as parent attribute or not. + std::vector sequential_encoder_marked_as_parent_; + std::vector point_ids_; + std::unique_ptr sequencer_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_ATTRIBUTE_ENCODERS_CONTROLLER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc new file mode 100644 index 00000000000..d01fb26aad4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc @@ -0,0 +1,235 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_integer_attribute_decoder.h" + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h" +#include "draco/compression/entropy/symbol_decoding.h" + +namespace draco { + +SequentialIntegerAttributeDecoder::SequentialIntegerAttributeDecoder() {} + +bool SequentialIntegerAttributeDecoder::Init(PointCloudDecoder *decoder, + int attribute_id) { + if (!SequentialAttributeDecoder::Init(decoder, attribute_id)) { + return false; + } + return true; +} + +bool SequentialIntegerAttributeDecoder::TransformAttributeToOriginalFormat( + const std::vector &point_ids) { +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (decoder() && + decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { + return true; // Don't revert the transform here for older files. + } +#endif + return StoreValues(static_cast(point_ids.size())); +} + +bool SequentialIntegerAttributeDecoder::DecodeValues( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + // Decode prediction scheme. + int8_t prediction_scheme_method; + if (!in_buffer->Decode(&prediction_scheme_method)) { + return false; + } + if (prediction_scheme_method != PREDICTION_NONE) { + int8_t prediction_transform_type; + if (!in_buffer->Decode(&prediction_transform_type)) { + return false; + } + prediction_scheme_ = CreateIntPredictionScheme( + static_cast(prediction_scheme_method), + static_cast(prediction_transform_type)); + } + + if (prediction_scheme_) { + if (!InitPredictionScheme(prediction_scheme_.get())) { + return false; + } + } + + if (!DecodeIntegerValues(point_ids, in_buffer)) { + return false; + } + +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + const int32_t num_values = static_cast(point_ids.size()); + if (decoder() && + decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { + // For older files, revert the transform right after we decode the data. + if (!StoreValues(num_values)) { + return false; + } + } +#endif + return true; +} + +std::unique_ptr> +SequentialIntegerAttributeDecoder::CreateIntPredictionScheme( + PredictionSchemeMethod method, + PredictionSchemeTransformType transform_type) { + if (transform_type != PREDICTION_TRANSFORM_WRAP) { + return nullptr; // For now we support only wrap transform. + } + return CreatePredictionSchemeForDecoder< + int32_t, PredictionSchemeWrapDecodingTransform>( + method, attribute_id(), decoder()); +} + +bool SequentialIntegerAttributeDecoder::DecodeIntegerValues( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + const int num_components = GetNumValueComponents(); + if (num_components <= 0) { + return false; + } + const size_t num_entries = point_ids.size(); + const size_t num_values = num_entries * num_components; + PreparePortableAttribute(static_cast(num_entries), num_components); + int32_t *const portable_attribute_data = GetPortableAttributeData(); + if (portable_attribute_data == nullptr) { + return false; + } + uint8_t compressed; + if (!in_buffer->Decode(&compressed)) { + return false; + } + if (compressed > 0) { + // Decode compressed values. + if (!DecodeSymbols(static_cast(num_values), num_components, + in_buffer, + reinterpret_cast(portable_attribute_data))) { + return false; + } + } else { + // Decode the integer data directly. + // Get the number of bytes for a given entry. + uint8_t num_bytes; + if (!in_buffer->Decode(&num_bytes)) { + return false; + } + if (num_bytes == DataTypeLength(DT_INT32)) { + if (portable_attribute()->buffer()->data_size() < + sizeof(int32_t) * num_values) { + return false; + } + if (!in_buffer->Decode(portable_attribute_data, + sizeof(int32_t) * num_values)) { + return false; + } + } else { + if (portable_attribute()->buffer()->data_size() < + num_bytes * num_values) { + return false; + } + if (in_buffer->remaining_size() < + static_cast(num_bytes) * static_cast(num_values)) { + return false; + } + for (size_t i = 0; i < num_values; ++i) { + if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) + return false; + } + } + } + + if (num_values > 0 && (prediction_scheme_ == nullptr || + !prediction_scheme_->AreCorrectionsPositive())) { + // Convert the values back to the original signed format. + ConvertSymbolsToSignedInts( + reinterpret_cast(portable_attribute_data), + static_cast(num_values), portable_attribute_data); + } + + // If the data was encoded with a prediction scheme, we must revert it. + if (prediction_scheme_) { + if (!prediction_scheme_->DecodePredictionData(in_buffer)) { + return false; + } + + if (num_values > 0) { + if (!prediction_scheme_->ComputeOriginalValues( + portable_attribute_data, portable_attribute_data, + static_cast(num_values), num_components, point_ids.data())) { + return false; + } + } + } + return true; +} + +bool SequentialIntegerAttributeDecoder::StoreValues(uint32_t num_values) { + switch (attribute()->data_type()) { + case DT_UINT8: + StoreTypedValues(num_values); + break; + case DT_INT8: + StoreTypedValues(num_values); + break; + case DT_UINT16: + StoreTypedValues(num_values); + break; + case DT_INT16: + StoreTypedValues(num_values); + break; + case DT_UINT32: + StoreTypedValues(num_values); + break; + case DT_INT32: + StoreTypedValues(num_values); + break; + default: + return false; + } + return true; +} + +template +void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) { + const int num_components = attribute()->num_components(); + const int entry_size = sizeof(AttributeTypeT) * num_components; + const std::unique_ptr att_val( + new AttributeTypeT[num_components]); + const int32_t *const portable_attribute_data = GetPortableAttributeData(); + int val_id = 0; + int out_byte_pos = 0; + for (uint32_t i = 0; i < num_values; ++i) { + for (int c = 0; c < num_components; ++c) { + const AttributeTypeT value = + static_cast(portable_attribute_data[val_id++]); + att_val[c] = value; + } + // Store the integer value into the attribute buffer. + attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size); + out_byte_pos += entry_size; + } +} + +void SequentialIntegerAttributeDecoder::PreparePortableAttribute( + int num_entries, int num_components) { + GeometryAttribute va; + va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32, + false, num_components * DataTypeLength(DT_INT32), 0); + std::unique_ptr port_att(new PointAttribute(va)); + port_att->SetIdentityMapping(); + port_att->Reset(num_entries); + SetPortableAttribute(std::move(port_att)); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.h new file mode 100644 index 00000000000..ef48ed817a5 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.h @@ -0,0 +1,76 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_INTEGER_ATTRIBUTE_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_INTEGER_ATTRIBUTE_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder.h" +#include "draco/compression/attributes/sequential_attribute_decoder.h" +#include "draco/draco_features.h" + +namespace draco { + +// Decoder for attributes encoded with the SequentialIntegerAttributeEncoder. +class SequentialIntegerAttributeDecoder : public SequentialAttributeDecoder { + public: + SequentialIntegerAttributeDecoder(); + bool Init(PointCloudDecoder *decoder, int attribute_id) override; + + bool TransformAttributeToOriginalFormat( + const std::vector &point_ids) override; + + protected: + bool DecodeValues(const std::vector &point_ids, + DecoderBuffer *in_buffer) override; + virtual bool DecodeIntegerValues(const std::vector &point_ids, + DecoderBuffer *in_buffer); + + // Returns a prediction scheme that should be used for decoding of the + // integer values. + virtual std::unique_ptr> + CreateIntPredictionScheme(PredictionSchemeMethod method, + PredictionSchemeTransformType transform_type); + + // Returns the number of integer attribute components. In general, this + // can be different from the number of components of the input attribute. + virtual int32_t GetNumValueComponents() const { + return attribute()->num_components(); + } + + // Called after all integer values are decoded. The implementation should + // use this method to store the values into the attribute. + virtual bool StoreValues(uint32_t num_values); + + void PreparePortableAttribute(int num_entries, int num_components); + + int32_t *GetPortableAttributeData() { + if (portable_attribute()->size() == 0) { + return nullptr; + } + return reinterpret_cast( + portable_attribute()->GetAddress(AttributeValueIndex(0))); + } + + private: + // Stores decoded values into the attribute with a data type AttributeTypeT. + template + void StoreTypedValues(uint32_t num_values); + + std::unique_ptr> + prediction_scheme_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_INTEGER_ATTRIBUTE_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc new file mode 100644 index 00000000000..2889e0521a0 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc @@ -0,0 +1,230 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_integer_attribute_encoder.h" + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_encoding_transform.h" +#include "draco/compression/entropy/symbol_encoding.h" +#include "draco/core/bit_utils.h" + +namespace draco { + +SequentialIntegerAttributeEncoder::SequentialIntegerAttributeEncoder() {} + +bool SequentialIntegerAttributeEncoder::Init(PointCloudEncoder *encoder, + int attribute_id) { + if (!SequentialAttributeEncoder::Init(encoder, attribute_id)) { + return false; + } + if (GetUniqueId() == SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER) { + // When encoding integers, this encoder currently works only for integer + // attributes up to 32 bits. + switch (attribute()->data_type()) { + case DT_INT8: + case DT_UINT8: + case DT_INT16: + case DT_UINT16: + case DT_INT32: + case DT_UINT32: + break; + default: + return false; + } + } + // Init prediction scheme. + const PredictionSchemeMethod prediction_scheme_method = + GetPredictionMethodFromOptions(attribute_id, *encoder->options()); + + prediction_scheme_ = CreateIntPredictionScheme(prediction_scheme_method); + + if (prediction_scheme_ && !InitPredictionScheme(prediction_scheme_.get())) { + prediction_scheme_ = nullptr; + } + + return true; +} + +bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat( + const std::vector &point_ids) { + if (encoder()) { + if (!PrepareValues(point_ids, encoder()->point_cloud()->num_points())) { + return false; + } + } else { + if (!PrepareValues(point_ids, 0)) { + return false; + } + } + + // Update point to attribute mapping with the portable attribute if the + // attribute is a parent attribute (for now, we can skip it otherwise). + if (is_parent_encoder()) { + // First create map between original attribute value indices and new ones + // (determined by the encoding order). + const PointAttribute *const orig_att = attribute(); + PointAttribute *const portable_att = portable_attribute(); + IndexTypeVector + value_to_value_map(orig_att->size()); + for (int i = 0; i < point_ids.size(); ++i) { + value_to_value_map[orig_att->mapped_index(point_ids[i])] = + AttributeValueIndex(i); + } + // Go over all points of the original attribute and update the mapping in + // the portable attribute. + for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) { + portable_att->SetPointMapEntry( + i, value_to_value_map[orig_att->mapped_index(i)]); + } + } + return true; +} + +std::unique_ptr> +SequentialIntegerAttributeEncoder::CreateIntPredictionScheme( + PredictionSchemeMethod method) { + return CreatePredictionSchemeForEncoder< + int32_t, PredictionSchemeWrapEncodingTransform>( + method, attribute_id(), encoder()); +} + +bool SequentialIntegerAttributeEncoder::EncodeValues( + const std::vector &point_ids, EncoderBuffer *out_buffer) { + // Initialize general quantization data. + const PointAttribute *const attrib = attribute(); + if (attrib->size() == 0) { + return true; + } + + int8_t prediction_scheme_method = PREDICTION_NONE; + if (prediction_scheme_) { + if (!SetPredictionSchemeParentAttributes(prediction_scheme_.get())) { + return false; + } + prediction_scheme_method = + static_cast(prediction_scheme_->GetPredictionMethod()); + } + out_buffer->Encode(prediction_scheme_method); + if (prediction_scheme_) { + out_buffer->Encode( + static_cast(prediction_scheme_->GetTransformType())); + } + + const int num_components = portable_attribute()->num_components(); + const int num_values = + static_cast(num_components * portable_attribute()->size()); + const int32_t *const portable_attribute_data = GetPortableAttributeData(); + + // We need to keep the portable data intact, but several encoding steps can + // result in changes of this data, e.g., by applying prediction schemes that + // change the data in place. To preserve the portable data we store and + // process all encoded data in a separate array. + std::vector encoded_data(num_values); + + // All integer values are initialized. Process them using the prediction + // scheme if we have one. + if (prediction_scheme_) { + prediction_scheme_->ComputeCorrectionValues( + portable_attribute_data, &encoded_data[0], num_values, num_components, + point_ids.data()); + } + + if (prediction_scheme_ == nullptr || + !prediction_scheme_->AreCorrectionsPositive()) { + const int32_t *const input = + prediction_scheme_ ? encoded_data.data() : portable_attribute_data; + ConvertSignedIntsToSymbols(input, num_values, + reinterpret_cast(&encoded_data[0])); + } + + if (encoder() == nullptr || encoder()->options()->GetGlobalBool( + "use_built_in_attribute_compression", true)) { + out_buffer->Encode(static_cast(1)); + Options symbol_encoding_options; + if (encoder() != nullptr) { + SetSymbolEncodingCompressionLevel(&symbol_encoding_options, + 10 - encoder()->options()->GetSpeed()); + } + if (!EncodeSymbols(reinterpret_cast(encoded_data.data()), + static_cast(point_ids.size()) * num_components, + num_components, &symbol_encoding_options, out_buffer)) { + return false; + } + } else { + // No compression. Just store the raw integer values, using the number of + // bytes as needed. + + // To compute the maximum bit-length, first OR all values. + uint32_t masked_value = 0; + for (uint32_t i = 0; i < static_cast(num_values); ++i) { + masked_value |= encoded_data[i]; + } + // Compute the msb of the ORed value. + int value_msb_pos = 0; + if (masked_value != 0) { + value_msb_pos = MostSignificantBit(masked_value); + } + const int num_bytes = 1 + value_msb_pos / 8; + + out_buffer->Encode(static_cast(0)); + out_buffer->Encode(static_cast(num_bytes)); + + if (num_bytes == DataTypeLength(DT_INT32)) { + out_buffer->Encode(encoded_data.data(), sizeof(int32_t) * num_values); + } else { + for (uint32_t i = 0; i < static_cast(num_values); ++i) { + out_buffer->Encode(encoded_data.data() + i, num_bytes); + } + } + } + if (prediction_scheme_) { + prediction_scheme_->EncodePredictionData(out_buffer); + } + return true; +} + +bool SequentialIntegerAttributeEncoder::PrepareValues( + const std::vector &point_ids, int num_points) { + // Convert all values to int32_t format. + const PointAttribute *const attrib = attribute(); + const int num_components = attrib->num_components(); + const int num_entries = static_cast(point_ids.size()); + PreparePortableAttribute(num_entries, num_components, num_points); + int32_t dst_index = 0; + int32_t *const portable_attribute_data = GetPortableAttributeData(); + for (PointIndex pi : point_ids) { + const AttributeValueIndex att_id = attrib->mapped_index(pi); + if (!attrib->ConvertValue(att_id, + portable_attribute_data + dst_index)) { + return false; + } + dst_index += num_components; + } + return true; +} + +void SequentialIntegerAttributeEncoder::PreparePortableAttribute( + int num_entries, int num_components, int num_points) { + GeometryAttribute va; + va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32, + false, num_components * DataTypeLength(DT_INT32), 0); + std::unique_ptr port_att(new PointAttribute(va)); + port_att->Reset(num_entries); + SetPortableAttribute(std::move(port_att)); + if (num_points) { + portable_attribute()->SetExplicitMapping(num_points); + } +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.h new file mode 100644 index 00000000000..c1d6222ef40 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.h @@ -0,0 +1,67 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_INTEGER_ATTRIBUTE_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_INTEGER_ATTRIBUTE_ENCODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder.h" +#include "draco/compression/attributes/sequential_attribute_encoder.h" + +namespace draco { + +// Attribute encoder designed for lossless encoding of integer attributes. The +// attribute values can be pre-processed by a prediction scheme and compressed +// with a built-in entropy coder. +class SequentialIntegerAttributeEncoder : public SequentialAttributeEncoder { + public: + SequentialIntegerAttributeEncoder(); + uint8_t GetUniqueId() const override { + return SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER; + } + + bool Init(PointCloudEncoder *encoder, int attribute_id) override; + bool TransformAttributeToPortableFormat( + const std::vector &point_ids) override; + + protected: + bool EncodeValues(const std::vector &point_ids, + EncoderBuffer *out_buffer) override; + + // Returns a prediction scheme that should be used for encoding of the + // integer values. + virtual std::unique_ptr> + CreateIntPredictionScheme(PredictionSchemeMethod method); + + // Prepares the integer values that are going to be encoded. + virtual bool PrepareValues(const std::vector &point_ids, + int num_points); + + void PreparePortableAttribute(int num_entries, int num_components, + int num_points); + + int32_t *GetPortableAttributeData() { + return reinterpret_cast( + portable_attribute()->GetAddress(AttributeValueIndex(0))); + } + + private: + // Optional prediction scheme can be used to modify the integer values in + // order to make them easier to compress. + std::unique_ptr> + prediction_scheme_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_INTEGER_ATTRIBUTE_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc new file mode 100644 index 00000000000..017344393dc --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc @@ -0,0 +1,94 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_normal_attribute_decoder.h" + +#include "draco/attributes/attribute_octahedron_transform.h" +#include "draco/compression/attributes/normal_compression_utils.h" + +namespace draco { + +SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() + : quantization_bits_(-1) {} + +bool SequentialNormalAttributeDecoder::Init(PointCloudDecoder *decoder, + int attribute_id) { + if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) + return false; + // Currently, this encoder works only for 3-component normal vectors. + if (attribute()->num_components() != 3) { + return false; + } + // Also the data type must be DT_FLOAT32. + if (attribute()->data_type() != DT_FLOAT32) { + return false; + } + return true; +} + +bool SequentialNormalAttributeDecoder::DecodeIntegerValues( + const std::vector &point_ids, DecoderBuffer *in_buffer) { +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { + uint8_t quantization_bits; + if (!in_buffer->Decode(&quantization_bits)) { + return false; + } + quantization_bits_ = quantization_bits; + } +#endif + return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids, + in_buffer); +} + +bool SequentialNormalAttributeDecoder::DecodeDataNeededByPortableTransform( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) { + // For newer file version, decode attribute transform data here. + uint8_t quantization_bits; + if (!in_buffer->Decode(&quantization_bits)) { + return false; + } + quantization_bits_ = quantization_bits; + } + + // Store the decoded transform data in portable attribute. + AttributeOctahedronTransform octahedral_transform; + octahedral_transform.SetParameters(quantization_bits_); + return octahedral_transform.TransferToAttribute(portable_attribute()); +} + +bool SequentialNormalAttributeDecoder::StoreValues(uint32_t num_points) { + // Convert all quantized values back to floats. + const int num_components = attribute()->num_components(); + const int entry_size = sizeof(float) * num_components; + float att_val[3]; + int quant_val_id = 0; + int out_byte_pos = 0; + const int32_t *const portable_attribute_data = GetPortableAttributeData(); + OctahedronToolBox octahedron_tool_box; + if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) + return false; + for (uint32_t i = 0; i < num_points; ++i) { + const int32_t s = portable_attribute_data[quant_val_id++]; + const int32_t t = portable_attribute_data[quant_val_id++]; + octahedron_tool_box.QuantizedOctaherdalCoordsToUnitVector(s, t, att_val); + // Store the decoded floating point value into the attribute buffer. + attribute()->buffer()->Write(out_byte_pos, att_val, entry_size); + out_byte_pos += entry_size; + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h new file mode 100644 index 00000000000..860eacb4c84 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h @@ -0,0 +1,82 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ + +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h" +#include "draco/compression/attributes/sequential_integer_attribute_decoder.h" +#include "draco/draco_features.h" + +namespace draco { + +// Decoder for attributes encoded with SequentialNormalAttributeEncoder. +class SequentialNormalAttributeDecoder + : public SequentialIntegerAttributeDecoder { + public: + SequentialNormalAttributeDecoder(); + bool Init(PointCloudDecoder *decoder, int attribute_id) override; + + protected: + int32_t GetNumValueComponents() const override { + return 2; // We quantize everything into two components. + } + bool DecodeIntegerValues(const std::vector &point_ids, + DecoderBuffer *in_buffer) override; + bool DecodeDataNeededByPortableTransform( + const std::vector &point_ids, + DecoderBuffer *in_buffer) override; + bool StoreValues(uint32_t num_points) override; + + private: + int32_t quantization_bits_; + + std::unique_ptr> + CreateIntPredictionScheme( + PredictionSchemeMethod method, + PredictionSchemeTransformType transform_type) override { + switch (transform_type) { +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + case PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON: { + typedef PredictionSchemeNormalOctahedronDecodingTransform + Transform; + // At this point the decoder has not read the quantization bits, + // which is why we must construct the transform by default. + // See Transform.DecodeTransformData for more details. + return CreatePredictionSchemeForDecoder( + method, attribute_id(), decoder()); + } +#endif + case PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED: { + typedef PredictionSchemeNormalOctahedronCanonicalizedDecodingTransform< + int32_t> + Transform; + // At this point the decoder has not read the quantization bits, + // which is why we must construct the transform by default. + // See Transform.DecodeTransformData for more details. + return CreatePredictionSchemeForDecoder( + method, attribute_id(), decoder()); + } + default: + return nullptr; // Currently, we support only octahedron transform and + // octahedron transform canonicalized. + } + } +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc new file mode 100644 index 00000000000..23fa8bb7b39 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc @@ -0,0 +1,53 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_normal_attribute_encoder.h" + +#include "draco/compression/attributes/normal_compression_utils.h" + +namespace draco { + +bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder, + int attribute_id) { + if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) + return false; + // Currently this encoder works only for 3-component normal vectors. + if (attribute()->num_components() != 3) { + return false; + } + + // Initialize AttributeOctahedronTransform. + const int quantization_bits = encoder->options()->GetAttributeInt( + attribute_id, "quantization_bits", -1); + if (quantization_bits < 1) { + return false; + } + attribute_octahedron_transform_.SetParameters(quantization_bits); + return true; +} + +bool SequentialNormalAttributeEncoder::EncodeDataNeededByPortableTransform( + EncoderBuffer *out_buffer) { + return attribute_octahedron_transform_.EncodeParameters(out_buffer); +} + +bool SequentialNormalAttributeEncoder::PrepareValues( + const std::vector &point_ids, int num_points) { + SetPortableAttribute( + attribute_octahedron_transform_.GeneratePortableAttribute( + *(attribute()), point_ids, num_points)); + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.h new file mode 100644 index 00000000000..53705c5982b --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.h @@ -0,0 +1,82 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_ENCODER_H_ + +#include "draco/attributes/attribute_octahedron_transform.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h" +#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_encoding_transform.h" +#include "draco/compression/attributes/sequential_integer_attribute_encoder.h" +#include "draco/compression/config/compression_shared.h" + +namespace draco { + +// Class for encoding normal vectors using an octahedral encoding, see Cigolle +// et al.'14 “A Survey of Efficient Representations for Independent Unit +// Vectors”. Compared to the basic quantization encoder, this encoder results +// in a better compression rate under the same accuracy settings. Note that this +// encoder doesn't preserve the lengths of input vectors, therefore it will not +// work correctly when the input values are not normalized. +class SequentialNormalAttributeEncoder + : public SequentialIntegerAttributeEncoder { + public: + uint8_t GetUniqueId() const override { + return SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS; + } + bool IsLossyEncoder() const override { return true; } + + bool EncodeDataNeededByPortableTransform(EncoderBuffer *out_buffer) override; + + protected: + bool Init(PointCloudEncoder *encoder, int attribute_id) override; + + // Put quantized values in portable attribute for sequential encoding. + bool PrepareValues(const std::vector &point_ids, + int num_points) override; + + std::unique_ptr> + CreateIntPredictionScheme(PredictionSchemeMethod /* method */) override { + typedef PredictionSchemeNormalOctahedronCanonicalizedEncodingTransform< + int32_t> + Transform; + const int32_t quantization_bits = encoder()->options()->GetAttributeInt( + attribute_id(), "quantization_bits", -1); + const int32_t max_value = (1 << quantization_bits) - 1; + const Transform transform(max_value); + const PredictionSchemeMethod default_prediction_method = + SelectPredictionMethod(attribute_id(), encoder()); + const int32_t prediction_method = encoder()->options()->GetAttributeInt( + attribute_id(), "prediction_scheme", default_prediction_method); + + if (prediction_method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + return CreatePredictionSchemeForEncoder( + MESH_PREDICTION_GEOMETRIC_NORMAL, attribute_id(), encoder(), + transform); + } + if (prediction_method == PREDICTION_DIFFERENCE) { + return CreatePredictionSchemeForEncoder( + PREDICTION_DIFFERENCE, attribute_id(), encoder(), transform); + } + DRACO_DCHECK(false); // Should never be reached. + return nullptr; + } + + // Used for the conversion to quantized normals in octahedral format. + AttributeOctahedronTransform attribute_octahedron_transform_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc new file mode 100644 index 00000000000..bf925c4a595 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc @@ -0,0 +1,120 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_quantization_attribute_decoder.h" + +#include "draco/attributes/attribute_quantization_transform.h" +#include "draco/core/quantization_utils.h" + +namespace draco { + +SequentialQuantizationAttributeDecoder::SequentialQuantizationAttributeDecoder() + : quantization_bits_(-1), max_value_dif_(0.f) {} + +bool SequentialQuantizationAttributeDecoder::Init(PointCloudDecoder *decoder, + int attribute_id) { + if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) { + return false; + } + const PointAttribute *const attribute = + decoder->point_cloud()->attribute(attribute_id); + // Currently we can quantize only floating point arguments. + if (attribute->data_type() != DT_FLOAT32) { + return false; + } + return true; +} + +bool SequentialQuantizationAttributeDecoder::DecodeIntegerValues( + const std::vector &point_ids, DecoderBuffer *in_buffer) { +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0) && + !DecodeQuantizedDataInfo()) { + return false; + } +#endif + return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids, + in_buffer); +} + +bool SequentialQuantizationAttributeDecoder:: + DecodeDataNeededByPortableTransform( + const std::vector &point_ids, DecoderBuffer *in_buffer) { + if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) { + // Decode quantization data here only for files with bitstream version 2.0+ + if (!DecodeQuantizedDataInfo()) { + return false; + } + } + + // Store the decoded transform data in portable attribute; + AttributeQuantizationTransform transform; + transform.SetParameters(quantization_bits_, min_value_.get(), + attribute()->num_components(), max_value_dif_); + return transform.TransferToAttribute(portable_attribute()); +} + +bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_values) { + return DequantizeValues(num_values); +} + +bool SequentialQuantizationAttributeDecoder::DecodeQuantizedDataInfo() { + const int num_components = attribute()->num_components(); + min_value_ = std::unique_ptr(new float[num_components]); + if (!decoder()->buffer()->Decode(min_value_.get(), + sizeof(float) * num_components)) { + return false; + } + if (!decoder()->buffer()->Decode(&max_value_dif_)) { + return false; + } + uint8_t quantization_bits; + if (!decoder()->buffer()->Decode(&quantization_bits) || + quantization_bits > 31) { + return false; + } + quantization_bits_ = quantization_bits; + return true; +} + +bool SequentialQuantizationAttributeDecoder::DequantizeValues( + uint32_t num_values) { + // Convert all quantized values back to floats. + const int32_t max_quantized_value = + (1u << static_cast(quantization_bits_)) - 1; + const int num_components = attribute()->num_components(); + const int entry_size = sizeof(float) * num_components; + const std::unique_ptr att_val(new float[num_components]); + int quant_val_id = 0; + int out_byte_pos = 0; + Dequantizer dequantizer; + if (!dequantizer.Init(max_value_dif_, max_quantized_value)) { + return false; + } + const int32_t *const portable_attribute_data = GetPortableAttributeData(); + for (uint32_t i = 0; i < num_values; ++i) { + for (int c = 0; c < num_components; ++c) { + float value = + dequantizer.DequantizeFloat(portable_attribute_data[quant_val_id++]); + value = value + min_value_[c]; + att_val[c] = value; + } + // Store the floating point value into the attribute buffer. + attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size); + out_byte_pos += entry_size; + } + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h new file mode 100644 index 00000000000..c0b7637a750 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h @@ -0,0 +1,56 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ + +#include "draco/compression/attributes/sequential_integer_attribute_decoder.h" +#include "draco/draco_features.h" + +namespace draco { + +// Decoder for attribute values encoded with the +// SequentialQuantizationAttributeEncoder. +class SequentialQuantizationAttributeDecoder + : public SequentialIntegerAttributeDecoder { + public: + SequentialQuantizationAttributeDecoder(); + bool Init(PointCloudDecoder *decoder, int attribute_id) override; + + protected: + bool DecodeIntegerValues(const std::vector &point_ids, + DecoderBuffer *in_buffer) override; + bool DecodeDataNeededByPortableTransform( + const std::vector &point_ids, + DecoderBuffer *in_buffer) override; + bool StoreValues(uint32_t num_points) override; + + // Decodes data necessary for dequantizing the encoded values. + virtual bool DecodeQuantizedDataInfo(); + + // Dequantizes all values and stores them into the output attribute. + virtual bool DequantizeValues(uint32_t num_values); + + private: + // Max number of quantization bits used to encode each component of the + // attribute. + int32_t quantization_bits_; + + std::unique_ptr min_value_; + float max_value_dif_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc new file mode 100644 index 00000000000..cd5b8b141e0 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc @@ -0,0 +1,79 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/attributes/sequential_quantization_attribute_encoder.h" + +#include "draco/core/quantization_utils.h" + +namespace draco { + +SequentialQuantizationAttributeEncoder:: + SequentialQuantizationAttributeEncoder() {} + +bool SequentialQuantizationAttributeEncoder::Init(PointCloudEncoder *encoder, + int attribute_id) { + if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) { + return false; + } + // This encoder currently works only for floating point attributes. + const PointAttribute *const attribute = + encoder->point_cloud()->attribute(attribute_id); + if (attribute->data_type() != DT_FLOAT32) { + return false; + } + + // Initialize AttributeQuantizationTransform. + const int quantization_bits = encoder->options()->GetAttributeInt( + attribute_id, "quantization_bits", -1); + if (quantization_bits < 1) { + return false; + } + if (encoder->options()->IsAttributeOptionSet(attribute_id, + "quantization_origin") && + encoder->options()->IsAttributeOptionSet(attribute_id, + "quantization_range")) { + // Quantization settings are explicitly specified in the provided options. + std::vector quantization_origin(attribute->num_components()); + encoder->options()->GetAttributeVector(attribute_id, "quantization_origin", + attribute->num_components(), + &quantization_origin[0]); + const float range = encoder->options()->GetAttributeFloat( + attribute_id, "quantization_range", 1.f); + attribute_quantization_transform_.SetParameters( + quantization_bits, quantization_origin.data(), + attribute->num_components(), range); + } else { + // Compute quantization settings from the attribute values. + if (!attribute_quantization_transform_.ComputeParameters( + *attribute, quantization_bits)) { + return false; + } + } + return true; +} + +bool SequentialQuantizationAttributeEncoder:: + EncodeDataNeededByPortableTransform(EncoderBuffer *out_buffer) { + return attribute_quantization_transform_.EncodeParameters(out_buffer); +} + +bool SequentialQuantizationAttributeEncoder::PrepareValues( + const std::vector &point_ids, int num_points) { + SetPortableAttribute( + attribute_quantization_transform_.GeneratePortableAttribute( + *(attribute()), point_ids, num_points)); + return true; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.h new file mode 100644 index 00000000000..e9762bdd6d0 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.h @@ -0,0 +1,52 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_ENCODER_H_ + +#include "draco/attributes/attribute_quantization_transform.h" +#include "draco/compression/attributes/sequential_integer_attribute_encoder.h" + +namespace draco { + +class MeshEncoder; + +// Attribute encoder that quantizes floating point attribute values. The +// quantized values can be optionally compressed using an entropy coding. +class SequentialQuantizationAttributeEncoder + : public SequentialIntegerAttributeEncoder { + public: + SequentialQuantizationAttributeEncoder(); + uint8_t GetUniqueId() const override { + return SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION; + } + bool Init(PointCloudEncoder *encoder, int attribute_id) override; + + bool IsLossyEncoder() const override { return true; } + + bool EncodeDataNeededByPortableTransform(EncoderBuffer *out_buffer) override; + + protected: + // Put quantized values in portable attribute for sequential encoding. + bool PrepareValues(const std::vector &point_ids, + int num_points) override; + + private: + // Used for the quantization. + AttributeQuantizationTransform attribute_quantization_transform_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h new file mode 100644 index 00000000000..faacbd5b940 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides shared functions for adaptive rANS bit coding. +#ifndef DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_CODING_SHARED_H_ +#define DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_CODING_SHARED_H_ + +#include "draco/core/macros.h" + +namespace draco { + +// Clamp the probability p to a uint8_t in the range [1,255]. +inline uint8_t clamp_probability(double p) { + DRACO_DCHECK_LE(p, 1.0); + DRACO_DCHECK_LE(0.0, p); + uint32_t p_int = static_cast((p * 256) + 0.5); + p_int -= (p_int == 256); + p_int += (p_int == 0); + return static_cast(p_int); +} + +// Update the probability according to new incoming bit. +inline double update_probability(double old_p, bool bit) { + static constexpr double w = 128.0; + static constexpr double w0 = (w - 1.0) / w; + static constexpr double w1 = 1.0 / w; + return old_p * w0 + (!bit) * w1; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_CODING_SHARED_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.cc new file mode 100644 index 00000000000..056842c4a99 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.cc @@ -0,0 +1,70 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/bit_coders/adaptive_rans_bit_decoder.h" + +#include "draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h" + +namespace draco { + +AdaptiveRAnsBitDecoder::AdaptiveRAnsBitDecoder() : p0_f_(0.5) {} + +AdaptiveRAnsBitDecoder::~AdaptiveRAnsBitDecoder() { Clear(); } + +bool AdaptiveRAnsBitDecoder::StartDecoding(DecoderBuffer *source_buffer) { + Clear(); + + uint32_t size_in_bytes; + if (!source_buffer->Decode(&size_in_bytes)) { + return false; + } + if (size_in_bytes > source_buffer->remaining_size()) { + return false; + } + if (ans_read_init(&ans_decoder_, + reinterpret_cast( + const_cast(source_buffer->data_head())), + size_in_bytes) != 0) { + return false; + } + source_buffer->Advance(size_in_bytes); + return true; +} + +bool AdaptiveRAnsBitDecoder::DecodeNextBit() { + const uint8_t p0 = clamp_probability(p0_f_); + const bool bit = static_cast(rabs_read(&ans_decoder_, p0)); + p0_f_ = update_probability(p0_f_, bit); + return bit; +} + +void AdaptiveRAnsBitDecoder::DecodeLeastSignificantBits32(int nbits, + uint32_t *value) { + DRACO_DCHECK_EQ(true, nbits <= 32); + DRACO_DCHECK_EQ(true, nbits > 0); + + uint32_t result = 0; + while (nbits) { + result = (result << 1) + DecodeNextBit(); + --nbits; + } + *value = result; +} + +void AdaptiveRAnsBitDecoder::Clear() { + ans_read_end(&ans_decoder_); + p0_f_ = 0.5; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.h b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.h new file mode 100644 index 00000000000..a1ea011dd6a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_decoder.h @@ -0,0 +1,54 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides basic classes and functions for rANS bit decoding. +#ifndef DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_DECODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_DECODER_H_ + +#include + +#include "draco/compression/entropy/ans.h" +#include "draco/core/decoder_buffer.h" + +namespace draco { + +// Class for decoding a sequence of bits that were encoded with +// AdaptiveRAnsBitEncoder. +class AdaptiveRAnsBitDecoder { + public: + AdaptiveRAnsBitDecoder(); + ~AdaptiveRAnsBitDecoder(); + + // Sets |source_buffer| as the buffer to decode bits from. + bool StartDecoding(DecoderBuffer *source_buffer); + + // Decode one bit. Returns true if the bit is a 1, otherwise false. + bool DecodeNextBit(); + + // Decode the next |nbits| and return the sequence in |value|. |nbits| must be + // > 0 and <= 32. + void DecodeLeastSignificantBits32(int nbits, uint32_t *value); + + void EndDecoding() {} + + private: + void Clear(); + + AnsDecoder ans_decoder_; + double p0_f_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.cc new file mode 100644 index 00000000000..5ce9dc388b8 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.cc @@ -0,0 +1,59 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/bit_coders/adaptive_rans_bit_encoder.h" + +#include "draco/compression/bit_coders/adaptive_rans_bit_coding_shared.h" + +namespace draco { + +AdaptiveRAnsBitEncoder::AdaptiveRAnsBitEncoder() {} + +AdaptiveRAnsBitEncoder::~AdaptiveRAnsBitEncoder() { Clear(); } + +void AdaptiveRAnsBitEncoder::StartEncoding() { Clear(); } + +void AdaptiveRAnsBitEncoder::EndEncoding(EncoderBuffer *target_buffer) { + // Buffer for ans to write. + std::vector buffer(bits_.size() + 16); + AnsCoder ans_coder; + ans_write_init(&ans_coder, buffer.data()); + + // Unfortunately we have to encode the bits in reversed order, while the + // probabilities that should be given are those of the forward sequence. + double p0_f = 0.5; + std::vector p0s; + p0s.reserve(bits_.size()); + for (bool b : bits_) { + p0s.push_back(clamp_probability(p0_f)); + p0_f = update_probability(p0_f, b); + } + auto bit = bits_.rbegin(); + auto pit = p0s.rbegin(); + while (bit != bits_.rend()) { + rabs_write(&ans_coder, *bit, *pit); + ++bit; + ++pit; + } + + const uint32_t size_in_bytes = ans_write_end(&ans_coder); + target_buffer->Encode(size_in_bytes); + target_buffer->Encode(buffer.data(), size_in_bytes); + + Clear(); +} + +void AdaptiveRAnsBitEncoder::Clear() { bits_.clear(); } + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.h b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.h new file mode 100644 index 00000000000..9b1832844ad --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/adaptive_rans_bit_encoder.h @@ -0,0 +1,61 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides basic classes and functions for rANS bit encoding. +#ifndef DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_ENCODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_ENCODER_H_ + +#include + +#include "draco/compression/entropy/ans.h" +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// Class for adaptive encoding a sequence of bits using rANS. +class AdaptiveRAnsBitEncoder { + public: + AdaptiveRAnsBitEncoder(); + ~AdaptiveRAnsBitEncoder(); + + // Must be called before any Encode* function is called. + void StartEncoding(); + + // Encode one bit. If |bit| is true encode a 1, otherwise encode a 0. + void EncodeBit(bool bit) { bits_.push_back(bit); } + + // Encode |nbits| of |value|, starting from the least significant bit. + // |nbits| must be > 0 and <= 32. + void EncodeLeastSignificantBits32(int nbits, uint32_t value) { + DRACO_DCHECK_EQ(true, nbits <= 32); + DRACO_DCHECK_EQ(true, nbits > 0); + uint32_t selector = (1 << (nbits - 1)); + while (selector) { + EncodeBit(value & selector); + selector = selector >> 1; + } + } + + // Ends the bit encoding and stores the result into the target_buffer. + void EndEncoding(EncoderBuffer *target_buffer); + + private: + void Clear(); + + std::vector bits_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_ADAPTIVE_RANS_BIT_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.cc new file mode 100644 index 00000000000..2abe3382a4c --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.cc @@ -0,0 +1,54 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/bit_coders/direct_bit_decoder.h" + +namespace draco { + +DirectBitDecoder::DirectBitDecoder() : pos_(bits_.end()), num_used_bits_(0) {} + +DirectBitDecoder::~DirectBitDecoder() { Clear(); } + +bool DirectBitDecoder::StartDecoding(DecoderBuffer *source_buffer) { + Clear(); + uint32_t size_in_bytes; + if (!source_buffer->Decode(&size_in_bytes)) { + return false; + } + + // Check that size_in_bytes is > 0 and a multiple of 4 as the encoder always + // encodes 32 bit elements. + if (size_in_bytes == 0 || size_in_bytes & 0x3) { + return false; + } + if (size_in_bytes > source_buffer->remaining_size()) { + return false; + } + const uint32_t num_32bit_elements = size_in_bytes / 4; + bits_.resize(num_32bit_elements); + if (!source_buffer->Decode(bits_.data(), size_in_bytes)) { + return false; + } + pos_ = bits_.begin(); + num_used_bits_ = 0; + return true; +} + +void DirectBitDecoder::Clear() { + bits_.clear(); + num_used_bits_ = 0; + pos_ = bits_.end(); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.h b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.h new file mode 100644 index 00000000000..b9fbc2d6fed --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_decoder.h @@ -0,0 +1,90 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides direct encoding of bits with arithmetic encoder interface. +#ifndef DRACO_COMPRESSION_BIT_CODERS_DIRECT_BIT_DECODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_DIRECT_BIT_DECODER_H_ + +#include + +#include "draco/core/decoder_buffer.h" + +namespace draco { + +class DirectBitDecoder { + public: + DirectBitDecoder(); + ~DirectBitDecoder(); + + // Sets |source_buffer| as the buffer to decode bits from. + bool StartDecoding(DecoderBuffer *source_buffer); + + // Decode one bit. Returns true if the bit is a 1, otherwise false. + bool DecodeNextBit() { + const uint32_t selector = 1 << (31 - num_used_bits_); + if (pos_ == bits_.end()) { + return false; + } + const bool bit = *pos_ & selector; + ++num_used_bits_; + if (num_used_bits_ == 32) { + ++pos_; + num_used_bits_ = 0; + } + return bit; + } + + // Decode the next |nbits| and return the sequence in |value|. |nbits| must be + // > 0 and <= 32. + void DecodeLeastSignificantBits32(int nbits, uint32_t *value) { + DRACO_DCHECK_EQ(true, nbits <= 32); + DRACO_DCHECK_EQ(true, nbits > 0); + const int remaining = 32 - num_used_bits_; + if (nbits <= remaining) { + if (pos_ == bits_.end()) { + *value = 0; + return; + } + *value = (*pos_ << num_used_bits_) >> (32 - nbits); + num_used_bits_ += nbits; + if (num_used_bits_ == 32) { + ++pos_; + num_used_bits_ = 0; + } + } else { + if (pos_ + 1 == bits_.end()) { + *value = 0; + return; + } + const uint32_t value_l = ((*pos_) << num_used_bits_); + num_used_bits_ = nbits - remaining; + ++pos_; + const uint32_t value_r = (*pos_) >> (32 - num_used_bits_); + *value = (value_l >> (32 - num_used_bits_ - remaining)) | value_r; + } + } + + void EndDecoding() {} + + private: + void Clear(); + + std::vector bits_; + std::vector::const_iterator pos_; + uint32_t num_used_bits_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_DIRECT_BIT_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.cc new file mode 100644 index 00000000000..d39143cf56a --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.cc @@ -0,0 +1,39 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/bit_coders/direct_bit_encoder.h" + +namespace draco { + +DirectBitEncoder::DirectBitEncoder() : local_bits_(0), num_local_bits_(0) {} + +DirectBitEncoder::~DirectBitEncoder() { Clear(); } + +void DirectBitEncoder::StartEncoding() { Clear(); } + +void DirectBitEncoder::EndEncoding(EncoderBuffer *target_buffer) { + bits_.push_back(local_bits_); + const uint32_t size_in_byte = static_cast(bits_.size()) * 4; + target_buffer->Encode(size_in_byte); + target_buffer->Encode(bits_.data(), size_in_byte); + Clear(); +} + +void DirectBitEncoder::Clear() { + bits_.clear(); + local_bits_ = 0; + num_local_bits_ = 0; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.h b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.h new file mode 100644 index 00000000000..705b2ca93c2 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/direct_bit_encoder.h @@ -0,0 +1,89 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides direct encoding of bits with arithmetic encoder interface. +#ifndef DRACO_COMPRESSION_BIT_CODERS_DIRECT_BIT_ENCODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_DIRECT_BIT_ENCODER_H_ + +#include + +#include "draco/core/encoder_buffer.h" + +namespace draco { + +class DirectBitEncoder { + public: + DirectBitEncoder(); + ~DirectBitEncoder(); + + // Must be called before any Encode* function is called. + void StartEncoding(); + + // Encode one bit. If |bit| is true encode a 1, otherwise encode a 0. + void EncodeBit(bool bit) { + if (bit) { + local_bits_ |= 1 << (31 - num_local_bits_); + } + num_local_bits_++; + if (num_local_bits_ == 32) { + bits_.push_back(local_bits_); + num_local_bits_ = 0; + local_bits_ = 0; + } + } + + // Encode |nbits| of |value|, starting from the least significant bit. + // |nbits| must be > 0 and <= 32. + void EncodeLeastSignificantBits32(int nbits, uint32_t value) { + DRACO_DCHECK_EQ(true, nbits <= 32); + DRACO_DCHECK_EQ(true, nbits > 0); + + const int remaining = 32 - num_local_bits_; + + // Make sure there are no leading bits that should not be encoded and + // start from here. + value = value << (32 - nbits); + if (nbits <= remaining) { + value = value >> num_local_bits_; + local_bits_ = local_bits_ | value; + num_local_bits_ += nbits; + if (num_local_bits_ == 32) { + bits_.push_back(local_bits_); + local_bits_ = 0; + num_local_bits_ = 0; + } + } else { + value = value >> (32 - nbits); + num_local_bits_ = nbits - remaining; + const uint32_t value_l = value >> num_local_bits_; + local_bits_ = local_bits_ | value_l; + bits_.push_back(local_bits_); + local_bits_ = value << (32 - num_local_bits_); + } + } + + // Ends the bit encoding and stores the result into the target_buffer. + void EndEncoding(EncoderBuffer *target_buffer); + + private: + void Clear(); + + std::vector bits_; + uint32_t local_bits_; + uint32_t num_local_bits_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_DIRECT_BIT_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_decoder.h b/extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_decoder.h new file mode 100644 index 00000000000..c14058b6569 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_decoder.h @@ -0,0 +1,77 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides direct encoding of bits with arithmetic encoder interface. +#ifndef DRACO_COMPRESSION_BIT_CODERS_FOLDED_INTEGER_BIT_DECODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_FOLDED_INTEGER_BIT_DECODER_H_ + +#include + +#include "draco/core/decoder_buffer.h" + +namespace draco { + +// See FoldedBit32Encoder for more details. +template +class FoldedBit32Decoder { + public: + FoldedBit32Decoder() {} + ~FoldedBit32Decoder() {} + + // Sets |source_buffer| as the buffer to decode bits from. + bool StartDecoding(DecoderBuffer *source_buffer) { + for (int i = 0; i < 32; i++) { + if (!folded_number_decoders_[i].StartDecoding(source_buffer)) { + return false; + } + } + return bit_decoder_.StartDecoding(source_buffer); + } + + // Decode one bit. Returns true if the bit is a 1, otherwise false. + bool DecodeNextBit() { return bit_decoder_.DecodeNextBit(); } + + // Decode the next |nbits| and return the sequence in |value|. |nbits| must be + // > 0 and <= 32. + void DecodeLeastSignificantBits32(int nbits, uint32_t *value) { + uint32_t result = 0; + for (int i = 0; i < nbits; ++i) { + const bool bit = folded_number_decoders_[i].DecodeNextBit(); + result = (result << 1) + bit; + } + *value = result; + } + + void EndDecoding() { + for (int i = 0; i < 32; i++) { + folded_number_decoders_[i].EndDecoding(); + } + bit_decoder_.EndDecoding(); + } + + private: + void Clear() { + for (int i = 0; i < 32; i++) { + folded_number_decoders_[i].Clear(); + } + bit_decoder_.Clear(); + } + + std::array folded_number_decoders_; + BitDecoderT bit_decoder_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_FOLDED_INTEGER_BIT_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_encoder.h b/extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_encoder.h new file mode 100644 index 00000000000..375b38a61fb --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/folded_integer_bit_encoder.h @@ -0,0 +1,82 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides direct encoding of bits with arithmetic encoder interface. +#ifndef DRACO_COMPRESSION_BIT_CODERS_FOLDED_INTEGER_BIT_ENCODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_FOLDED_INTEGER_BIT_ENCODER_H_ + +#include + +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// This coding scheme considers every bit of an (up to) 32bit integer as a +// separate context. This can be a significant advantage when encoding numbers +// where it is more likely that the front bits are zero. +// The behavior is essentially the same as other arithmetic encoding schemes, +// the only difference is that encoding and decoding of bits must be absolutely +// symmetric, bits handed in by EncodeBit32 must be also decoded in this way. +// This is the FoldedBit32Encoder, see also FoldedBit32Decoder. +template +class FoldedBit32Encoder { + public: + FoldedBit32Encoder() {} + ~FoldedBit32Encoder() {} + + // Must be called before any Encode* function is called. + void StartEncoding() { + for (int i = 0; i < 32; i++) { + folded_number_encoders_[i].StartEncoding(); + } + bit_encoder_.StartEncoding(); + } + + // Encode one bit. If |bit| is true encode a 1, otherwise encode a 0. + void EncodeBit(bool bit) { bit_encoder_.EncodeBit(bit); } + + // Encode |nbits| of |value|, starting from the least significant bit. + // |nbits| must be > 0 and <= 32. + void EncodeLeastSignificantBits32(int nbits, uint32_t value) { + uint32_t selector = 1 << (nbits - 1); + for (int i = 0; i < nbits; i++) { + const bool bit = (value & selector); + folded_number_encoders_[i].EncodeBit(bit); + selector = selector >> 1; + } + } + + // Ends the bit encoding and stores the result into the target_buffer. + void EndEncoding(EncoderBuffer *target_buffer) { + for (int i = 0; i < 32; i++) { + folded_number_encoders_[i].EndEncoding(target_buffer); + } + bit_encoder_.EndEncoding(target_buffer); + } + + private: + void Clear() { + for (int i = 0; i < 32; i++) { + folded_number_encoders_[i].Clear(); + } + bit_encoder_.Clear(); + } + + std::array folded_number_encoders_; + BitEncoderT bit_encoder_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_FOLDED_INTEGER_BIT_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.cc new file mode 100644 index 00000000000..a9b8fb9e91e --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.cc @@ -0,0 +1,82 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/bit_coders/rans_bit_decoder.h" + +#include "draco/compression/config/compression_shared.h" +#include "draco/core/bit_utils.h" +#include "draco/core/varint_decoding.h" + +namespace draco { + +RAnsBitDecoder::RAnsBitDecoder() : prob_zero_(0) {} + +RAnsBitDecoder::~RAnsBitDecoder() { Clear(); } + +bool RAnsBitDecoder::StartDecoding(DecoderBuffer *source_buffer) { + Clear(); + + if (!source_buffer->Decode(&prob_zero_)) { + return false; + } + + uint32_t size_in_bytes; +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (source_buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 2)) { + if (!source_buffer->Decode(&size_in_bytes)) { + return false; + } + + } else +#endif + { + if (!DecodeVarint(&size_in_bytes, source_buffer)) { + return false; + } + } + + if (size_in_bytes > source_buffer->remaining_size()) { + return false; + } + + if (ans_read_init(&ans_decoder_, + reinterpret_cast( + const_cast(source_buffer->data_head())), + size_in_bytes) != 0) { + return false; + } + source_buffer->Advance(size_in_bytes); + return true; +} + +bool RAnsBitDecoder::DecodeNextBit() { + const uint8_t bit = rabs_read(&ans_decoder_, prob_zero_); + return bit > 0; +} + +void RAnsBitDecoder::DecodeLeastSignificantBits32(int nbits, uint32_t *value) { + DRACO_DCHECK_EQ(true, nbits <= 32); + DRACO_DCHECK_EQ(true, nbits > 0); + + uint32_t result = 0; + while (nbits) { + result = (result << 1) + DecodeNextBit(); + --nbits; + } + *value = result; +} + +void RAnsBitDecoder::Clear() { ans_read_end(&ans_decoder_); } + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.h b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.h new file mode 100644 index 00000000000..25d243eac16 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_decoder.h @@ -0,0 +1,55 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides basic classes and functions for rANS coding. +#ifndef DRACO_COMPRESSION_BIT_CODERS_RANS_BIT_DECODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_RANS_BIT_DECODER_H_ + +#include + +#include "draco/compression/entropy/ans.h" +#include "draco/core/decoder_buffer.h" +#include "draco/draco_features.h" + +namespace draco { + +// Class for decoding a sequence of bits that were encoded with RAnsBitEncoder. +class RAnsBitDecoder { + public: + RAnsBitDecoder(); + ~RAnsBitDecoder(); + + // Sets |source_buffer| as the buffer to decode bits from. + // Returns false when the data is invalid. + bool StartDecoding(DecoderBuffer *source_buffer); + + // Decode one bit. Returns true if the bit is a 1, otherwise false. + bool DecodeNextBit(); + + // Decode the next |nbits| and return the sequence in |value|. |nbits| must be + // > 0 and <= 32. + void DecodeLeastSignificantBits32(int nbits, uint32_t *value); + + void EndDecoding() {} + + private: + void Clear(); + + AnsDecoder ans_decoder_; + uint8_t prob_zero_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_RANS_BIT_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.cc new file mode 100644 index 00000000000..8d00ea35292 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.cc @@ -0,0 +1,125 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/bit_coders/rans_bit_encoder.h" + +#include "draco/compression/entropy/ans.h" +#include "draco/core/bit_utils.h" +#include "draco/core/varint_encoding.h" + +namespace draco { + +RAnsBitEncoder::RAnsBitEncoder() : local_bits_(0), num_local_bits_(0) {} + +RAnsBitEncoder::~RAnsBitEncoder() { Clear(); } + +void RAnsBitEncoder::StartEncoding() { Clear(); } + +void RAnsBitEncoder::EncodeBit(bool bit) { + if (bit) { + bit_counts_[1]++; + local_bits_ |= 1 << num_local_bits_; + } else { + bit_counts_[0]++; + } + num_local_bits_++; + + if (num_local_bits_ == 32) { + bits_.push_back(local_bits_); + num_local_bits_ = 0; + local_bits_ = 0; + } +} + +void RAnsBitEncoder::EncodeLeastSignificantBits32(int nbits, uint32_t value) { + DRACO_DCHECK_EQ(true, nbits <= 32); + DRACO_DCHECK_EQ(true, nbits > 0); + + const uint32_t reversed = ReverseBits32(value) >> (32 - nbits); + const int ones = CountOneBits32(reversed); + bit_counts_[0] += (nbits - ones); + bit_counts_[1] += ones; + + const int remaining = 32 - num_local_bits_; + + if (nbits <= remaining) { + CopyBits32(&local_bits_, num_local_bits_, reversed, 0, nbits); + num_local_bits_ += nbits; + if (num_local_bits_ == 32) { + bits_.push_back(local_bits_); + local_bits_ = 0; + num_local_bits_ = 0; + } + } else { + CopyBits32(&local_bits_, num_local_bits_, reversed, 0, remaining); + bits_.push_back(local_bits_); + local_bits_ = 0; + CopyBits32(&local_bits_, 0, reversed, remaining, nbits - remaining); + num_local_bits_ = nbits - remaining; + } +} + +void RAnsBitEncoder::EndEncoding(EncoderBuffer *target_buffer) { + uint64_t total = bit_counts_[1] + bit_counts_[0]; + if (total == 0) { + total++; + } + + // The probability interval [0,1] is mapped to values of [0, 256]. However, + // the coding scheme can not deal with probabilities of 0 or 1, which is why + // we must clamp the values to interval [1, 255]. Specifically 128 + // corresponds to 0.5 exactly. And the value can be given as uint8_t. + const uint32_t zero_prob_raw = static_cast( + ((bit_counts_[0] / static_cast(total)) * 256.0) + 0.5); + + uint8_t zero_prob = 255; + if (zero_prob_raw < 255) { + zero_prob = static_cast(zero_prob_raw); + } + + zero_prob += (zero_prob == 0); + + // Space for 32 bit integer and some extra space. + std::vector buffer((bits_.size() + 8) * 8); + AnsCoder ans_coder; + ans_write_init(&ans_coder, buffer.data()); + + for (int i = num_local_bits_ - 1; i >= 0; --i) { + const uint8_t bit = (local_bits_ >> i) & 1; + rabs_write(&ans_coder, bit, zero_prob); + } + for (auto it = bits_.rbegin(); it != bits_.rend(); ++it) { + const uint32_t bits = *it; + for (int i = 31; i >= 0; --i) { + const uint8_t bit = (bits >> i) & 1; + rabs_write(&ans_coder, bit, zero_prob); + } + } + + const int size_in_bytes = ans_write_end(&ans_coder); + target_buffer->Encode(zero_prob); + EncodeVarint(static_cast(size_in_bytes), target_buffer); + target_buffer->Encode(buffer.data(), size_in_bytes); + + Clear(); +} + +void RAnsBitEncoder::Clear() { + bit_counts_.assign(2, 0); + bits_.clear(); + local_bits_ = 0; + num_local_bits_ = 0; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.h b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.h new file mode 100644 index 00000000000..1993dd3d3c2 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/rans_bit_encoder.h @@ -0,0 +1,57 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides basic classes and functions for rANS coding. +#ifndef DRACO_COMPRESSION_BIT_CODERS_RANS_BIT_ENCODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_RANS_BIT_ENCODER_H_ + +#include + +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// Class for encoding a sequence of bits using rANS. The probability table used +// to encode the bits is based off the total counts of bits. +// TODO(fgalligan): Investigate using an adaptive table for more compression. +class RAnsBitEncoder { + public: + RAnsBitEncoder(); + ~RAnsBitEncoder(); + + // Must be called before any Encode* function is called. + void StartEncoding(); + + // Encode one bit. If |bit| is true encode a 1, otherwise encode a 0. + void EncodeBit(bool bit); + + // Encode |nbits| of |value|, starting from the least significant bit. + // |nbits| must be > 0 and <= 32. + void EncodeLeastSignificantBits32(int nbits, uint32_t value); + + // Ends the bit encoding and stores the result into the target_buffer. + void EndEncoding(EncoderBuffer *target_buffer); + + private: + void Clear(); + + std::vector bit_counts_; + std::vector bits_; + uint32_t local_bits_; + uint32_t num_local_bits_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_RANS_BIT_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.cc new file mode 100644 index 00000000000..8ed50ef92ec --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.cc @@ -0,0 +1,49 @@ +#include "draco/compression/bit_coders/symbol_bit_decoder.h" + +#include "draco/compression/entropy/symbol_decoding.h" + +namespace draco { + +bool SymbolBitDecoder::StartDecoding(DecoderBuffer *source_buffer) { + uint32_t size; + if (!source_buffer->Decode(&size)) { + return false; + } + + symbols_.resize(size); + if (!DecodeSymbols(size, 1, source_buffer, symbols_.data())) { + return false; + } + std::reverse(symbols_.begin(), symbols_.end()); + return true; +} + +bool SymbolBitDecoder::DecodeNextBit() { + uint32_t symbol; + DecodeLeastSignificantBits32(1, &symbol); + DRACO_DCHECK(symbol == 0 || symbol == 1); + return symbol == 1; +} + +void SymbolBitDecoder::DecodeLeastSignificantBits32(int nbits, + uint32_t *value) { + DRACO_DCHECK_LE(1, nbits); + DRACO_DCHECK_LE(nbits, 32); + DRACO_DCHECK_NE(value, nullptr); + // Testing: check to make sure there is something to decode. + DRACO_DCHECK_GT(symbols_.size(), 0); + + (*value) = symbols_.back(); + symbols_.pop_back(); + + const int discarded_bits = 32 - nbits; + (*value) <<= discarded_bits; + (*value) >>= discarded_bits; +} + +void SymbolBitDecoder::Clear() { + symbols_.clear(); + symbols_.shrink_to_fit(); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.h b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.h new file mode 100644 index 00000000000..909d7174fb5 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_decoder.h @@ -0,0 +1,36 @@ +#ifndef DRACO_COMPRESSION_BIT_CODERS_SYMBOL_BIT_DECODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_SYMBOL_BIT_DECODER_H_ + +#include +#include + +#include "draco/core/decoder_buffer.h" + +namespace draco { + +// Class for decoding bits using the symbol entropy encoding. Wraps +// |DecodeSymbols|. Note that this uses a symbol-based encoding scheme for +// encoding bits. +class SymbolBitDecoder { + public: + // Sets |source_buffer| as the buffer to decode bits from. + bool StartDecoding(DecoderBuffer *source_buffer); + + // Decode one bit. Returns true if the bit is a 1, otherwise false. + bool DecodeNextBit(); + + // Decode the next |nbits| and return the sequence in |value|. |nbits| must be + // > 0 and <= 32. + void DecodeLeastSignificantBits32(int nbits, uint32_t *value); + + void EndDecoding() { Clear(); } + + private: + void Clear(); + + std::vector symbols_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_SYMBOL_BIT_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.cc b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.cc new file mode 100644 index 00000000000..83834236fa5 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.cc @@ -0,0 +1,30 @@ +#include "draco/compression/bit_coders/symbol_bit_encoder.h" + +#include "draco/compression/entropy/symbol_encoding.h" + +namespace draco { + +void SymbolBitEncoder::EncodeLeastSignificantBits32(int nbits, uint32_t value) { + DRACO_DCHECK_LE(1, nbits); + DRACO_DCHECK_LE(nbits, 32); + + const int discarded_bits = 32 - nbits; + value <<= discarded_bits; + value >>= discarded_bits; + + symbols_.push_back(value); +} + +void SymbolBitEncoder::EndEncoding(EncoderBuffer *target_buffer) { + target_buffer->Encode(static_cast(symbols_.size())); + EncodeSymbols(symbols_.data(), static_cast(symbols_.size()), 1, nullptr, + target_buffer); + Clear(); +} + +void SymbolBitEncoder::Clear() { + symbols_.clear(); + symbols_.shrink_to_fit(); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.h b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.h new file mode 100644 index 00000000000..7f1570c1a7c --- /dev/null +++ b/extern/draco/draco/src/draco/compression/bit_coders/symbol_bit_encoder.h @@ -0,0 +1,36 @@ +#ifndef DRACO_COMPRESSION_BIT_CODERS_SYMBOL_BIT_ENCODER_H_ +#define DRACO_COMPRESSION_BIT_CODERS_SYMBOL_BIT_ENCODER_H_ + +#include +#include + +#include "draco/core/encoder_buffer.h" + +namespace draco { + +// Class for encoding bits using the symbol entropy encoding. Wraps +// |EncodeSymbols|. Note that this uses a symbol-based encoding scheme for +// encoding bits. +class SymbolBitEncoder { + public: + // Must be called before any Encode* function is called. + void StartEncoding() { Clear(); } + + // Encode one bit. If |bit| is true encode a 1, otherwise encode a 0. + void EncodeBit(bool bit) { EncodeLeastSignificantBits32(1, bit ? 1 : 0); } + + // Encode |nbits| LSBs of |value| as a symbol. |nbits| must be > 0 and <= 32. + void EncodeLeastSignificantBits32(int nbits, uint32_t value); + + // Ends the bit encoding and stores the result into the target_buffer. + void EndEncoding(EncoderBuffer *target_buffer); + + private: + void Clear(); + + std::vector symbols_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_BIT_CODERS_SYMBOL_BIT_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/config/compression_shared.h b/extern/draco/draco/src/draco/compression/config/compression_shared.h new file mode 100644 index 00000000000..40061d3cd48 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/config/compression_shared.h @@ -0,0 +1,152 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_CONFIG_COMPRESSION_SHARED_H_ +#define DRACO_COMPRESSION_CONFIG_COMPRESSION_SHARED_H_ + +#include + +#include "draco/core/macros.h" +#include "draco/draco_features.h" + +namespace draco { + +// Latest Draco bit-stream version. +static constexpr uint8_t kDracoPointCloudBitstreamVersionMajor = 2; +static constexpr uint8_t kDracoPointCloudBitstreamVersionMinor = 3; +static constexpr uint8_t kDracoMeshBitstreamVersionMajor = 2; +static constexpr uint8_t kDracoMeshBitstreamVersionMinor = 2; + +// Concatenated latest bit-stream version. +static constexpr uint16_t kDracoPointCloudBitstreamVersion = + DRACO_BITSTREAM_VERSION(kDracoPointCloudBitstreamVersionMajor, + kDracoPointCloudBitstreamVersionMinor); + +static constexpr uint16_t kDracoMeshBitstreamVersion = DRACO_BITSTREAM_VERSION( + kDracoMeshBitstreamVersionMajor, kDracoMeshBitstreamVersionMinor); + +// Currently, we support point cloud and triangular mesh encoding. +// TODO(draco-eng) Convert enum to enum class (safety, not performance). +enum EncodedGeometryType { + INVALID_GEOMETRY_TYPE = -1, + POINT_CLOUD = 0, + TRIANGULAR_MESH, +}; + +// List of encoding methods for point clouds. +enum PointCloudEncodingMethod { + POINT_CLOUD_SEQUENTIAL_ENCODING = 0, + POINT_CLOUD_KD_TREE_ENCODING +}; + +// List of encoding methods for meshes. +enum MeshEncoderMethod { + MESH_SEQUENTIAL_ENCODING = 0, + MESH_EDGEBREAKER_ENCODING, +}; + +// List of various attribute encoders supported by our framework. The entries +// are used as unique identifiers of the encoders and their values should not +// be changed! +enum AttributeEncoderType { + BASIC_ATTRIBUTE_ENCODER = 0, + MESH_TRAVERSAL_ATTRIBUTE_ENCODER, + KD_TREE_ATTRIBUTE_ENCODER, +}; + +// List of various sequential attribute encoder/decoders that can be used in our +// pipeline. The values represent unique identifiers used by the decoder and +// they should not be changed. +enum SequentialAttributeEncoderType { + SEQUENTIAL_ATTRIBUTE_ENCODER_GENERIC = 0, + SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGER, + SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION, + SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS, +}; + +// List of all prediction methods currently supported by our framework. +enum PredictionSchemeMethod { + // Special value indicating that no prediction scheme was used. + PREDICTION_NONE = -2, + // Used when no specific prediction scheme is required. + PREDICTION_UNDEFINED = -1, + PREDICTION_DIFFERENCE = 0, + MESH_PREDICTION_PARALLELOGRAM = 1, + MESH_PREDICTION_MULTI_PARALLELOGRAM = 2, + MESH_PREDICTION_TEX_COORDS_DEPRECATED = 3, + MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM = 4, + MESH_PREDICTION_TEX_COORDS_PORTABLE = 5, + MESH_PREDICTION_GEOMETRIC_NORMAL = 6, + NUM_PREDICTION_SCHEMES +}; + +// List of all prediction scheme transforms used by our framework. +enum PredictionSchemeTransformType { + PREDICTION_TRANSFORM_NONE = -1, + // Basic delta transform where the prediction is computed as difference the + // predicted and original value. + PREDICTION_TRANSFORM_DELTA = 0, + // An improved delta transform where all computed delta values are wrapped + // around a fixed interval which lowers the entropy. + PREDICTION_TRANSFORM_WRAP = 1, + // Specialized transform for normal coordinates using inverted tiles. + PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON = 2, + // Specialized transform for normal coordinates using canonicalized inverted + // tiles. + PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED = 3, +}; + +// List of all mesh traversal methods supported by Draco framework. +enum MeshTraversalMethod { + MESH_TRAVERSAL_DEPTH_FIRST = 0, + MESH_TRAVERSAL_PREDICTION_DEGREE = 1, + NUM_TRAVERSAL_METHODS +}; + +// List of all variant of the edgebreaker method that is used for compression +// of mesh connectivity. +enum MeshEdgebreakerConnectivityEncodingMethod { + MESH_EDGEBREAKER_STANDARD_ENCODING = 0, + MESH_EDGEBREAKER_PREDICTIVE_ENCODING = 1, // Deprecated. + MESH_EDGEBREAKER_VALENCE_ENCODING = 2, +}; + +// Draco header V1 +struct DracoHeader { + int8_t draco_string[5]; + uint8_t version_major; + uint8_t version_minor; + uint8_t encoder_type; + uint8_t encoder_method; + uint16_t flags; +}; + +enum NormalPredictionMode { + ONE_TRIANGLE = 0, // To be deprecated. + TRIANGLE_AREA = 1, +}; + +// Different methods used for symbol entropy encoding. +enum SymbolCodingMethod { + SYMBOL_CODING_TAGGED = 0, + SYMBOL_CODING_RAW = 1, + NUM_SYMBOL_CODING_METHODS, +}; + +// Mask for setting and getting the bit for metadata in |flags| of header. +#define METADATA_FLAG_MASK 0x8000 + +} // namespace draco + +#endif // DRACO_COMPRESSION_CONFIG_COMPRESSION_SHARED_H_ diff --git a/extern/draco/draco/src/draco/compression/config/decoder_options.h b/extern/draco/draco/src/draco/compression/config/decoder_options.h new file mode 100644 index 00000000000..3b3889993e2 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/config/decoder_options.h @@ -0,0 +1,34 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_CONFIG_DECODER_OPTIONS_H_ +#define DRACO_COMPRESSION_CONFIG_DECODER_OPTIONS_H_ + +#include +#include + +#include "draco/attributes/geometry_attribute.h" +#include "draco/compression/config/draco_options.h" + +namespace draco { + +// Class containing options that can be passed to PointCloudDecoder to control +// decoding of the input geometry. The options can be specified either for the +// whole geometry or for a specific attribute type. Each option is identified +// by a unique name stored as an std::string. +typedef DracoOptions DecoderOptions; + +} // namespace draco + +#endif // DRACO_COMPRESSION_CONFIG_DECODER_OPTIONS_H_ diff --git a/extern/draco/draco/src/draco/compression/config/draco_options.h b/extern/draco/draco/src/draco/compression/config/draco_options.h new file mode 100644 index 00000000000..0d1247b2ad1 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/config/draco_options.h @@ -0,0 +1,249 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ +#define DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ + +#include +#include + +#include "draco/core/options.h" + +namespace draco { + +// Base option class used to control encoding and decoding. The geometry coding +// can be controlled through the following options: +// 1. Global options - Options specific to overall geometry or options common +// for all attributes +// 2. Per attribute options - Options specific to a given attribute. +// Each attribute is identified by the template +// argument AttributeKeyT that can be for example +// the attribute type or the attribute id. +// +// Example: +// +// DracoOptions options; +// +// // Set an option common for all attributes. +// options.SetGlobalInt("some_option_name", 2); +// +// // Geometry with two attributes. +// AttributeKey att_key0 = in_key0; +// AttributeKey att_key1 = in_key1; +// +// options.SetAttributeInt(att_key0, "some_option_name", 3); +// +// options.GetAttributeInt(att_key0, "some_option_name"); // Returns 3 +// options.GetAttributeInt(att_key1, "some_option_name"); // Returns 2 +// options.GetGlobalInt("some_option_name"); // Returns 2 +// +template +class DracoOptions { + public: + typedef AttributeKeyT AttributeKey; + + // Get an option for a specific attribute key. If the option is not found in + // an attribute specific storage, the implementation will return a global + // option of the given name (if available). If the option is not found, the + // provided default value |default_val| is returned instead. + int GetAttributeInt(const AttributeKey &att_key, const std::string &name, + int default_val) const; + + // Sets an option for a specific attribute key. + void SetAttributeInt(const AttributeKey &att_key, const std::string &name, + int val); + + float GetAttributeFloat(const AttributeKey &att_key, const std::string &name, + float default_val) const; + void SetAttributeFloat(const AttributeKey &att_key, const std::string &name, + float val); + bool GetAttributeBool(const AttributeKey &att_key, const std::string &name, + bool default_val) const; + void SetAttributeBool(const AttributeKey &att_key, const std::string &name, + bool val); + template + bool GetAttributeVector(const AttributeKey &att_key, const std::string &name, + int num_dims, DataTypeT *val) const; + template + void SetAttributeVector(const AttributeKey &att_key, const std::string &name, + int num_dims, const DataTypeT *val); + + bool IsAttributeOptionSet(const AttributeKey &att_key, + const std::string &name) const; + + // Gets/sets a global option that is not specific to any attribute. + int GetGlobalInt(const std::string &name, int default_val) const { + return global_options_.GetInt(name, default_val); + } + void SetGlobalInt(const std::string &name, int val) { + global_options_.SetInt(name, val); + } + float GetGlobalFloat(const std::string &name, float default_val) const { + return global_options_.GetFloat(name, default_val); + } + void SetGlobalFloat(const std::string &name, float val) { + global_options_.SetFloat(name, val); + } + bool GetGlobalBool(const std::string &name, bool default_val) const { + return global_options_.GetBool(name, default_val); + } + void SetGlobalBool(const std::string &name, bool val) { + global_options_.SetBool(name, val); + } + template + bool GetGlobalVector(const std::string &name, int num_dims, + DataTypeT *val) const { + return global_options_.GetVector(name, num_dims, val); + } + template + void SetGlobalVector(const std::string &name, int num_dims, + const DataTypeT *val) { + global_options_.SetVector(name, val, num_dims); + } + bool IsGlobalOptionSet(const std::string &name) const { + return global_options_.IsOptionSet(name); + } + + // Sets or replaces attribute options with the provided |options|. + void SetAttributeOptions(const AttributeKey &att_key, const Options &options); + void SetGlobalOptions(const Options &options) { global_options_ = options; } + + // Returns |Options| instance for the specified options class if it exists. + const Options *FindAttributeOptions(const AttributeKeyT &att_key) const; + const Options &GetGlobalOptions() const { return global_options_; } + + private: + Options *GetAttributeOptions(const AttributeKeyT &att_key); + + Options global_options_; + + // Storage for options related to geometry attributes. + std::map attribute_options_; +}; + +template +const Options *DracoOptions::FindAttributeOptions( + const AttributeKeyT &att_key) const { + auto it = attribute_options_.find(att_key); + if (it == attribute_options_.end()) { + return nullptr; + } + return &it->second; +} + +template +Options *DracoOptions::GetAttributeOptions( + const AttributeKeyT &att_key) { + auto it = attribute_options_.find(att_key); + if (it != attribute_options_.end()) { + return &it->second; + } + Options new_options; + it = attribute_options_.insert(std::make_pair(att_key, new_options)).first; + return &it->second; +} + +template +int DracoOptions::GetAttributeInt(const AttributeKeyT &att_key, + const std::string &name, + int default_val) const { + const Options *const att_options = FindAttributeOptions(att_key); + if (att_options && att_options->IsOptionSet(name)) { + return att_options->GetInt(name, default_val); + } + return global_options_.GetInt(name, default_val); +} + +template +void DracoOptions::SetAttributeInt(const AttributeKeyT &att_key, + const std::string &name, + int val) { + GetAttributeOptions(att_key)->SetInt(name, val); +} + +template +float DracoOptions::GetAttributeFloat( + const AttributeKeyT &att_key, const std::string &name, + float default_val) const { + const Options *const att_options = FindAttributeOptions(att_key); + if (att_options && att_options->IsOptionSet(name)) { + return att_options->GetFloat(name, default_val); + } + return global_options_.GetFloat(name, default_val); +} + +template +void DracoOptions::SetAttributeFloat( + const AttributeKeyT &att_key, const std::string &name, float val) { + GetAttributeOptions(att_key)->SetFloat(name, val); +} + +template +bool DracoOptions::GetAttributeBool(const AttributeKeyT &att_key, + const std::string &name, + bool default_val) const { + const Options *const att_options = FindAttributeOptions(att_key); + if (att_options && att_options->IsOptionSet(name)) { + return att_options->GetBool(name, default_val); + } + return global_options_.GetBool(name, default_val); +} + +template +void DracoOptions::SetAttributeBool(const AttributeKeyT &att_key, + const std::string &name, + bool val) { + GetAttributeOptions(att_key)->SetBool(name, val); +} + +template +template +bool DracoOptions::GetAttributeVector( + const AttributeKey &att_key, const std::string &name, int num_dims, + DataTypeT *val) const { + const Options *const att_options = FindAttributeOptions(att_key); + if (att_options && att_options->IsOptionSet(name)) { + return att_options->GetVector(name, num_dims, val); + } + return global_options_.GetVector(name, num_dims, val); +} + +template +template +void DracoOptions::SetAttributeVector( + const AttributeKey &att_key, const std::string &name, int num_dims, + const DataTypeT *val) { + GetAttributeOptions(att_key)->SetVector(name, val, num_dims); +} + +template +bool DracoOptions::IsAttributeOptionSet( + const AttributeKey &att_key, const std::string &name) const { + const Options *const att_options = FindAttributeOptions(att_key); + if (att_options) { + return att_options->IsOptionSet(name); + } + return global_options_.IsOptionSet(name); +} + +template +void DracoOptions::SetAttributeOptions( + const AttributeKey &att_key, const Options &options) { + Options *att_options = GetAttributeOptions(att_key); + *att_options = options; +} + +} // namespace draco + +#endif // DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ diff --git a/extern/draco/draco/src/draco/compression/config/encoder_options.h b/extern/draco/draco/src/draco/compression/config/encoder_options.h new file mode 100644 index 00000000000..ed1b020683d --- /dev/null +++ b/extern/draco/draco/src/draco/compression/config/encoder_options.h @@ -0,0 +1,97 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_CONFIG_ENCODER_OPTIONS_H_ +#define DRACO_COMPRESSION_CONFIG_ENCODER_OPTIONS_H_ + +#include "draco/attributes/geometry_attribute.h" +#include "draco/compression/config/draco_options.h" +#include "draco/compression/config/encoding_features.h" +#include "draco/draco_features.h" + +namespace draco { + +// EncoderOptions allow users to specify so called feature options that are used +// to inform the encoder which encoding features can be used (i.e. which +// features are going to be available to the decoder). +template +class EncoderOptionsBase : public DracoOptions { + public: + static EncoderOptionsBase CreateDefaultOptions() { + EncoderOptionsBase options; +#ifdef DRACO_STANDARD_EDGEBREAKER_SUPPORTED + options.SetSupportedFeature(features::kEdgebreaker, true); +#endif +#ifdef DRACO_PREDICTIVE_EDGEBREAKER_SUPPORTED + options.SetSupportedFeature(features::kPredictiveEdgebreaker, true); +#endif + return options; + } + static EncoderOptionsBase CreateEmptyOptions() { + return EncoderOptionsBase(); + } + + // Returns speed options with default value of 5. + int GetEncodingSpeed() const { + return this->GetGlobalInt("encoding_speed", 5); + } + int GetDecodingSpeed() const { + return this->GetGlobalInt("decoding_speed", 5); + } + + // Returns the maximum speed for both encoding/decoding. + int GetSpeed() const { + const int encoding_speed = this->GetGlobalInt("encoding_speed", -1); + const int decoding_speed = this->GetGlobalInt("decoding_speed", -1); + const int max_speed = std::max(encoding_speed, decoding_speed); + if (max_speed == -1) { + return 5; // Default value. + } + return max_speed; + } + + void SetSpeed(int encoding_speed, int decoding_speed) { + this->SetGlobalInt("encoding_speed", encoding_speed); + this->SetGlobalInt("decoding_speed", decoding_speed); + } + + // Sets a given feature as supported or unsupported by the target decoder. + // Encoder will always use only supported features when encoding the input + // geometry. + void SetSupportedFeature(const std::string &name, bool supported) { + feature_options_.SetBool(name, supported); + } + bool IsFeatureSupported(const std::string &name) const { + return feature_options_.GetBool(name); + } + + void SetFeatureOptions(const Options &options) { feature_options_ = options; } + const Options &GetFeaturelOptions() const { return feature_options_; } + + private: + // Use helper methods to construct the encoder options. + // See CreateDefaultOptions(); + EncoderOptionsBase() {} + + // List of supported/unsupported features that can be used by the encoder. + Options feature_options_; +}; + +// Encoder options where attributes are identified by their attribute id. +// Used to set options that are specific to a given geometry. +typedef EncoderOptionsBase EncoderOptions; + +} // namespace draco + +#endif // DRACO_COMPRESSION_CONFIG_ENCODER_OPTIONS_H_ diff --git a/extern/draco/draco/src/draco/compression/config/encoding_features.h b/extern/draco/draco/src/draco/compression/config/encoding_features.h new file mode 100644 index 00000000000..d6a8b7128a8 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/config/encoding_features.h @@ -0,0 +1,39 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File provides helpful macros that define features available for encoding +// the input of the input geometry. These macros can be used as an input in +// the EncoderOptions::SetSupportedFeature() method instead of the text. +// The most recent set of features supported +// by the default implementation is: +// +// kEdgebreaker +// - edgebreaker method for encoding meshes. +// kPredictiveEdgebreaker +// - advanced version of the edgebreaker method (slower but better +// compression). +// +#ifndef DRACO_COMPRESSION_CONFIG_ENCODING_FEATURES_H_ +#define DRACO_COMPRESSION_CONFIG_ENCODING_FEATURES_H_ + +namespace draco { +namespace features { + +constexpr const char *kEdgebreaker = "standard_edgebreaker"; +constexpr const char *kPredictiveEdgebreaker = "predictive_edgebreaker"; + +} // namespace features +} // namespace draco + +#endif // DRACO_COMPRESSION_CONFIG_ENCODING_FEATURES_H_ diff --git a/extern/draco/draco/src/draco/compression/decode.cc b/extern/draco/draco/src/draco/compression/decode.cc new file mode 100644 index 00000000000..ab70ef1ec60 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/decode.cc @@ -0,0 +1,132 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/decode.h" + +#include "draco/compression/config/compression_shared.h" + +#ifdef DRACO_MESH_COMPRESSION_SUPPORTED +#include "draco/compression/mesh/mesh_edgebreaker_decoder.h" +#include "draco/compression/mesh/mesh_sequential_decoder.h" +#endif + +#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED +#include "draco/compression/point_cloud/point_cloud_kd_tree_decoder.h" +#include "draco/compression/point_cloud/point_cloud_sequential_decoder.h" +#endif + +namespace draco { + +#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED +StatusOr> CreatePointCloudDecoder( + int8_t method) { + if (method == POINT_CLOUD_SEQUENTIAL_ENCODING) { + return std::unique_ptr( + new PointCloudSequentialDecoder()); + } else if (method == POINT_CLOUD_KD_TREE_ENCODING) { + return std::unique_ptr(new PointCloudKdTreeDecoder()); + } + return Status(Status::DRACO_ERROR, "Unsupported encoding method."); +} +#endif + +#ifdef DRACO_MESH_COMPRESSION_SUPPORTED +StatusOr> CreateMeshDecoder(uint8_t method) { + if (method == MESH_SEQUENTIAL_ENCODING) { + return std::unique_ptr(new MeshSequentialDecoder()); + } else if (method == MESH_EDGEBREAKER_ENCODING) { + return std::unique_ptr(new MeshEdgebreakerDecoder()); + } + return Status(Status::DRACO_ERROR, "Unsupported encoding method."); +} +#endif + +StatusOr Decoder::GetEncodedGeometryType( + DecoderBuffer *in_buffer) { + DecoderBuffer temp_buffer(*in_buffer); + DracoHeader header; + DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)) + return static_cast(header.encoder_type); +} + +StatusOr> Decoder::DecodePointCloudFromBuffer( + DecoderBuffer *in_buffer) { + DRACO_ASSIGN_OR_RETURN(EncodedGeometryType type, + GetEncodedGeometryType(in_buffer)) + if (type == POINT_CLOUD) { +#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED + std::unique_ptr point_cloud(new PointCloud()); + DRACO_RETURN_IF_ERROR(DecodeBufferToGeometry(in_buffer, point_cloud.get())) + return std::move(point_cloud); +#endif + } else if (type == TRIANGULAR_MESH) { +#ifdef DRACO_MESH_COMPRESSION_SUPPORTED + std::unique_ptr mesh(new Mesh()); + DRACO_RETURN_IF_ERROR(DecodeBufferToGeometry(in_buffer, mesh.get())) + return static_cast>(std::move(mesh)); +#endif + } + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); +} + +StatusOr> Decoder::DecodeMeshFromBuffer( + DecoderBuffer *in_buffer) { + std::unique_ptr mesh(new Mesh()); + DRACO_RETURN_IF_ERROR(DecodeBufferToGeometry(in_buffer, mesh.get())) + return std::move(mesh); +} + +Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer, + PointCloud *out_geometry) { +#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED + DecoderBuffer temp_buffer(*in_buffer); + DracoHeader header; + DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)) + if (header.encoder_type != POINT_CLOUD) { + return Status(Status::DRACO_ERROR, "Input is not a point cloud."); + } + DRACO_ASSIGN_OR_RETURN(std::unique_ptr decoder, + CreatePointCloudDecoder(header.encoder_method)) + + DRACO_RETURN_IF_ERROR(decoder->Decode(options_, in_buffer, out_geometry)) + return OkStatus(); +#else + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); +#endif +} + +Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer, + Mesh *out_geometry) { +#ifdef DRACO_MESH_COMPRESSION_SUPPORTED + DecoderBuffer temp_buffer(*in_buffer); + DracoHeader header; + DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)) + if (header.encoder_type != TRIANGULAR_MESH) { + return Status(Status::DRACO_ERROR, "Input is not a mesh."); + } + DRACO_ASSIGN_OR_RETURN(std::unique_ptr decoder, + CreateMeshDecoder(header.encoder_method)) + + DRACO_RETURN_IF_ERROR(decoder->Decode(options_, in_buffer, out_geometry)) + return OkStatus(); +#else + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); +#endif +} + +void Decoder::SetSkipAttributeTransform(GeometryAttribute::Type att_type) { + options_.SetAttributeBool(att_type, "skip_attribute_transform", true); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/decode.h b/extern/draco/draco/src/draco/compression/decode.h new file mode 100644 index 00000000000..5f3fad26bb4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/decode.h @@ -0,0 +1,80 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_DECODE_H_ +#define DRACO_COMPRESSION_DECODE_H_ + +#include "draco/compression/config/compression_shared.h" +#include "draco/compression/config/decoder_options.h" +#include "draco/core/decoder_buffer.h" +#include "draco/core/status_or.h" +#include "draco/draco_features.h" +#include "draco/mesh/mesh.h" + +namespace draco { + +// Class responsible for decoding of meshes and point clouds that were +// compressed by a Draco encoder. +class Decoder { + public: + // Returns the geometry type encoded in the input |in_buffer|. + // The return value is one of POINT_CLOUD, MESH or INVALID_GEOMETRY in case + // the input data is invalid. + // The decoded geometry type can be used to choose an appropriate decoding + // function for a given geometry type (see below). + static StatusOr GetEncodedGeometryType( + DecoderBuffer *in_buffer); + + // Decodes point cloud from the provided buffer. The buffer must be filled + // with data that was encoded with either the EncodePointCloudToBuffer or + // EncodeMeshToBuffer methods in encode.h. In case the input buffer contains + // mesh, the returned instance can be down-casted to Mesh. + StatusOr> DecodePointCloudFromBuffer( + DecoderBuffer *in_buffer); + + // Decodes a triangular mesh from the provided buffer. The mesh must be filled + // with data that was encoded using the EncodeMeshToBuffer method in encode.h. + // The function will return nullptr in case the input is invalid or if it was + // encoded with the EncodePointCloudToBuffer method. + StatusOr> DecodeMeshFromBuffer( + DecoderBuffer *in_buffer); + + // Decodes the buffer into a provided geometry. If the geometry is + // incompatible with the encoded data. For example, when |out_geometry| is + // draco::Mesh while the data contains a point cloud, the function will return + // an error status. + Status DecodeBufferToGeometry(DecoderBuffer *in_buffer, + PointCloud *out_geometry); + Status DecodeBufferToGeometry(DecoderBuffer *in_buffer, Mesh *out_geometry); + + // When set, the decoder is going to skip attribute transform for a given + // attribute type. For example for quantized attributes, the decoder would + // skip the dequantization step and the returned geometry would contain an + // attribute with quantized values. The attribute would also contain an + // instance of AttributeTransform class that is used to describe the skipped + // transform, including all parameters that are needed to perform the + // transform manually. + void SetSkipAttributeTransform(GeometryAttribute::Type att_type); + + // Returns the options instance used by the decoder that can be used by users + // to control the decoding process. + DecoderOptions *options() { return &options_; } + + private: + DecoderOptions options_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_DECODE_H_ diff --git a/extern/draco/draco/src/draco/compression/encode.cc b/extern/draco/draco/src/draco/compression/encode.cc new file mode 100644 index 00000000000..f380aec1591 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/encode.cc @@ -0,0 +1,96 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/encode.h" + +#include "draco/compression/expert_encode.h" + +namespace draco { + +Encoder::Encoder() {} + +Status Encoder::EncodePointCloudToBuffer(const PointCloud &pc, + EncoderBuffer *out_buffer) { + ExpertEncoder encoder(pc); + encoder.Reset(CreateExpertEncoderOptions(pc)); + return encoder.EncodeToBuffer(out_buffer); +} + +Status Encoder::EncodeMeshToBuffer(const Mesh &m, EncoderBuffer *out_buffer) { + ExpertEncoder encoder(m); + encoder.Reset(CreateExpertEncoderOptions(m)); + DRACO_RETURN_IF_ERROR(encoder.EncodeToBuffer(out_buffer)); + set_num_encoded_points(encoder.num_encoded_points()); + set_num_encoded_faces(encoder.num_encoded_faces()); + return OkStatus(); +} + +EncoderOptions Encoder::CreateExpertEncoderOptions(const PointCloud &pc) const { + EncoderOptions ret_options = EncoderOptions::CreateEmptyOptions(); + ret_options.SetGlobalOptions(options().GetGlobalOptions()); + ret_options.SetFeatureOptions(options().GetFeaturelOptions()); + // Convert type-based attribute options to specific attributes in the provided + // point cloud. + for (int i = 0; i < pc.num_attributes(); ++i) { + const Options *att_options = + options().FindAttributeOptions(pc.attribute(i)->attribute_type()); + if (att_options) { + ret_options.SetAttributeOptions(i, *att_options); + } + } + return ret_options; +} + +void Encoder::Reset( + const EncoderOptionsBase &options) { + Base::Reset(options); +} + +void Encoder::Reset() { Base::Reset(); } + +void Encoder::SetSpeedOptions(int encoding_speed, int decoding_speed) { + Base::SetSpeedOptions(encoding_speed, decoding_speed); +} + +void Encoder::SetAttributeQuantization(GeometryAttribute::Type type, + int quantization_bits) { + options().SetAttributeInt(type, "quantization_bits", quantization_bits); +} + +void Encoder::SetAttributeExplicitQuantization(GeometryAttribute::Type type, + int quantization_bits, + int num_dims, + const float *origin, + float range) { + options().SetAttributeInt(type, "quantization_bits", quantization_bits); + options().SetAttributeVector(type, "quantization_origin", num_dims, origin); + options().SetAttributeFloat(type, "quantization_range", range); +} + +void Encoder::SetEncodingMethod(int encoding_method) { + Base::SetEncodingMethod(encoding_method); +} + +Status Encoder::SetAttributePredictionScheme(GeometryAttribute::Type type, + int prediction_scheme_method) { + Status status = CheckPredictionScheme(type, prediction_scheme_method); + if (!status.ok()) { + return status; + } + options().SetAttributeInt(type, "prediction_scheme", + prediction_scheme_method); + return status; +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/encode.h b/extern/draco/draco/src/draco/compression/encode.h new file mode 100644 index 00000000000..bce8b34c238 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/encode.h @@ -0,0 +1,140 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ENCODE_H_ +#define DRACO_COMPRESSION_ENCODE_H_ + +#include "draco/compression/config/compression_shared.h" +#include "draco/compression/config/encoder_options.h" +#include "draco/compression/encode_base.h" +#include "draco/core/encoder_buffer.h" +#include "draco/core/status.h" +#include "draco/mesh/mesh.h" + +namespace draco { + +// Basic helper class for encoding geometry using the Draco compression library. +// The class provides various methods that can be used to control several common +// options used during the encoding, such as the number of quantization bits for +// a given attribute. All these options are defined per attribute type, i.e., +// if there are more attributes of the same type (such as multiple texture +// coordinate attributes), the same options are going to be used for all of the +// attributes of this type. If different attributes of the same type need to +// use different options, use ExpertEncoder in expert_encode.h. +class Encoder + : public EncoderBase> { + public: + typedef EncoderBase> Base; + + Encoder(); + virtual ~Encoder() {} + + // Encodes a point cloud to the provided buffer. + virtual Status EncodePointCloudToBuffer(const PointCloud &pc, + EncoderBuffer *out_buffer); + + // Encodes a mesh to the provided buffer. + virtual Status EncodeMeshToBuffer(const Mesh &m, EncoderBuffer *out_buffer); + + // Set encoder options used during the geometry encoding. Note that this call + // overwrites any modifications to the options done with the functions below, + // i.e., it resets the encoder. + void Reset(const EncoderOptionsBase &options); + void Reset(); + + // Sets the desired encoding and decoding speed for the given options. + // + // 0 = slowest speed, but the best compression. + // 10 = fastest, but the worst compression. + // -1 = undefined. + // + // Note that both speed options affect the encoder choice of used methods and + // algorithms. For example, a requirement for fast decoding may prevent the + // encoder from using the best compression methods even if the encoding speed + // is set to 0. In general, the faster of the two options limits the choice of + // features that can be used by the encoder. Additionally, setting + // |decoding_speed| to be faster than the |encoding_speed| may allow the + // encoder to choose the optimal method out of the available features for the + // given |decoding_speed|. + void SetSpeedOptions(int encoding_speed, int decoding_speed); + + // Sets the quantization compression options for a named attribute. The + // attribute values will be quantized in a box defined by the maximum extent + // of the attribute values. I.e., the actual precision of this option depends + // on the scale of the attribute values. + void SetAttributeQuantization(GeometryAttribute::Type type, + int quantization_bits); + + // Sets the explicit quantization compression for a named attribute. The + // attribute values will be quantized in a coordinate system defined by the + // provided origin and range (the input values should be within interval: + // ). + void SetAttributeExplicitQuantization(GeometryAttribute::Type type, + int quantization_bits, int num_dims, + const float *origin, float range); + + // Sets the desired prediction method for a given attribute. By default, + // prediction scheme is selected automatically by the encoder using other + // provided options (such as speed) and input geometry type (mesh, point + // cloud). This function should be called only when a specific prediction is + // preferred (e.g., when it is known that the encoder would select a less + // optimal prediction for the given input data). + // + // |prediction_scheme_method| should be one of the entries defined in + // compression/config/compression_shared.h : + // + // PREDICTION_NONE - use no prediction. + // PREDICTION_DIFFERENCE - delta coding + // MESH_PREDICTION_PARALLELOGRAM - parallelogram prediction for meshes. + // MESH_PREDICTION_CONSTRAINED_PARALLELOGRAM + // - better and more costly version of the parallelogram prediction. + // MESH_PREDICTION_TEX_COORDS_PORTABLE + // - specialized predictor for tex coordinates. + // MESH_PREDICTION_GEOMETRIC_NORMAL + // - specialized predictor for normal coordinates. + // + // Note that in case the desired prediction cannot be used, the default + // prediction will be automatically used instead. + Status SetAttributePredictionScheme(GeometryAttribute::Type type, + int prediction_scheme_method); + + // Sets the desired encoding method for a given geometry. By default, encoding + // method is selected based on the properties of the input geometry and based + // on the other options selected in the used EncoderOptions (such as desired + // encoding and decoding speed). This function should be called only when a + // specific method is required. + // + // |encoding_method| can be one of the values defined in + // compression/config/compression_shared.h based on the type of the input + // geometry that is going to be encoded. For point clouds, allowed entries are + // POINT_CLOUD_SEQUENTIAL_ENCODING + // POINT_CLOUD_KD_TREE_ENCODING + // + // For meshes the input can be + // MESH_SEQUENTIAL_ENCODING + // MESH_EDGEBREAKER_ENCODING + // + // If the selected method cannot be used for the given input, the subsequent + // call of EncodePointCloudToBuffer or EncodeMeshToBuffer is going to fail. + void SetEncodingMethod(int encoding_method); + + protected: + // Creates encoder options for the expert encoder used during the actual + // encoding. + EncoderOptions CreateExpertEncoderOptions(const PointCloud &pc) const; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ENCODE_H_ diff --git a/extern/draco/draco/src/draco/compression/encode_base.h b/extern/draco/draco/src/draco/compression/encode_base.h new file mode 100644 index 00000000000..0c63a972bf4 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/encode_base.h @@ -0,0 +1,131 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_ +#define DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_ + +#include "draco/attributes/geometry_attribute.h" +#include "draco/compression/config/compression_shared.h" +#include "draco/core/status.h" + +namespace draco { + +// Base class for our geometry encoder classes. |EncoderOptionsT| specifies +// options class used by the encoder. Please, see encode.h and expert_encode.h +// for more details and method descriptions. +template +class EncoderBase { + public: + typedef EncoderOptionsT OptionsType; + + EncoderBase() + : options_(EncoderOptionsT::CreateDefaultOptions()), + num_encoded_points_(0), + num_encoded_faces_(0) {} + virtual ~EncoderBase() {} + + const EncoderOptionsT &options() const { return options_; } + EncoderOptionsT &options() { return options_; } + + // If enabled, it tells the encoder to keep track of the number of encoded + // points and faces (default = false). + // Note that this can slow down encoding for certain encoders. + void SetTrackEncodedProperties(bool flag); + + // Returns the number of encoded points and faces during the last encoding + // operation. Returns 0 if SetTrackEncodedProperties() was not set. + size_t num_encoded_points() const { return num_encoded_points_; } + size_t num_encoded_faces() const { return num_encoded_faces_; } + + protected: + void Reset(const EncoderOptionsT &options) { options_ = options; } + + void Reset() { options_ = EncoderOptionsT::CreateDefaultOptions(); } + + void SetSpeedOptions(int encoding_speed, int decoding_speed) { + options_.SetSpeed(encoding_speed, decoding_speed); + } + + void SetEncodingMethod(int encoding_method) { + options_.SetGlobalInt("encoding_method", encoding_method); + } + + void SetEncodingSubmethod(int encoding_submethod) { + options_.SetGlobalInt("encoding_submethod", encoding_submethod); + } + + Status CheckPredictionScheme(GeometryAttribute::Type att_type, + int prediction_scheme) const { + // Out of bound checks: + if (prediction_scheme < PREDICTION_NONE) { + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme requested."); + } + if (prediction_scheme >= NUM_PREDICTION_SCHEMES) { + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme requested."); + } + // Deprecated prediction schemes: + if (prediction_scheme == MESH_PREDICTION_TEX_COORDS_DEPRECATED) { + return Status(Status::DRACO_ERROR, + "MESH_PREDICTION_TEX_COORDS_DEPRECATED is deprecated."); + } + if (prediction_scheme == MESH_PREDICTION_MULTI_PARALLELOGRAM) { + return Status(Status::DRACO_ERROR, + "MESH_PREDICTION_MULTI_PARALLELOGRAM is deprecated."); + } + // Attribute specific checks: + if (prediction_scheme == MESH_PREDICTION_TEX_COORDS_PORTABLE) { + if (att_type != GeometryAttribute::TEX_COORD) { + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme for attribute type."); + } + } + if (prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL) { + if (att_type != GeometryAttribute::NORMAL) { + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme for attribute type."); + } + } + // TODO(hemmer): Try to enable more prediction schemes for normals. + if (att_type == GeometryAttribute::NORMAL) { + if (!(prediction_scheme == PREDICTION_DIFFERENCE || + prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) { + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme for attribute type."); + } + } + return OkStatus(); + } + + protected: + void set_num_encoded_points(size_t num) { num_encoded_points_ = num; } + void set_num_encoded_faces(size_t num) { num_encoded_faces_ = num; } + + private: + EncoderOptionsT options_; + + size_t num_encoded_points_; + size_t num_encoded_faces_; +}; + +template +void EncoderBase::SetTrackEncodedProperties(bool flag) { + options_.SetGlobalBool("store_number_of_encoded_points", flag); + options_.SetGlobalBool("store_number_of_encoded_faces", flag); +} + +} // namespace draco + +#endif // DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/ans.h b/extern/draco/draco/src/draco/compression/entropy/ans.h new file mode 100644 index 00000000000..c765256b96e --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/ans.h @@ -0,0 +1,527 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_CORE_ANS_H_ +#define DRACO_CORE_ANS_H_ +// An implementation of Asymmetric Numeral Systems (rANS). +// See http://arxiv.org/abs/1311.2540v2 for more information on rANS. +// This file is based off libvpx's ans.h. + +#include + +#define DRACO_ANS_DIVIDE_BY_MULTIPLY 1 +#if DRACO_ANS_DIVIDE_BY_MULTIPLY +#include "draco/core/divide.h" +#endif +#include "draco/core/macros.h" + +namespace draco { + +#if DRACO_ANS_DIVIDE_BY_MULTIPLY + +#define DRACO_ANS_DIVREM(quotient, remainder, dividend, divisor) \ + do { \ + quotient = fastdiv(dividend, divisor); \ + remainder = dividend - quotient * divisor; \ + } while (0) +#define DRACO_ANS_DIV(dividend, divisor) fastdiv(dividend, divisor) +#else +#define DRACO_ANS_DIVREM(quotient, remainder, dividend, divisor) \ + do { \ + quotient = dividend / divisor; \ + remainder = dividend % divisor; \ + } while (0) +#define DRACO_ANS_DIV(dividend, divisor) ((dividend) / (divisor)) +#endif + +struct AnsCoder { + AnsCoder() : buf(nullptr), buf_offset(0), state(0) {} + uint8_t *buf; + int buf_offset; + uint32_t state; +}; + +struct AnsDecoder { + AnsDecoder() : buf(nullptr), buf_offset(0), state(0) {} + const uint8_t *buf; + int buf_offset; + uint32_t state; +}; + +typedef uint8_t AnsP8; +#define DRACO_ANS_P8_PRECISION 256u +#define DRACO_ANS_L_BASE (4096u) +#define DRACO_ANS_IO_BASE 256 + +static uint32_t mem_get_le16(const void *vmem) { + uint32_t val; + const uint8_t *mem = (const uint8_t *)vmem; + + val = mem[1] << 8; + val |= mem[0]; + return val; +} + +static uint32_t mem_get_le24(const void *vmem) { + uint32_t val; + const uint8_t *mem = (const uint8_t *)vmem; + + val = mem[2] << 16; + val |= mem[1] << 8; + val |= mem[0]; + return val; +} + +static inline uint32_t mem_get_le32(const void *vmem) { + uint32_t val; + const uint8_t *mem = (const uint8_t *)vmem; + + val = mem[3] << 24; + val |= mem[2] << 16; + val |= mem[1] << 8; + val |= mem[0]; + return val; +} + +static inline void mem_put_le16(void *vmem, uint32_t val) { + uint8_t *mem = reinterpret_cast(vmem); + + mem[0] = (val >> 0) & 0xff; + mem[1] = (val >> 8) & 0xff; +} + +static inline void mem_put_le24(void *vmem, uint32_t val) { + uint8_t *mem = reinterpret_cast(vmem); + + mem[0] = (val >> 0) & 0xff; + mem[1] = (val >> 8) & 0xff; + mem[2] = (val >> 16) & 0xff; +} + +static inline void mem_put_le32(void *vmem, uint32_t val) { + uint8_t *mem = reinterpret_cast(vmem); + + mem[0] = (val >> 0) & 0xff; + mem[1] = (val >> 8) & 0xff; + mem[2] = (val >> 16) & 0xff; + mem[3] = (val >> 24) & 0xff; +} + +static inline void ans_write_init(struct AnsCoder *const ans, + uint8_t *const buf) { + ans->buf = buf; + ans->buf_offset = 0; + ans->state = DRACO_ANS_L_BASE; +} + +static inline int ans_write_end(struct AnsCoder *const ans) { + uint32_t state; + DRACO_DCHECK_GE(ans->state, DRACO_ANS_L_BASE); + DRACO_DCHECK_LT(ans->state, DRACO_ANS_L_BASE * DRACO_ANS_IO_BASE); + state = ans->state - DRACO_ANS_L_BASE; + if (state < (1 << 6)) { + ans->buf[ans->buf_offset] = (0x00 << 6) + state; + return ans->buf_offset + 1; + } else if (state < (1 << 14)) { + mem_put_le16(ans->buf + ans->buf_offset, (0x01 << 14) + state); + return ans->buf_offset + 2; + } else if (state < (1 << 22)) { + mem_put_le24(ans->buf + ans->buf_offset, (0x02 << 22) + state); + return ans->buf_offset + 3; + } else { + DRACO_DCHECK(0 && "State is too large to be serialized"); + return ans->buf_offset; + } +} + +// rABS with descending spread. +// p or p0 takes the place of l_s from the paper. +// DRACO_ANS_P8_PRECISION is m. +static inline void rabs_desc_write(struct AnsCoder *ans, int val, AnsP8 p0) { + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + const unsigned l_s = val ? p : p0; + unsigned quot, rem; + if (ans->state >= + DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) { + ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE; + ans->state /= DRACO_ANS_IO_BASE; + } + DRACO_ANS_DIVREM(quot, rem, ans->state, l_s); + ans->state = quot * DRACO_ANS_P8_PRECISION + rem + (val ? 0 : p); +} + +#define DRACO_ANS_IMPL1 0 +#define UNPREDICTABLE(x) x +static inline int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) { + int val; +#if DRACO_ANS_IMPL1 + unsigned l_s; +#else + unsigned quot, rem, x, xn; +#endif + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + if (ans->state < DRACO_ANS_L_BASE && ans->buf_offset > 0) { + ans->state = ans->state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; + } +#if DRACO_ANS_IMPL1 + val = ans->state % DRACO_ANS_P8_PRECISION < p; + l_s = val ? p : p0; + ans->state = (ans->state / DRACO_ANS_P8_PRECISION) * l_s + + ans->state % DRACO_ANS_P8_PRECISION - (!val * p); +#else + x = ans->state; + quot = x / DRACO_ANS_P8_PRECISION; + rem = x % DRACO_ANS_P8_PRECISION; + xn = quot * p; + val = rem < p; + if (UNPREDICTABLE(val)) { + ans->state = xn + rem; + } else { + // ans->state = quot * p0 + rem - p; + ans->state = x - xn - p; + } +#endif + return val; +} + +// rABS with ascending spread. +// p or p0 takes the place of l_s from the paper. +// DRACO_ANS_P8_PRECISION is m. +static inline void rabs_asc_write(struct AnsCoder *ans, int val, AnsP8 p0) { + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + const unsigned l_s = val ? p : p0; + unsigned quot, rem; + if (ans->state >= + DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) { + ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE; + ans->state /= DRACO_ANS_IO_BASE; + } + DRACO_ANS_DIVREM(quot, rem, ans->state, l_s); + ans->state = quot * DRACO_ANS_P8_PRECISION + rem + (val ? p0 : 0); +} + +static inline int rabs_asc_read(struct AnsDecoder *ans, AnsP8 p0) { + int val; +#if DRACO_ANS_IMPL1 + unsigned l_s; +#else + unsigned quot, rem, x, xn; +#endif + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + if (ans->state < DRACO_ANS_L_BASE) { + ans->state = ans->state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; + } +#if DRACO_ANS_IMPL1 + val = ans->state % DRACO_ANS_P8_PRECISION < p; + l_s = val ? p : p0; + ans->state = (ans->state / DRACO_ANS_P8_PRECISION) * l_s + + ans->state % DRACO_ANS_P8_PRECISION - (!val * p); +#else + x = ans->state; + quot = x / DRACO_ANS_P8_PRECISION; + rem = x % DRACO_ANS_P8_PRECISION; + xn = quot * p; + val = rem >= p0; + if (UNPREDICTABLE(val)) { + ans->state = xn + rem - p0; + } else { + // ans->state = quot * p0 + rem - p0; + ans->state = x - xn; + } +#endif + return val; +} + +#define rabs_read rabs_desc_read +#define rabs_write rabs_desc_write + +// uABS with normalization. +static inline void uabs_write(struct AnsCoder *ans, int val, AnsP8 p0) { + AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + const unsigned l_s = val ? p : p0; + while (ans->state >= + DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) { + ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE; + ans->state /= DRACO_ANS_IO_BASE; + } + if (!val) { + ans->state = DRACO_ANS_DIV(ans->state * DRACO_ANS_P8_PRECISION, p0); + } else { + ans->state = + DRACO_ANS_DIV((ans->state + 1) * DRACO_ANS_P8_PRECISION + p - 1, p) - 1; + } +} + +static inline int uabs_read(struct AnsDecoder *ans, AnsP8 p0) { + AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + int s; + // unsigned int xp1; + unsigned xp, sp; + unsigned state = ans->state; + while (state < DRACO_ANS_L_BASE && ans->buf_offset > 0) { + state = state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; + } + sp = state * p; + // xp1 = (sp + p) / DRACO_ANS_P8_PRECISION; + xp = sp / DRACO_ANS_P8_PRECISION; + // s = xp1 - xp; + s = (sp & 0xFF) >= p0; + if (UNPREDICTABLE(s)) { + ans->state = xp; + } else { + ans->state = state - xp; + } + return s; +} + +static inline int uabs_read_bit(struct AnsDecoder *ans) { + int s; + unsigned state = ans->state; + while (state < DRACO_ANS_L_BASE && ans->buf_offset > 0) { + state = state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; + } + s = static_cast(state & 1); + ans->state = state >> 1; + return s; +} + +static inline int ans_read_init(struct AnsDecoder *const ans, + const uint8_t *const buf, int offset) { + unsigned x; + if (offset < 1) { + return 1; + } + ans->buf = buf; + x = buf[offset - 1] >> 6; + if (x == 0) { + ans->buf_offset = offset - 1; + ans->state = buf[offset - 1] & 0x3F; + } else if (x == 1) { + if (offset < 2) { + return 1; + } + ans->buf_offset = offset - 2; + ans->state = mem_get_le16(buf + offset - 2) & 0x3FFF; + } else if (x == 2) { + if (offset < 3) { + return 1; + } + ans->buf_offset = offset - 3; + ans->state = mem_get_le24(buf + offset - 3) & 0x3FFFFF; + } else { + return 1; + } + ans->state += DRACO_ANS_L_BASE; + if (ans->state >= DRACO_ANS_L_BASE * DRACO_ANS_IO_BASE) { + return 1; + } + return 0; +} + +static inline int ans_read_end(struct AnsDecoder *const ans) { + return ans->state == DRACO_ANS_L_BASE; +} + +static inline int ans_reader_has_error(const struct AnsDecoder *const ans) { + return ans->state < DRACO_ANS_L_BASE && ans->buf_offset == 0; +} + +struct rans_sym { + uint32_t prob; + uint32_t cum_prob; // not-inclusive. +}; + +// Class for performing rANS encoding using a desired number of precision bits. +// The max number of precision bits is currently 19. The actual number of +// symbols in the input alphabet should be (much) smaller than that, otherwise +// the compression rate may suffer. +template +class RAnsEncoder { + public: + RAnsEncoder() {} + + // Provides the input buffer where the data is going to be stored. + inline void write_init(uint8_t *const buf) { + ans_.buf = buf; + ans_.buf_offset = 0; + ans_.state = l_rans_base; + } + + // Needs to be called after all symbols are encoded. + inline int write_end() { + uint32_t state; + DRACO_DCHECK_GE(ans_.state, l_rans_base); + DRACO_DCHECK_LT(ans_.state, l_rans_base * DRACO_ANS_IO_BASE); + state = ans_.state - l_rans_base; + if (state < (1 << 6)) { + ans_.buf[ans_.buf_offset] = (0x00 << 6) + state; + return ans_.buf_offset + 1; + } else if (state < (1 << 14)) { + mem_put_le16(ans_.buf + ans_.buf_offset, (0x01 << 14) + state); + return ans_.buf_offset + 2; + } else if (state < (1 << 22)) { + mem_put_le24(ans_.buf + ans_.buf_offset, (0x02 << 22) + state); + return ans_.buf_offset + 3; + } else if (state < (1 << 30)) { + mem_put_le32(ans_.buf + ans_.buf_offset, (0x03u << 30u) + state); + return ans_.buf_offset + 4; + } else { + DRACO_DCHECK(0 && "State is too large to be serialized"); + return ans_.buf_offset; + } + } + + // rANS with normalization. + // sym->prob takes the place of l_s from the paper. + // rans_precision is m. + inline void rans_write(const struct rans_sym *const sym) { + const uint32_t p = sym->prob; + while (ans_.state >= l_rans_base / rans_precision * DRACO_ANS_IO_BASE * p) { + ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE; + ans_.state /= DRACO_ANS_IO_BASE; + } + // TODO(ostava): The division and multiplication should be optimized. + ans_.state = + (ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob; + } + + private: + static constexpr int rans_precision = 1 << rans_precision_bits_t; + static constexpr int l_rans_base = rans_precision * 4; + AnsCoder ans_; +}; + +struct rans_dec_sym { + uint32_t val; + uint32_t prob; + uint32_t cum_prob; // not-inclusive. +}; + +// Class for performing rANS decoding using a desired number of precision bits. +// The number of precision bits needs to be the same as with the RAnsEncoder +// that was used to encode the input data. +template +class RAnsDecoder { + public: + RAnsDecoder() {} + + // Initializes the decoder from the input buffer. The |offset| specifies the + // number of bytes encoded by the encoder. A non zero return value is an + // error. + inline int read_init(const uint8_t *const buf, int offset) { + unsigned x; + if (offset < 1) { + return 1; + } + ans_.buf = buf; + x = buf[offset - 1] >> 6; + if (x == 0) { + ans_.buf_offset = offset - 1; + ans_.state = buf[offset - 1] & 0x3F; + } else if (x == 1) { + if (offset < 2) { + return 1; + } + ans_.buf_offset = offset - 2; + ans_.state = mem_get_le16(buf + offset - 2) & 0x3FFF; + } else if (x == 2) { + if (offset < 3) { + return 1; + } + ans_.buf_offset = offset - 3; + ans_.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF; + } else if (x == 3) { + ans_.buf_offset = offset - 4; + ans_.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF; + } else { + return 1; + } + ans_.state += l_rans_base; + if (ans_.state >= l_rans_base * DRACO_ANS_IO_BASE) { + return 1; + } + return 0; + } + + inline int read_end() { return ans_.state == l_rans_base; } + + inline int reader_has_error() { + return ans_.state < l_rans_base && ans_.buf_offset == 0; + } + + inline int rans_read() { + unsigned rem; + unsigned quo; + struct rans_dec_sym sym; + while (ans_.state < l_rans_base && ans_.buf_offset > 0) { + ans_.state = ans_.state * DRACO_ANS_IO_BASE + ans_.buf[--ans_.buf_offset]; + } + // |rans_precision| is a power of two compile time constant, and the below + // division and modulo are going to be optimized by the compiler. + quo = ans_.state / rans_precision; + rem = ans_.state % rans_precision; + fetch_sym(&sym, rem); + ans_.state = quo * sym.prob + rem - sym.cum_prob; + return sym.val; + } + + // Construct a lookup table with |rans_precision| number of entries. + // Returns false if the table couldn't be built (because of wrong input data). + inline bool rans_build_look_up_table(const uint32_t token_probs[], + uint32_t num_symbols) { + lut_table_.resize(rans_precision); + probability_table_.resize(num_symbols); + uint32_t cum_prob = 0; + uint32_t act_prob = 0; + for (uint32_t i = 0; i < num_symbols; ++i) { + probability_table_[i].prob = token_probs[i]; + probability_table_[i].cum_prob = cum_prob; + cum_prob += token_probs[i]; + if (cum_prob > rans_precision) { + return false; + } + for (uint32_t j = act_prob; j < cum_prob; ++j) { + lut_table_[j] = i; + } + act_prob = cum_prob; + } + if (cum_prob != rans_precision) { + return false; + } + return true; + } + + private: + inline void fetch_sym(struct rans_dec_sym *out, uint32_t rem) { + uint32_t symbol = lut_table_[rem]; + out->val = symbol; + out->prob = probability_table_[symbol].prob; + out->cum_prob = probability_table_[symbol].cum_prob; + } + + static constexpr int rans_precision = 1 << rans_precision_bits_t; + static constexpr int l_rans_base = rans_precision * 4; + std::vector lut_table_; + std::vector probability_table_; + AnsDecoder ans_; +}; + +#undef DRACO_ANS_DIVREM +#undef DRACO_ANS_P8_PRECISION +#undef DRACO_ANS_L_BASE +#undef DRACO_ANS_IO_BASE + +} // namespace draco + +#endif // DRACO_CORE_ANS_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h new file mode 100644 index 00000000000..0a68e29fe26 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h @@ -0,0 +1,54 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// File providing shared functionality for RAnsSymbolEncoder and +// RAnsSymbolDecoder (see rans_symbol_encoder.h / rans_symbol_decoder.h). +#ifndef DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_CODING_H_ +#define DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_CODING_H_ + +#include "draco/compression/entropy/ans.h" + +namespace draco { + +// Computes the desired precision of the rANS method for the specified number of +// unique symbols the input data (defined by their bit_length). +constexpr int ComputeRAnsUnclampedPrecision(int symbols_bit_length) { + return (3 * symbols_bit_length) / 2; +} + +// Computes the desired precision clamped to guarantee a valid functionality of +// our rANS library (which is between 12 to 20 bits). +constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength( + int symbols_bit_length) { + return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12 + ? 12 + : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20 + ? 20 + : ComputeRAnsUnclampedPrecision(symbols_bit_length); +} + +// Compute approximate frequency table size needed for storing the provided +// symbols. +static inline int64_t ApproximateRAnsFrequencyTableBits( + int32_t max_value, int num_unique_symbols) { + // Approximate number of bits for storing zero frequency entries using the + // run length encoding (with max length of 64). + const int64_t table_zero_frequency_bits = + 8 * (num_unique_symbols + (max_value - num_unique_symbols) / 64); + return 8 * num_unique_symbols + table_zero_frequency_bits; +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_CODING_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_decoder.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_decoder.h new file mode 100644 index 00000000000..10cdc6781a0 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_decoder.h @@ -0,0 +1,164 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_DECODER_H_ +#define DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_DECODER_H_ + +#include "draco/compression/config/compression_shared.h" +#include "draco/compression/entropy/rans_symbol_coding.h" +#include "draco/core/decoder_buffer.h" +#include "draco/core/varint_decoding.h" +#include "draco/draco_features.h" + +namespace draco { + +// A helper class for decoding symbols using the rANS algorithm (see ans.h). +// The class can be used to decode the probability table and the data encoded +// by the RAnsSymbolEncoder. |unique_symbols_bit_length_t| must be the same as +// the one used for the corresponding RAnsSymbolEncoder. +template +class RAnsSymbolDecoder { + public: + RAnsSymbolDecoder() : num_symbols_(0) {} + + // Initialize the decoder and decode the probability table. + bool Create(DecoderBuffer *buffer); + + uint32_t num_symbols() const { return num_symbols_; } + + // Starts decoding from the buffer. The buffer will be advanced past the + // encoded data after this call. + bool StartDecoding(DecoderBuffer *buffer); + uint32_t DecodeSymbol() { return ans_.rans_read(); } + void EndDecoding(); + + private: + static constexpr int rans_precision_bits_ = + ComputeRAnsPrecisionFromUniqueSymbolsBitLength( + unique_symbols_bit_length_t); + static constexpr int rans_precision_ = 1 << rans_precision_bits_; + + std::vector probability_table_; + uint32_t num_symbols_; + RAnsDecoder ans_; +}; + +template +bool RAnsSymbolDecoder::Create( + DecoderBuffer *buffer) { + // Check that the DecoderBuffer version is set. + if (buffer->bitstream_version() == 0) { + return false; + } + // Decode the number of alphabet symbols. +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { + if (!buffer->Decode(&num_symbols_)) { + return false; + } + + } else +#endif + { + if (!DecodeVarint(&num_symbols_, buffer)) { + return false; + } + } + probability_table_.resize(num_symbols_); + if (num_symbols_ == 0) { + return true; + } + // Decode the table. + for (uint32_t i = 0; i < num_symbols_; ++i) { + uint8_t prob_data = 0; + // Decode the first byte and extract the number of extra bytes we need to + // get, or the offset to the next symbol with non-zero probability. + if (!buffer->Decode(&prob_data)) { + return false; + } + // Token is stored in the first two bits of the first byte. Values 0-2 are + // used to indicate the number of extra bytes, and value 3 is a special + // symbol used to denote run-length coding of zero probability entries. + // See rans_symbol_encoder.h for more details. + const int token = prob_data & 3; + if (token == 3) { + const uint32_t offset = prob_data >> 2; + if (i + offset >= num_symbols_) { + return false; + } + // Set zero probability for all symbols in the specified range. + for (uint32_t j = 0; j < offset + 1; ++j) { + probability_table_[i + j] = 0; + } + i += offset; + } else { + const int extra_bytes = token; + uint32_t prob = prob_data >> 2; + for (int b = 0; b < extra_bytes; ++b) { + uint8_t eb; + if (!buffer->Decode(&eb)) { + return false; + } + // Shift 8 bits for each extra byte and subtract 2 for the two first + // bits. + prob |= static_cast(eb) << (8 * (b + 1) - 2); + } + probability_table_[i] = prob; + } + } + if (!ans_.rans_build_look_up_table(&probability_table_[0], num_symbols_)) { + return false; + } + return true; +} + +template +bool RAnsSymbolDecoder::StartDecoding( + DecoderBuffer *buffer) { + uint64_t bytes_encoded; + // Decode the number of bytes encoded by the encoder. +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED + if (buffer->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { + if (!buffer->Decode(&bytes_encoded)) { + return false; + } + + } else +#endif + { + if (!DecodeVarint(&bytes_encoded, buffer)) { + return false; + } + } + if (bytes_encoded > static_cast(buffer->remaining_size())) { + return false; + } + const uint8_t *const data_head = + reinterpret_cast(buffer->data_head()); + // Advance the buffer past the rANS data. + buffer->Advance(bytes_encoded); + if (ans_.read_init(data_head, static_cast(bytes_encoded)) != 0) { + return false; + } + return true; +} + +template +void RAnsSymbolDecoder::EndDecoding() { + ans_.read_end(); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_DECODER_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h new file mode 100644 index 00000000000..4e07ec87123 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h @@ -0,0 +1,290 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_ENCODER_H_ +#define DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_ENCODER_H_ + +#include +#include +#include + +#include "draco/compression/entropy/ans.h" +#include "draco/compression/entropy/rans_symbol_coding.h" +#include "draco/core/encoder_buffer.h" +#include "draco/core/varint_encoding.h" + +namespace draco { + +// A helper class for encoding symbols using the rANS algorithm (see ans.h). +// The class can be used to initialize and encode probability table needed by +// rANS, and to perform encoding of symbols into the provided EncoderBuffer. +template +class RAnsSymbolEncoder { + public: + RAnsSymbolEncoder() + : num_symbols_(0), num_expected_bits_(0), buffer_offset_(0) {} + + // Creates a probability table needed by the rANS library and encode it into + // the provided buffer. + bool Create(const uint64_t *frequencies, int num_symbols, + EncoderBuffer *buffer); + + void StartEncoding(EncoderBuffer *buffer); + void EncodeSymbol(uint32_t symbol) { + ans_.rans_write(&probability_table_[symbol]); + } + void EndEncoding(EncoderBuffer *buffer); + + // rANS requires to encode the input symbols in the reverse order. + static constexpr bool needs_reverse_encoding() { return true; } + + private: + // Functor used for sorting symbol ids according to their probabilities. + // The functor sorts symbol indices that index an underlying map between + // symbol ids and their probabilities. We don't sort the probability table + // directly, because that would require an additional indirection during the + // EncodeSymbol() function. + struct ProbabilityLess { + explicit ProbabilityLess(const std::vector *probs) + : probabilities(probs) {} + bool operator()(int i, int j) const { + return probabilities->at(i).prob < probabilities->at(j).prob; + } + const std::vector *probabilities; + }; + + // Encodes the probability table into the output buffer. + bool EncodeTable(EncoderBuffer *buffer); + + static constexpr int rans_precision_bits_ = + ComputeRAnsPrecisionFromUniqueSymbolsBitLength( + unique_symbols_bit_length_t); + static constexpr int rans_precision_ = 1 << rans_precision_bits_; + + std::vector probability_table_; + // The number of symbols in the input alphabet. + uint32_t num_symbols_; + // Expected number of bits that is needed to encode the input. + uint64_t num_expected_bits_; + + RAnsEncoder ans_; + // Initial offset of the encoder buffer before any ans data was encoded. + uint64_t buffer_offset_; +}; + +template +bool RAnsSymbolEncoder::Create( + const uint64_t *frequencies, int num_symbols, EncoderBuffer *buffer) { + // Compute the total of the input frequencies. + uint64_t total_freq = 0; + int max_valid_symbol = 0; + for (int i = 0; i < num_symbols; ++i) { + total_freq += frequencies[i]; + if (frequencies[i] > 0) { + max_valid_symbol = i; + } + } + num_symbols = max_valid_symbol + 1; + num_symbols_ = num_symbols; + probability_table_.resize(num_symbols); + const double total_freq_d = static_cast(total_freq); + const double rans_precision_d = static_cast(rans_precision_); + // Compute probabilities by rescaling the normalized frequencies into interval + // [1, rans_precision - 1]. The total probability needs to be equal to + // rans_precision. + int total_rans_prob = 0; + for (int i = 0; i < num_symbols; ++i) { + const uint64_t freq = frequencies[i]; + + // Normalized probability. + const double prob = static_cast(freq) / total_freq_d; + + // RAns probability in range of [1, rans_precision - 1]. + uint32_t rans_prob = static_cast(prob * rans_precision_d + 0.5f); + if (rans_prob == 0 && freq > 0) { + rans_prob = 1; + } + probability_table_[i].prob = rans_prob; + total_rans_prob += rans_prob; + } + // Because of rounding errors, the total precision may not be exactly accurate + // and we may need to adjust the entries a little bit. + if (total_rans_prob != rans_precision_) { + std::vector sorted_probabilities(num_symbols); + for (int i = 0; i < num_symbols; ++i) { + sorted_probabilities[i] = i; + } + std::sort(sorted_probabilities.begin(), sorted_probabilities.end(), + ProbabilityLess(&probability_table_)); + if (total_rans_prob < rans_precision_) { + // This happens rather infrequently, just add the extra needed precision + // to the most frequent symbol. + probability_table_[sorted_probabilities.back()].prob += + rans_precision_ - total_rans_prob; + } else { + // We have over-allocated the precision, which is quite common. + // Rescale the probabilities of all symbols. + int32_t error = total_rans_prob - rans_precision_; + while (error > 0) { + const double act_total_prob_d = static_cast(total_rans_prob); + const double act_rel_error_d = rans_precision_d / act_total_prob_d; + for (int j = num_symbols - 1; j > 0; --j) { + int symbol_id = sorted_probabilities[j]; + if (probability_table_[symbol_id].prob <= 1) { + if (j == num_symbols - 1) { + return false; // Most frequent symbol would be empty. + } + break; + } + const int32_t new_prob = static_cast( + floor(act_rel_error_d * + static_cast(probability_table_[symbol_id].prob))); + int32_t fix = probability_table_[symbol_id].prob - new_prob; + if (fix == 0u) { + fix = 1; + } + if (fix >= static_cast(probability_table_[symbol_id].prob)) { + fix = probability_table_[symbol_id].prob - 1; + } + if (fix > error) { + fix = error; + } + probability_table_[symbol_id].prob -= fix; + total_rans_prob -= fix; + error -= fix; + if (total_rans_prob == rans_precision_) { + break; + } + } + } + } + } + + // Compute the cumulative probability (cdf). + uint32_t total_prob = 0; + for (int i = 0; i < num_symbols; ++i) { + probability_table_[i].cum_prob = total_prob; + total_prob += probability_table_[i].prob; + } + if (total_prob != rans_precision_) { + return false; + } + + // Estimate the number of bits needed to encode the input. + // From Shannon entropy the total number of bits N is: + // N = -sum{i : all_symbols}(F(i) * log2(P(i))) + // where P(i) is the normalized probability of symbol i and F(i) is the + // symbol's frequency in the input data. + double num_bits = 0; + for (int i = 0; i < num_symbols; ++i) { + if (probability_table_[i].prob == 0) { + continue; + } + const double norm_prob = + static_cast(probability_table_[i].prob) / rans_precision_d; + num_bits += static_cast(frequencies[i]) * log2(norm_prob); + } + num_expected_bits_ = static_cast(ceil(-num_bits)); + if (!EncodeTable(buffer)) { + return false; + } + return true; +} + +template +bool RAnsSymbolEncoder::EncodeTable( + EncoderBuffer *buffer) { + EncodeVarint(num_symbols_, buffer); + // Use varint encoding for the probabilities (first two bits represent the + // number of bytes used - 1). + for (uint32_t i = 0; i < num_symbols_; ++i) { + const uint32_t prob = probability_table_[i].prob; + int num_extra_bytes = 0; + if (prob >= (1 << 6)) { + num_extra_bytes++; + if (prob >= (1 << 14)) { + num_extra_bytes++; + if (prob >= (1 << 22)) { + // The maximum number of precision bits is 20 so we should not really + // get to this point. + return false; + } + } + } + if (prob == 0) { + // When the probability of the symbol is 0, set the first two bits to 1 + // (unique identifier) and use the remaining 6 bits to store the offset + // to the next symbol with non-zero probability. + uint32_t offset = 0; + for (; offset < (1 << 6) - 1; ++offset) { + // Note: we don't have to check whether the next symbol id is larger + // than num_symbols_ because we know that the last symbol always has + // non-zero probability. + const uint32_t next_prob = probability_table_[i + offset + 1].prob; + if (next_prob > 0) { + break; + } + } + buffer->Encode(static_cast((offset << 2) | 3)); + i += offset; + } else { + // Encode the first byte (including the number of extra bytes). + buffer->Encode(static_cast((prob << 2) | (num_extra_bytes & 3))); + // Encode the extra bytes. + for (int b = 0; b < num_extra_bytes; ++b) { + buffer->Encode(static_cast(prob >> (8 * (b + 1) - 2))); + } + } + } + return true; +} + +template +void RAnsSymbolEncoder::StartEncoding( + EncoderBuffer *buffer) { + // Allocate extra storage just in case. + const uint64_t required_bits = 2 * num_expected_bits_ + 32; + + buffer_offset_ = buffer->size(); + const int64_t required_bytes = (required_bits + 7) / 8; + buffer->Resize(buffer_offset_ + required_bytes + sizeof(buffer_offset_)); + uint8_t *const data = + reinterpret_cast(const_cast(buffer->data())); + ans_.write_init(data + buffer_offset_); +} + +template +void RAnsSymbolEncoder::EndEncoding( + EncoderBuffer *buffer) { + char *const src = const_cast(buffer->data()) + buffer_offset_; + + // TODO(fgalligan): Look into changing this to uint32_t as write_end() + // returns an int. + const uint64_t bytes_written = static_cast(ans_.write_end()); + EncoderBuffer var_size_buffer; + EncodeVarint(bytes_written, &var_size_buffer); + const uint32_t size_len = static_cast(var_size_buffer.size()); + char *const dst = src + size_len; + memmove(dst, src, bytes_written); + + // Store the size of the encoded data. + memcpy(src, var_size_buffer.data(), size_len); + + // Resize the buffer to match the number of encoded bytes. + buffer->Resize(buffer_offset_ + bytes_written + size_len); +} + +} // namespace draco + +#endif // DRACO_COMPRESSION_ENTROPY_RANS_SYMBOL_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/shannon_entropy.cc b/extern/draco/draco/src/draco/compression/entropy/shannon_entropy.cc new file mode 100644 index 00000000000..137eafe5fac --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/shannon_entropy.cc @@ -0,0 +1,147 @@ +#include "draco/compression/entropy/shannon_entropy.h" + +#include +#include + +#include "draco/compression/entropy/rans_symbol_coding.h" + +namespace draco { + +int64_t ComputeShannonEntropy(const uint32_t *symbols, int num_symbols, + int max_value, int *out_num_unique_symbols) { + // First find frequency of all unique symbols in the input array. + int num_unique_symbols = 0; + std::vector symbol_frequencies(max_value + 1, 0); + for (int i = 0; i < num_symbols; ++i) { + ++symbol_frequencies[symbols[i]]; + } + double total_bits = 0; + double num_symbols_d = num_symbols; + for (int i = 0; i < max_value + 1; ++i) { + if (symbol_frequencies[i] > 0) { + ++num_unique_symbols; + // Compute Shannon entropy for the symbol. + // We don't want to use std::log2 here for Android build. + total_bits += + symbol_frequencies[i] * + log2(static_cast(symbol_frequencies[i]) / num_symbols_d); + } + } + if (out_num_unique_symbols) { + *out_num_unique_symbols = num_unique_symbols; + } + // Entropy is always negative. + return static_cast(-total_bits); +} + +double ComputeBinaryShannonEntropy(uint32_t num_values, + uint32_t num_true_values) { + if (num_values == 0) { + return 0; + } + + // We can exit early if the data set has 0 entropy. + if (num_true_values == 0 || num_values == num_true_values) { + return 0; + } + const double true_freq = + static_cast(num_true_values) / static_cast(num_values); + const double false_freq = 1.0 - true_freq; + return -(true_freq * std::log2(true_freq) + + false_freq * std::log2(false_freq)); +} + +ShannonEntropyTracker::ShannonEntropyTracker() {} + +ShannonEntropyTracker::EntropyData ShannonEntropyTracker::Peek( + const uint32_t *symbols, int num_symbols) { + return UpdateSymbols(symbols, num_symbols, false); +} + +ShannonEntropyTracker::EntropyData ShannonEntropyTracker::Push( + const uint32_t *symbols, int num_symbols) { + return UpdateSymbols(symbols, num_symbols, true); +} + +ShannonEntropyTracker::EntropyData ShannonEntropyTracker::UpdateSymbols( + const uint32_t *symbols, int num_symbols, bool push_changes) { + EntropyData ret_data = entropy_data_; + ret_data.num_values += num_symbols; + for (int i = 0; i < num_symbols; ++i) { + const uint32_t symbol = symbols[i]; + if (frequencies_.size() <= symbol) { + frequencies_.resize(symbol + 1, 0); + } + + // Update the entropy of the stream. Note that entropy of |N| values + // represented by |S| unique symbols is defined as: + // + // entropy = -sum_over_S(symbol_frequency / N * log2(symbol_frequency / N)) + // + // To avoid the need to recompute the entire sum when new values are added, + // we can instead update a so called entropy norm that is defined as: + // + // entropy_norm = sum_over_S(symbol_frequency * log2(symbol_frequency)) + // + // In this case, all we need to do is update entries on the symbols where + // the frequency actually changed. + // + // Note that entropy_norm and entropy can be easily transformed to the + // actual entropy as: + // + // entropy = log2(N) - entropy_norm / N + // + double old_symbol_entropy_norm = 0; + int &frequency = frequencies_[symbol]; + if (frequency > 1) { + old_symbol_entropy_norm = frequency * std::log2(frequency); + } else if (frequency == 0) { + ret_data.num_unique_symbols++; + if (symbol > static_cast(ret_data.max_symbol)) { + ret_data.max_symbol = symbol; + } + } + frequency++; + const double new_symbol_entropy_norm = frequency * std::log2(frequency); + + // Update the final entropy. + ret_data.entropy_norm += new_symbol_entropy_norm - old_symbol_entropy_norm; + } + if (push_changes) { + // Update entropy data of the stream. + entropy_data_ = ret_data; + } else { + // We are only peeking so do not update the stream. + // Revert changes in the frequency table. + for (int i = 0; i < num_symbols; ++i) { + const uint32_t symbol = symbols[i]; + frequencies_[symbol]--; + } + } + return ret_data; +} + +int64_t ShannonEntropyTracker::GetNumberOfDataBits( + const EntropyData &entropy_data) { + if (entropy_data.num_values < 2) { + return 0; + } + // We need to compute the number of bits required to represent the stream + // using the entropy norm. Note that: + // + // entropy = log2(num_values) - entropy_norm / num_values + // + // and number of bits required for the entropy is: num_values * entropy + // + return static_cast( + ceil(entropy_data.num_values * std::log2(entropy_data.num_values) - + entropy_data.entropy_norm)); +} + +int64_t ShannonEntropyTracker::GetNumberOfRAnsTableBits( + const EntropyData &entropy_data) { + return ApproximateRAnsFrequencyTableBits(entropy_data.max_symbol + 1, + entropy_data.num_unique_symbols); +} + +} // namespace draco diff --git a/extern/draco/draco/src/draco/compression/entropy/shannon_entropy.h b/extern/draco/draco/src/draco/compression/entropy/shannon_entropy.h new file mode 100644 index 00000000000..85165f4cb8d --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/shannon_entropy.h @@ -0,0 +1,110 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_COMPRESSION_ENTROPY_SHANNON_ENTROPY_H_ +#define DRACO_COMPRESSION_ENTROPY_SHANNON_ENTROPY_H_ + +#include + +#include + +namespace draco { + +// Computes an approximate Shannon entropy of symbols stored in the provided +// input array |symbols|. The entropy corresponds to the number of bits that is +// required to represent/store all the symbols using an optimal entropy coding +// algorithm. See for example "A mathematical theory of communication" by +// Shannon'48 (http://ieeexplore.ieee.org/document/6773024/). +// +// |max_value| is a required input that define the maximum value in the input +// |symbols| array. +// +// |out_num_unique_symbols| is an optional output argument that stores the +// number of unique symbols contained within the |symbols| array. +// TODO(ostava): This should be renamed or the return value should be changed to +// return the actual entropy and not the number of bits needed to represent the +// input symbols. +int64_t ComputeShannonEntropy(const uint32_t *symbols, int num_symbols, + int max_value, int *out_num_unique_symbols); + +// Computes the Shannon entropy of |num_values| Boolean entries, where +// |num_true_values| are set to true. +// Returns entropy between 0-1. +double ComputeBinaryShannonEntropy(uint32_t num_values, + uint32_t num_true_values); + +// Class that can be used to keep track of the Shannon entropy on streamed data. +// As new symbols are pushed to the tracker, the entropy is automatically +// recomputed. The class also support recomputing the entropy without actually +// pushing the symbols to the tracker through the Peek() method. +class ShannonEntropyTracker { + public: + ShannonEntropyTracker(); + + // Struct for holding entropy data about the symbols added to the tracker. + // It can be used to compute the number of bits needed to store the data using + // the method: + // ShannonEntropyTracker::GetNumberOfDataBits(entropy_data); + // or to compute the approximate size of the frequency table needed by the + // rans coding using method: + // ShannonEntropyTracker::GetNumberOfRAnsTableBits(entropy_data); + struct EntropyData { + double entropy_norm; + int num_values; + int max_symbol; + int num_unique_symbols; + EntropyData() + : entropy_norm(0.0), + num_values(0), + max_symbol(0), + num_unique_symbols(0) {} + }; + + // Adds new symbols to the tracker and recomputes the entropy accordingly. + EntropyData Push(const uint32_t *symbols, int num_symbols); + + // Returns new entropy data for the tracker as if |symbols| were added to the + // tracker without actually changing the status of the tracker. + EntropyData Peek(const uint32_t *symbols, int num_symbols); + + // Gets the number of bits needed for encoding symbols added to the tracker. + int64_t GetNumberOfDataBits() const { + return GetNumberOfDataBits(entropy_data_); + } + + // Gets the number of bits needed for encoding frequency table using the rans + // encoder. + int64_t GetNumberOfRAnsTableBits() const { + return GetNumberOfRAnsTableBits(entropy_data_); + } + + // Gets the number of bits needed for encoding given |entropy_data|. + static int64_t GetNumberOfDataBits(const EntropyData &entropy_data); + + // Gets the number of bits needed for encoding frequency table using the rans + // encoder for the given |entropy_data|. + static int64_t GetNumberOfRAnsTableBits(const EntropyData &entropy_data); + + private: + EntropyData UpdateSymbols(const uint32_t *symbols, int num_symbols, + bool push_changes); + + std::vector frequencies_; + + EntropyData entropy_data_; +}; + +} // namespace draco + +#endif // DRACO_COMPRESSION_ENTROPY_SHANNON_ENTROPY_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc new file mode 100644 index 00000000000..93d29971c89 --- /dev/null +++ b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc @@ -0,0 +1,181 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/entropy/symbol_decoding.h" + +#include +#include + +#include "draco/compression/entropy/rans_symbol_decoder.h" + +namespace draco { + +template