From b4b888fd2a72f63a2b5a7115eb1c1ff9bdfb7a3e Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 9 Dec 2020 16:09:13 -0500 Subject: [PATCH 01/12] Cleanup: Reduce Variable scope clip_buttons --- .../blender/editors/space_clip/clip_buttons.c | 125 +++++++----------- 1 file changed, 47 insertions(+), 78 deletions(-) diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index e0f603eb3d1..fe03a37d4aa 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -104,17 +104,11 @@ void ED_clip_buttons_register(ARegionType *art) void uiTemplateMovieClip( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, bool compact) { - PropertyRNA *prop; - PointerRNA clipptr; - MovieClip *clip; - uiLayout *row, *split; - uiBlock *block; - if (!ptr->data) { return; } - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); @@ -129,8 +123,8 @@ void uiTemplateMovieClip( return; } - clipptr = RNA_property_pointer_get(ptr, prop); - clip = clipptr.data; + PointerRNA clipptr = RNA_property_pointer_get(ptr, prop); + MovieClip *clip = clipptr.data; uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr); @@ -149,20 +143,18 @@ void uiTemplateMovieClip( } if (clip) { - uiLayout *col; - - row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); + uiLayout *row = uiLayoutRow(layout, false); + uiBlock *block = uiLayoutGetBlock(row); uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, ""); row = uiLayoutRow(layout, false); - split = uiLayoutSplit(row, 0.0f, false); + uiLayout *split = uiLayoutSplit(row, 0.0f, false); row = uiLayoutRow(split, true); uiItemR(row, &clipptr, "filepath", 0, "", ICON_NONE); uiItemO(row, "", ICON_FILE_REFRESH, "clip.reload"); - col = uiLayoutColumn(layout, false); + uiLayout *col = uiLayoutColumn(layout, false); uiTemplateColorspaceSettings(col, &clipptr, "colorspace_settings"); } } @@ -171,17 +163,11 @@ void uiTemplateMovieClip( void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname) { - PropertyRNA *prop; - PointerRNA scopesptr; - uiBlock *block; - uiLayout *col; - MovieClipScopes *scopes; - if (!ptr->data) { return; } - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); @@ -196,8 +182,8 @@ void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname) return; } - scopesptr = RNA_property_pointer_get(ptr, prop); - scopes = (MovieClipScopes *)scopesptr.data; + PointerRNA scopesptr = RNA_property_pointer_get(ptr, prop); + MovieClipScopes *scopes = (MovieClipScopes *)scopesptr.data; if (scopes->track_preview_height < UI_UNIT_Y) { scopes->track_preview_height = UI_UNIT_Y; @@ -206,8 +192,8 @@ void uiTemplateTrack(uiLayout *layout, PointerRNA *ptr, const char *propname) scopes->track_preview_height = UI_UNIT_Y * 20; } - col = uiLayoutColumn(layout, true); - block = uiLayoutGetBlock(col); + uiLayout *col = uiLayoutColumn(layout, true); + uiBlock *block = uiLayoutGetBlock(col); uiDefBut(block, UI_BTYPE_TRACK_PREVIEW, @@ -319,8 +305,6 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) } else if (event == B_MARKER_PAT_DIM) { float dim[2], pat_dim[2], pat_min[2], pat_max[2]; - float scale_x, scale_y; - int a; BKE_tracking_marker_pattern_minmax(cb->marker, pat_min, pat_max); @@ -329,10 +313,10 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) dim[0] = cb->marker_pat[0] / width; dim[1] = cb->marker_pat[1] / height; - scale_x = dim[0] / pat_dim[0]; - scale_y = dim[1] / pat_dim[1]; + float scale_x = dim[0] / pat_dim[0]; + float scale_y = dim[1] / pat_dim[1]; - for (a = 0; a < 4; a++) { + for (int a = 0; a < 4; a++) { cb->marker->pattern_corners[a][0] *= scale_x; cb->marker->pattern_corners[a][1] *= scale_y; } @@ -415,23 +399,11 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *trackptr, bool compact) { - PropertyRNA *prop; - uiBlock *block; - uiBut *bt; - PointerRNA clipptr; - MovieClip *clip; - MovieClipUser *user; - MovieTrackingTrack *track; - MovieTrackingMarker *marker; - MarkerUpdateCb *cb; - const char *tip; - float pat_min[2], pat_max[2]; - if (!ptr->data) { return; } - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); @@ -446,15 +418,15 @@ void uiTemplateMarker(uiLayout *layout, return; } - clipptr = RNA_property_pointer_get(ptr, prop); - clip = (MovieClip *)clipptr.data; - user = userptr->data; - track = trackptr->data; + PointerRNA clipptr = RNA_property_pointer_get(ptr, prop); + MovieClip *clip = (MovieClip *)clipptr.data; + MovieClipUser *user = userptr->data; + MovieTrackingTrack *track = trackptr->data; int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); - marker = BKE_tracking_marker_get(track, clip_framenr); + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr); - cb = MEM_callocN(sizeof(MarkerUpdateCb), "uiTemplateMarker update_cb"); + MarkerUpdateCb *cb = MEM_callocN(sizeof(MarkerUpdateCb), "uiTemplateMarker update_cb"); cb->compact = compact; cb->clip = clip; cb->user = user; @@ -464,7 +436,8 @@ void uiTemplateMarker(uiLayout *layout, cb->framenr = user->framenr; if (compact) { - block = uiLayoutGetBlock(layout); + const char *tip; + uiBlock *block = uiLayoutGetBlock(layout); if (cb->marker_flag & MARKER_DISABLED) { tip = TIP_("Marker is disabled at current frame"); @@ -473,7 +446,7 @@ void uiTemplateMarker(uiLayout *layout, tip = TIP_("Marker is enabled at current frame"); } - bt = uiDefIconButBitI(block, + uiBut *bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE_N, MARKER_DISABLED, 0, @@ -492,15 +465,13 @@ void uiTemplateMarker(uiLayout *layout, UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } else { - int width, height, step, digits; - float pat_dim[2], search_dim[2], search_pos[2]; - uiLayout *col; + int width, height; BKE_movieclip_get_size(clip, user, &width, &height); if (track->flag & TRACK_LOCKED) { uiLayoutSetActive(layout, false); - block = uiLayoutAbsoluteBlock(layout); + uiBlock *block = uiLayoutAbsoluteBlock(layout); uiDefBut(block, UI_BTYPE_LABEL, 0, @@ -519,8 +490,8 @@ void uiTemplateMarker(uiLayout *layout, return; } - step = 100; - digits = 2; + float pat_min[2], pat_max[2]; + float pat_dim[2], search_dim[2], search_pos[2]; BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); @@ -538,10 +509,14 @@ void uiTemplateMarker(uiLayout *layout, cb->marker_flag = marker->flag; - block = uiLayoutAbsoluteBlock(layout); + uiBlock *block = uiLayoutAbsoluteBlock(layout); UI_block_func_handle_set(block, marker_block_handler, cb); UI_block_funcN_set(block, marker_update_cb, cb, NULL); + const char *tip; + int step = 100; + int digits = 2; + if (cb->marker_flag & MARKER_DISABLED) { tip = TIP_("Marker is disabled at current frame"); } @@ -565,7 +540,7 @@ void uiTemplateMarker(uiLayout *layout, 0, tip); - col = uiLayoutColumn(layout, true); + uiLayout *col = uiLayoutColumn(layout, true); uiLayoutSetActive(col, (cb->marker_flag & MARKER_DISABLED) == 0); block = uiLayoutAbsoluteBlock(col); @@ -585,7 +560,7 @@ void uiTemplateMarker(uiLayout *layout, 0, 0, ""); - bt = uiDefButF(block, + uiBut *bt = uiDefButF(block, UI_BTYPE_NUM, B_MARKER_POS, IFACE_("X:"), @@ -802,21 +777,11 @@ void uiTemplateMovieclipInformation(uiLayout *layout, const char *propname, PointerRNA *userptr) { - PropertyRNA *prop; - PointerRNA clipptr; - MovieClip *clip; - MovieClipUser *user; - uiLayout *col; - char str[1024]; - int width, height, framenr; - ImBuf *ibuf; - size_t ofs = 0; - if (!ptr->data) { return; } - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); @@ -831,17 +796,21 @@ void uiTemplateMovieclipInformation(uiLayout *layout, return; } - clipptr = RNA_property_pointer_get(ptr, prop); - clip = (MovieClip *)clipptr.data; - user = userptr->data; + PointerRNA clipptr = RNA_property_pointer_get(ptr, prop); + MovieClip *clip = (MovieClip *)clipptr.data; + MovieClipUser *user = userptr->data; - col = uiLayoutColumn(layout, false); + uiLayout *col = uiLayoutColumn(layout, false); uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT); - ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP); + ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP); + int width, height; /* Display frame dimensions, channels number and byffer type. */ BKE_movieclip_get_size(clip, user, &width, &height); + + char str[1024]; + size_t ofs = 0; ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, TIP_("%d x %d"), width, height); if (ibuf) { @@ -882,7 +851,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout, uiItemL(col, str, ICON_NONE); /* Display current frame number. */ - framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); + int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); if (framenr <= clip->len) { BLI_snprintf(str, sizeof(str), TIP_("Frame: %d / %d"), framenr, clip->len); } From 9460051c1aa6aed8bcc027d61e314c13bc250564 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 23 Dec 2020 11:11:36 +0100 Subject: [PATCH 02/12] Sculpt Undo: Fix broken memory size and potential use of uninitialized variables. That code looked really like a joke tbh... Random reported memory usage is not really that important, but the uninitialized items counts was potentially fairly severe. --- .../editors/sculpt_paint/sculpt_undo.c | 78 ++++++++++++------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index af2aad14008..9677152cf7e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -921,7 +921,7 @@ SculptUndoNode *SCULPT_undo_get_first_node() return usculpt->nodes.first; } -static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode) +static size_t sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode) { PBVHNode *node = unode->node; BLI_bitmap **grid_hidden = BKE_pbvh_grid_hidden(pbvh); @@ -929,28 +929,34 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode int *grid_indices, totgrid; BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL); - unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden"); + size_t alloc_size = sizeof(*unode->grid_hidden) * (size_t)totgrid; + unode->grid_hidden = MEM_callocN(alloc_size, "unode->grid_hidden"); for (int i = 0; i < totgrid; i++) { if (grid_hidden[grid_indices[i]]) { unode->grid_hidden[i] = MEM_dupallocN(grid_hidden[grid_indices[i]]); + alloc_size += MEM_allocN_len(unode->grid_hidden[i]); } else { unode->grid_hidden[i] = NULL; } } + + return alloc_size; } /* Allocate node and initialize its default fields specific for the given undo type. * Will also add the node to the list in the undo step. */ static SculptUndoNode *sculpt_undo_alloc_node_type(Object *object, SculptUndoType type) { - SculptUndoNode *unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode"); + const size_t alloc_size = sizeof(SculptUndoNode); + SculptUndoNode *unode = MEM_callocN(alloc_size, "SculptUndoNode"); BLI_strncpy(unode->idname, object->id.name, sizeof(unode->idname)); unode->type = type; UndoSculpt *usculpt = sculpt_undo_get_nodes(); BLI_addtail(&usculpt->nodes, unode); + usculpt->undo_size += alloc_size; return unode; } @@ -975,7 +981,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt { UndoSculpt *usculpt = sculpt_undo_get_nodes(); SculptSession *ss = ob->sculpt; - int totvert, allvert, totgrid, maxgrid, gridsize, *grids; + int totvert = 0; + int allvert = 0; + int totgrid = 0; + int maxgrid = 0; + int gridsize = 0; + int *grids = NULL; SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type); unode->node = node; @@ -986,39 +997,43 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->totvert = totvert; } - else { - maxgrid = 0; - } - /* General TODO, fix count_alloc. */ switch (type) { - case SCULPT_UNDO_COORDS: - unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); - unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); + case SCULPT_UNDO_COORDS: { + size_t alloc_size = sizeof(*unode->co) * (size_t)allvert; + unode->co = MEM_callocN(alloc_size, "SculptUndoNode.co"); + usculpt->undo_size += alloc_size; - usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert; + /* FIXME: Should explain why this is allocated here, to be freed in + * `SCULPT_undo_push_end_ex()`? */ + alloc_size = sizeof(*unode->no) * (size_t)allvert; + unode->no = MEM_callocN(alloc_size, "SculptUndoNode.no"); + usculpt->undo_size += alloc_size; break; - case SCULPT_UNDO_HIDDEN: + } + case SCULPT_UNDO_HIDDEN: { if (maxgrid) { - sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode); + usculpt->undo_size += sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode); } else { unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden"); + usculpt->undo_size += BLI_BITMAP_SIZE(allvert); } break; - case SCULPT_UNDO_MASK: - unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask"); - - usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert; - + } + case SCULPT_UNDO_MASK: { + const size_t alloc_size = sizeof(*unode->mask) * (size_t)allvert; + unode->mask = MEM_callocN(alloc_size, "SculptUndoNode.mask"); + usculpt->undo_size += alloc_size; break; - case SCULPT_UNDO_COLOR: - unode->col = MEM_callocN(sizeof(MPropCol) * allvert, "SculptUndoNode.col"); - - usculpt->undo_size += (sizeof(MPropCol) * sizeof(int)) * allvert; - + } + case SCULPT_UNDO_COLOR: { + const size_t alloc_size = sizeof(*unode->col) * (size_t)allvert; + unode->col = MEM_callocN(alloc_size, "SculptUndoNode.col"); + usculpt->undo_size += alloc_size; break; + } case SCULPT_UNDO_DYNTOPO_BEGIN: case SCULPT_UNDO_DYNTOPO_END: case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: @@ -1033,16 +1048,24 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->maxgrid = maxgrid; unode->totgrid = totgrid; unode->gridsize = gridsize; - unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids"); + + const size_t alloc_size = sizeof(*unode->grids) * (size_t)totgrid; + unode->grids = MEM_callocN(alloc_size, "SculptUndoNode.grids"); + usculpt->undo_size += alloc_size; } else { /* Regular mesh. */ unode->maxvert = ss->totvert; - unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index"); + + const size_t alloc_size = sizeof(*unode->index) * (size_t)allvert; + unode->index = MEM_callocN(alloc_size, "SculptUndoNode.index"); + usculpt->undo_size += alloc_size; } if (ss->deform_modifiers_active) { - unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos"); + const size_t alloc_size = sizeof(*unode->orig_co) * (size_t)allvert; + unode->orig_co = MEM_callocN(alloc_size, "undoSculpt orig_cos"); + usculpt->undo_size += alloc_size; } return unode; @@ -1364,6 +1387,7 @@ void SCULPT_undo_push_end_ex(const bool use_nested_undo) /* We don't need normals in the undo stack. */ for (unode = usculpt->nodes.first; unode; unode = unode->next) { if (unode->no) { + usculpt->undo_size -= MEM_allocN_len(unode->no); MEM_freeN(unode->no); unode->no = NULL; } From 78d2ce19c4fbb5678995efae74a6128a3dcc4e73 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 23 Dec 2020 13:56:57 +0100 Subject: [PATCH 03/12] Fix T84013: Crash closing maximized File Browser opened from Preferences After 1e799dd26ec1, the logic to recognize a temporary File Browser window didn't work correctly anymore. It would recognize a maximized File Browser inside a temporary window as a temporary File Browser window, and attempt to close this (rather than returning to the previous layout). The logic there was pretty weak, and still is I think. A more stable solution would need bigger refactoring. With this, it's also not possible to maximize or fullscreen an area within a temporary window (Preferences, File Browser, render window) anymore. Think that won't make a noticable difference, since you couldn't open multiple areas there anyway, and the area seems to be maximized already. Cleaned up the code a bit to not become more confusing with the changes. --- source/blender/editors/screen/screen_ops.c | 7 +- .../windowmanager/intern/wm_event_system.c | 71 +++++++++++-------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 8768404d74f..87255bf8b5c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3138,6 +3138,8 @@ static int screen_maximize_area_exec(bContext *C, wmOperator *op) ScrArea *area = NULL; const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels"); + BLI_assert(!screen->temp); + /* search current screen for 'fullscreen' areas */ /* prevents restoring info header, when mouse is over it */ LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) { @@ -3169,11 +3171,14 @@ static int screen_maximize_area_exec(bContext *C, wmOperator *op) static bool screen_maximize_area_poll(bContext *C) { + const wmWindow *win = CTX_wm_window(C); const bScreen *screen = CTX_wm_screen(C); const ScrArea *area = CTX_wm_area(C); return ED_operator_areaactive(C) && /* Don't allow maximizing global areas but allow minimizing from them. */ - ((screen->state != SCREENNORMAL) || !ED_area_is_global(area)); + ((screen->state != SCREENNORMAL) || !ED_area_is_global(area)) && + /* Don't change temporary screens. */ + !WM_window_is_temp_screen(win); } static void SCREEN_OT_screen_full_area(wmOperatorType *ot) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 20fa500f0b3..90aa6a92d3c 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2259,38 +2259,47 @@ static int wm_handler_fileselect_do(bContext *C, bScreen *screen = WM_window_get_active_screen(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(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 != 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). */ - wm_window_make_drawable(wm, ctx_win); - /* Ensure correct cursor position, otherwise, popups may close immediately after - * 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 == win) { - handler->context.win = NULL; - } - } - else if (file_area->full) { - ED_screen_full_prevspace(C, file_area); - } - else { - ED_area_prevspace(C, file_area); - } - - temp_win = win; - break; + if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) { + continue; } + + if (ctx_area->full) { + /* Users should not be able to maximize/fullscreen an area in a temporary screen. So if + * there's a maximized file browser in a temporary screen, it was likely opened by + * #EVT_FILESELECT_FULL_OPEN. */ + continue; + } + + int win_size[2]; + bool 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 != 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). */ + wm_window_make_drawable(wm, ctx_win); + /* Ensure correct cursor position, otherwise, popups may close immediately after + * 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 == win) { + handler->context.win = NULL; + } + } + else if (file_area->full) { + ED_screen_full_prevspace(C, file_area); + } + else { + ED_area_prevspace(C, file_area); + } + + temp_win = win; + break; } if (!temp_win && ctx_area->full) { From 27fcaa61733827dbb81b69fdeec0db2f656c6f03 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 23 Dec 2020 14:25:58 +0100 Subject: [PATCH 04/12] Cleanup: Move functions to new ED (editor) operators file & general cleanup With the new `ed_util_ops.c` introduced in 2250b5cefee7, existing code can be cleaned up to use it. * Move new ID preview operators to `ed_util_ops.c` * Move ED operator registration to `ed_util_ops.c` * Use doxygen sections in `ed_util_ops.c` * Rename ID related ED operators to use `ED_OT_lib_id_` prefix. * Remove unused `#include`s --- source/blender/editors/include/ED_util.h | 3 - .../editors/interface/interface_templates.c | 4 +- source/blender/editors/screen/screen_ops.c | 10 -- source/blender/editors/util/ed_util.c | 117 ------------- source/blender/editors/util/ed_util_ops.c | 156 ++++++++++++++++-- 5 files changed, 148 insertions(+), 142 deletions(-) diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 1e87a940a7d..54e2b3ba501 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -52,9 +52,6 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct ID *old_id, struct ID *new_id); -void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot); -void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot); - void ED_operatortypes_edutils(void); /* ************** XXX OLD CRUFT WARNING ************* */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index f134038918d..8349577ff04 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1392,7 +1392,7 @@ static void template_id_name_button( UI_but_extra_operator_icon_add(but, template_ui->unlink_op, WM_OP_INVOKE_DEFAULT, ICON_X); } else if (!never_unlink) { - UI_but_extra_operator_icon_add(but, "ED_OT_lib_unlink", WM_OP_INVOKE_DEFAULT, ICON_X); + UI_but_extra_operator_icon_add(but, "ED_OT_lib_id_unlink", WM_OP_INVOKE_DEFAULT, ICON_X); } } @@ -1401,7 +1401,7 @@ static void template_id_name_button( if (add_extra_fake_user_icon && id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { UI_but_extra_operator_icon_add(but, - "ED_OT_lib_fake_user_toggle", + "ED_OT_lib_id_fake_user_toggle", WM_OP_INVOKE_DEFAULT, ID_FAKE_USERS(id) ? ICON_FAKE_USER_ON : ICON_FAKE_USER_OFF); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 87255bf8b5c..ca0b9aa93b7 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -5506,16 +5506,6 @@ void ED_operatortypes_screen(void) /* new/delete */ WM_operatortype_append(SCREEN_OT_new); WM_operatortype_append(SCREEN_OT_delete); - - /* tools shared by more space types */ - WM_operatortype_append(ED_OT_undo); - WM_operatortype_append(ED_OT_undo_push); - WM_operatortype_append(ED_OT_redo); - WM_operatortype_append(ED_OT_undo_redo); - WM_operatortype_append(ED_OT_undo_history); - - WM_operatortype_append(ED_OT_lib_id_load_custom_preview); - WM_operatortype_append(ED_OT_lib_id_generate_preview); } /** \} */ diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 5d2584c566d..4b1335cf047 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -29,50 +29,34 @@ #include "DNA_armature_types.h" #include "DNA_mesh_types.h" -#include "DNA_object_types.h" -#include "DNA_packedFile_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "BLI_fileops.h" #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" -#include "BLI_utildefines.h" #include "BLT_translation.h" -#include "BKE_context.h" #include "BKE_global.h" -#include "BKE_icons.h" -#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_multires.h" #include "BKE_object.h" #include "BKE_packedFile.h" #include "BKE_paint.h" -#include "BKE_report.h" #include "BKE_screen.h" #include "BKE_undo_system.h" -#include "BKE_workspace.h" #include "DEG_depsgraph.h" #include "ED_armature.h" #include "ED_image.h" #include "ED_mesh.h" -#include "ED_node.h" #include "ED_object.h" -#include "ED_outliner.h" #include "ED_paint.h" -#include "ED_render.h" #include "ED_space_api.h" #include "ED_util.h" #include "GPU_immediate.h" -#include "GPU_state.h" #include "UI_interface.h" #include "UI_resources.h" @@ -484,104 +468,3 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_i st->id_remap(area, sl, old_id, new_id); } } - -static bool lib_id_preview_editing_poll(bContext *C) -{ - const PointerRNA idptr = CTX_data_pointer_get(C, "id"); - BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type)); - - const ID *id = idptr.data; - if (!id) { - return false; - } - if (ID_IS_LINKED(id)) { - CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit external library data")); - return false; - } - if (ID_IS_OVERRIDE_LIBRARY(id)) { - CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit previews of overridden library data")); - return false; - } - if (!BKE_previewimg_id_get_p(id)) { - CTX_wm_operator_poll_msg_set(C, TIP_("Data-block does not support previews")); - return false; - } - - return true; -} - -static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) -{ - char path[FILE_MAX]; - - RNA_string_get(op->ptr, "filepath", path); - - if (!BLI_is_file(path)) { - BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path); - return OPERATOR_CANCELLED; - } - - PointerRNA idptr = CTX_data_pointer_get(C, "id"); - ID *id = idptr.data; - - BKE_previewimg_id_custom_set(id, path); - - WM_event_add_notifier(C, NC_ASSET, NULL); - - return OPERATOR_FINISHED; -} - -void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) -{ - ot->name = "Load Custom Preview"; - ot->description = "Choose an image to help identify the data-block visually"; - ot->idname = "ED_OT_lib_id_load_custom_preview"; - - /* api callbacks */ - ot->poll = lib_id_preview_editing_poll; - ot->exec = lib_id_load_custom_preview_exec; - ot->invoke = WM_operator_filesel; - - /* flags */ - ot->flag = OPTYPE_INTERNAL; - - WM_operator_properties_filesel(ot, - FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, - FILE_SPECIAL, - FILE_OPENFILE, - WM_FILESEL_FILEPATH, - FILE_DEFAULTDISPLAY, - FILE_SORT_DEFAULT); -} - -static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) -{ - PointerRNA idptr = CTX_data_pointer_get(C, "id"); - ID *id = idptr.data; - - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - - PreviewImage *preview = BKE_previewimg_id_get(id); - if (preview) { - BKE_previewimg_clear(preview); - } - UI_icon_render_id(C, NULL, id, true, true); - - WM_event_add_notifier(C, NC_ASSET, NULL); - - return OPERATOR_FINISHED; -} - -void ED_OT_lib_id_generate_preview(wmOperatorType *ot) -{ - ot->name = "Generate Preview"; - ot->description = "Create an automatic preview for the selected data-block"; - ot->idname = "ED_OT_lib_id_generate_preview"; - - /* api callbacks */ - ot->poll = lib_id_preview_editing_poll; - ot->exec = lib_id_generate_preview_exec; - - /* flags */ - ot->flag = OPTYPE_INTERNAL; -} diff --git a/source/blender/editors/util/ed_util_ops.c b/source/blender/editors/util/ed_util_ops.c index d8d1a64c1ee..88df20c5966 100644 --- a/source/blender/editors/util/ed_util_ops.c +++ b/source/blender/editors/util/ed_util_ops.c @@ -22,15 +22,22 @@ #include +#include "BLI_fileops.h" #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_icons.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BLT_translation.h" + +#include "DNA_space_types.h" #include "DNA_windowmanager_types.h" +#include "ED_render.h" +#include "ED_undo.h" #include "ED_util.h" #include "RNA_access.h" @@ -40,7 +47,118 @@ #include "WM_api.h" #include "WM_types.h" -static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op) +/* -------------------------------------------------------------------- */ +/** \name ID Previews + * \{ */ + +static bool lib_id_preview_editing_poll(bContext *C) +{ + const PointerRNA idptr = CTX_data_pointer_get(C, "id"); + BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type)); + + const ID *id = idptr.data; + if (!id) { + return false; + } + if (ID_IS_LINKED(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit external library data")); + return false; + } + if (ID_IS_OVERRIDE_LIBRARY(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit previews of overridden library data")); + return false; + } + if (!BKE_previewimg_id_get_p(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Data-block does not support previews")); + return false; + } + + return true; +} + +static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) +{ + char path[FILE_MAX]; + + RNA_string_get(op->ptr, "filepath", path); + + if (!BLI_is_file(path)) { + BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path); + return OPERATOR_CANCELLED; + } + + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + BKE_previewimg_id_custom_set(id, path); + + WM_event_add_notifier(C, NC_ASSET, NULL); + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) +{ + ot->name = "Load Custom Preview"; + ot->description = "Choose an image to help identify the data-block visually"; + ot->idname = "ED_OT_lib_id_load_custom_preview"; + + /* api callbacks */ + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_load_custom_preview_exec; + ot->invoke = WM_operator_filesel; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, + FILE_SPECIAL, + FILE_OPENFILE, + WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + + PreviewImage *preview = BKE_previewimg_id_get(id); + if (preview) { + BKE_previewimg_clear(preview); + } + UI_icon_render_id(C, NULL, id, true, true); + + WM_event_add_notifier(C, NC_ASSET, NULL); + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_id_generate_preview(wmOperatorType *ot) +{ + ot->name = "Generate Preview"; + ot->description = "Create an automatic preview for the selected data-block"; + ot->idname = "ED_OT_lib_id_generate_preview"; + + /* api callbacks */ + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_generate_preview_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic ID Operators + * \{ */ + +static int lib_id_fake_user_toggle_exec(bContext *C, wmOperator *op) { PropertyPointerRNA pprop; PointerRNA idptr = PointerRNA_NULL; @@ -74,21 +192,21 @@ static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void ED_OT_lib_fake_user_toggle(wmOperatorType *ot) +static void ED_OT_lib_id_fake_user_toggle(wmOperatorType *ot) { /* identifiers */ ot->name = "Toggle Fake User"; ot->description = "Save this data-block even if it has no users"; - ot->idname = "ED_OT_lib_fake_user_toggle"; + ot->idname = "ED_OT_lib_id_fake_user_toggle"; /* api callbacks */ - ot->exec = lib_fake_user_toggle_exec; + ot->exec = lib_id_fake_user_toggle_exec; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; } -static int lib_unlink_exec(bContext *C, wmOperator *op) +static int lib_id_unlink_exec(bContext *C, wmOperator *op) { PropertyPointerRNA pprop; PointerRNA idptr; @@ -112,20 +230,26 @@ static int lib_unlink_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void ED_OT_lib_unlink(wmOperatorType *ot) +static void ED_OT_lib_id_unlink(wmOperatorType *ot) { /* identifiers */ ot->name = "Unlink Data-Block"; ot->description = "Remove a usage of a data-block, clearing the assignment"; - ot->idname = "ED_OT_lib_unlink"; + ot->idname = "ED_OT_lib_id_unlink"; /* api callbacks */ - ot->exec = lib_unlink_exec; + ot->exec = lib_id_unlink_exec; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name General editor utils. + * \{ */ + static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); @@ -147,9 +271,21 @@ static void ED_OT_flush_edits(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } +/** \} */ + void ED_operatortypes_edutils(void) { - WM_operatortype_append(ED_OT_lib_fake_user_toggle); - WM_operatortype_append(ED_OT_lib_unlink); + WM_operatortype_append(ED_OT_lib_id_load_custom_preview); + WM_operatortype_append(ED_OT_lib_id_generate_preview); + + WM_operatortype_append(ED_OT_lib_id_fake_user_toggle); + WM_operatortype_append(ED_OT_lib_id_unlink); + WM_operatortype_append(ED_OT_flush_edits); + + WM_operatortype_append(ED_OT_undo); + WM_operatortype_append(ED_OT_undo_push); + WM_operatortype_append(ED_OT_redo); + WM_operatortype_append(ED_OT_undo_redo); + WM_operatortype_append(ED_OT_undo_history); } From 21cb28802965fa20cace5edd56575fcce7df0581 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 23 Dec 2020 14:43:40 +0100 Subject: [PATCH 05/12] Fix incorrect debugging text in extra operator icons for buttons --- source/blender/editors/interface/interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 7713efd1c78..d47d9c5e874 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1626,10 +1626,10 @@ static uiButExtraOpIcon *ui_but_extra_operator_icon_add_ptr(uiBut *but, extra_op_icon->icon = (BIFIconID)icon; extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params), - "uiButExtraOpIcon.optype_hook"); + "uiButExtraOpIcon.optype_params"); extra_op_icon->optype_params->optype = optype; extra_op_icon->optype_params->opptr = MEM_callocN(sizeof(*extra_op_icon->optype_params->opptr), - "uiButExtraOpIcon.optype_hook.opptr"); + "uiButExtraOpIcon.optype_params.opptr"); WM_operator_properties_create_ptr(extra_op_icon->optype_params->opptr, extra_op_icon->optype_params->optype); extra_op_icon->optype_params->opcontext = opcontext; From 5cfda8e7f74da959a5c1081d45e7608bef95191d Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 23 Dec 2020 15:31:31 +0100 Subject: [PATCH 06/12] Fix crash closing File Browser window after closing temporary render window This seems to be a longer standing issue. Steps to reproduce were: * With factory settings, Ctrl+O then F12 * Close the render window using the window close button * Close the File Browser window using the window close button This could be OS specific though, at least on macOS this caused a crash. --- source/blender/editors/space_file/filesel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index b919a30e6cd..6b74b344375 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -1142,7 +1142,9 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil return; } if (sfile->op) { - wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL; + wmWindow *temp_win = (wm->winactive && WM_window_is_temp_screen(wm->winactive)) ? + wm->winactive : + NULL; if (temp_win) { int win_size[2]; bool is_maximized; From 635694c0ff8fc5c9828bf920ecb81bb9bf792a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Barschkis?= Date: Wed, 23 Dec 2020 13:54:47 +0100 Subject: [PATCH 07/12] Fluid: Added new viscosity solver Mainly updated the Mantaflow version. It includes the new viscosity solver plugin based on the method from 'Accurate Viscous Free Surfaces for Buckling, Coiling, and Rotating Liquids' (Batty & Bridson). In the UI, this update adds a new 'Viscosity' section to the fluid modifier UI (liquid domains only). For now, there is a single 'strength' value to control the viscosity of liquids. --- extern/mantaflow/CMakeLists.txt | 1 + extern/mantaflow/helper/util/rcmatrix.h | 2 +- .../mantaflow/preprocessed/conjugategrad.cpp | 94 +- extern/mantaflow/preprocessed/conjugategrad.h | 468 +++++- extern/mantaflow/preprocessed/general.h | 35 +- extern/mantaflow/preprocessed/gitinfo.h | 2 +- .../preprocessed/plugin/extforces.cpp | 25 +- .../preprocessed/plugin/pressure.cpp | 14 +- .../preprocessed/plugin/viscosity.cpp | 1430 +++++++++++++++++ .../preprocessed/plugin/vortexplugins.cpp | 4 +- .../mantaflow/preprocessed/plugin/waves.cpp | 13 +- .../mantaflow/preprocessed/registration.cpp | 2 + intern/mantaflow/intern/MANTA_main.cpp | 27 +- intern/mantaflow/intern/MANTA_main.h | 2 + .../mantaflow/intern/strings/fluid_script.h | 11 +- .../mantaflow/intern/strings/liquid_script.h | 17 +- .../startup/bl_ui/properties_physics_fluid.py | 41 + .../blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/intern/fluid.c | 3 + .../blenloader/intern/versioning_290.c | 40 +- .../blenloader/intern/versioning_userdef.c | 9 +- source/blender/makesdna/DNA_fluid_defaults.h | 1 + source/blender/makesdna/DNA_fluid_types.h | 63 +- source/blender/makesrna/intern/rna_fluid.c | 16 + 24 files changed, 2149 insertions(+), 173 deletions(-) create mode 100644 extern/mantaflow/preprocessed/plugin/viscosity.cpp diff --git a/extern/mantaflow/CMakeLists.txt b/extern/mantaflow/CMakeLists.txt index ccf272650e3..82bf95a9742 100644 --- a/extern/mantaflow/CMakeLists.txt +++ b/extern/mantaflow/CMakeLists.txt @@ -200,6 +200,7 @@ set(SRC ${MANTA_PP}/plugin/ptsplugins.cpp ${MANTA_PP}/plugin/secondaryparticles.cpp ${MANTA_PP}/plugin/surfaceturbulence.cpp + ${MANTA_PP}/plugin/viscosity.cpp ${MANTA_PP}/plugin/vortexplugins.cpp ${MANTA_PP}/plugin/waveletturbulence.cpp ${MANTA_PP}/plugin/waves.cpp diff --git a/extern/mantaflow/helper/util/rcmatrix.h b/extern/mantaflow/helper/util/rcmatrix.h index f1f0efe6416..330fd1f64f7 100644 --- a/extern/mantaflow/helper/util/rcmatrix.h +++ b/extern/mantaflow/helper/util/rcmatrix.h @@ -1035,7 +1035,7 @@ template struct RCFixedMatrix { typedef RCMatrix Matrix; typedef RCFixedMatrix FixedMatrix; -} // namespace Manta +} #undef parallel_for #undef parallel_end diff --git a/extern/mantaflow/preprocessed/conjugategrad.cpp b/extern/mantaflow/preprocessed/conjugategrad.cpp index da82a412a97..bdcceb29520 100644 --- a/extern/mantaflow/preprocessed/conjugategrad.cpp +++ b/extern/mantaflow/preprocessed/conjugategrad.cpp @@ -397,7 +397,7 @@ struct UpdateSearchVec : public KernelBase { }; //***************************************************************************** -// CG class +// CG class template GridCg::GridCg(Grid &dst, @@ -406,10 +406,8 @@ GridCg::GridCg(Grid &dst, Grid &search, const FlagGrid &flags, Grid &tmp, - Grid *pA0, - Grid *pAi, - Grid *pAj, - Grid *pAk) + std::vector *> matrixAVec, + std::vector *> rhsVec) : GridCgInterface(), mInited(false), mIterations(0), @@ -419,10 +417,8 @@ GridCg::GridCg(Grid &dst, mSearch(search), mFlags(flags), mTmp(tmp), - mpA0(pA0), - mpAi(pAi), - mpAj(pAj), - mpAk(pAk), + mMatrixA(matrixAVec), + mVecRhs(rhsVec), mPcMethod(PC_None), mpPCA0(nullptr), mpPCAi(nullptr), @@ -445,19 +441,37 @@ template void GridCg::doInit() if (mPcMethod == PC_ICP) { assertMsg(mDst.is3D(), "ICP only supports 3D grids so far"); - InitPreconditionIncompCholesky( - mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk); - ApplyPreconditionIncompCholesky( - mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk); + InitPreconditionIncompCholesky(mFlags, + *mpPCA0, + *mpPCAi, + *mpPCAj, + *mpPCAk, + *mMatrixA[0], + *mMatrixA[1], + *mMatrixA[2], + *mMatrixA[3]); + ApplyPreconditionIncompCholesky(mTmp, + mResidual, + mFlags, + *mpPCA0, + *mpPCAi, + *mpPCAj, + *mpPCAk, + *mMatrixA[0], + *mMatrixA[1], + *mMatrixA[2], + *mMatrixA[3]); } else if (mPcMethod == PC_mICP) { assertMsg(mDst.is3D(), "mICP only supports 3D grids so far"); - InitPreconditionModifiedIncompCholesky2(mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk); + InitPreconditionModifiedIncompCholesky2( + mFlags, *mpPCA0, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3]); ApplyPreconditionModifiedIncompCholesky2( - mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk); + mTmp, mResidual, mFlags, *mpPCA0, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3]); } else if (mPcMethod == PC_MGP) { - InitPreconditionMultigrid(mMG, *mpA0, *mpAi, *mpAj, *mpAk, mAccuracy); + InitPreconditionMultigrid( + mMG, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3], mAccuracy); ApplyPreconditionMultigrid(mMG, mTmp, mResidual); } else { @@ -465,7 +479,6 @@ template void GridCg::doInit() } mSearch.copyFrom(mTmp); - mSigma = GridDotProduct(mTmp, mResidual); } @@ -480,7 +493,7 @@ template bool GridCg::iterate() // this could reinterpret the mpA pointers (not so clean right now) // tmp = applyMat(search) - APPLYMAT(mFlags, mTmp, mSearch, *mpA0, *mpAi, *mpAj, *mpAk); + APPLYMAT(mFlags, mTmp, mSearch, mMatrixA, mVecRhs); // alpha = sigma/dot(tmp, search) Real dp = GridDotProduct(mTmp, mSearch); @@ -492,11 +505,20 @@ template bool GridCg::iterate() gridScaledAdd(mResidual, mTmp, -alpha); // residual += tmp * -alpha if (mPcMethod == PC_ICP) - ApplyPreconditionIncompCholesky( - mTmp, mResidual, mFlags, *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk, *mpA0, *mpAi, *mpAj, *mpAk); + ApplyPreconditionIncompCholesky(mTmp, + mResidual, + mFlags, + *mpPCA0, + *mpPCAi, + *mpPCAj, + *mpPCAk, + *mMatrixA[0], + *mMatrixA[1], + *mMatrixA[2], + *mMatrixA[3]); else if (mPcMethod == PC_mICP) ApplyPreconditionModifiedIncompCholesky2( - mTmp, mResidual, mFlags, *mpPCA0, *mpA0, *mpAi, *mpAj, *mpAk); + mTmp, mResidual, mFlags, *mpPCA0, *mMatrixA[0], *mMatrixA[1], *mMatrixA[2], *mMatrixA[3]); else if (mPcMethod == PC_MGP) ApplyPreconditionMultigrid(mMG, mTmp, mResidual); else @@ -584,13 +606,15 @@ void GridCg::setMGPreconditioner(PreconditionType method, GridMg *MG) assertMsg(method == PC_MGP, "GridCg::setMGPreconditioner: Invalid method specified."); mPcMethod = method; - mMG = MG; } // explicit instantiation template class GridCg; template class GridCg; +template class GridCg; +template class GridCg; +template class GridCg; //***************************************************************************** // diffusion for real and vec grids, e.g. for viscosity @@ -638,10 +662,15 @@ void cgSolveDiffusion(const FlagGrid &flags, if (grid.getType() & GridBase::TypeReal) { Grid &u = ((Grid &)grid); rhs.copyFrom(u); - if (flags.is3D()) - gcg = new GridCg(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); - else - gcg = new GridCg(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); + vector *> matA{&A0, &Ai, &Aj}; + + if (flags.is3D()) { + matA.push_back(&Ak); + gcg = new GridCg(u, rhs, residual, search, flags, tmp, matA); + } + else { + gcg = new GridCg(u, rhs, residual, search, flags, tmp, matA); + } gcg->setAccuracy(cgAccuracy); gcg->solve(maxIter); @@ -653,12 +682,17 @@ void cgSolveDiffusion(const FlagGrid &flags, else if ((grid.getType() & GridBase::TypeVec3) || (grid.getType() & GridBase::TypeMAC)) { Grid &vec = ((Grid &)grid); Grid u(parent); + vector *> matA{&A0, &Ai, &Aj}; // core solve is same as for a regular real grid - if (flags.is3D()) - gcg = new GridCg(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); - else - gcg = new GridCg(u, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); + if (flags.is3D()) { + matA.push_back(&Ak); + gcg = new GridCg(u, rhs, residual, search, flags, tmp, matA); + } + else { + gcg = new GridCg(u, rhs, residual, search, flags, tmp, matA); + } + gcg->setAccuracy(cgAccuracy); // diffuse every component separately diff --git a/extern/mantaflow/preprocessed/conjugategrad.h b/extern/mantaflow/preprocessed/conjugategrad.h index 58ccff28179..4974aa6a4d6 100644 --- a/extern/mantaflow/preprocessed/conjugategrad.h +++ b/extern/mantaflow/preprocessed/conjugategrad.h @@ -78,13 +78,9 @@ template class GridCg : public GridCgInterface { Grid &search, const FlagGrid &flags, Grid &tmp, - Grid *A0, - Grid *pAi, - Grid *pAj, - Grid *pAk); - ~GridCg() - { - } + std::vector *> matrixAVec, + std::vector *> rhsVec = {}); + ~GridCg(){}; void doInit(); bool iterate(); @@ -133,7 +129,10 @@ template class GridCg : public GridCgInterface { const FlagGrid &mFlags; Grid &mTmp; - Grid *mpA0, *mpAi, *mpAj, *mpAk; + //! shape of A matrix defined here (e.g. diagonal, positive neighbor cells, etc) + std::vector *> mMatrixA; + //! shape of rhs vector defined here (e.g. 1 rhs for regular fluids solve, 3 rhs for viscosity) + std::vector *> mVecRhs; PreconditionType mPcMethod; //! preconditioning grids @@ -154,11 +153,9 @@ struct ApplyMatrix : public KernelBase { ApplyMatrix(const FlagGrid &flags, Grid &dst, const Grid &src, - Grid &A0, - Grid &Ai, - Grid &Aj, - Grid &Ak) - : KernelBase(&flags, 0), flags(flags), dst(dst), src(src), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak) + const std::vector *> matrixA, + const std::vector *> vecRhs) + : KernelBase(&flags, 0), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs) { runMessage(); run(); @@ -167,11 +164,18 @@ struct ApplyMatrix : public KernelBase { const FlagGrid &flags, Grid &dst, const Grid &src, - Grid &A0, - Grid &Ai, - Grid &Aj, - Grid &Ak) const + const std::vector *> matrixA, + const std::vector *> vecRhs) const { + unusedParameter(vecRhs); // Not needed in this matrix application + + if (matrixA.size() != 4) + errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step"); + Grid &A0 = *matrixA[0]; + Grid &Ai = *matrixA[1]; + Grid &Aj = *matrixA[2]; + Grid &Ak = *matrixA[3]; + if (!flags.isFluid(idx)) { dst[idx] = src[idx]; return; @@ -196,26 +200,16 @@ struct ApplyMatrix : public KernelBase { return src; } typedef Grid type2; - inline Grid &getArg3() + inline const std::vector *> &getArg3() { - return A0; + return matrixA; } - typedef Grid type3; - inline Grid &getArg4() + typedef std::vector *> type3; + inline const std::vector *> &getArg4() { - return Ai; + return vecRhs; } - typedef Grid type4; - inline Grid &getArg5() - { - return Aj; - } - typedef Grid type5; - inline Grid &getArg6() - { - return Ak; - } - typedef Grid type6; + typedef std::vector *> type4; void runMessage() { debMsg("Executing kernel ApplyMatrix ", 3); @@ -226,7 +220,7 @@ struct ApplyMatrix : public KernelBase { void operator()(const tbb::blocked_range &__r) const { for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) - op(idx, flags, dst, src, A0, Ai, Aj, Ak); + op(idx, flags, dst, src, matrixA, vecRhs); } void run() { @@ -235,10 +229,8 @@ struct ApplyMatrix : public KernelBase { const FlagGrid &flags; Grid &dst; const Grid &src; - Grid &A0; - Grid &Ai; - Grid &Aj; - Grid &Ak; + const std::vector *> matrixA; + const std::vector *> vecRhs; }; //! Kernel: Apply symmetric stored Matrix. 2D version @@ -247,11 +239,9 @@ struct ApplyMatrix2D : public KernelBase { ApplyMatrix2D(const FlagGrid &flags, Grid &dst, const Grid &src, - Grid &A0, - Grid &Ai, - Grid &Aj, - Grid &Ak) - : KernelBase(&flags, 0), flags(flags), dst(dst), src(src), A0(A0), Ai(Ai), Aj(Aj), Ak(Ak) + const std::vector *> matrixA, + const std::vector *> vecRhs) + : KernelBase(&flags, 0), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs) { runMessage(); run(); @@ -260,12 +250,16 @@ struct ApplyMatrix2D : public KernelBase { const FlagGrid &flags, Grid &dst, const Grid &src, - Grid &A0, - Grid &Ai, - Grid &Aj, - Grid &Ak) const + const std::vector *> matrixA, + const std::vector *> vecRhs) const { - unusedParameter(Ak); // only there for parameter compatibility with ApplyMatrix + unusedParameter(vecRhs); // Not needed in this matrix application + + if (matrixA.size() != 3) + errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step"); + Grid &A0 = *matrixA[0]; + Grid &Ai = *matrixA[1]; + Grid &Aj = *matrixA[2]; if (!flags.isFluid(idx)) { dst[idx] = src[idx]; @@ -290,26 +284,16 @@ struct ApplyMatrix2D : public KernelBase { return src; } typedef Grid type2; - inline Grid &getArg3() + inline const std::vector *> &getArg3() { - return A0; + return matrixA; } - typedef Grid type3; - inline Grid &getArg4() + typedef std::vector *> type3; + inline const std::vector *> &getArg4() { - return Ai; + return vecRhs; } - typedef Grid type4; - inline Grid &getArg5() - { - return Aj; - } - typedef Grid type5; - inline Grid &getArg6() - { - return Ak; - } - typedef Grid type6; + typedef std::vector *> type4; void runMessage() { debMsg("Executing kernel ApplyMatrix2D ", 3); @@ -320,7 +304,7 @@ struct ApplyMatrix2D : public KernelBase { void operator()(const tbb::blocked_range &__r) const { for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) - op(idx, flags, dst, src, A0, Ai, Aj, Ak); + op(idx, flags, dst, src, matrixA, vecRhs); } void run() { @@ -329,12 +313,358 @@ struct ApplyMatrix2D : public KernelBase { const FlagGrid &flags; Grid &dst; const Grid &src; - Grid &A0; - Grid &Ai; - Grid &Aj; - Grid &Ak; + const std::vector *> matrixA; + const std::vector *> vecRhs; }; +struct ApplyMatrixViscosityU : public KernelBase { + ApplyMatrixViscosityU(const FlagGrid &flags, + Grid &dst, + const Grid &src, + const std::vector *> matrixA, + const std::vector *> vecRhs) + : KernelBase(&flags, 1), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + const FlagGrid &flags, + Grid &dst, + const Grid &src, + const std::vector *> matrixA, + const std::vector *> vecRhs) const + { + if (matrixA.size() != 15) + errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step"); + Grid &A0 = *matrixA[0]; + Grid &Aplusi = *matrixA[1]; + Grid &Aplusj = *matrixA[2]; + Grid &Aplusk = *matrixA[3]; + Grid &Aminusi = *matrixA[4]; + Grid &Aminusj = *matrixA[5]; + Grid &Aminusk = *matrixA[6]; + + if (vecRhs.size() != 2) + errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step"); + Grid &srcV = *vecRhs[0]; + Grid &srcW = *vecRhs[1]; + + dst(i, j, k) = src(i, j, k) * A0(i, j, k) + src(i + 1, j, k) * Aplusi(i, j, k) + + src(i, j + 1, k) * Aplusj(i, j, k) + src(i, j, k + 1) * Aplusk(i, j, k) + + src(i - 1, j, k) * Aminusi(i, j, k) + src(i, j - 1, k) * Aminusj(i, j, k) + + src(i, j, k - 1) * Aminusk(i, j, k); + + dst(i, j, k) += srcV(i, j + 1, k) * (*matrixA[7])(i, j, k) + + srcV(i - 1, j + 1, k) * (*matrixA[8])(i, j, k) + + srcV(i, j, k) * (*matrixA[9])(i, j, k) + + srcV(i - 1, j, k) * (*matrixA[10])(i, j, k) + + srcW(i, j, k + 1) * (*matrixA[11])(i, j, k) + + srcW(i - 1, j, k + 1) * (*matrixA[12])(i, j, k) + + srcW(i, j, k) * (*matrixA[13])(i, j, k) + + srcW(i - 1, j, k) * (*matrixA[14])(i, j, k); + } + inline const FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + inline Grid &getArg1() + { + return dst; + } + typedef Grid type1; + inline const Grid &getArg2() + { + return src; + } + typedef Grid type2; + inline const std::vector *> &getArg3() + { + return matrixA; + } + typedef std::vector *> type3; + inline const std::vector *> &getArg4() + { + return vecRhs; + } + typedef std::vector *> type4; + void runMessage() + { + debMsg("Executing kernel ApplyMatrixViscosityU ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 1; j < _maxY; j++) + for (int i = 1; i < _maxX; i++) + op(i, j, k, flags, dst, src, matrixA, vecRhs); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 1; i < _maxX; i++) + op(i, j, k, flags, dst, src, matrixA, vecRhs); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(1, maxY), *this); + } + const FlagGrid &flags; + Grid &dst; + const Grid &src; + const std::vector *> matrixA; + const std::vector *> vecRhs; +}; + +struct ApplyMatrixViscosityV : public KernelBase { + ApplyMatrixViscosityV(const FlagGrid &flags, + Grid &dst, + const Grid &src, + const std::vector *> matrixA, + const std::vector *> vecRhs) + : KernelBase(&flags, 1), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + const FlagGrid &flags, + Grid &dst, + const Grid &src, + const std::vector *> matrixA, + const std::vector *> vecRhs) const + { + if (matrixA.size() != 15) + errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step"); + Grid &A0 = *matrixA[0]; + Grid &Aplusi = *matrixA[1]; + Grid &Aplusj = *matrixA[2]; + Grid &Aplusk = *matrixA[3]; + Grid &Aminusi = *matrixA[4]; + Grid &Aminusj = *matrixA[5]; + Grid &Aminusk = *matrixA[6]; + + if (vecRhs.size() != 2) + errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step"); + Grid &srcU = *vecRhs[0]; + Grid &srcW = *vecRhs[1]; + + dst(i, j, k) = src(i, j, k) * A0(i, j, k) + src(i + 1, j, k) * Aplusi(i, j, k) + + src(i, j + 1, k) * Aplusj(i, j, k) + src(i, j, k + 1) * Aplusk(i, j, k) + + src(i - 1, j, k) * Aminusi(i, j, k) + src(i, j - 1, k) * Aminusj(i, j, k) + + src(i, j, k - 1) * Aminusk(i, j, k); + + dst(i, j, k) += srcU(i + 1, j, k) * (*matrixA[7])(i, j, k) + + srcU(i + 1, j - 1, k) * (*matrixA[8])(i, j, k) + + srcU(i, j, k) * (*matrixA[9])(i, j, k) + + srcU(i, j - 1, k) * (*matrixA[10])(i, j, k) + + srcW(i, j, k + 1) * (*matrixA[11])(i, j, k) + + srcW(i, j - 1, k + 1) * (*matrixA[12])(i, j, k) + + srcW(i, j, k) * (*matrixA[13])(i, j, k) + + srcW(i, j - 1, k) * (*matrixA[14])(i, j, k); + } + inline const FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + inline Grid &getArg1() + { + return dst; + } + typedef Grid type1; + inline const Grid &getArg2() + { + return src; + } + typedef Grid type2; + inline const std::vector *> &getArg3() + { + return matrixA; + } + typedef std::vector *> type3; + inline const std::vector *> &getArg4() + { + return vecRhs; + } + typedef std::vector *> type4; + void runMessage() + { + debMsg("Executing kernel ApplyMatrixViscosityV ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 1; j < _maxY; j++) + for (int i = 1; i < _maxX; i++) + op(i, j, k, flags, dst, src, matrixA, vecRhs); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 1; i < _maxX; i++) + op(i, j, k, flags, dst, src, matrixA, vecRhs); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(1, maxY), *this); + } + const FlagGrid &flags; + Grid &dst; + const Grid &src; + const std::vector *> matrixA; + const std::vector *> vecRhs; +}; + +struct ApplyMatrixViscosityW : public KernelBase { + ApplyMatrixViscosityW(const FlagGrid &flags, + Grid &dst, + const Grid &src, + const std::vector *> matrixA, + const std::vector *> vecRhs) + : KernelBase(&flags, 1), flags(flags), dst(dst), src(src), matrixA(matrixA), vecRhs(vecRhs) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + const FlagGrid &flags, + Grid &dst, + const Grid &src, + const std::vector *> matrixA, + const std::vector *> vecRhs) const + { + if (matrixA.size() != 15) + errMsg("ConjugatedGrad: Invalid A matrix in apply matrix step"); + Grid &A0 = *matrixA[0]; + Grid &Aplusi = *matrixA[1]; + Grid &Aplusj = *matrixA[2]; + Grid &Aplusk = *matrixA[3]; + Grid &Aminusi = *matrixA[4]; + Grid &Aminusj = *matrixA[5]; + Grid &Aminusk = *matrixA[6]; + + if (vecRhs.size() != 2) + errMsg("ConjugatedGrad: Invalid rhs vector in apply matrix step"); + Grid &srcU = *vecRhs[0]; + Grid &srcV = *vecRhs[1]; + + dst(i, j, k) = src(i, j, k) * A0(i, j, k) + src(i + 1, j, k) * Aplusi(i, j, k) + + src(i, j + 1, k) * Aplusj(i, j, k) + src(i, j, k + 1) * Aplusk(i, j, k) + + src(i - 1, j, k) * Aminusi(i, j, k) + src(i, j - 1, k) * Aminusj(i, j, k) + + src(i, j, k - 1) * Aminusk(i, j, k); + + dst(i, j, k) += srcU(i + 1, j, k) * (*matrixA[7])(i, j, k) + + srcU(i + 1, j, k - 1) * (*matrixA[8])(i, j, k) + + srcU(i, j, k) * (*matrixA[9])(i, j, k) + + srcU(i, j, k - 1) * (*matrixA[10])(i, j, k) + + srcV(i, j + 1, k) * (*matrixA[11])(i, j, k) + + srcV(i, j + 1, k - 1) * (*matrixA[12])(i, j, k) + + srcV(i, j, k) * (*matrixA[13])(i, j, k) + + srcV(i, j, k - 1) * (*matrixA[14])(i, j, k); + } + inline const FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + inline Grid &getArg1() + { + return dst; + } + typedef Grid type1; + inline const Grid &getArg2() + { + return src; + } + typedef Grid type2; + inline const std::vector *> &getArg3() + { + return matrixA; + } + typedef std::vector *> type3; + inline const std::vector *> &getArg4() + { + return vecRhs; + } + typedef std::vector *> type4; + void runMessage() + { + debMsg("Executing kernel ApplyMatrixViscosityW ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 1; j < _maxY; j++) + for (int i = 1; i < _maxX; i++) + op(i, j, k, flags, dst, src, matrixA, vecRhs); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 1; i < _maxX; i++) + op(i, j, k, flags, dst, src, matrixA, vecRhs); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(1, maxY), *this); + } + const FlagGrid &flags; + Grid &dst; + const Grid &src; + const std::vector *> matrixA; + const std::vector *> vecRhs; +}; + +/* NOTE: Use this template for new matrix application kernels + +//! Template for matrix application kernels +KERNEL() +void ApplyMatrixTemplate (const FlagGrid& flags, Grid& dst, const Grid& src, + const std::vector *> matrixA, const std::vector *> vecRhs) +{ + // The kernel must define how to use the grids from the matrixA and vecRhs lists +} + +*/ + //! Kernel: Construct the matrix for the poisson equation struct MakeLaplaceMatrix : public KernelBase { diff --git a/extern/mantaflow/preprocessed/general.h b/extern/mantaflow/preprocessed/general.h index 7a840517cef..50eac71e87e 100644 --- a/extern/mantaflow/preprocessed/general.h +++ b/extern/mantaflow/preprocessed/general.h @@ -42,7 +42,7 @@ inline void updateQtGui(bool full, int frame, float time, const std::string &cur # ifdef _DEBUG # define DEBUG 1 # endif // _DEBUG -#endif // DEBUG +#endif // DEBUG // Standard exception class Error : public std::exception { @@ -242,6 +242,39 @@ inline bool c_isnan(float c) return d != d; } +//! Swap so that a inline void sort(T &a, T &b) +{ + if (a > b) + std::swap(a, b); +} + +//! Swap so that a inline void sort(T &a, T &b, T &c) +{ + if (a > b) + std::swap(a, b); + if (a > c) + std::swap(a, c); + if (b > c) + std::swap(b, c); +} + +//! Swap so that a inline void sort(T &a, T &b, T &c, T &d) +{ + if (a > b) + std::swap(a, b); + if (c > d) + std::swap(c, d); + if (a > c) + std::swap(a, c); + if (b > d) + std::swap(b, d); + if (b > c) + std::swap(b, c); +} + } // namespace Manta #endif diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index a0590e6a0b0..afc34a00d3d 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit 327917cd59b03bef3a953b5f58fc1637b3a83e01" +#define MANTA_GIT_VERSION "commit e2285cb9bc492987f728123be6cfc1fe11fe73d6" diff --git a/extern/mantaflow/preprocessed/plugin/extforces.cpp b/extern/mantaflow/preprocessed/plugin/extforces.cpp index 558008afe3b..88935fa7ae9 100644 --- a/extern/mantaflow/preprocessed/plugin/extforces.cpp +++ b/extern/mantaflow/preprocessed/plugin/extforces.cpp @@ -1135,26 +1135,27 @@ struct KnAddForceIfLower : public KernelBase { if (!curFluid && !curEmpty) return; + Real minVal, maxVal, sum; if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k))) { Real forceMACX = 0.5 * (force(i - 1, j, k).x + force(i, j, k).x); - Real min = std::min(vel(i, j, k).x, forceMACX); - Real max = std::max(vel(i, j, k).x, forceMACX); - Real sum = vel(i, j, k).x + forceMACX; - vel(i, j, k).x = (forceMACX > 0) ? std::min(sum, max) : std::max(sum, min); + minVal = min(vel(i, j, k).x, forceMACX); + maxVal = max(vel(i, j, k).x, forceMACX); + sum = vel(i, j, k).x + forceMACX; + vel(i, j, k).x = (forceMACX > 0) ? min(sum, maxVal) : max(sum, minVal); } if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k))) { Real forceMACY = 0.5 * (force(i, j - 1, k).y + force(i, j, k).y); - Real min = std::min(vel(i, j, k).y, forceMACY); - Real max = std::max(vel(i, j, k).y, forceMACY); - Real sum = vel(i, j, k).y + forceMACY; - vel(i, j, k).y = (forceMACY > 0) ? std::min(sum, max) : std::max(sum, min); + minVal = min(vel(i, j, k).y, forceMACY); + maxVal = max(vel(i, j, k).y, forceMACY); + sum = vel(i, j, k).y + forceMACY; + vel(i, j, k).y = (forceMACY > 0) ? min(sum, maxVal) : max(sum, minVal); } if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1)))) { Real forceMACZ = 0.5 * (force(i, j, k - 1).z + force(i, j, k).z); - Real min = std::min(vel(i, j, k).z, forceMACZ); - Real max = std::max(vel(i, j, k).z, forceMACZ); - Real sum = vel(i, j, k).z + forceMACZ; - vel(i, j, k).z = (forceMACZ > 0) ? std::min(sum, max) : std::max(sum, min); + minVal = min(vel(i, j, k).z, forceMACZ); + maxVal = max(vel(i, j, k).z, forceMACZ); + sum = vel(i, j, k).z + forceMACZ; + vel(i, j, k).z = (forceMACZ > 0) ? min(sum, maxVal) : max(sum, minVal); } } inline const FlagGrid &getArg0() diff --git a/extern/mantaflow/preprocessed/plugin/pressure.cpp b/extern/mantaflow/preprocessed/plugin/pressure.cpp index 1100a58db47..593aeb16859 100644 --- a/extern/mantaflow/preprocessed/plugin/pressure.cpp +++ b/extern/mantaflow/preprocessed/plugin/pressure.cpp @@ -1138,11 +1138,15 @@ void solvePressureSystem(Grid &rhs, // note: the last factor increases the max iterations for 2d, which right now can't use a // preconditioner GridCgInterface *gcg; - if (vel.is3D()) - gcg = new GridCg(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); - else - gcg = new GridCg( - pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); + vector *> matA{&A0, &Ai, &Aj}; + + if (vel.is3D()) { + matA.push_back(&Ak); + gcg = new GridCg(pressure, rhs, residual, search, flags, tmp, matA); + } + else { + gcg = new GridCg(pressure, rhs, residual, search, flags, tmp, matA); + } gcg->setAccuracy(cgAccuracy); gcg->setUseL2Norm(useL2Norm); diff --git a/extern/mantaflow/preprocessed/plugin/viscosity.cpp b/extern/mantaflow/preprocessed/plugin/viscosity.cpp new file mode 100644 index 00000000000..5dc478b13dd --- /dev/null +++ b/extern/mantaflow/preprocessed/plugin/viscosity.cpp @@ -0,0 +1,1430 @@ + + +// DO NOT EDIT ! +// This file is generated using the MantaFlow preprocessor (prep generate). + +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2020 Sebastian Barschkis, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Accurate Viscous Free Surfaces for Buckling, Coiling, and Rotating Liquids + * Batty et al., SCA 2008 + * + ******************************************************************************/ + +#include "conjugategrad.h" +#include "general.h" +#include "grid.h" +#include "vectorbase.h" + +#include + +#if OPENMP == 1 || TBB == 1 +# define ENABLE_PARALLEL 0 +#endif + +#if ENABLE_PARALLEL == 1 +# include +# include + +static const int manta_num_threads = std::thread::hardware_concurrency(); + +# define parallel_block \ + { \ + std::vector threads; \ + { + +# define do_parallel threads.push_back( std::thread([&]() { +# define do_end \ + } ) ); + +# define block_end \ + } \ + for (auto &thread : threads) { \ + thread.join(); \ + } \ + } + +#endif + +#define FOR_INT_IJK(num) \ + for (int k_off = 0; k_off < num; ++k_off) \ + for (int j_off = 0; j_off < num; ++j_off) \ + for (int i_off = 0; i_off < num; ++i_off) + +using namespace std; + +namespace Manta { + +//! Assumes phi0<0 and phi1>=0, phi2>=0, and phi3>=0 or vice versa. +//! In particular, phi0 must not equal any of phi1, phi2 or phi3. +static Real sortedTetFraction(Real phi0, Real phi1, Real phi2, Real phi3) +{ + return phi0 * phi0 * phi0 / ((phi0 - phi1) * (phi0 - phi2) * (phi0 - phi3)); +} + +//! Assumes phi0<0, phi1<0, and phi2>=0, and phi3>=0 or vice versa. +//! In particular, phi0 and phi1 must not equal any of phi2 and phi3. +static Real sortedPrismFraction(Real phi0, Real phi1, Real phi2, Real phi3) +{ + Real a = phi0 / (phi0 - phi2); + Real b = phi0 / (phi0 - phi3); + Real c = phi1 / (phi1 - phi3); + Real d = phi1 / (phi1 - phi2); + return a * b * (1 - d) + b * (1 - c) * d + c * d; +} + +Real volumeFraction(Real phi0, Real phi1, Real phi2, Real phi3) +{ + sort(phi0, phi1, phi2, phi3); + if (phi3 <= 0) + return 1; + else if (phi2 <= 0) + return 1 - sortedTetFraction(phi3, phi2, phi1, phi0); + else if (phi1 <= 0) + return sortedPrismFraction(phi0, phi1, phi2, phi3); + else if (phi0 <= 0) + return sortedTetFraction(phi0, phi1, phi2, phi3); + else + return 0; +} + +//! The average of the two possible decompositions of the cube into five tetrahedra. +Real volumeFraction(Real phi000, + Real phi100, + Real phi010, + Real phi110, + Real phi001, + Real phi101, + Real phi011, + Real phi111) +{ + return (volumeFraction(phi000, phi001, phi101, phi011) + + volumeFraction(phi000, phi101, phi100, phi110) + + volumeFraction(phi000, phi010, phi011, phi110) + + volumeFraction(phi101, phi011, phi111, phi110) + + 2 * volumeFraction(phi000, phi011, phi101, phi110) + + volumeFraction(phi100, phi101, phi001, phi111) + + volumeFraction(phi100, phi001, phi000, phi010) + + volumeFraction(phi100, phi110, phi111, phi010) + + volumeFraction(phi001, phi111, phi011, phi010) + + 2 * volumeFraction(phi100, phi111, phi001, phi010)) / + 12; +} + +//! Kernel loop over grid with 2x base resolution! + +struct KnEstimateVolumeFraction : public KernelBase { + KnEstimateVolumeFraction(Grid &volumes, + const Grid &phi, + const Vec3 &startCentre, + const Real dx) + : KernelBase(&volumes, 0), volumes(volumes), phi(phi), startCentre(startCentre), dx(dx) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + Grid &volumes, + const Grid &phi, + const Vec3 &startCentre, + const Real dx) const + { + const Vec3 centre = startCentre + Vec3(i, j, k) * 0.5; + const Real offset = 0.5 * dx; + const int order = 2; + + Real phi000 = phi.getInterpolatedHi(centre + Vec3(-offset, -offset, -offset), order); + Real phi001 = phi.getInterpolatedHi(centre + Vec3(-offset, -offset, +offset), order); + Real phi010 = phi.getInterpolatedHi(centre + Vec3(-offset, +offset, -offset), order); + Real phi011 = phi.getInterpolatedHi(centre + Vec3(-offset, +offset, +offset), order); + Real phi100 = phi.getInterpolatedHi(centre + Vec3(+offset, -offset, -offset), order); + Real phi101 = phi.getInterpolatedHi(centre + Vec3(+offset, -offset, +offset), order); + Real phi110 = phi.getInterpolatedHi(centre + Vec3(+offset, +offset, -offset), order); + Real phi111 = phi.getInterpolatedHi(centre + Vec3(+offset, +offset, +offset), order); + + volumes(i, j, k) = volumeFraction( + phi000, phi100, phi010, phi110, phi001, phi101, phi011, phi111); + } + inline Grid &getArg0() + { + return volumes; + } + typedef Grid type0; + inline const Grid &getArg1() + { + return phi; + } + typedef Grid type1; + inline const Vec3 &getArg2() + { + return startCentre; + } + typedef Vec3 type2; + inline const Real &getArg3() + { + return dx; + } + typedef Real type3; + void runMessage() + { + debMsg("Executing kernel KnEstimateVolumeFraction ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 0; j < _maxY; j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, volumes, phi, startCentre, dx); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, volumes, phi, startCentre, dx); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(0, maxY), *this); + } + Grid &volumes; + const Grid φ + const Vec3 &startCentre; + const Real dx; +}; + +struct KnUpdateVolumeGrid : public KernelBase { + KnUpdateVolumeGrid(Grid &cVolLiquid, + Grid &uVolLiquid, + Grid &vVolLiquid, + Grid &wVolLiquid, + Grid &exVolLiquid, + Grid &eyVolLiquid, + Grid &ezVolLiquid, + const Grid &src) + : KernelBase(&cVolLiquid, 0), + cVolLiquid(cVolLiquid), + uVolLiquid(uVolLiquid), + vVolLiquid(vVolLiquid), + wVolLiquid(wVolLiquid), + exVolLiquid(exVolLiquid), + eyVolLiquid(eyVolLiquid), + ezVolLiquid(ezVolLiquid), + src(src) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + Grid &cVolLiquid, + Grid &uVolLiquid, + Grid &vVolLiquid, + Grid &wVolLiquid, + Grid &exVolLiquid, + Grid &eyVolLiquid, + Grid &ezVolLiquid, + const Grid &src) const + { + // Work out c + cVolLiquid(i, j, k) = 0; + FOR_INT_IJK(2) + { + cVolLiquid(i, j, k) += src(2 * i + i_off, 2 * j + j_off, 2 * k + k_off); + } + cVolLiquid(i, j, k) /= 8; + + // Work out u + if (i >= 1) { + uVolLiquid(i, j, k) = 0; + int base_i = 2 * i - 1; + int base_j = 2 * j; + int base_k = 2 * k; + FOR_INT_IJK(2) + { + uVolLiquid(i, j, k) += src(base_i + i_off, base_j + j_off, base_k + k_off); + } + uVolLiquid(i, j, k) /= 8; + } + + // v + if (j >= 1) { + vVolLiquid(i, j, k) = 0; + int base_i = 2 * i; + int base_j = 2 * j - 1; + int base_k = 2 * k; + FOR_INT_IJK(2) + { + vVolLiquid(i, j, k) += src(base_i + i_off, base_j + j_off, base_k + k_off); + } + vVolLiquid(i, j, k) /= 8; + } + + // w + if (k >= 1) { + wVolLiquid(i, j, k) = 0; + int base_i = 2 * i; + int base_j = 2 * j; + int base_k = 2 * k - 1; + FOR_INT_IJK(2) + { + wVolLiquid(i, j, k) += src(base_i + i_off, base_j + j_off, base_k + k_off); + } + wVolLiquid(i, j, k) /= 8; + } + + // e-x + if (j >= 1 && k >= 1) { + exVolLiquid(i, j, k) = 0; + int base_i = 2 * i; + int base_j = 2 * j - 1; + int base_k = 2 * k - 1; + FOR_INT_IJK(2) + { + exVolLiquid(i, j, k) += src(base_i + i_off, base_j + j_off, base_k + k_off); + } + exVolLiquid(i, j, k) /= 8; + } + + // e-y + if (i >= 1 && k >= 1) { + eyVolLiquid(i, j, k) = 0; + int base_i = 2 * i - 1; + int base_j = 2 * j; + int base_k = 2 * k - 1; + FOR_INT_IJK(2) + { + eyVolLiquid(i, j, k) += src(base_i + i_off, base_j + j_off, base_k + k_off); + } + eyVolLiquid(i, j, k) /= 8; + } + + // e-z + if (i >= 1 && j >= 1) { + ezVolLiquid(i, j, k) = 0; + int base_i = 2 * i - 1; + int base_j = 2 * j - 1; + int base_k = 2 * k; + FOR_INT_IJK(2) + { + ezVolLiquid(i, j, k) += src(base_i + i_off, base_j + j_off, base_k + k_off); + } + ezVolLiquid(i, j, k) /= 8; + } + } + inline Grid &getArg0() + { + return cVolLiquid; + } + typedef Grid type0; + inline Grid &getArg1() + { + return uVolLiquid; + } + typedef Grid type1; + inline Grid &getArg2() + { + return vVolLiquid; + } + typedef Grid type2; + inline Grid &getArg3() + { + return wVolLiquid; + } + typedef Grid type3; + inline Grid &getArg4() + { + return exVolLiquid; + } + typedef Grid type4; + inline Grid &getArg5() + { + return eyVolLiquid; + } + typedef Grid type5; + inline Grid &getArg6() + { + return ezVolLiquid; + } + typedef Grid type6; + inline const Grid &getArg7() + { + return src; + } + typedef Grid type7; + void runMessage() + { + debMsg("Executing kernel KnUpdateVolumeGrid ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 0; j < _maxY; j++) + for (int i = 0; i < _maxX; i++) + op(i, + j, + k, + cVolLiquid, + uVolLiquid, + vVolLiquid, + wVolLiquid, + exVolLiquid, + eyVolLiquid, + ezVolLiquid, + src); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 0; i < _maxX; i++) + op(i, + j, + k, + cVolLiquid, + uVolLiquid, + vVolLiquid, + wVolLiquid, + exVolLiquid, + eyVolLiquid, + ezVolLiquid, + src); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(0, maxY), *this); + } + Grid &cVolLiquid; + Grid &uVolLiquid; + Grid &vVolLiquid; + Grid &wVolLiquid; + Grid &exVolLiquid; + Grid &eyVolLiquid; + Grid &ezVolLiquid; + const Grid &src; +}; + +void computeWeights(const Grid &phi, + Grid &doubleSized, + Grid &cVolLiquid, + Grid &uVolLiquid, + Grid &vVolLiquid, + Grid &wVolLiquid, + Grid &exVolLiquid, + Grid &eyVolLiquid, + Grid &ezVolLiquid, + Real dx) +{ + KnEstimateVolumeFraction(doubleSized, phi, Vec3(0.25 * dx, 0.25 * dx, 0.25 * dx), 0.5 * dx); + KnUpdateVolumeGrid(cVolLiquid, + uVolLiquid, + vVolLiquid, + wVolLiquid, + exVolLiquid, + eyVolLiquid, + ezVolLiquid, + doubleSized); +} + +struct KnUpdateFaceStates : public KernelBase { + KnUpdateFaceStates(const FlagGrid &flags, + Grid &uState, + Grid &vState, + Grid &wState) + : KernelBase(&flags, 0), flags(flags), uState(uState), vState(vState), wState(wState) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + const FlagGrid &flags, + Grid &uState, + Grid &vState, + Grid &wState) const + { + bool curObs = flags.isObstacle(i, j, k); + uState(i, j, k) = (i > 0 && !flags.isObstacle(i - 1, j, k) && !curObs) ? + FlagGrid::TypeFluid : + FlagGrid::TypeObstacle; + vState(i, j, k) = (j > 0 && !flags.isObstacle(i, j - 1, k) && !curObs) ? + FlagGrid::TypeFluid : + FlagGrid::TypeObstacle; + wState(i, j, k) = (k > 0 && !flags.isObstacle(i, j, k - 1) && !curObs) ? + FlagGrid::TypeFluid : + FlagGrid::TypeObstacle; + } + inline const FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + inline Grid &getArg1() + { + return uState; + } + typedef Grid type1; + inline Grid &getArg2() + { + return vState; + } + typedef Grid type2; + inline Grid &getArg3() + { + return wState; + } + typedef Grid type3; + void runMessage() + { + debMsg("Executing kernel KnUpdateFaceStates ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 0; j < _maxY; j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, flags, uState, vState, wState); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, flags, uState, vState, wState); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(0, maxY), *this); + } + const FlagGrid &flags; + Grid &uState; + Grid &vState; + Grid &wState; +}; + +struct KnApplyVelocities : public KernelBase { + KnApplyVelocities(MACGrid &dst, + const Grid &uState, + const Grid &vState, + const Grid &wState, + Grid &srcU, + Grid &srcV, + Grid &srcW) + : KernelBase(&dst, 0), + dst(dst), + uState(uState), + vState(vState), + wState(wState), + srcU(srcU), + srcV(srcV), + srcW(srcW) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + MACGrid &dst, + const Grid &uState, + const Grid &vState, + const Grid &wState, + Grid &srcU, + Grid &srcV, + Grid &srcW) const + { + dst(i, j, k).x = (uState(i, j, k) == FlagGrid::TypeFluid) ? srcU(i, j, k) : 0; + dst(i, j, k).y = (vState(i, j, k) == FlagGrid::TypeFluid) ? srcV(i, j, k) : 0; + if (dst.is3D()) + dst(i, j, k).z = (wState(i, j, k) == FlagGrid::TypeFluid) ? srcW(i, j, k) : 0; + } + inline MACGrid &getArg0() + { + return dst; + } + typedef MACGrid type0; + inline const Grid &getArg1() + { + return uState; + } + typedef Grid type1; + inline const Grid &getArg2() + { + return vState; + } + typedef Grid type2; + inline const Grid &getArg3() + { + return wState; + } + typedef Grid type3; + inline Grid &getArg4() + { + return srcU; + } + typedef Grid type4; + inline Grid &getArg5() + { + return srcV; + } + typedef Grid type5; + inline Grid &getArg6() + { + return srcW; + } + typedef Grid type6; + void runMessage() + { + debMsg("Executing kernel KnApplyVelocities ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = 0; j < _maxY; j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, dst, uState, vState, wState, srcU, srcV, srcW); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, dst, uState, vState, wState, srcU, srcV, srcW); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(0, maxY), *this); + } + MACGrid &dst; + const Grid &uState; + const Grid &vState; + const Grid &wState; + Grid &srcU; + Grid &srcV; + Grid &srcW; +}; + +void solveViscosity(const FlagGrid &flags, + MACGrid &vel, + Grid &cVolLiquid, + Grid &uVolLiquid, + Grid &vVolLiquid, + Grid &wVolLiquid, + Grid &exVolLiquid, + Grid &eyVolLiquid, + Grid &ezVolLiquid, + Grid &viscosity, + const Real dt, + const Real dx, + const Real cgAccuracy, + const Real cgMaxIterFac) +{ + const Real factor = dt * square(1.0 / dx); + const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4); + GridCg *uGcg; + GridCg *vGcg; + GridCg *wGcg; + + // Tmp grids for CG solve in U, V, W dimensions + FluidSolver *parent = flags.getParent(); + Grid uResidual(parent); + Grid vResidual(parent); + Grid wResidual(parent); + Grid uSearch(parent); + Grid vSearch(parent); + Grid wSearch(parent); + Grid uTmp(parent); + Grid vTmp(parent); + Grid wTmp(parent); + Grid uRhs(parent); + Grid vRhs(parent); + Grid wRhs(parent); + + // A matrix U grids + Grid uA0(parent); // diagonal elements in A matrix + Grid uAplusi(parent); // neighbor at i+1 + Grid uAplusj(parent); // neighbor at j+1 + Grid uAplusk(parent); // neighbor at k+1 + Grid uAminusi(parent); // neighbor at i-1 + Grid uAminusj(parent); // neighbor at j-1 + Grid uAminusk(parent); // neighbor at k-1 + Grid uAhelper1(parent); // additional helper grids for off diagonal elements + Grid uAhelper2(parent); + Grid uAhelper3(parent); + Grid uAhelper4(parent); + Grid uAhelper5(parent); + Grid uAhelper6(parent); + Grid uAhelper7(parent); + Grid uAhelper8(parent); + + // A matrix V grids + Grid vA0(parent); + Grid vAplusi(parent); + Grid vAplusj(parent); + Grid vAplusk(parent); + Grid vAminusi(parent); + Grid vAminusj(parent); + Grid vAminusk(parent); + Grid vAhelper1(parent); + Grid vAhelper2(parent); + Grid vAhelper3(parent); + Grid vAhelper4(parent); + Grid vAhelper5(parent); + Grid vAhelper6(parent); + Grid vAhelper7(parent); + Grid vAhelper8(parent); + + // A matrix W grids + Grid wA0(parent); + Grid wAplusi(parent); + Grid wAplusj(parent); + Grid wAplusk(parent); + Grid wAminusi(parent); + Grid wAminusj(parent); + Grid wAminusk(parent); + Grid wAhelper1(parent); + Grid wAhelper2(parent); + Grid wAhelper3(parent); + Grid wAhelper4(parent); + Grid wAhelper5(parent); + Grid wAhelper6(parent); + Grid wAhelper7(parent); + Grid wAhelper8(parent); + + // Solution grids for CG solvers + Grid uSolution(parent); + Grid vSolution(parent); + Grid wSolution(parent); + + // Save state of voxel face (fluid or obstacle) + Grid uState(parent); + Grid vState(parent); + Grid wState(parent); + + // Save state of voxel face (fluid or obstacle) + KnUpdateFaceStates(flags, uState, vState, wState); + + // Shorter names for flags, we will use them often + int isFluid = FlagGrid::TypeFluid; + int isObstacle = FlagGrid::TypeObstacle; + + // Main viscosity loop: construct A matrices and rhs's in all dimensions + FOR_IJK_BND(flags, 1) + { + + // U-terms: 2u_xx+ v_xy +uyy + u_zz + w_xz + if (uState(i, j, k) == isFluid) { + + uRhs(i, j, k) = uVolLiquid(i, j, k) * vel(i, j, k).x; + uA0(i, j, k) = uVolLiquid(i, j, k); + + Real viscRight = viscosity(i, j, k); + Real viscLeft = viscosity(i - 1, j, k); + Real volRight = cVolLiquid(i, j, k); + Real volLeft = cVolLiquid(i - 1, j, k); + + Real viscTop = 0.25 * (viscosity(i - 1, j + 1, k) + viscosity(i - 1, j, k) + + viscosity(i, j + 1, k) + viscosity(i, j, k)); + Real viscBottom = 0.25 * (viscosity(i - 1, j, k) + viscosity(i - 1, j - 1, k) + + viscosity(i, j, k) + viscosity(i, j - 1, k)); + Real volTop = ezVolLiquid(i, j + 1, k); + Real volBottom = ezVolLiquid(i, j, k); + + Real viscFront = 0.25 * (viscosity(i - 1, j, k + 1) + viscosity(i - 1, j, k) + + viscosity(i, j, k + 1) + viscosity(i, j, k)); + Real viscBack = 0.25 * (viscosity(i - 1, j, k) + viscosity(i - 1, j, k - 1) + + viscosity(i, j, k) + viscosity(i, j, k - 1)); + Real volFront = eyVolLiquid(i, j, k + 1); + Real volBack = eyVolLiquid(i, j, k); + + Real factorRight = 2 * factor * viscRight * volRight; + Real factorLeft = 2 * factor * viscLeft * volLeft; + Real factorTop = factor * viscTop * volTop; + Real factorBottom = factor * viscBottom * volBottom; + Real factorFront = factor * viscFront * volFront; + Real factorBack = factor * viscBack * volBack; + + // u_x_right + uA0(i, j, k) += factorRight; + if (uState(i + 1, j, k) == isFluid) { + uAplusi(i, j, k) += -factorRight; + } + else if (uState(i + 1, j, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i + 1, j, k).x * factorRight; + } + + // u_x_left + uA0(i, j, k) += factorLeft; + if (uState(i - 1, j, k) == isFluid) { + uAminusi(i, j, k) += -factorLeft; + } + else if (uState(i - 1, j, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i - 1, j, k).x * factorLeft; + } + + // u_y_top + uA0(i, j, k) += factorTop; + if (uState(i, j + 1, k) == isFluid) { + uAplusj(i, j, k) += -factorTop; + } + else if (uState(i, j + 1, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i, j + 1, k).x * factorTop; + } + + // u_y_bottom + uA0(i, j, k) += factorBottom; + if (uState(i, j - 1, k) == isFluid) { + uAminusj(i, j, k) += -factorBottom; + } + else if (uState(i, j - 1, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i, j - 1, k).x * factorBottom; + } + + // u_z_front + uA0(i, j, k) += factorFront; + if (uState(i, j, k + 1) == isFluid) { + uAplusk(i, j, k) += -factorFront; + } + else if (uState(i, j, k + 1) == isObstacle) { + uRhs(i, j, k) -= -vel(i, j, k + 1).x * factorFront; + } + + // u_z_back + uA0(i, j, k) += factorBack; + if (uState(i, j, k - 1) == isFluid) { + uAminusk(i, j, k) += -factorBack; + } + else if (uState(i, j, k - 1) == isObstacle) { + uRhs(i, j, k) -= -vel(i, j, k - 1).x * factorBack; + } + + // v_x_top + if (vState(i, j + 1, k) == isFluid) { + uAhelper1(i, j, k) += -factorTop; + } + else if (vState(i, j + 1, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i, j + 1, k).y * factorTop; + } + + if (vState(i - 1, j + 1, k) == isFluid) { + uAhelper2(i, j, k) += factorTop; + } + else if (vState(i - 1, j + 1, k) == isObstacle) { + uRhs(i, j, k) -= vel(i - 1, j + 1, k).y * factorTop; + } + + // v_x_bottom + if (vState(i, j, k) == isFluid) { + uAhelper3(i, j, k) += factorBottom; + } + else if (vState(i, j, k) == isObstacle) { + uRhs(i, j, k) -= vel(i, j, k).y * factorBottom; + } + + if (vState(i - 1, j, k) == isFluid) { + uAhelper4(i, j, k) += -factorBottom; + } + else if (vState(i - 1, j, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i - 1, j, k).y * factorBottom; + } + + // w_x_front + if (wState(i, j, k + 1) == isFluid) { + uAhelper5(i, j, k) += -factorFront; + } + else if (wState(i, j, k + 1) == isObstacle) { + uRhs(i, j, k) -= -vel(i, j, k + 1).z * factorFront; + } + + if (wState(i - 1, j, k + 1) == isFluid) { + uAhelper6(i, j, k) += factorFront; + } + else if (wState(i - 1, j, k + 1) == isObstacle) { + uRhs(i, j, k) -= vel(i - 1, j, k + 1).z * factorFront; + } + + // w_x_back + if (wState(i, j, k) == isFluid) { + uAhelper7(i, j, k) += factorBack; + } + else if (wState(i, j, k) == isObstacle) { + uRhs(i, j, k) -= vel(i, j, k).z * factorBack; + } + + if (wState(i - 1, j, k) == isFluid) { + uAhelper8(i, j, k) += -factorBack; + } + else if (wState(i - 1, j, k) == isObstacle) { + uRhs(i, j, k) -= -vel(i - 1, j, k).z * factorBack; + } + } + + // V-terms: vxx + 2vyy + vzz + u_yx + w_yz + if (vState(i, j, k) == isFluid) { + + vRhs(i, j, k) = vVolLiquid(i, j, k) * vel(i, j, k).y; + vA0(i, j, k) = vVolLiquid(i, j, k); + + Real viscRight = 0.25 * (viscosity(i, j - 1, k) + viscosity(i + 1, j - 1, k) + + viscosity(i, j, k) + viscosity(i + 1, j, k)); + Real viscLeft = 0.25 * (viscosity(i, j - 1, k) + viscosity(i - 1, j - 1, k) + + viscosity(i, j, k) + viscosity(i - 1, j, k)); + Real volRight = ezVolLiquid(i + 1, j, k); + Real volLeft = ezVolLiquid(i, j, k); + + Real viscTop = viscosity(i, j, k); + Real viscBottom = viscosity(i, j - 1, k); + Real volTop = cVolLiquid(i, j, k); + Real volBottom = cVolLiquid(i, j - 1, k); + + Real viscFront = 0.25 * (viscosity(i, j - 1, k) + viscosity(i, j - 1, k + 1) + + viscosity(i, j, k) + viscosity(i, j, k + 1)); + Real viscBack = 0.25 * (viscosity(i, j - 1, k) + viscosity(i, j - 1, k - 1) + + viscosity(i, j, k) + viscosity(i, j, k - 1)); + Real volFront = exVolLiquid(i, j, k + 1); + Real volBack = exVolLiquid(i, j, k); + + Real factorRight = factor * viscRight * volRight; + Real factorLeft = factor * viscLeft * volLeft; + Real factorTop = 2 * factor * viscTop * volTop; + Real factorBottom = 2 * factor * viscBottom * volBottom; + Real factorFront = factor * viscFront * volFront; + Real factorBack = factor * viscBack * volBack; + + // v_x_right + vA0(i, j, k) += factorRight; + if (vState(i + 1, j, k) == isFluid) { + vAplusi(i, j, k) += -factorRight; + } + else if (vState(i + 1, j, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i + 1, j, k).y * factorRight; + } + + // v_x_left + vA0(i, j, k) += factorLeft; + if (vState(i - 1, j, k) == isFluid) { + vAminusi(i, j, k) += -factorLeft; + } + else if (vState(i - 1, j, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i - 1, j, k).y * factorLeft; + } + + // vy_top + vA0(i, j, k) += factorTop; + if (vState(i, j + 1, k) == isFluid) { + vAplusj(i, j, k) += -factorTop; + } + else if (vState(i, j + 1, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j + 1, k).y * factorTop; + } + + // vy_bottom + vA0(i, j, k) += factorBottom; + if (vState(i, j - 1, k) == isFluid) { + vAminusj(i, j, k) += -factorBottom; + } + else if (vState(i, j - 1, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j - 1, k).y * factorBottom; + } + + // v_z_front + vA0(i, j, k) += factorFront; + if (vState(i, j, k + 1) == isFluid) { + vAplusk(i, j, k) += -factorFront; + } + else if (vState(i, j, k + 1) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j, k + 1).y * factorFront; + } + + // v_z_back + vA0(i, j, k) += factorBack; + if (vState(i, j, k - 1) == isFluid) { + vAminusk(i, j, k) += -factorBack; + } + else if (vState(i, j, k - 1) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j, k - 1).y * factorBack; + } + + // u_y_right + if (uState(i + 1, j, k) == isFluid) { + vAhelper1(i, j, k) += -factorRight; + } + else if (uState(i + 1, j, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i + 1, j, k).x * factorRight; + } + + if (uState(i + 1, j - 1, k) == isFluid) { + vAhelper2(i, j, k) += factorRight; + } + else if (uState(i + 1, j - 1, k) == isObstacle) { + vRhs(i, j, k) -= vel(i + 1, j - 1, k).x * factorRight; + } + + // u_y_left + if (uState(i, j, k) == isFluid) { + vAhelper3(i, j, k) += factorLeft; + } + else if (uState(i, j, k) == isObstacle) { + vRhs(i, j, k) -= vel(i, j, k).x * factorLeft; + } + + if (uState(i, j - 1, k) == isFluid) { + vAhelper4(i, j, k) += -factorLeft; + } + else if (uState(i, j - 1, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j - 1, k).x * factorLeft; + } + + // w_y_front + if (wState(i, j, k + 1) == isFluid) { + vAhelper5(i, j, k) += -factorFront; + } + else if (wState(i, j, k + 1) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j, k + 1).z * factorFront; + } + + if (wState(i, j - 1, k + 1) == isFluid) { + vAhelper6(i, j, k) += factorFront; + } + else if (wState(i, j - 1, k + 1) == isObstacle) { + vRhs(i, j, k) -= vel(i, j - 1, k + 1).z * factorFront; + } + + // w_y_back + if (wState(i, j, k) == isFluid) { + vAhelper7(i, j, k) += factorBack; + } + else if (wState(i, j, k) == isObstacle) { + vRhs(i, j, k) -= vel(i, j, k).z * factorBack; + } + + if (wState(i, j - 1, k) == isFluid) { + vAhelper8(i, j, k) += -factorBack; + } + else if (wState(i, j - 1, k) == isObstacle) { + vRhs(i, j, k) -= -vel(i, j - 1, k).z * factorBack; + } + } + + // W-terms: wxx+ wyy+ 2wzz + u_zx + v_zy + if (wState(i, j, k) == isFluid) { + + wRhs(i, j, k) = wVolLiquid(i, j, k) * vel(i, j, k).z; + wA0(i, j, k) = wVolLiquid(i, j, k); + + Real viscRight = 0.25 * (viscosity(i, j, k) + viscosity(i, j, k - 1) + + viscosity(i + 1, j, k) + viscosity(i + 1, j, k - 1)); + Real viscLeft = 0.25 * (viscosity(i, j, k) + viscosity(i, j, k - 1) + + viscosity(i - 1, j, k) + viscosity(i - 1, j, k - 1)); + Real volRight = eyVolLiquid(i + 1, j, k); + Real volLeft = eyVolLiquid(i, j, k); + + Real viscTop = 0.25 * (viscosity(i, j, k) + viscosity(i, j, k - 1) + viscosity(i, j + 1, k) + + viscosity(i, j + 1, k - 1)); + ; + Real viscBottom = 0.25 * (viscosity(i, j, k) + viscosity(i, j, k - 1) + + viscosity(i, j - 1, k) + viscosity(i, j - 1, k - 1)); + ; + Real volTop = exVolLiquid(i, j + 1, k); + Real volBottom = exVolLiquid(i, j, k); + + Real viscFront = viscosity(i, j, k); + Real viscBack = viscosity(i, j, k - 1); + Real volFront = cVolLiquid(i, j, k); + Real volBack = cVolLiquid(i, j, k - 1); + + Real factorRight = factor * viscRight * volRight; + Real factorLeft = factor * viscLeft * volLeft; + Real factorTop = factor * viscTop * volTop; + Real factorBottom = factor * viscBottom * volBottom; + Real factorFront = 2 * factor * viscFront * volFront; + Real factorBack = 2 * factor * viscBack * volBack; + + // w_x_right + wA0(i, j, k) += factorRight; + if (wState(i + 1, j, k) == isFluid) { + wAplusi(i, j, k) += -factorRight; + } + else if (wState(i + 1, j, k) == isObstacle) { + wRhs(i, j, k) -= -vel(i + 1, j, k).z * factorRight; + } + + // w_x_left + wA0(i, j, k) += factorLeft; + if (wState(i - 1, j, k) == isFluid) { + wAminusi(i, j, k) += -factorLeft; + } + else if (wState(i - 1, j, k) == isObstacle) { + wRhs(i, j, k) -= -vel(i - 1, j, k).z * factorLeft; + } + + // w_y_top + wA0(i, j, k) += factorTop; + if (wState(i, j + 1, k) == isFluid) { + wAplusj(i, j, k) += -factorTop; + } + else if (wState(i, j + 1, k) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j + 1, k).z * factorTop; + } + + // w_y_bottom + wA0(i, j, k) += factorBottom; + if (wState(i, j - 1, k) == isFluid) { + wAminusj(i, j, k) += -factorBottom; + } + else if (wState(i, j - 1, k) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j - 1, k).z * factorBottom; + } + + // w_z_front + wA0(i, j, k) += factorFront; + if (wState(i, j, k + 1) == isFluid) { + wAplusk(i, j, k) += -factorFront; + } + else if (wState(i, j, k + 1) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j, k + 1).z * factorFront; + } + + // w_z_back + wA0(i, j, k) += factorBack; + if (wState(i, j, k - 1) == isFluid) { + wAminusk(i, j, k) += -factorBack; + } + else if (wState(i, j, k - 1) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j, k - 1).z * factorBack; + } + + // u_z_right + if (uState(i + 1, j, k) == isFluid) { + wAhelper1(i, j, k) += -factorRight; + } + else if (uState(i + 1, j, k) == isObstacle) { + wRhs(i, j, k) -= -vel(i + 1, j, k).x * factorRight; + } + + if (uState(i + 1, j, k - 1) == isFluid) { + wAhelper2(i, j, k) += factorRight; + } + else if (uState(i + 1, j, k - 1) == isObstacle) { + wRhs(i, j, k) -= vel(i + 1, j, k - 1).x * factorRight; + } + + // u_z_left + if (uState(i, j, k) == isFluid) { + wAhelper3(i, j, k) += factorLeft; + } + else if (uState(i, j, k) == isObstacle) { + wRhs(i, j, k) -= vel(i, j, k).x * factorLeft; + } + + if (uState(i, j, k - 1) == isFluid) { + wAhelper4(i, j, k) += -factorLeft; + } + else if (uState(i, j, k - 1) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j, k - 1).x * factorLeft; + } + + // v_z_top + if (vState(i, j + 1, k) == isFluid) { + wAhelper5(i, j, k) += -factorTop; + } + else if (vState(i, j + 1, k) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j + 1, k).y * factorTop; + } + + if (vState(i, j + 1, k - 1) == isFluid) { + wAhelper6(i, j, k) += factorTop; + } + else if (vState(i, j + 1, k - 1) == isObstacle) { + wRhs(i, j, k) -= vel(i, j + 1, k - 1).y * factorTop; + } + + // v_z_bottom + if (vState(i, j, k) == isFluid) { + wAhelper7(i, j, k) += factorBottom; + } + else if (vState(i, j, k) == isObstacle) { + wRhs(i, j, k) -= vel(i, j, k).y * factorBottom; + } + + if (vState(i, j, k - 1) == isFluid) { + wAhelper8(i, j, k) += -factorBottom; + } + else if (vState(i, j, k - 1) == isObstacle) { + wRhs(i, j, k) -= -vel(i, j, k - 1).y * factorBottom; + } + } + } + + // CG solver for U + if (flags.is3D()) { + vector *> uMatA{&uA0, + &uAplusi, + &uAplusj, + &uAplusk, + &uAminusi, + &uAminusj, + &uAminusk, + &uAhelper1, + &uAhelper2, + &uAhelper3, + &uAhelper4, + &uAhelper5, + &uAhelper6, + &uAhelper7, + &uAhelper8}; + vector *> uVecRhs{&vRhs, &wRhs}; + uGcg = new GridCg( + uSolution, uRhs, uResidual, uSearch, flags, uTmp, uMatA, uVecRhs); + } + else { + errMsg("2D Matrix application not yet supported in viscosity solver"); + } + + // CG solver for V + if (flags.is3D()) { + vector *> vMatA{&vA0, + &vAplusi, + &vAplusj, + &vAplusk, + &vAminusi, + &vAminusj, + &vAminusk, + &vAhelper1, + &vAhelper2, + &vAhelper3, + &vAhelper4, + &vAhelper5, + &vAhelper6, + &vAhelper7, + &vAhelper8}; + vector *> vVecRhs{&uRhs, &wRhs}; + vGcg = new GridCg( + vSolution, vRhs, vResidual, vSearch, flags, vTmp, vMatA, vVecRhs); + } + else { + errMsg("2D Matrix application not yet supported in viscosity solver"); + } + + // CG solver for W + if (flags.is3D()) { + vector *> wMatA{&wA0, + &wAplusi, + &wAplusj, + &wAplusk, + &wAminusi, + &wAminusj, + &wAminusk, + &wAhelper1, + &wAhelper2, + &wAhelper3, + &wAhelper4, + &wAhelper5, + &wAhelper6, + &wAhelper7, + &wAhelper8}; + vector *> wVecRhs{&uRhs, &vRhs}; + wGcg = new GridCg( + wSolution, wRhs, wResidual, wSearch, flags, wTmp, wMatA, wVecRhs); + } + else { + errMsg("2D Matrix application not yet supported in viscosity solver"); + } + + // Same accuracy for all dimensions + uGcg->setAccuracy(cgAccuracy); + vGcg->setAccuracy(cgAccuracy); + wGcg->setAccuracy(cgAccuracy); + + // CG solve. Preconditioning not supported yet. Instead, U, V, W can optionally be solved in + // parallel. + for (int uIter = 0, vIter = 0, wIter = 0; uIter < maxIter || vIter < maxIter || wIter < maxIter; + uIter++, vIter++, wIter++) { +#if ENABLE_PARALLEL == 1 + parallel_block do_parallel +#endif + if (uIter < maxIter && !uGcg->iterate()) uIter = maxIter; +#if ENABLE_PARALLEL == 1 + do_end do_parallel +#endif + if (vIter < maxIter && !vGcg->iterate()) vIter = maxIter; +#if ENABLE_PARALLEL == 1 + do_end do_parallel +#endif + if (wIter < maxIter && !wGcg->iterate()) wIter = maxIter; +#if ENABLE_PARALLEL == 1 + do_end block_end +#endif + + // Make sure that next CG iteration has updated rhs grids + uRhs.copyFrom(uSearch); + vRhs.copyFrom(vSearch); + wRhs.copyFrom(wSearch); + } + debMsg( + "Viscosity::solveViscosity done. " + "Iterations (u,v,w): (" + << uGcg->getIterations() << "," << vGcg->getIterations() << "," << wGcg->getIterations() + << "), " + "Residual (u,v,w): (" + << uGcg->getResNorm() << "," << vGcg->getResNorm() << "," << wGcg->getResNorm() << ")", + 2); + + delete uGcg; + delete vGcg; + delete wGcg; + + // Apply solutions to global velocity grid + KnApplyVelocities(vel, uState, vState, wState, uSolution, vSolution, wSolution); +} + +//! To use the viscosity plugin, scenes must call this function before solving pressure. +//! Note that the 'volumes' grid uses 2x the base resolution + +void applyViscosity(const FlagGrid &flags, + const Grid &phi, + MACGrid &vel, + Grid &volumes, + Grid &viscosity, + const Real cgAccuracy = 1e-9, + const Real cgMaxIterFac = 1.5) +{ + const Real dx = flags.getParent()->getDx(); + const Real dt = flags.getParent()->getDt(); + + // Reserve temp grids for volume weight calculation + FluidSolver *parent = flags.getParent(); + Grid cVolLiquid(parent); + Grid uVolLiquid(parent); + Grid vVolLiquid(parent); + Grid wVolLiquid(parent); + Grid exVolLiquid(parent); + Grid eyVolLiquid(parent); + Grid ezVolLiquid(parent); + + // Ensure final weight grid gets cleared at every step + volumes.clear(); + + // Save viscous fluid volume in double-sized volumes grid + computeWeights(phi, + volumes, + cVolLiquid, + uVolLiquid, + vVolLiquid, + wVolLiquid, + exVolLiquid, + eyVolLiquid, + ezVolLiquid, + dx); + + // Set up A matrix and rhs. Solve with CG. Update velocity grid. + solveViscosity(flags, + vel, + cVolLiquid, + uVolLiquid, + vVolLiquid, + wVolLiquid, + exVolLiquid, + eyVolLiquid, + ezVolLiquid, + viscosity, + dt, + dx, + cgAccuracy, + cgMaxIterFac); +} +static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds) +{ + try { + PbArgs _args(_linargs, _kwds); + FluidSolver *parent = _args.obtainParent(); + bool noTiming = _args.getOpt("notiming", -1, 0); + pbPreparePlugin(parent, "applyViscosity", !noTiming); + PyObject *_retval = nullptr; + { + ArgLocker _lock; + const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); + const Grid &phi = *_args.getPtr>("phi", 1, &_lock); + MACGrid &vel = *_args.getPtr("vel", 2, &_lock); + Grid &volumes = *_args.getPtr>("volumes", 3, &_lock); + Grid &viscosity = *_args.getPtr>("viscosity", 4, &_lock); + const Real cgAccuracy = _args.getOpt("cgAccuracy", 5, 1e-9, &_lock); + const Real cgMaxIterFac = _args.getOpt("cgMaxIterFac", 6, 1.5, &_lock); + _retval = getPyNone(); + applyViscosity(flags, phi, vel, volumes, viscosity, cgAccuracy, cgMaxIterFac); + _args.check(); + } + pbFinalizePlugin(parent, "applyViscosity", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("applyViscosity", e.what()); + return 0; + } +} +static const Pb::Register _RP_applyViscosity("", "applyViscosity", _W_0); +extern "C" { +void PbRegister_applyViscosity() +{ + KEEP_UNUSED(_RP_applyViscosity); +} +} + +} // namespace Manta + +#if ENABLE_PARALLEL == 1 + +# undef parallel_block +# undef do_parallel +# undef do_end +# undef block_end +# undef parallel_for +# undef parallel_end + +#endif diff --git a/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp b/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp index d5d7d597a7c..18222c4ccda 100644 --- a/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp +++ b/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp @@ -576,8 +576,10 @@ void VICintegration(VortexSheetMesh &mesh, // prepare CG solver const int maxIter = (int)(cgMaxIterFac * vel.getSize().max()); + vector *> matA{&A0, &Ai, &Aj, &Ak}; + GridCgInterface *gcg = new GridCg( - solution, rhs, residual, search, flags, temp1, &A0, &Ai, &Aj, &Ak); + solution, rhs, residual, search, flags, temp1, matA); gcg->setAccuracy(cgAccuracy); gcg->setUseL2Norm(true); gcg->setICPreconditioner( diff --git a/extern/mantaflow/preprocessed/plugin/waves.cpp b/extern/mantaflow/preprocessed/plugin/waves.cpp index 6fb3b16c742..53c56b8c506 100644 --- a/extern/mantaflow/preprocessed/plugin/waves.cpp +++ b/extern/mantaflow/preprocessed/plugin/waves.cpp @@ -423,10 +423,15 @@ void cgSolveWE(const FlagGrid &flags, const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4); GridCgInterface *gcg; - if (flags.is3D()) - gcg = new GridCg(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); - else - gcg = new GridCg(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); + vector *> matA{&A0, &Ai, &Aj}; + + if (flags.is3D()) { + matA.push_back(&Ak); + gcg = new GridCg(out, rhs, residual, search, flags, tmp, matA); + } + else { + gcg = new GridCg(out, rhs, residual, search, flags, tmp, matA); + } gcg->setAccuracy(cgAccuracy); diff --git a/extern/mantaflow/preprocessed/registration.cpp b/extern/mantaflow/preprocessed/registration.cpp index d5dae479f0e..fd32463b95f 100644 --- a/extern/mantaflow/preprocessed/registration.cpp +++ b/extern/mantaflow/preprocessed/registration.cpp @@ -145,6 +145,7 @@ extern void PbRegister_flipComputeSurfaceNormals(); extern void PbRegister_flipUpdateNeighborRatio(); extern void PbRegister_particleSurfaceTurbulence(); extern void PbRegister_debugCheckParts(); +extern void PbRegister_applyViscosity(); extern void PbRegister_markAsFixed(); extern void PbRegister_texcoordInflow(); extern void PbRegister_meshSmokeInflow(); @@ -342,6 +343,7 @@ void MantaEnsureRegistration() PbRegister_flipUpdateNeighborRatio(); PbRegister_particleSurfaceTurbulence(); PbRegister_debugCheckParts(); + PbRegister_applyViscosity(); PbRegister_markAsFixed(); PbRegister_texcoordInflow(); PbRegister_meshSmokeInflow(); diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index d49915e2452..d5d41e71f22 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -72,6 +72,7 @@ MANTA::MANTA(int *res, FluidModifierData *fmd) mUsingFractions = (fds->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid; mUsingMesh = (fds->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid; mUsingDiffusion = (fds->flags & FLUID_DOMAIN_USE_DIFFUSION) && mUsingLiquid; + mUsingViscosity = (fds->flags & FLUID_DOMAIN_USE_VISCOSITY) && mUsingLiquid; mUsingMVel = (fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid; mUsingGuiding = (fds->flags & FLUID_DOMAIN_USE_GUIDE); mUsingDrops = (fds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid; @@ -221,6 +222,10 @@ MANTA::MANTA(int *res, FluidModifierData *fmd) initSuccess &= initLiquidMesh(); } + if (mUsingViscosity) { + initSuccess &= initLiquidViscosity(); + } + if (mUsingDiffusion) { initSuccess &= initCurvature(); } @@ -440,6 +445,17 @@ bool MANTA::initLiquidMesh(FluidModifierData *fmd) return runPythonString(pythonCommands); } +bool MANTA::initLiquidViscosity(FluidModifierData *fmd) +{ + vector pythonCommands; + string tmpString = fluid_variables_viscosity + fluid_solver_viscosity + liquid_alloc_viscosity; + string finalString = parseScript(tmpString, fmd); + pythonCommands.push_back(finalString); + + mUsingViscosity = true; + return runPythonString(pythonCommands); +} + bool MANTA::initCurvature(FluidModifierData *fmd) { std::vector pythonCommands; @@ -871,8 +887,10 @@ void MANTA::initializeRNAMap(FluidModifierData *fmd) mRNAMap["CACHE_DIR"] = cacheDirectory; mRNAMap["COMPRESSION_OPENVDB"] = vdbCompressionMethod; mRNAMap["PRECISION_OPENVDB"] = vdbPrecisionHalf; - mRNAMap["CLIP_OPENVDB"] = to_string(fds->clipping); + mRNAMap["CLIP_OPENVDB"] = to_string(fds->clipping); mRNAMap["PP_PARTICLE_MAXIMUM"] = to_string(fds->sys_particle_maximum); + mRNAMap["USING_VISCOSITY"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_VISCOSITY); + mRNAMap["VISCOSITY_VALUE"] = to_string(fds->viscosity_value); /* Fluid object names. */ mRNAMap["NAME_FLAGS"] = FLUID_NAME_FLAGS; @@ -1728,6 +1746,7 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd) bool guiding = fds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE; bool invel = fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL; bool outflow = fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW; + bool viscosity = fds->flags & FLUID_DOMAIN_USE_VISCOSITY; string manta_script; @@ -1742,6 +1761,8 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd) manta_script += fluid_variables_particles + liquid_variables_particles; if (guiding) manta_script += fluid_variables_guiding; + if (viscosity) + manta_script += fluid_variables_viscosity; /* Solvers. */ manta_script += header_solvers + fluid_solver; @@ -1751,6 +1772,8 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd) manta_script += fluid_solver_particles; if (guiding) manta_script += fluid_solver_guiding; + if (viscosity) + manta_script += fluid_solver_viscosity; /* Grids. */ manta_script += header_grids + fluid_alloc + liquid_alloc; @@ -1768,6 +1791,8 @@ bool MANTA::exportLiquidScript(FluidModifierData *fmd) manta_script += fluid_alloc_invel; if (outflow) manta_script += fluid_alloc_outflow; + if (viscosity) + manta_script += liquid_alloc_viscosity; /* Domain init. */ manta_script += header_gridinit + liquid_init_phi; diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h index 163b168e43d..7129a545243 100644 --- a/intern/mantaflow/intern/MANTA_main.h +++ b/intern/mantaflow/intern/MANTA_main.h @@ -67,6 +67,7 @@ struct MANTA { bool initColorsHigh(struct FluidModifierData *fmd = nullptr); bool initLiquid(FluidModifierData *fmd = nullptr); bool initLiquidMesh(FluidModifierData *fmd = nullptr); + bool initLiquidViscosity(FluidModifierData *fmd = nullptr); bool initObstacle(FluidModifierData *fmd = nullptr); bool initCurvature(FluidModifierData *fmd = nullptr); bool initGuiding(FluidModifierData *fmd = nullptr); @@ -757,6 +758,7 @@ struct MANTA { bool mUsingNoise; bool mUsingMesh; bool mUsingDiffusion; + bool mUsingViscosity; bool mUsingMVel; bool mUsingLiquid; bool mUsingSmoke; diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h index 8c9025dd435..73e8552d260 100644 --- a/intern/mantaflow/intern/strings/fluid_script.h +++ b/intern/mantaflow/intern/strings/fluid_script.h @@ -79,6 +79,11 @@ const std::string fluid_solver_guiding = mantaMsg('Solver guiding')\n\ sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n"; +const std::string fluid_solver_viscosity = + "\n\ +mantaMsg('Solver viscosity')\n\ +sv$ID$ = Solver(name='solver_viscosity$ID$', gridSize=gs_sv$ID$, dim=dim_s$ID$)\n"; + ////////////////////////////////////////////////////////////////////// // VARIABLES ////////////////////////////////////////////////////////////////////// @@ -133,7 +138,7 @@ end_frame_s$ID$ = $END_FRAME$\n\ \n\ # Fluid diffusion / viscosity\n\ domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\ -viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\ +kinViscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\ \n\ # Factors to convert Blender units to Manta units\n\ ratioMetersToRes_s$ID$ = float(domainSize_s$ID$) / float(res_s$ID$) # [meters / cells]\n\ @@ -199,6 +204,10 @@ tau_sg$ID$ = 1.0\n\ sigma_sg$ID$ = 0.99/tau_sg$ID$\n\ theta_sg$ID$ = 1.0\n"; +const std::string fluid_variables_viscosity = + "\n\ +gs_sv$ID$ = vec3($RESX$*2, $RESY$*2, $RESZ$*2)\n"; + const std::string fluid_with_obstacle = "\n\ using_obstacle_s$ID$ = True\n"; diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h index 8e0d113d680..c44727bd47e 100644 --- a/intern/mantaflow/intern/strings/liquid_script.h +++ b/intern/mantaflow/intern/strings/liquid_script.h @@ -40,6 +40,8 @@ radiusFactor_s$ID$ = $PARTICLE_RADIUS$\n\ using_mesh_s$ID$ = $USING_MESH$\n\ using_final_mesh_s$ID$ = $USING_IMPROVED_MESH$\n\ using_fractions_s$ID$ = $USING_FRACTIONS$\n\ +using_apic_s$ID$ = $USING_APIC$\n\ +using_viscosity_s$ID$ = $USING_VISCOSITY$\n\ fracThreshold_s$ID$ = $FRACTIONS_THRESHOLD$\n\ fracDistance_s$ID$ = $FRACTIONS_DISTANCE$\n\ flipRatio_s$ID$ = $FLIP_RATIO$\n\ @@ -51,7 +53,7 @@ smoothenNeg_s$ID$ = $MESH_SMOOTHEN_NEG$\n\ randomness_s$ID$ = $PARTICLE_RANDOMNESS$\n\ surfaceTension_s$ID$ = $LIQUID_SURFACE_TENSION$\n\ maxSysParticles_s$ID$ = $PP_PARTICLE_MAXIMUM$\n\ -using_apic_s$ID$ = $USING_APIC$\n"; +viscosityValue_s$ID$ = $VISCOSITY_VALUE$\n"; const std::string liquid_variables_particles = "\n\ @@ -135,6 +137,13 @@ liquid_mesh_dict_s$ID$ = { 'lMesh' : mesh_sm$ID$ }\n\ if using_speedvectors_s$ID$:\n\ liquid_meshvel_dict_s$ID$ = { 'lVelMesh' : mVel_mesh$ID$ }\n"; +const std::string liquid_alloc_viscosity = + "\n\ +# Viscosity grids\n\ +volumes_s$ID$ = sv$ID$.create(RealGrid)\n\ +viscosity_s$ID$ = s$ID$.create(RealGrid)\n\ +viscosity_s$ID$.setConst(viscosityValue_s$ID$)\n"; + const std::string liquid_alloc_curvature = "\n\ mantaMsg('Liquid alloc curvature')\n\ @@ -306,7 +315,7 @@ def liquid_step_$ID$():\n\ if using_diffusion_s$ID$:\n\ mantaMsg('Viscosity')\n\ # diffusion param for solve = const * dt / dx^2\n\ - alphaV = viscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\ + alphaV = kinViscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\ \n\ @@ -315,7 +324,11 @@ def liquid_step_$ID$():\n\ curvature_s$ID$.clamp(-1.0, 1.0)\n\ \n\ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ + if using_viscosity_s$ID$:\n\ + viscosity_s$ID$.setConst(viscosityValue_s$ID$)\n\ + applyViscosity(flags=flags_s$ID$, phi=phi_s$ID$, vel=vel_s$ID$, volumes=volumes_s$ID$, viscosity=viscosity_s$ID$)\n\ \n\ + setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\ if using_guiding_s$ID$:\n\ mantaMsg('Guiding and pressure')\n\ PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=domainClosed_s$ID$)\n\ diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index 3afe7a47028..5c3975ffb76 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -1006,6 +1006,46 @@ class PHYSICS_PT_particles(PhysicButtonsPanel, Panel): split.operator("fluid.free_particles", text="Free Particles") +class PHYSICS_PT_viscosity(PhysicButtonsPanel, Panel): + bl_label = "Viscosity" + bl_parent_id = 'PHYSICS_PT_liquid' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + @classmethod + def poll(cls, context): + # Fluid viscosity only enabled for liquids + if not PhysicButtonsPanel.poll_liquid_domain(context): + return False + + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + md = context.fluid.domain_settings + domain = context.fluid.domain_settings + is_baking_any = domain.is_cache_baking_any + has_baked_any = domain.has_cache_baked_any + self.layout.enabled = not is_baking_any and not has_baked_any + self.layout.prop(md, "use_viscosity", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + domain = context.fluid.domain_settings + layout.active = domain.use_viscosity + + is_baking_any = domain.is_cache_baking_any + has_baked_any = domain.has_cache_baked_any + has_baked_data = domain.has_cache_baked_data + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + flow.enabled = not is_baking_any and not has_baked_any and not has_baked_data + + col = flow.column(align=True) + col.prop(domain, "viscosity_value", text="Strength") + + class PHYSICS_PT_diffusion(PhysicButtonsPanel, Panel): bl_label = "Diffusion" bl_parent_id = 'PHYSICS_PT_liquid' @@ -1470,6 +1510,7 @@ classes = ( PHYSICS_PT_noise, PHYSICS_PT_fire, PHYSICS_PT_liquid, + PHYSICS_PT_viscosity, PHYSICS_PT_diffusion, PHYSICS_PT_particles, PHYSICS_PT_mesh, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 1ed4d1183a1..06a11fc8d1d 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 8 +#define BLENDER_FILE_SUBVERSION 9 /* 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/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 1bdc2a5dfd2..b93e6148b86 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -5011,6 +5011,9 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd, tfds->sys_particle_maximum = fds->sys_particle_maximum; tfds->simulation_method = fds->simulation_method; + /* viscosity options */ + tfds->viscosity_value = fds->viscosity_value; + /* diffusion options*/ tfds->surface_tension = fds->surface_tension; tfds->viscosity_base = fds->viscosity_base; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 8a85278a931..63ef436d8e2 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1430,18 +1430,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, 9)) { FOREACH_NODETREE_BEGIN (bmain, ntree, id) { if (ntree->type == NTREE_GEOMETRY) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -1474,5 +1463,32 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Ensure that new viscosity strength field is initialized correctly. */ + if (!DNA_struct_elem_find(fd->filesdna, "FluidModifierData", "float", "viscosity_value")) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Fluid) { + FluidModifierData *fmd = (FluidModifierData *)md; + if (fmd->domain != NULL) { + fmd->domain->viscosity_value = 0.05; + } + } + } + } + } + } + + /** + * 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 f1572c563bf..b9f09e0326d 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -820,6 +820,12 @@ void blo_do_versions_userdef(UserDef *userdef) userdef->uiflag &= ~USER_UIFLAG_UNUSED_3; } + if (!USER_VERSION_ATLEAST(292, 9)) { + if (BLI_listbase_is_empty(&userdef->asset_libraries)) { + BKE_preferences_asset_library_default_add(userdef); + } + } + /** * Versioning code until next subversion bump goes here. * @@ -831,9 +837,6 @@ void blo_do_versions_userdef(UserDef *userdef) */ { /* Keep this block, even when empty. */ - if (BLI_listbase_is_empty(&userdef->asset_libraries)) { - BKE_preferences_asset_library_default_add(userdef); - } } LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) { diff --git a/source/blender/makesdna/DNA_fluid_defaults.h b/source/blender/makesdna/DNA_fluid_defaults.h index 2ee83cf3387..9454342654c 100644 --- a/source/blender/makesdna/DNA_fluid_defaults.h +++ b/source/blender/makesdna/DNA_fluid_defaults.h @@ -113,6 +113,7 @@ .flip_ratio = 0.97f, \ .sys_particle_maximum = 0, \ .simulation_method = FLUID_DOMAIN_METHOD_FLIP, \ + .viscosity_value = 0.05f, \ .surface_tension = 0.0f, \ .viscosity_base = 1.0f, \ .viscosity_exponent = 6.0f, \ diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 98007a2b0b1..2ba0d15fbb3 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -52,6 +52,7 @@ enum { FLUID_DOMAIN_DELETE_IN_OBSTACLE = (1 << 14), /* Delete fluid inside obstacles. */ FLUID_DOMAIN_USE_DIFFUSION = (1 << 15), /* Use diffusion (e.g. viscosity, surface tension). */ FLUID_DOMAIN_USE_RESUMABLE_CACHE = (1 << 16), /* Determine if cache should be resumable. */ + FLUID_DOMAIN_USE_VISCOSITY = (1 << 17), /* Use viscosity. */ }; /** @@ -289,7 +290,7 @@ enum { #define FLUID_NAME_GUIDING "fluid_guiding" /* Fluid object names.*/ -#define FLUID_NAME_FLAGS "flags" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FLAGS "flags" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VELOCITY "velocity" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VEL "vel" #define FLUID_NAME_VELOCITYTMP "velocity_previous" /* == OpenVDB grid attribute name. */ @@ -300,7 +301,7 @@ enum { #define FLUID_NAME_PHIOBS "phi_obstacle" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PHISIN "phiSIn" #define FLUID_NAME_PHIIN "phi_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_PHIOUT "phi_out" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHIOUT "phi_out" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_FORCES "forces" #define FLUID_NAME_FORCE_X "x_force" #define FLUID_NAME_FORCE_Y "y_force" @@ -322,37 +323,37 @@ enum { #define FLUID_NAME_PHIOUTIN "phi_out_inflow" /* Smoke object names. */ -#define FLUID_NAME_SHADOW "shadow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_SHADOW "shadow" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_EMISSION "emission" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_EMISSIONIN "emissionIn" -#define FLUID_NAME_DENSITY "density" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_DENSITY "density" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_DENSITYIN "density_inflow" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_HEAT "heat" #define FLUID_NAME_HEATIN "heatIn" -#define FLUID_NAME_TEMPERATURE "temperature" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_TEMPERATURE "temperature" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_TEMPERATUREIN "temperature_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORR "color_r" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORG "color_g" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORB "color_b" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORRIN "color_r_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORGIN "color_g_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORBIN "color_b_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_FLAME "flame" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_FUEL "fuel" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_REACT "react" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_FUELIN "fuel_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_REACTIN "react_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORR "color_r" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORG "color_g" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORB "color_b" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORRIN "color_r_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORGIN "color_g_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORBIN "color_b_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FLAME "flame" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FUEL "fuel" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_REACT "react" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FUELIN "fuel_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_REACTIN "react_inflow" /* == OpenVDB grid attribute name. */ /* Liquid object names. */ #define FLUID_NAME_PHIPARTS "phi_particles" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_PHI "phi" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_PHITMP "phi_previous" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHI "phi" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHITMP "phi_previous" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VELOCITYOLD "velOld" #define FLUID_NAME_VELOCITYPARTS "velParts" #define FLUID_NAME_MAPWEIGHTS "mapWeights" #define FLUID_NAME_PP "pp" #define FLUID_NAME_PVEL "pVel" -#define FLUID_NAME_PARTS "particles" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PARTS "particles" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PARTSVELOCITY "particles_velocity" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PINDEX "pindex" #define FLUID_NAME_GPI "gpi" @@ -375,8 +376,8 @@ enum { #define FLUID_NAME_TEXTURE_U2 "textureU2" #define FLUID_NAME_TEXTURE_V2 "textureV2" #define FLUID_NAME_TEXTURE_W2 "textureW2" -#define FLUID_NAME_UV0 "uv_grid_0" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_UV1 "uv_grid_1" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_UV0 "uv_grid_0" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_UV1 "uv_grid_1" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_COLORR_NOISE "color_r_noise" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_COLORG_NOISE "color_g_noise" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_COLORB_NOISE "color_b_noise" /* == OpenVDB grid attribute name. */ @@ -596,6 +597,10 @@ typedef struct FluidDomainSettings { short simulation_method; char _pad4[6]; + /* Viscosity options. */ + float viscosity_value; + char _pad5[4]; + /* Diffusion options. */ float surface_tension; float viscosity_base; @@ -610,7 +615,7 @@ typedef struct FluidDomainSettings { int mesh_scale; int totvert; short mesh_generator; - char _pad5[6]; /* Unused. */ + char _pad6[6]; /* Unused. */ /* Secondary particle options. */ int particle_type; @@ -631,7 +636,7 @@ typedef struct FluidDomainSettings { int sndparticle_update_radius; char sndparticle_boundary; char sndparticle_combined_export; - char _pad6[6]; /* Unused. */ + char _pad7[6]; /* Unused. */ /* Fluid guiding options. */ float guide_alpha; /* Guiding weight scalar (determines strength). */ @@ -639,7 +644,7 @@ typedef struct FluidDomainSettings { float guide_vel_factor; /* Multiply guiding velocity by this factor. */ int guide_res[3]; /* Res for velocity guide grids - independent from base res. */ short guide_source; - char _pad7[2]; /* Unused. */ + char _pad8[2]; /* Unused. */ /* Cache options. */ int cache_frame_start; @@ -659,7 +664,7 @@ typedef struct FluidDomainSettings { char error[64]; /* Bake error description. */ short cache_type; char cache_id[4]; /* Run-time only */ - char _pad8[2]; + char _pad9[2]; /* Unused. */ /* Time options. */ float dt; @@ -694,19 +699,19 @@ typedef struct FluidDomainSettings { char interp_method; char gridlines_color_field; /* Simulation field used to color map onto gridlines. */ char gridlines_cell_filter; - char _pad9[7]; + char _pad10[7]; /* Unused. */ /* OpenVDB cache options. */ int openvdb_compression; float clipping; char openvdb_data_depth; - char _pad10[7]; /* Unused. */ + char _pad11[7]; /* Unused. */ /* -- Deprecated / unsed options (below). -- */ /* View options. */ int viewsettings; - char _pad11[4]; /* Unused. */ + char _pad12[4]; /* Unused. */ /* Pointcache options. */ /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading @@ -716,7 +721,7 @@ typedef struct FluidDomainSettings { int cache_comp; int cache_high_comp; char cache_file_format; - char _pad12[7]; /* Unused. */ + char _pad13[7]; /* Unused. */ } FluidDomainSettings; diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index bb8280ede91..afe564dff0a 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -1929,6 +1929,22 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) "Maximum number of fluid particles that are allowed in this simulation"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset"); + /* viscosity options */ + + prop = RNA_def_property(srna, "use_viscosity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_VISCOSITY); + RNA_def_property_ui_text(prop, "Use Viscosity", "Enable fluid viscosity settings"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset"); + + prop = RNA_def_property(srna, "viscosity_value", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 5.0, 0.01, 3); + RNA_def_property_ui_text(prop, + "Strength", + "Viscosity of liquid (higher values result in more viscous fluids, a " + "value of 0 will still apply some viscosity)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset"); + /* diffusion options */ prop = RNA_def_property(srna, "use_diffusion", PROP_BOOLEAN, PROP_NONE); From 9d04fa39d13b75b207fa7ab0315cb7731ecfff06 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 23 Dec 2020 15:45:55 +0100 Subject: [PATCH 08/12] Fix T84063: crash reading pointer properties in Attribute shader node Path resolving can find e.g. a datablock rather than a float or integer, treat that as a failure to find a valid property. --- intern/cycles/blender/blender_object.cpp | 4 ++++ source/blender/draw/intern/draw_instance_data.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 4a70cbbf41f..5261fbcee07 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -351,6 +351,10 @@ static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value) return false; } + if (prop == NULL) { + return false; + } + PropertyType type = RNA_property_type(prop); int arraylen = RNA_property_array_length(&ptr, prop); diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index ba03cee8149..449f2cd9606 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -633,6 +633,10 @@ static bool drw_uniform_property_lookup(ID *id, const char *name, float r_data[4 return false; } + if (prop == NULL) { + return false; + } + PropertyType type = RNA_property_type(prop); int arraylen = RNA_property_array_length(&ptr, prop); From d29a720c45e55047e4f0e02df4652ba03a49c528 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 23 Dec 2020 12:19:45 +0100 Subject: [PATCH 09/12] Fix T84002: Sculpt: Masking operations crash if multires is in play. This fixes the main issue there (essentially a followup to rB90e12e823ff0: Fix T81854: crash when undoing switch between sculpt and edit mode). We basically remove more (hopefully all the remaining!) modifications of orig mesh from `sculpt_update_object`, as those done here will not be immediately available in the evaluated data (that specific bug happened because masking data was added to orig mesh there, but not flushed to depsgraph evaluated one). This also goes towards a better separation between handling of evaluated data and orig one. Note that modification of orig mesh data can still happen, e.g. values in some cdlayers, but at least all pointers should now be valid in the evaluated mesh. There are still some issues, e.g. we now get an assert/crash in `multires_reshape_assign_final_coords_from_ccg` when undoing out of the Sculpt mode, presumably because subdiv_ccg data remains unchanged then (and hence still has the `has_mask` flag set), while actual mesh data do not have that cdlayer anymore... This commit also cleans up/simplifies some code, `ED_object_sculptmode_enter_ex` was (indirectly) calling `BKE_sculpt_face_sets_ensure_from_base_mesh_visibility` twice e.g. --- source/blender/blenkernel/BKE_paint.h | 3 - source/blender/blenkernel/intern/paint.c | 24 +++---- source/blender/editors/sculpt_paint/sculpt.c | 75 +++++++------------- 3 files changed, 32 insertions(+), 70 deletions(-) diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index aaed2649ad9..bd2ac3da21b 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -635,9 +635,6 @@ void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(struct Mesh *mesh); void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg); -/* Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the - * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the - * mesh to the Face Sets. */ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh); bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index d726a4b1e37..7c2fc40d537 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1596,7 +1596,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, Scene *scene = DEG_get_input_scene(depsgraph); Sculpt *sd = scene->toolsettings->sculpt; SculptSession *ss = ob->sculpt; - Mesh *me = BKE_object_get_original_mesh(ob); + const Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0; @@ -1612,20 +1612,13 @@ static void sculpt_update_object(Depsgraph *depsgraph, if (need_mask) { if (mmd == NULL) { - if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { - BKE_sculpt_mask_layers_ensure(ob, NULL); - } + BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK)); } else { - if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) { - BKE_sculpt_mask_layers_ensure(ob, mmd); - } + BLI_assert(CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)); } } - /* tessfaces aren't used and will become invalid */ - BKE_mesh_tessface_clear(me); - ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, @@ -1660,12 +1653,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, /* Sculpt Face Sets. */ if (use_face_sets) { - if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - /* By checking here if the data-layer already exist this avoids copying the visibility from - * the mesh and looping over all vertices on every sculpt editing operation, using this - * function only the first time the Face Sets data-layer needs to be created. */ - BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(me); - } + BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)); ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); } else { @@ -1928,6 +1916,10 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc return deformed; } +/** + * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the + * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the + * mesh to the Face Sets. */ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) { const int face_sets_default_visible_id = 1; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 38d2bed7d97..c91ab3f0ee1 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1188,25 +1188,6 @@ void SCULPT_floodfill_free(SculptFloodFill *flood) * * \{ */ -/* Check if there are any active modifiers in stack. - * Used for flushing updates at enter/exit sculpt mode. */ -static bool sculpt_has_active_modifiers(Scene *scene, Object *ob) -{ - ModifierData *md; - VirtualModifierData virtualModifierData; - - md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); - - /* Exception for shape keys because we can edit those. */ - for (; md; md = md->next) { - if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { - return true; - } - } - - return false; -} - static bool sculpt_tool_needs_original(const char sculpt_tool) { return ELEM(sculpt_tool, @@ -8320,7 +8301,7 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob) /* Here we can detect geometry that was just added to Sculpt Mode as it has the * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not - * initialized, which is used is some operators that modify the mesh topology to preform certain + * initialized, which is used is some operators that modify the mesh topology to perform certain * actions in the new polys. After these operations are finished, all polys should have a valid * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility * correctly. */ @@ -8334,23 +8315,6 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob) ss->face_sets[i] = new_face_set; } } - - /* Update the Face Sets visibility with the vertex visibility changes that may have been done - * outside Sculpt Mode */ - Mesh *mesh = ob->data; - BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); -} - -static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, - Object *ob, - MultiresModifierData *mmd) -{ - int flush_recalc = 0; - /* Multires in sculpt mode could have different from object mode subdivision level. */ - flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; - /* If object has got active modifiers, its dm could be different in sculpt mode. */ - flush_recalc |= sculpt_has_active_modifiers(scene, ob); - return flush_recalc; } void ED_object_sculptmode_enter_ex(Main *bmain, @@ -8368,13 +8332,6 @@ void ED_object_sculptmode_enter_ex(Main *bmain, MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); - - if (flush_recalc) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - BKE_scene_graph_evaluated_ensure(depsgraph, bmain); - } - /* Create sculpt mode session data. */ if (ob->sculpt) { BKE_sculptsession_free(ob); @@ -8383,14 +8340,30 @@ void ED_object_sculptmode_enter_ex(Main *bmain, /* Copy the current mesh visibility to the Face Sets. */ BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(me); - sculpt_init_session(depsgraph, scene, ob); + /* Mask layer is required for Multires. */ + BKE_sculpt_mask_layers_ensure(ob, mmd); - /* Mask layer is required. */ - if (mmd) { - /* XXX, we could attempt to support adding mask data mid-sculpt mode (with multi-res) - * but this ends up being quite tricky (and slow). */ - BKE_sculpt_mask_layers_ensure(ob, mmd); - } + /* Tessfaces aren't used and will become invalid. */ + BKE_mesh_tessface_clear(me); + + /* We always need to flush updates from depsgraph here, since at the very least + * `BKE_sculpt_face_sets_ensure_from_base_mesh_visibility()` will have updated some data layer of + * the mesh. + * + * All known potential sources of updates: + * - Addition of, or changes to, the `CD_SCULPT_FACE_SETS` data layer + * (`BKE_sculpt_face_sets_ensure_from_base_mesh_visibility`). + * - Addition of a `CD_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`). + * - Object has any active modifier (modifier stack can be different in Sculpt mode). + * - Multires: + * + Differences of subdiv levels between sculpt and object modes + * (`mmd->sculptlvl != mmd->lvl`). + * + Addition of a `CD_GRID_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`). + */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + BKE_scene_graph_evaluated_ensure(depsgraph, bmain); + + sculpt_init_session(depsgraph, scene, ob); if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f && fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) { From 8a9dedf829544e30f822bcb016a9c134af6979e5 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 23 Dec 2020 16:01:24 +0100 Subject: [PATCH 10/12] Workaround T84084: Assert/crash when undoing from Sculpt mode to Object one. Disclaimer: This workaround avoids crashing with current state of the code and is only committed as temporary band-aid until we can assess the full issue and decide if/how it needs to be adressed. --- .../blenkernel/intern/multires_reshape_ccg.c | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/multires_reshape_ccg.c b/source/blender/blenkernel/intern/multires_reshape_ccg.c index 55f7766c878..aa003909bb0 100644 --- a/source/blender/blenkernel/intern/multires_reshape_ccg.c +++ b/source/blender/blenkernel/intern/multires_reshape_ccg.c @@ -61,8 +61,24 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext sizeof(float[3])); if (reshape_level_key.has_mask) { - BLI_assert(grid_element.mask != NULL); - *grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y); + /* Assert about a non-NULL `grid_element.mask` may fail here, this code may be called + * from cleanup code during COW evaluation phase by depsgraph (e.g. + * `object_update_from_subsurf_ccg` call in `BKE_object_free_derived_caches`). + * + * `reshape_level_key.has_mask` is ultimately set from MultiRes modifier apply code + * (through `multires_as_ccg` -> `multires_ccg_settings_init`), when object is in sculpt + * mode only, and there is matching loop cdlayer. + * + * `grid_element.mask` is directly set from existing matching loop cdlayer during + * initialization of `MultiresReshapeContext` struct. + * + * Since ccg data is preserved during undos, we may end up with a state where there is no + * mask data in mesh loops' cdlayer, while ccg's `has_mask` is still set to true. + */ + // BLI_assert(grid_element.mask != NULL); + if (grid_element.mask != NULL) { + *grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y); + } } } } From d8dc4c5b32b4cb08e2d438d76f6a02e732d23220 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 23 Dec 2020 16:37:47 +0100 Subject: [PATCH 11/12] Geometry Nodes: new Rotate Points node This node updates the "rotation" attribute on points. Multiple ways to specify the rotation are supported. Differential Revision: https://developer.blender.org/D9883 Ref T83668. --- release/scripts/startup/nodeitems_builtins.py | 1 + source/blender/blenkernel/BKE_node.h | 1 + source/blender/blenkernel/intern/node.c | 1 + source/blender/editors/space_node/drawnode.c | 22 ++ source/blender/makesdna/DNA_node_types.h | 23 ++ source/blender/makesrna/intern/rna_nodetree.c | 65 ++++++ source/blender/nodes/CMakeLists.txt | 1 + source/blender/nodes/NOD_geometry.h | 1 + source/blender/nodes/NOD_static_types.h | 1 + .../nodes/geometry/node_geometry_util.cc | 15 +- .../nodes/geometry/node_geometry_util.hh | 3 +- .../geometry/nodes/node_geo_rotate_points.cc | 207 ++++++++++++++++++ 12 files changed, 337 insertions(+), 4 deletions(-) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_rotate_points.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 7ceb52a55e5..65af1bccd80 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -514,6 +514,7 @@ geometry_node_categories = [ NodeItem("GeometryNodePointDistribute"), NodeItem("GeometryNodePointInstance"), NodeItem("GeometryNodePointSeparate"), + NodeItem("GeometryNodeRotatePoints"), ]), GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[ NodeItem("ShaderNodeMapRange"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index e18f46c9988..89a51afede9 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1356,6 +1356,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_ATTRIBUTE_COLOR_RAMP 1013 #define GEO_NODE_POINT_SEPARATE 1014 #define GEO_NODE_ATTRIBUTE_COMPARE 1015 +#define GEO_NODE_ROTATE_POINTS 1016 /** \} */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 676d0bf9385..5d3994068ec 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -4744,6 +4744,7 @@ static void registerGeometryNodes(void) register_node_type_geo_join_geometry(); register_node_type_geo_attribute_mix(); register_node_type_geo_attribute_color_ramp(); + register_node_type_geo_rotate_points(); } static void registerFunctionNodes(void) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 0ce31707204..409327b0d1c 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3260,6 +3260,25 @@ static void node_geometry_buts_attribute_color_ramp(uiLayout *layout, uiTemplateColorRamp(layout, ptr, "color_ramp", 0); } +static void node_geometry_buts_rotate_points(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage; + + uiItemR(layout, ptr, "type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + + uiLayout *col = uiLayoutColumn(layout, false); + if (storage->type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE) { + uiItemR(col, ptr, "input_type_axis", DEFAULT_FLAGS, IFACE_("Axis"), ICON_NONE); + uiItemR(col, ptr, "input_type_angle", DEFAULT_FLAGS, IFACE_("Angle"), ICON_NONE); + } + else { + uiItemR(col, ptr, "input_type_rotation", DEFAULT_FLAGS, IFACE_("Rotation"), ICON_NONE); + } +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3296,6 +3315,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_ATTRIBUTE_COLOR_RAMP: ntype->draw_buttons = node_geometry_buts_attribute_color_ramp; break; + case GEO_NODE_ROTATE_POINTS: + ntype->draw_buttons = node_geometry_buts_rotate_points; + break; } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 64dd489b850..3b655790de9 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1111,6 +1111,19 @@ typedef struct NodeInputVector { float vector[3]; } NodeInputVector; +typedef struct NodeGeometryRotatePoints { + /* GeometryNodeRotatePointsType */ + uint8_t type; + /* GeometryNodeRotatePointsSpace */ + uint8_t space; + + /* GeometryNodeAttributeInputMode */ + uint8_t input_type_axis; + uint8_t input_type_angle; + uint8_t input_type_rotation; + char _pad[3]; +} NodeGeometryRotatePoints; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 @@ -1529,6 +1542,16 @@ typedef enum GeometryNodePointDistributeMethod { GEO_NODE_POINT_DISTRIBUTE_POISSON = 1, } GeometryNodePointDistributeMethod; +typedef enum GeometryNodeRotatePointsType { + GEO_NODE_ROTATE_POINTS_TYPE_EULER = 0, + GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE = 1, +} GeometryNodeRotatePointsType; + +typedef enum GeometryNodeRotatePointsSpace { + GEO_NODE_ROTATE_POINTS_SPACE_OBJECT = 0, + GEO_NODE_ROTATE_POINTS_SPACE_POINT = 1, +} GeometryNodeRotatePointsSpace; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index cbd677582a9..a625b671c98 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -452,6 +452,11 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float ITEM_FLOAT, {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_vector[] = { + ITEM_ATTRIBUTE, + ITEM_VECTOR, + {0, NULL, 0, NULL, NULL}, +}; static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_boolean[] = { ITEM_ATTRIBUTE, ITEM_FLOAT, @@ -8584,6 +8589,66 @@ static void def_geo_attribute_color_ramp(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_rotate_points(StructRNA *srna) +{ + static const EnumPropertyItem type_items[] = { + {GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE, + "AXIS_ANGLE", + ICON_NONE, + "Axis Angle", + "Rotate around an axis by an angle"}, + {GEO_NODE_ROTATE_POINTS_TYPE_EULER, + "EULER", + ICON_NONE, + "Euler", + "Rotate around the x, y and z axis"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem space_items[] = { + {GEO_NODE_ROTATE_POINTS_SPACE_OBJECT, + "OBJECT", + ICON_NONE, + "Object", + "Rotate points in the local space of the object"}, + {GEO_NODE_ROTATE_POINTS_SPACE_POINT, + "POINT", + ICON_NONE, + "Point", + "Rotate every point in its local space (as defined by the 'rotation' attribute)"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeGeometryRotatePoints", "storage"); + + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, type_items); + RNA_def_property_ui_text(prop, "Type", "Method used to describe the rotation"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, space_items); + RNA_def_property_ui_text(prop, "Space", "Base orientation of the points"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "input_type_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector); + RNA_def_property_ui_text(prop, "Input Type Axis", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_angle", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type Angle", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_rotation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector); + RNA_def_property_ui_text(prop, "Input Type Rotation", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 60d4ee8f7c4..00e5f8246f3 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -155,6 +155,7 @@ set(SRC geometry/nodes/node_geo_point_distribute_poisson_disk.cc geometry/nodes/node_geo_point_instance.cc geometry/nodes/node_geo_point_separate.cc + geometry/nodes/node_geo_rotate_points.cc geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 19a7acf2299..4653c9aae3f 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -42,6 +42,7 @@ void register_node_type_geo_point_separate(void); void register_node_type_geo_attribute_compare(void); void register_node_type_geo_attribute_mix(void); void register_node_type_geo_attribute_color_ramp(void); +void register_node_type_geo_rotate_points(void); #ifdef __cplusplus } diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 5156bac0e73..d6ae98594a5 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -284,6 +284,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "") DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "") +DefNode(GeometryNode, GEO_NODE_ROTATE_POINTS, def_geo_rotate_points, "ROTATE_POINTS", RotatePoints, "Rotate Points", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index bcebaa6a37b..eace75b46b6 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -19,19 +19,28 @@ namespace blender::nodes { +/** + * Update the availability of a group of input sockets with the same name, + * used for switching between attribute inputs or single values. + * + * \param mode: Controls which socket of the group to make available. + * \param name_is_available: If false, make all sockets with this name unavailable. + */ void update_attribute_input_socket_availabilities(bNode &node, const StringRef name, - const GeometryNodeAttributeInputMode mode) + const GeometryNodeAttributeInputMode mode, + const bool name_is_available) { const GeometryNodeAttributeInputMode mode_ = (GeometryNodeAttributeInputMode)mode; LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { if (name == socket->name) { - const bool is_available = + const bool socket_is_available = + name_is_available && ((socket->type == SOCK_STRING && mode_ == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) || (socket->type == SOCK_FLOAT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) || (socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) || (socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR)); - nodeSetSocketAvailability(socket, is_available); + nodeSetSocketAvailability(socket, socket_is_available); } } } diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 7c12611a898..d9c066d576f 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -41,7 +41,8 @@ bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree); namespace blender::nodes { void update_attribute_input_socket_availabilities(bNode &node, const StringRef name, - const GeometryNodeAttributeInputMode mode); + const GeometryNodeAttributeInputMode mode, + const bool can_be_available = true); CustomDataType attribute_domain_highest_complexity(Span); diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_points.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_points.cc new file mode 100644 index 00000000000..1272e36a216 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_points.cc @@ -0,0 +1,207 @@ +/* + * 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. + */ + +#include "node_geometry_util.hh" + +#include "BLI_math_rotation.h" + +static bNodeSocketTemplate geo_node_rotate_points_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Axis")}, + {SOCK_VECTOR, N_("Axis"), 0.0, 0.0, 1.0, 0.0, -FLT_MAX, FLT_MAX, PROP_XYZ}, + {SOCK_STRING, N_("Angle")}, + {SOCK_FLOAT, N_("Angle"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX, PROP_ANGLE}, + {SOCK_STRING, N_("Rotation")}, + {SOCK_VECTOR, N_("Rotation"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX, PROP_EULER}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_rotate_points_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void rotate_points__axis_angle__object_space(const int domain_size, + const Float3ReadAttribute &axis, + const FloatReadAttribute &angles, + MutableSpan rotations) +{ + for (const int i : IndexRange(domain_size)) { + float old_rotation[3][3]; + eul_to_mat3(old_rotation, rotations[i]); + float rotation[3][3]; + axis_angle_to_mat3(rotation, axis[i], angles[i]); + float new_rotation[3][3]; + mul_m3_m3m3(new_rotation, rotation, old_rotation); + mat3_to_eul(rotations[i], new_rotation); + } +} + +static void rotate_points__axis_angle__point_space(const int domain_size, + const Float3ReadAttribute &axis, + const FloatReadAttribute &angles, + MutableSpan rotations) +{ + for (const int i : IndexRange(domain_size)) { + float old_rotation[3][3]; + eul_to_mat3(old_rotation, rotations[i]); + float rotation[3][3]; + axis_angle_to_mat3(rotation, axis[i], angles[i]); + float new_rotation[3][3]; + mul_m3_m3m3(new_rotation, old_rotation, rotation); + mat3_to_eul(rotations[i], new_rotation); + } +} + +static void rotate_points__euler__object_space(const int domain_size, + const Float3ReadAttribute &eulers, + MutableSpan rotations) +{ + for (const int i : IndexRange(domain_size)) { + float old_rotation[3][3]; + eul_to_mat3(old_rotation, rotations[i]); + float rotation[3][3]; + eul_to_mat3(rotation, eulers[i]); + float new_rotation[3][3]; + mul_m3_m3m3(new_rotation, rotation, old_rotation); + mat3_to_eul(rotations[i], new_rotation); + } +} + +static void rotate_points__euler__point_space(const int domain_size, + const Float3ReadAttribute &eulers, + MutableSpan rotations) +{ + for (const int i : IndexRange(domain_size)) { + float old_rotation[3][3]; + eul_to_mat3(old_rotation, rotations[i]); + float rotation[3][3]; + eul_to_mat3(rotation, eulers[i]); + float new_rotation[3][3]; + mul_m3_m3m3(new_rotation, old_rotation, rotation); + mat3_to_eul(rotations[i], new_rotation); + } +} + +static void rotate_points_on_component(GeometryComponent &component, + const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage; + + WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write( + "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); + if (!rotation_attribute) { + return; + } + + MutableSpan rotations = rotation_attribute->get_span().typed(); + const int domain_size = rotations.size(); + + if (storage.type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE) { + Float3ReadAttribute axis = params.get_input_attribute( + "Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1}); + FloatReadAttribute angles = params.get_input_attribute( + "Angle", component, ATTR_DOMAIN_POINT, 0); + + if (storage.space == GEO_NODE_ROTATE_POINTS_SPACE_OBJECT) { + rotate_points__axis_angle__object_space(domain_size, axis, angles, rotations); + } + else { + rotate_points__axis_angle__point_space(domain_size, axis, angles, rotations); + } + } + else { + Float3ReadAttribute eulers = params.get_input_attribute( + "Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); + + if (storage.space == GEO_NODE_ROTATE_POINTS_SPACE_OBJECT) { + rotate_points__euler__object_space(domain_size, eulers, rotations); + } + else { + rotate_points__euler__point_space(domain_size, eulers, rotations); + } + } + + rotation_attribute->apply_span(); +} + +static void geo_node_rotate_points_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + + if (geometry_set.has()) { + rotate_points_on_component(geometry_set.get_component_for_write(), params); + } + if (geometry_set.has()) { + rotate_points_on_component(geometry_set.get_component_for_write(), + params); + } + + params.set_output("Geometry", geometry_set); +} + +static void geo_node_rotate_points_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN( + sizeof(NodeGeometryRotatePoints), __func__); + + node_storage->type = GEO_NODE_ROTATE_POINTS_TYPE_EULER; + node_storage->space = GEO_NODE_ROTATE_POINTS_SPACE_OBJECT; + node_storage->input_type_axis = GEO_NODE_ATTRIBUTE_INPUT_VECTOR; + node_storage->input_type_angle = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + node_storage->input_type_rotation = GEO_NODE_ATTRIBUTE_INPUT_VECTOR; + + node->storage = node_storage; +} + +static void geo_node_rotate_points_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage; + update_attribute_input_socket_availabilities( + *node, + "Axis", + (GeometryNodeAttributeInputMode)node_storage->input_type_axis, + node_storage->type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE); + update_attribute_input_socket_availabilities( + *node, + "Angle", + (GeometryNodeAttributeInputMode)node_storage->input_type_angle, + node_storage->type == GEO_NODE_ROTATE_POINTS_TYPE_AXIS_ANGLE); + update_attribute_input_socket_availabilities( + *node, + "Rotation", + (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, + node_storage->type == GEO_NODE_ROTATE_POINTS_TYPE_EULER); +} + +} // namespace blender::nodes + +void register_node_type_geo_rotate_points() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_ROTATE_POINTS, "Rotate Points", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_rotate_points_in, geo_node_rotate_points_out); + node_type_init(&ntype, blender::nodes::geo_node_rotate_points_init); + node_type_update(&ntype, blender::nodes::geo_node_rotate_points_update); + node_type_storage( + &ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage); + ntype.geometry_node_execute = blender::nodes::geo_node_rotate_points_exec; + nodeRegisterType(&ntype); +} From c9efb5424079189951a0eebc968a33787878b039 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 23 Dec 2020 12:13:44 -0600 Subject: [PATCH 12/12] Cleanup: Clang format --- .../nodes/COM_ColorExposureNode.cpp | 2 +- .../blender/editors/space_clip/clip_buttons.c | 56 +++++++++---------- source/blender/makesdna/DNA_brush_types.h | 2 +- source/blender/makesdna/DNA_fluid_types.h | 42 +++++++------- source/blender/makesrna/intern/rna_scene.c | 5 +- 5 files changed, 54 insertions(+), 53 deletions(-) diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp b/source/blender/compositor/nodes/COM_ColorExposureNode.cpp index 10738fcfe47..cd0285ac373 100644 --- a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cpp @@ -26,7 +26,7 @@ ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode) } void ExposureNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const + const CompositorContext & /*context*/) const { ExposureOperation *operation = new ExposureOperation(); converter.addOperation(operation); diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index fe03a37d4aa..78dc6eabbd2 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -124,7 +124,7 @@ void uiTemplateMovieClip( } PointerRNA clipptr = RNA_property_pointer_get(ptr, prop); - MovieClip *clip = clipptr.data; + MovieClip *clip = clipptr.data; uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr); @@ -447,20 +447,20 @@ void uiTemplateMarker(uiLayout *layout, } uiBut *bt = uiDefIconButBitI(block, - UI_BTYPE_TOGGLE_N, - MARKER_DISABLED, - 0, - ICON_HIDE_OFF, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - &cb->marker_flag, - 0, - 0, - 1, - 0, - tip); + UI_BTYPE_TOGGLE_N, + MARKER_DISABLED, + 0, + ICON_HIDE_OFF, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + &cb->marker_flag, + 0, + 0, + 1, + 0, + tip); UI_but_funcN_set(bt, marker_update_cb, cb, NULL); UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } @@ -561,19 +561,19 @@ void uiTemplateMarker(uiLayout *layout, 0, ""); uiBut *bt = uiDefButF(block, - UI_BTYPE_NUM, - B_MARKER_POS, - IFACE_("X:"), - 0.5 * UI_UNIT_X, - 9 * UI_UNIT_Y, - 7.25 * UI_UNIT_X, - UI_UNIT_Y, - &cb->marker_pos[0], - -10 * width, - 10.0 * width, - 0, - 0, - TIP_("X-position of marker at frame in screen coordinates")); + UI_BTYPE_NUM, + B_MARKER_POS, + IFACE_("X:"), + 0.5 * UI_UNIT_X, + 9 * UI_UNIT_Y, + 7.25 * UI_UNIT_X, + UI_UNIT_Y, + &cb->marker_pos[0], + -10 * width, + 10.0 * width, + 0, + 0, + TIP_("X-position of marker at frame in screen coordinates")); UI_but_number_step_size_set(bt, step); UI_but_number_precision_set(bt, digits); bt = uiDefButF(block, diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 1709ea5dc63..4b020019062 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -373,7 +373,7 @@ typedef struct Brush { typedef struct tPaletteColorHSV { float rgb[3]; float value; - float h; + float h; float s; float v; } tPaletteColorHSV; diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 2ba0d15fbb3..e787b44e557 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -290,7 +290,7 @@ enum { #define FLUID_NAME_GUIDING "fluid_guiding" /* Fluid object names.*/ -#define FLUID_NAME_FLAGS "flags" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FLAGS "flags" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VELOCITY "velocity" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VEL "vel" #define FLUID_NAME_VELOCITYTMP "velocity_previous" /* == OpenVDB grid attribute name. */ @@ -301,7 +301,7 @@ enum { #define FLUID_NAME_PHIOBS "phi_obstacle" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PHISIN "phiSIn" #define FLUID_NAME_PHIIN "phi_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_PHIOUT "phi_out" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHIOUT "phi_out" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_FORCES "forces" #define FLUID_NAME_FORCE_X "x_force" #define FLUID_NAME_FORCE_Y "y_force" @@ -323,37 +323,37 @@ enum { #define FLUID_NAME_PHIOUTIN "phi_out_inflow" /* Smoke object names. */ -#define FLUID_NAME_SHADOW "shadow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_SHADOW "shadow" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_EMISSION "emission" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_EMISSIONIN "emissionIn" -#define FLUID_NAME_DENSITY "density" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_DENSITY "density" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_DENSITYIN "density_inflow" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_HEAT "heat" #define FLUID_NAME_HEATIN "heatIn" -#define FLUID_NAME_TEMPERATURE "temperature" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_TEMPERATURE "temperature" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_TEMPERATUREIN "temperature_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORR "color_r" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORG "color_g" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORB "color_b" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORRIN "color_r_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORGIN "color_g_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_COLORBIN "color_b_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_FLAME "flame" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_FUEL "fuel" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_REACT "react" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_FUELIN "fuel_inflow" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_REACTIN "react_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORR "color_r" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORG "color_g" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORB "color_b" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORRIN "color_r_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORGIN "color_g_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_COLORBIN "color_b_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FLAME "flame" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FUEL "fuel" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_REACT "react" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_FUELIN "fuel_inflow" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_REACTIN "react_inflow" /* == OpenVDB grid attribute name. */ /* Liquid object names. */ #define FLUID_NAME_PHIPARTS "phi_particles" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_PHI "phi" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_PHITMP "phi_previous" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHI "phi" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PHITMP "phi_previous" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_VELOCITYOLD "velOld" #define FLUID_NAME_VELOCITYPARTS "velParts" #define FLUID_NAME_MAPWEIGHTS "mapWeights" #define FLUID_NAME_PP "pp" #define FLUID_NAME_PVEL "pVel" -#define FLUID_NAME_PARTS "particles" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_PARTS "particles" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PARTSVELOCITY "particles_velocity" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_PINDEX "pindex" #define FLUID_NAME_GPI "gpi" @@ -376,8 +376,8 @@ enum { #define FLUID_NAME_TEXTURE_U2 "textureU2" #define FLUID_NAME_TEXTURE_V2 "textureV2" #define FLUID_NAME_TEXTURE_W2 "textureW2" -#define FLUID_NAME_UV0 "uv_grid_0" /* == OpenVDB grid attribute name. */ -#define FLUID_NAME_UV1 "uv_grid_1" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_UV0 "uv_grid_0" /* == OpenVDB grid attribute name. */ +#define FLUID_NAME_UV1 "uv_grid_1" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_COLORR_NOISE "color_r_noise" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_COLORG_NOISE "color_g_noise" /* == OpenVDB grid attribute name. */ #define FLUID_NAME_COLORB_NOISE "color_b_noise" /* == OpenVDB grid attribute name. */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b93922e46f2..e37df0225cf 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4241,8 +4241,9 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) prop = RNA_def_property(srna, "use_ztransp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_ZTRA); - RNA_def_property_ui_text( - prop, "Z-Transparent", "Render Z-transparent faces in this layer (on top of Solid and Halos)"); + RNA_def_property_ui_text(prop, + "Z-Transparent", + "Render Z-transparent faces in this layer (on top of Solid and Halos)"); if (scene) { RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); }