Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2020-12-16 16:43:09 +01:00
commit 92bc9477d1
175 changed files with 2185 additions and 809 deletions

@ -1 +1 @@
Subproject commit 9e40c01dffd3f720b23b906d20df8e999d34a4af
Subproject commit 877a343fed9613d8e02e7fe7181d3bbb628506f2

@ -1 +1 @@
Subproject commit 1a3f127714e8da9f0af12d9a174dae9793ae63c1
Subproject commit a3fa40ec0ba525bc96cbfad49f854a0230b0524e

View File

@ -222,12 +222,21 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False):
fw("]\n")
fw("\n\n")
fw("if __name__ == \"__main__\":\n")
# We could remove this in the future, as loading new key-maps in older Blender versions
# makes less and less sense as Blender changes.
fw(" # Only add keywords that are supported.\n")
fw(" from bpy.app import version as blender_version\n")
fw(" keywords = {}\n")
fw(" if blender_version >= (2, 92, 0):\n")
fw(" keywords[\"keyconfig_version\"] = keyconfig_version\n")
fw(" import os\n")
fw(" from bl_keymap_utils.io import keyconfig_import_from_data\n")
fw(" keyconfig_import_from_data(\n")
fw(" os.path.splitext(os.path.basename(__file__))[0],\n")
fw(" keyconfig_data,\n")
fw(" keyconfig_version=keyconfig_version,\n")
fw(" **keywords,\n")
fw(" )\n")

View File

@ -2501,6 +2501,8 @@ def km_sequencer(params):
("sequencer.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("sequencer.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True, "shift": True},
{"properties": [("keep_offset", True)]}),
("sequencer.images_separate", {"type": 'Y', "value": 'PRESS'}, None),
("sequencer.meta_toggle", {"type": 'TAB', "value": 'PRESS'}, None),
("sequencer.meta_make", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),

View File

@ -22,6 +22,7 @@ from bpy_extras.asset_utils import (
SpaceAssetInfo,
)
class ASSET_OT_tag_add(bpy.types.Operator):
"""Add a new keyword tag to the active asset"""

View File

@ -18,6 +18,7 @@
import bpy
def geometry_node_group_empty_new(context):
group = bpy.data.node_groups.new("Geometry Nodes", 'GeometryNodeTree')
group.inputs.new('NodeSocketGeometry', "Geometry")
@ -33,6 +34,7 @@ def geometry_node_group_empty_new(context):
return group
def geometry_modifier_poll(context) -> bool:
ob = context.object
@ -42,6 +44,7 @@ def geometry_modifier_poll(context) -> bool:
return True
class NewGeometryNodesModifier(bpy.types.Operator):
"""Create a new modifier with a new geometry node group"""

View File

@ -573,6 +573,7 @@ class QuickLiquid(Operator):
return {'FINISHED'}
classes = (
QuickExplode,
QuickFur,

View File

@ -893,6 +893,7 @@ class GreasePencilLayerDisplayPanel:
row = layout.row(align=True)
row.prop(gpl, "use_solo_mode", text="Show Only on Keyframed")
class GreasePencilFlipTintColors(Operator):
bl_label = "Flip Colors"
bl_idname = "gpencil.tint_flip"

View File

@ -550,7 +550,6 @@ def brush_settings(layout, context, brush, popover=False):
if context.preferences.experimental.use_sculpt_tools_tilt and capabilities.has_tilt:
layout.prop(brush, "tilt_strength_factor", slider=True)
row = layout.row(align=True)
row.prop(brush, "hardness", slider=True)
row.prop(brush, "invert_hardness_pressure", text="")

View File

@ -267,7 +267,11 @@ class FILEBROWSER_PT_bookmarks_system(Panel):
@classmethod
def poll(cls, context):
return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
return (
not context.preferences.filepaths.hide_system_bookmarks and
panel_poll_is_upper_region(context.region) and
not panel_poll_is_asset_browsing(context)
)
def draw(self, context):
layout = self.layout
@ -301,7 +305,10 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
@classmethod
def poll(cls, context):
return panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
return (
panel_poll_is_upper_region(context.region) and
not panel_poll_is_asset_browsing(context)
)
def draw(self, context):
layout = self.layout
@ -338,7 +345,11 @@ class FILEBROWSER_PT_bookmarks_recents(Panel):
@classmethod
def poll(cls, context):
return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
return (
not context.preferences.filepaths.hide_recent_locations and
panel_poll_is_upper_region(context.region) and
not panel_poll_is_asset_browsing(context)
)
def draw(self, context):
layout = self.layout
@ -362,7 +373,11 @@ class FILEBROWSER_PT_advanced_filter(Panel):
@classmethod
def poll(cls, context):
# only useful in append/link (library) context currently...
return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
return (
context.space_data.params.use_library_browsing and
panel_poll_is_upper_region(context.region) and
not panel_poll_is_asset_browsing(context)
)
def draw(self, context):
layout = self.layout
@ -573,23 +588,33 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
active_file = context.active_file
active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context)
layout.use_property_split = True
if not active_file or not active_asset:
layout.label(text="No asset selected.")
layout.label(text="No asset selected.", icon='INFO')
return
box = layout.box()
# If the active file is an ID, use its name directly so renaming is possible from right here.
layout.prop(context.id if not None else active_file, "name", text="")
class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
bl_label = "Preview"
def draw(self, context):
layout = self.layout
active_file = context.active_file
row = layout.row()
box = row.box()
box.template_icon(icon_value=active_file.preview_icon_id, scale=5.0)
if bpy.ops.ed.lib_id_load_custom_preview.poll():
box.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="Load Custom")
layout.prop(active_file, "name")
col = row.column(align=True)
col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="")
col.separator()
col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="")
class ASSETBROWSER_PT_metadata_details(asset_utils.AssetBrowserPanel, Panel):
bl_region_type = 'TOOL_PROPS'
class ASSETBROWSER_PT_metadata_details(asset_utils.AssetMetaDataPanel, Panel):
bl_label = "Details"
bl_parent_id = "ASSETBROWSER_PT_metadata"
def draw(self, context):
layout = self.layout
@ -647,6 +672,7 @@ classes = (
FILEBROWSER_MT_context_menu,
ASSETBROWSER_PT_navigation_bar,
ASSETBROWSER_PT_metadata,
ASSETBROWSER_PT_metadata_preview,
ASSETBROWSER_PT_metadata_details,
ASSETBROWSER_PT_metadata_tags,
ASSETBROWSER_UL_metadata_tags,

View File

@ -1465,7 +1465,7 @@ class IMAGE_PT_overlay(Panel):
bl_ui_units_x = 13
def draw(self, context):
pass
pass
class IMAGE_PT_overlay_uv_edit(Panel):
@ -1496,7 +1496,6 @@ class IMAGE_PT_overlay_uv_edit(Panel):
subrow.prop(uvedit, "display_stretch_type", text="")
class IMAGE_PT_overlay_uv_edit_geometry(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'
@ -1529,7 +1528,6 @@ class IMAGE_PT_overlay_uv_edit_geometry(Panel):
row.prop(uvedit, "show_faces", text="Faces")
class IMAGE_PT_overlay_texture_paint(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'HEADER'

View File

@ -168,7 +168,6 @@ class NODE_HT_header(Header):
else:
row.template_ID(snode, "node_tree", new="node.new_geometry_nodes_modifier")
else:
# Custom node tree is edited as independent ID block
NODE_MT_editor_menus.draw_collapsible(context, layout)

View File

@ -61,8 +61,10 @@ class PROPERTIES_PT_navigation_bar(Panel):
layout.scale_x = 1.4
layout.scale_y = 1.4
if view.search_filter:
layout.prop_tabs_enum(view, "context", data_highlight=view,
property_highlight="tab_search_results", icon_only=True)
layout.prop_tabs_enum(
view, "context", data_highlight=view,
property_highlight="tab_search_results", icon_only=True,
)
else:
layout.prop_tabs_enum(view, "context", icon_only=True)

View File

@ -139,12 +139,11 @@ class SEQUENCER_HT_header(Header):
SEQUENCER_MT_editor_menus.draw_collapsible(context, layout)
layout.separator_spacer()
if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
layout.separator_spacer()
layout.prop(st, "display_mode", text="", icon_only=True)
layout.prop(st, "preview_channels", text="", icon_only=True)
gpd = context.gpencil_data
@ -157,6 +156,12 @@ class SEQUENCER_HT_header(Header):
if tool_settings.use_proportional_edit:
row.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
row = layout.row(align=True)
row.prop(st, "show_strip_overlay", text="", icon='OVERLAY')
sub = row.row(align=True)
sub.popover(panel="SEQUENCER_PT_overlay", text="")
sub.active = st.show_strip_overlay
class SEQUENCER_MT_editor_menus(Menu):
bl_idname = "SEQUENCER_MT_editor_menus"
@ -176,6 +181,80 @@ class SEQUENCER_MT_editor_menus(Menu):
layout.menu("SEQUENCER_MT_strip")
class SEQUENCER_PT_overlay(Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Overlays"
bl_ui_units_x = 7
def draw(self, _context):
pass
class SEQUENCER_PT_overlay(Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Overlays"
bl_ui_units_x = 7
def draw(self, _context):
pass
class SEQUENCER_PT_preview_overlay(Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'HEADER'
bl_parent_id = 'SEQUENCER_PT_overlay'
bl_label = "Preview Overlays"
@classmethod
def poll(cls, context):
st = context.space_data
return st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'} and st.display_mode == 'IMAGE'
def draw(self, context):
ed = context.scene.sequence_editor
st = context.space_data
layout = self.layout
layout.active = st.show_strip_overlay
layout.prop(ed, "show_overlay", text="Frame Overlay")
layout.prop(st, "show_safe_areas", text="Safe Areas")
layout.prop(st, "show_metadata", text="Metadata")
layout.prop(st, "show_annotation", text="Annotations")
class SEQUENCER_PT_sequencer_overlay(Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'HEADER'
bl_parent_id = 'SEQUENCER_PT_overlay'
bl_label = "Sequencer Overlays"
@classmethod
def poll(cls, context):
st = context.space_data
return st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}
def draw(self, context):
st = context.space_data
layout = self.layout
layout.active = st.show_strip_overlay
layout.prop(st, "show_strip_name", text="Name")
layout.prop(st, "show_strip_source", text="Source")
layout.prop(st, "show_strip_duration", text="Duration")
layout.separator()
layout.prop(st, "show_strip_offset", text="Offsets")
layout.prop(st, "show_fcurves", text="F-Curves")
layout.separator()
layout.prop_menu_enum(st, "waveform_display_type")
class SEQUENCER_MT_view_cache(Menu):
bl_label = "Cache"
@ -294,6 +373,12 @@ class SEQUENCER_MT_view(Menu):
layout.operator("view2d.zoom_border", text="Zoom")
layout.menu("SEQUENCER_MT_preview_zoom")
if st.display_mode == 'IMAGE':
layout.prop(st, "use_zoom_to_fit")
elif st.display_mode == 'WAVEFORM':
layout.separator()
layout.prop(st, "show_separate_color", text="Show Separate Color Channels")
layout.separator()
layout.menu("SEQUENCER_MT_proxy")
@ -318,22 +403,8 @@ class SEQUENCER_MT_view(Menu):
layout.separator()
layout.prop(st, "show_seconds")
layout.prop(st, "show_strip_offset")
layout.prop(st, "show_fcurves")
layout.prop(st, "show_markers")
layout.menu("SEQUENCER_MT_view_cache", text="Show Cache")
layout.prop_menu_enum(st, "waveform_display_type", text="Show Waveforms")
if is_preview:
layout.separator()
if st.display_mode == 'IMAGE':
layout.prop(st, "use_zoom_to_fit")
layout.prop(ed, "show_overlay", text="Show Frame Overlay")
layout.prop(st, "show_safe_areas", text="Show Safe Areas")
layout.prop(st, "show_metadata", text="Show Metadata")
layout.prop(st, "show_annotation", text="Show Annotations")
elif st.display_mode == 'WAVEFORM':
layout.prop(st, "show_separate_color", text="Show Separate Color Channels")
layout.separator()
@ -2222,6 +2293,10 @@ classes = (
SEQUENCER_PT_active_tool,
SEQUENCER_PT_strip,
SEQUENCER_PT_overlay,
SEQUENCER_PT_preview_overlay,
SEQUENCER_PT_sequencer_overlay,
SEQUENCER_PT_effect,
SEQUENCER_PT_scene,
SEQUENCER_PT_mask,

View File

@ -297,6 +297,7 @@ class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel):
col.label(text="New Keyframe Type")
col.prop(tool_settings, "keyframe_type", text="")
class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
bl_label = "Auto Keyframing"
bl_options = {'HIDE_HEADER'}

View File

@ -2938,10 +2938,10 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_sequencer_generic.blade,
],
'SEQUENCER_PREVIEW': [
_defs_sequencer_generic.sample,
*_tools_select,
*_tools_annotate,
_defs_sequencer_generic.blade,
_defs_sequencer_generic.sample,
*_tools_annotate,
],
}

View File

@ -211,7 +211,7 @@ class USERPREF_PT_interface_display(InterfacePanel, CenterAlignMixIn, Panel):
col.separator()
col = layout.column(heading="Tooltips", align=True)
col.prop(view, "show_tooltips", text = "User Tooltips")
col.prop(view, "show_tooltips", text="User Tooltips")
sub = col.column()
sub.active = view.show_tooltips
sub.prop(view, "show_tooltips_python")
@ -1362,14 +1362,15 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
row.separator()
row.label(text="Path")
subrow = row.row()
subrow.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False)
for i, library in enumerate(paths.asset_libraries):
name_col.prop(library, "name", text="")
row = path_col.row()
row.prop(library, "path", text="")
row.operator("preferences.asset_library_remove", text="", icon='X', emboss=False).index = i
row = box.row()
row.alignment = 'LEFT'
row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False)
# -----------------------------------------------------------------------------
@ -1881,12 +1882,12 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
is_visible = is_visible and is_enabled
if is_visible:
if search and search not in info["name"].lower():
if info["author"]:
if search not in info["author"].lower():
continue
else:
continue
if search and not (
(search in info["name"].lower()) or
(info["author"] and (search in info["author"].lower())) or
((filter == "All") and (search in info["category"].lower()))
):
continue
# Skip 2.7x add-ons included with Blender, unless in debug mode.
is_addon_27x = info.get("blender", (0,)) < (2, 80)

View File

@ -5306,6 +5306,7 @@ class VIEW3D_MT_sculpt_mask_edit_pie(Menu):
op.filter_type = 'CONTRAST_DECREASE'
op.auto_iteration_count = False
class VIEW3D_MT_sculpt_automasking_pie(Menu):
bl_label = "Automasking"

View File

@ -966,6 +966,7 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
row.active = mesh.use_mirror_vertex_group_x
row.prop(mesh, "use_mirror_topology")
class VIEW3D_PT_tools_weightpaint_symmetry_for_topbar(Panel):
bl_space_type = 'TOPBAR'
bl_region_type = 'HEADER'

View File

@ -481,7 +481,7 @@ def not_implemented_node(idname):
geometry_node_categories = [
# Geometry Nodes
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
NodeItem("GeometryNodeRandomAttribute"),
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeFill"),
NodeItem("GeometryNodeAttributeMix"),

70
release/steam/README.md Normal file
View File

@ -0,0 +1,70 @@
Creating Steam builds for Blender
=================================
This script automates creation of the Steam files: download of the archives,
extraction of the archives, preparation of the build scripts (VDF files), actual
building of the Steam game files.
Requirements
============
* MacOS machine - Tested on Catalina 10.15.6. Extracting contents from the DMG
archive did not work Windows nor on Linux using 7-zip. All DMG archives tested
failed to be extracted. As such only MacOS is known to work.
* Steam SDK downloaded from SteamWorks - The `steamcmd` is used to generate the
Steam game files. The path to the `steamcmd` is what is actually needed.
* SteamWorks credentials - Needed to log in using `steamcmd`.
* Login to SteamWorks with the `steamcmd` from the command-line at least once -
Needded to ensure the user is properly logged in. On a new machine the user
will have to go through two-factor authentication.
* App ID and Depot IDs - Needed to create the VDF files.
* Python 3.x - 3.7 was tested.
* Base URL - for downloading the archives.
Usage
=====
```bash
$ export STEAMUSER=SteamUserName
$ export STEAMPW=SteamUserPW
$ export BASEURL=https://download.blender.org/release/Blender2.83/
$ export VERSION=2.83.3
$ export APPID=appidnr
$ export WINID=winidnr
$ export LINID=linuxidnr
$ export MACOSID=macosidnr
# log in to SteamWorks from command-line at least once
$ ../sdk/tools/ContentBuilder/builder_osx/steamcmd +login $STEAMUSER $STEAMPW
# once that has been done we can now actually start our tool
$ python3.7 create_steam_builds.py --baseurl $BASEURL --version $VERSION --appid $APPID --winid $WINID --linuxid $LINID --macosid $MACOSID --steamuser $STEAMUSER --steampw $STEAMPW --steamcmd ../sdk/tools/ContentBuilder/builder_osx/steamcmd
```
All arguments in the above example are required.
At the start the tool will login using `steamcmd`. This is necessary to let the
Steam SDK update itself if necessary.
There are a few optional arguments:
* `--dryrun`: If set building the game files will not actually happen. A set of
log files and a preview manifest per depot will be created in the output folder.
This can be used to double-check everything works as expected.
* `--skipdl`: If set will skip downloading of the archives. The tool expects the
archives to already exist in the correct content location.
* `--skipextract`: If set will skip extraction of all archives. The tool expects
the archives to already have been correctly extracted in the content location.
Run the tool with `-h` for detailed information on each argument.
The content and output folders are generated through appending the version
without dots to the words `content` and `output` respectively, e.g. `content2833`
and `output2833`. These folders are created next to the tool.
From all `.template` files the Steam build scripts will be generated also in the
same directory as the tool. The files will have the extension `.vdf`.
In case of errors the tool will have a non-zero return code.

View File

@ -0,0 +1,17 @@
"appbuild"
{
"appid" "[APPID]"
"desc" "Blender [VERSION]" // description for this build
"buildoutput" "./[OUTPUT]" // build output folder for .log, .csm & .csd files, relative to location of this file
"contentroot" "./[CONTENT]" // root content folder, relative to location of this file
"setlive" "" // branch to set live after successful build, non if empty
"preview" "[DRYRUN]" // 1 to enable preview builds, 0 to commit build to steampipe
"local" "" // set to flie path of local content server
"depots"
{
"[WINID]" "depot_build_win.vdf"
"[LINUXID]" "depot_build_linux.vdf"
"[MACOSID]" "depot_build_macos.vdf"
}
}

View File

@ -0,0 +1,397 @@
#!/usr/bin/env python3
import argparse
import pathlib
import requests
import shutil
import subprocess
from typing import Callable, Iterator, List, Tuple
# supported archive and platform endings, used to create actual archive names
archive_endings = ["windows64.zip", "linux64.tar.xz", "macOS.dmg"]
def add_optional_argument(option: str, help: str) -> None:
global parser
"""Add an optional argument
Args:
option (str): Option to add
help (str): Help description for the argument
"""
parser.add_argument(option, help=help, action='store_const', const=1)
def blender_archives(version: str) -> Iterator[str]:
"""Generator for Blender archives for version.
Yields for items in archive_endings an archive name in the form of
blender-{version}-{ending}.
Args:
version (str): Version string of the form 2.83.2
Yields:
Iterator[str]: Name in the form of blender-{version}-{ending}
"""
global archive_endings
for ending in archive_endings:
yield f"blender-{version}-{ending}"
def get_archive_type(archive_type: str, version: str) -> str:
"""Return the archive of given type and version.
Args:
archive_type (str): extension for archive type to check for
version (str): Version string in the form 2.83.2
Raises:
Exception: Execption when archive type isn't found
Returns:
str: archive name for given type
"""
for archive in blender_archives(version):
if archive.endswith(archive_type):
return archive
raise Exception("Unknown archive type")
def execute_command(cmd: List[str], name: str, errcode: int, cwd=".", capture_output=True) -> str:
"""Execute the given command.
Returns the process stdout upon success if any.
On error print message the command with name that has failed. Print stdout
and stderr of the process if any, and then exit with given error code.
Args:
cmd (List[str]): Command in list format, each argument as their own item
name (str): Name of command to use when printing to command-line
errcode (int): Error code to use in case of exit()
cwd (str, optional): Folder to use as current work directory for command
execution. Defaults to ".".
capture_output (bool, optional): Whether to capture command output or not.
Defaults to True.
Returns:
str: stdout if any, or empty string
"""
cmd_process = subprocess.run(
cmd, capture_output=capture_output, encoding="UTF-8", cwd=cwd)
if cmd_process.returncode == 0:
if cmd_process.stdout:
return cmd_process.stdout
else:
return ""
else:
print(f"ERROR: {name} failed.")
if cmd_process.stdout:
print(cmd_process.stdout)
if cmd_process.stderr:
print(cmd_process.stderr)
exit(errcode)
return ""
def download_archives(base_url: str, archives: Callable[[str], Iterator[str]], version: str, dst_dir: pathlib.Path):
"""Download archives from the given base_url.
Archives is a generator for Blender archive names based on version.
Archive names are appended to the base_url to load from, and appended to
dst_dir to save to.
Args:
base_url (str): Base URL to load archives from
archives (Callable[[str], Iterator[str]]): Generator for Blender archive
names based on version
version (str): Version string in the form of 2.83.2
dst_dir (pathlib.Path): Download destination
"""
if base_url[-1] != '/':
base_url = base_url + '/'
for archive in archives(version):
download_url = f"{base_url}{archive}"
target_file = dst_dir.joinpath(archive)
download_file(download_url, target_file)
def download_file(from_url: str, to_file: pathlib.Path) -> None:
"""Download from_url as to_file.
Actual downloading will be skipped if --skipdl is given on the command-line.
Args:
from_url (str): Full URL to resource to download
to_file (pathlib.Path): Full path to save downloaded resource as
"""
global args
if not args.skipdl or not to_file.exists():
print(f"Downloading {from_url}")
with open(to_file, "wb") as download_zip:
response = requests.get(from_url)
if response.status_code != requests.codes.ok:
print(f"ERROR: failed to download {from_url} (status code: {response.status_code})")
exit(1313)
download_zip.write(response.content)
else:
print(f"Downloading {from_url} skipped")
print(" ... OK")
def copy_contents_from_dmg_to_path(dmg_file: pathlib.Path, dst: pathlib.Path) -> None:
"""Copy the contents of the given DMG file to the destination folder.
Args:
dmg_file (pathlib.Path): Full path to DMG archive to extract from
dst (pathlib.Path): Full path to destination to extract to
"""
hdiutil_attach = ["hdiutil",
"attach",
"-readonly",
f"{dmg_file}"
]
attached = execute_command(hdiutil_attach, "hdiutil attach", 1)
# Last line of output is what we want, it is of the form
# /dev/somedisk Apple_HFS /Volumes/Blender
# We want to retain the mount point, and the folder the mount is
# created on. The mounted disk we need for detaching, the folder we
# need to be able to copy the contents to where we can use them
attachment_items = attached.splitlines()[-1].split()
mounted_disk = attachment_items[0]
source_location = pathlib.Path(attachment_items[2], "Blender.app")
print(f"{source_location} -> {dst}")
shutil.copytree(source_location, dst)
hdiutil_detach = ["hdiutil",
"detach",
f"{mounted_disk}"
]
execute_command(hdiutil_detach, "hdiutil detach", 2)
def create_build_script(template_name: str, vars: List[Tuple[str, str]]) -> pathlib.Path:
"""
Create the Steam build script
Use the given template and template variable tuple list.
Returns pathlib.Path to the created script.
Args:
template_name (str): [description]
vars (List[Tuple[str, str]]): [description]
Returns:
pathlib.Path: Full path to the generated script
"""
build_script = pathlib.Path(".", template_name).read_text()
for var in vars:
build_script = build_script.replace(var[0], var[1])
build_script_file = template_name.replace(".template", "")
build_script_path = pathlib.Path(".", build_script_file)
build_script_path.write_text(build_script)
return build_script_path
def clean_up() -> None:
"""Remove intermediate files depending on given command-line arguments
"""
global content_location, args
if not args.leavearch and not args.leaveextracted:
shutil.rmtree(content_location)
if args.leavearch and not args.leaveextracted:
shutil.rmtree(content_location.joinpath(zip_extract_folder))
shutil.rmtree(content_location.joinpath(tarxz_extract_folder))
shutil.rmtree(content_location.joinpath(dmg_extract_folder))
if args.leaveextracted and not args.leavearch:
import os
os.remove(content_location.joinpath(zipped_blender))
os.remove(content_location.joinpath(tarxz_blender))
os.remove(content_location.joinpath(dmg_blender))
def extract_archive(archive: str, extract_folder_name: str,
cmd: List[str], errcode: int) -> None:
"""Extract all files from archive to given folder name.
Will not extract if
target folder already exists, or if --skipextract was given on the
command-line.
Args:
archive (str): Archive name to extract
extract_folder_name (str): Folder name to extract to
cmd (List[str]): Command with arguments to use
errcode (int): Error code to use for exit()
"""
global args, content_location
extract_location = content_location.joinpath(extract_folder_name)
pre_extract = set(content_location.glob("*"))
if not args.skipextract or not extract_location.exists():
print(f"Extracting files from {archive}...")
cmd.append(content_location.joinpath(archive))
execute_command(cmd, cmd[0], errcode, cwd=content_location)
# in case we use a non-release archive the naming will be incorrect.
# simply rename to expected target name
post_extract = set(content_location.glob("*"))
diff_extract = post_extract - pre_extract
if not extract_location in diff_extract:
folder_to_rename = list(diff_extract)[0]
folder_to_rename.rename(extract_location)
print(" OK")
else:
print(f"Skipping extraction {archive}!")
# ==============================================================================
parser = argparse.ArgumentParser()
parser.add_argument("--baseurl", required=True,
help="The base URL for files to download, "
"i.e. https://download.blender.org/release/Blender2.83/")
parser.add_argument("--version", required=True,
help="The Blender version to release, in the form 2.83.3")
parser.add_argument("--appid", required=True,
help="The Blender App ID on Steam")
parser.add_argument("--winid", required=True,
help="The Windows depot ID")
parser.add_argument("--linuxid", required=True,
help="The Linux depot ID")
parser.add_argument("--macosid", required=True,
help="The MacOS depot ID")
parser.add_argument("--steamcmd", required=True,
help="Path to the steamcmd")
parser.add_argument("--steamuser", required=True,
help="The login for the Steam builder user")
parser.add_argument("--steampw", required=True,
help="Login password for the Steam builder user")
add_optional_argument("--dryrun",
"If set the Steam files will not be uploaded")
add_optional_argument("--leavearch",
help="If set don't clean up the downloaded archives")
add_optional_argument("--leaveextracted",
help="If set don't clean up the extraction folders")
add_optional_argument("--skipdl",
help="If set downloading the archives is skipped if it already exists locally.")
add_optional_argument("--skipextract",
help="If set skips extracting of archives. The tool assumes the archives"
"have already been extracted to their correct locations")
args = parser.parse_args()
VERSIONNODOTS = args.version.replace('.', '')
OUTPUT = f"output{VERSIONNODOTS}"
CONTENT = f"content{VERSIONNODOTS}"
# ===== set up main locations
content_location = pathlib.Path(".", CONTENT).absolute()
output_location = pathlib.Path(".", OUTPUT).absolute()
content_location.mkdir(parents=True, exist_ok=True)
output_location.mkdir(parents=True, exist_ok=True)
# ===== login
# Logging into Steam once to ensure the SDK updates itself properly. If we don't
# do that the combined +login and +run_app_build_http at the end of the tool
# will fail.
steam_login = [args.steamcmd,
"+login",
args.steamuser,
args.steampw,
"+quit"
]
print("Logging in to Steam...")
execute_command(steam_login, "Login to Steam", 10)
print(" OK")
# ===== prepare Steam build scripts
template_vars = [
("[APPID]", args.appid),
("[OUTPUT]", OUTPUT),
("[CONTENT]", CONTENT),
("[VERSION]", args.version),
("[WINID]", args.winid),
("[LINUXID]", args.linuxid),
("[MACOSID]", args.macosid),
("[DRYRUN]", f"{args.dryrun}" if args.dryrun else "0")
]
blender_app_build = create_build_script(
"blender_app_build.vdf.template", template_vars)
create_build_script("depot_build_win.vdf.template", template_vars)
create_build_script("depot_build_linux.vdf.template", template_vars)
create_build_script("depot_build_macos.vdf.template", template_vars)
# ===== download archives
download_archives(args.baseurl, blender_archives,
args.version, content_location)
# ===== set up file and folder names
zipped_blender = get_archive_type("zip", args.version)
zip_extract_folder = zipped_blender.replace(".zip", "")
tarxz_blender = get_archive_type("tar.xz", args.version)
tarxz_extract_folder = tarxz_blender.replace(".tar.xz", "")
dmg_blender = get_archive_type("dmg", args.version)
dmg_extract_folder = dmg_blender.replace(".dmg", "")
# ===== extract
unzip_cmd = ["unzip", "-q"]
extract_archive(zipped_blender, zip_extract_folder, unzip_cmd, 3)
untarxz_cmd = ["tar", "-xf"]
extract_archive(tarxz_blender, tarxz_extract_folder, untarxz_cmd, 4)
if not args.skipextract or not content_location.joinpath(dmg_extract_folder).exists():
print("Extracting files from Blender MacOS archive...")
blender_dmg = content_location.joinpath(dmg_blender)
target_location = content_location.joinpath(
dmg_extract_folder, "Blender.app")
copy_contents_from_dmg_to_path(blender_dmg, target_location)
print(" OK")
else:
print("Skipping extraction of .dmg!")
# ===== building
print("Build Steam game files...")
steam_build = [args.steamcmd,
"+login",
args.steamuser,
args.steampw,
"+run_app_build_http",
blender_app_build.absolute(),
"+quit"
]
execute_command(steam_build, "Build with steamcmd", 13)
print(" OK")
clean_up()

View File

@ -0,0 +1,31 @@
"DepotBuildConfig"
{
// Set your assigned depot ID here
"DepotID" "[LINUXID]"
// Set a root for all content.
// All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths)
// will be resolved relative to this root.
// If you don't define ContentRoot, then it will be assumed to be
// the location of this script file, which probably isn't what you want
"ContentRoot" "./blender-[VERSION]-linux64/"
// include all files recursivley
"FileMapping"
{
// This can be a full path, or a path relative to ContentRoot
"LocalPath" "*"
// This is a path relative to the install folder of your game
"DepotPath" "."
// If LocalPath contains wildcards, setting this means that all
// matching files within subdirectories of LocalPath will also
// be included.
"recursive" "1"
}
// but exclude all symbol files
// This can be a full path, or a path relative to ContentRoot
"FileExclusion" "*.pdb"
}

View File

@ -0,0 +1,30 @@
"DepotBuildConfig"
{
// Set your assigned depot ID here
"DepotID" "[MACOSID]"
// Set a root for all content.
// All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths)
// will be resolved relative to this root.
// If you don't define ContentRoot, then it will be assumed to be
// the location of this script file, which probably isn't what you want
"ContentRoot" "./blender-[VERSION]-macOS/"
// include all files recursivley
"FileMapping"
{
// This can be a full path, or a path relative to ContentRoot
"LocalPath" "*"
// This is a path relative to the install folder of your game
"DepotPath" "."
// If LocalPath contains wildcards, setting this means that all
// matching files within subdirectories of LocalPath will also
// be included.
"recursive" "1"
}
// but exclude all symbol files
// This can be a full path, or a path relative to ContentRoot
"FileExclusion" "*.pdb"
}

View File

@ -0,0 +1,31 @@
"DepotBuildConfig"
{
// Set your assigned depot ID here
"DepotID" "[WINID]"
// Set a root for all content.
// All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths)
// will be resolved relative to this root.
// If you don't define ContentRoot, then it will be assumed to be
// the location of this script file, which probably isn't what you want
"ContentRoot" "./blender-[VERSION]-windows64/"
// include all files recursivley
"FileMapping"
{
// This can be a full path, or a path relative to ContentRoot
"LocalPath" "*"
// This is a path relative to the install folder of your game
"DepotPath" "."
// If LocalPath contains wildcards, setting this means that all
// matching files within subdirectories of LocalPath will also
// be included.
"recursive" "1"
}
// but exclude all symbol files
// This can be a full path, or a path relative to ContentRoot
"FileExclusion" "*.pdb"
}

View File

@ -30,10 +30,10 @@
extern "C" {
#endif
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
struct BlendExpander;
struct BlendLibReader;
struct BlendWriter;
struct bArmature;
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */

View File

@ -26,14 +26,14 @@
extern "C" {
#endif
struct BlendDataReader;
struct BlendWriter;
struct Object;
struct ReportList;
struct Scene;
struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
struct BlendWriter;
struct BlendDataReader;
/* ---------------------------------------------------- */
/* Animation Visualization */

View File

@ -45,8 +45,6 @@ struct NlaKeyframingContext;
struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
struct Scene;
struct bAction;
struct bActionGroup;
struct bContext;

View File

@ -27,8 +27,8 @@
extern "C" {
#endif
struct BlendWriter;
struct BlendDataReader;
struct BlendWriter;
struct ID;
struct PreviewImage;

View File

@ -35,7 +35,6 @@ extern "C" {
struct CustomData;
struct CustomDataLayer;
struct ID;
struct PointerRNA;
struct ReportList;
/* Attribute.domain */

View File

@ -26,8 +26,6 @@
#include "BLI_color.hh"
#include "BLI_float3.hh"
struct Mesh;
namespace blender::bke {
using fn::CPPType;

View File

@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 6
#define BLENDER_FILE_SUBVERSION 7
/* 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

View File

@ -26,9 +26,9 @@
extern "C" {
#endif
struct BVHTree;
struct Collection;
struct CollisionModifierData;
struct BVHTree;
struct Depsgraph;
struct MVert;
struct MVertTri;

View File

@ -23,6 +23,10 @@
* \ingroup bke
*/
struct BlendDataReader;
struct BlendExpander;
struct BlendLibReader;
struct BlendWriter;
struct Depsgraph;
struct ID;
struct ListBase;
@ -31,10 +35,6 @@ struct Scene;
struct bConstraint;
struct bConstraintTarget;
struct bPoseChannel;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
struct BlendExpander;
/* ---------------------------------------------------------------------------- */
#ifdef __cplusplus

View File

@ -29,10 +29,9 @@
extern "C" {
#endif
struct Object;
struct Material;
struct ID;
struct Main;
struct Material;
struct Object;
uint32_t BKE_cryptomatte_hash(const char *name, int name_len);
uint32_t BKE_cryptomatte_object_hash(const struct Object *object);

View File

@ -35,9 +35,7 @@ struct BMLoop;
struct BMesh;
struct BoundBox;
struct Depsgraph;
struct EditMeshData;
struct Mesh;
struct MeshStatVis;
struct Object;
struct Scene;

View File

@ -24,9 +24,9 @@
extern "C" {
#endif
struct Object;
struct GeometrySet;
struct Collection;
struct GeometrySet;
struct Object;
void BKE_geometry_set_free(struct GeometrySet *geometry_set);

View File

@ -32,10 +32,10 @@
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.h"
struct Mesh;
struct PointCloud;
struct Object;
struct Collection;
struct Mesh;
struct Object;
struct PointCloud;
/* Each geometry component has a specific type. The type determines what kind of data the component
* stores. Functions modifying a geometry will usually just modify a subset of the component types.

View File

@ -36,19 +36,17 @@ struct ListBase;
struct MDeformVert;
struct Main;
struct Material;
struct MaterialGPencilStyle;
struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
struct ViewLayer;
struct bDeformGroup;
struct bGPDcurve;
struct bGPDframe;
struct bGPDlayer;
struct bGPDlayer_Mask;
struct bGPDspoint;
struct bGPDstroke;
struct bGPDcurve;
struct bGPdata;
#define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))

View File

@ -30,10 +30,10 @@ extern "C" {
struct Main;
struct Object;
struct Scene;
struct bGPdata;
struct bGPDcurve;
struct bGPDlayer;
struct bGPDstroke;
struct bGPDcurve;
struct bGPdata;
void BKE_gpencil_convert_curve(struct Main *bmain,
struct Scene *scene,

View File

@ -32,12 +32,11 @@ struct Depsgraph;
struct Main;
struct Object;
struct Scene;
struct bGPDcurve;
struct bGPDframe;
struct bGPDlayer;
struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
struct bGPDcurve;
/* Object boundbox. */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);

View File

@ -27,6 +27,9 @@ extern "C" {
#endif
struct ARegionType;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Depsgraph;
struct GpencilModifierData;
struct ID;
@ -35,9 +38,6 @@ struct Main;
struct ModifierUpdateDepsgraphContext;
struct Object;
struct Scene;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
/* NOTE: bakeModifier() called from UI:
* needs to create new data-blocks, hence the need for this. */
struct bGPDframe;

View File

@ -26,7 +26,6 @@
extern "C" {
#endif
struct Ipo;
struct Main;
void do_versions_ipos_to_animato(struct Main *main);

View File

@ -38,7 +38,6 @@ struct Main;
struct Mesh;
struct Object;
struct Scene;
struct bGPDstroke;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);

View File

@ -51,7 +51,6 @@
extern "C" {
#endif
struct BlendDataReader;
struct BlendWriter;
struct GHash;
struct ID;

View File

@ -72,6 +72,7 @@ void BKE_lib_override_library_dependencies_tag(struct Main *bmain,
void BKE_lib_override_library_override_group_tag(struct Main *bmain,
struct ID *id_root,
const uint tag,
const uint missing_tag,
const bool do_create_main_relashionships);
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,

View File

@ -38,8 +38,6 @@
extern "C" {
#endif
struct wmWindowManager;
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
/* Also IDRemap->flag. */

View File

@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
struct BLI_Stack;
struct BMEditMesh;
struct BMesh;
struct BMeshCreateParams;
struct BMeshFromMeshParams;

View File

@ -35,6 +35,7 @@ struct BlendWriter;
struct CustomData_MeshMasks;
struct DepsNodeHandle;
struct Depsgraph;
struct GeometrySet;
struct ID;
struct ListBase;
struct Main;
@ -43,7 +44,6 @@ struct ModifierData;
struct Object;
struct Scene;
struct bArmature;
struct GeometrySet;
typedef enum {
/* Should not be used, only for None modifier type */

View File

@ -1347,7 +1347,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_POINT_INSTANCE 1005
#define GEO_NODE_SUBDIVISION_SURFACE 1006
#define GEO_NODE_OBJECT_INFO 1007
#define GEO_NODE_RANDOM_ATTRIBUTE 1008
#define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008
#define GEO_NODE_ATTRIBUTE_MATH 1009
#define GEO_NODE_JOIN_GEOMETRY 1010
#define GEO_NODE_ATTRIBUTE_FILL 1011

View File

@ -34,6 +34,9 @@ extern "C" {
struct BMFace;
struct BMesh;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Brush;
struct CurveMapping;
struct Depsgraph;
@ -55,7 +58,6 @@ struct Paint;
struct PaintCurve;
struct Palette;
struct PaletteColor;
struct ReportList;
struct Scene;
struct StrokeCache;
struct SubdivCCG;
@ -67,9 +69,6 @@ struct ViewLayer;
struct bContext;
struct bToolRef;
struct tPaletteColorHSV;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
extern const char PAINT_CURSOR_SCULPT[3];
extern const char PAINT_CURSOR_VERTEX_PAINT[3];

View File

@ -42,9 +42,9 @@ struct ParticleSystemModifierData;
struct BVHTreeRay;
struct BVHTreeRayHit;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct CustomData_MeshMasks;
struct Depsgraph;
struct EdgeHash;

View File

@ -48,7 +48,6 @@ struct PBVH;
struct PBVHNode;
struct SubdivCCG;
struct TaskParallelSettings;
struct TaskParallelTLS;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;

View File

@ -77,7 +77,10 @@ extern "C" {
#define PTCACHE_READ_OLD 3
/* Structs */
struct BlendDataReader;
struct BlendWriter;
struct ClothModifierData;
struct DynamicPaintSurface;
struct FluidModifierData;
struct ListBase;
struct Main;
@ -89,9 +92,6 @@ struct RigidBodyWorld;
struct Scene;
struct SoftBody;
struct ViewLayer;
struct BlendWriter;
struct BlendDataReader;
struct DynamicPaintSurface;
/* temp structure for read/write */
typedef struct PTCacheData {

View File

@ -51,7 +51,6 @@ struct View3D;
struct View3DShading;
struct WorkSpace;
struct bContext;
struct bContextDataResult;
struct bScreen;
struct uiLayout;
struct uiList;

View File

@ -27,14 +27,14 @@ extern "C" {
#endif
struct ARegionType;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct ID;
struct ListBase;
struct ModifierUpdateDepsgraphContext;
struct Object;
struct ShaderFxData;
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
#define SHADER_FX_ACTIVE(_fx, _is_render) \
((((_fx)->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \

View File

@ -26,7 +26,6 @@ extern "C" {
#endif
struct Main;
struct Speaker;
void *BKE_speaker_add(struct Main *bmain, const char *name);

View File

@ -906,14 +906,20 @@ bool BKE_appdir_program_python_search(char *fullpath,
const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME);
#endif
const char *basename = "python";
#if defined(WIN32) && !defined(NDEBUG)
const char *basename_debug = "python_d";
#endif
char python_version[16];
/* Check both possible names. */
const char *python_names[] = {
#ifdef PYTHON_EXECUTABLE_NAME
python_build_def,
python_build_def,
#endif
python_version,
basename,
#if defined(WIN32) && !defined(NDEBUG)
basename_debug,
#endif
python_version,
basename,
};
bool is_found = false;

View File

@ -62,7 +62,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
return ibuf->rect_float != NULL;
}
}
else if (ibuf) {
if (ibuf) {
if (ibuf->rect_float) {
return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
}

View File

@ -369,6 +369,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
static bool lib_override_hierarchy_recursive_tag(Main *bmain,
ID *id,
const uint tag,
const uint missing_tag,
Library *override_group_lib_reference)
{
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id);
@ -377,9 +378,16 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
return (id->tag & tag) != 0;
}
/* Note: in case some reference ID is missing from linked data (and therefore its override uses
* a placeholder as reference), use `missing_tag` instead of `tag` for this override. */
if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
id->override_library->reference->lib == override_group_lib_reference) {
id->tag |= tag;
if (id->override_library->reference->tag & LIB_TAG_MISSING) {
id->tag |= missing_tag;
}
else {
id->tag |= tag;
}
}
/* This way we won't process again that ID, should we encounter it again through another
@ -397,7 +405,7 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain,
/* We only consider IDs from the same library. */
if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) {
if (lib_override_hierarchy_recursive_tag(
bmain, *entry->id_pointer, tag, override_group_lib_reference) &&
bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) &&
override_group_lib_reference == NULL) {
id->tag |= tag;
}
@ -430,7 +438,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
/* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key
* has a driver using an armature object's bone, we need to override the shape-key/obdata,
* the objects using them, etc.) */
lib_override_hierarchy_recursive_tag(bmain, id_root, tag, NULL);
lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL);
BKE_main_relations_free(bmain);
}
@ -447,6 +455,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain,
void BKE_lib_override_library_override_group_tag(Main *bmain,
ID *id_root,
const uint tag,
const uint missing_tag,
const bool do_create_main_relashionships)
{
if (do_create_main_relashionships) {
@ -456,7 +465,7 @@ void BKE_lib_override_library_override_group_tag(Main *bmain,
/* We tag all liboverride data-blocks from the same library as reference one,
* being used by the root ID. */
lib_override_hierarchy_recursive_tag(
bmain, id_root, tag, id_root->override_library->reference->lib);
bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib);
BKE_main_relations_free(bmain);
}
@ -492,8 +501,9 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da
}
/* We tag all collections and objects for override. And we also tag all other data-blocks which
* would use one of those. */
if (ELEM(GS(id->name), ID_OB, ID_GR)) {
* would use one of those.
* Note: missing IDs (aka placeholders) are never overridden. */
if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) {
id->tag |= LIB_TAG_DOIT;
}
@ -725,7 +735,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
/* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag
* linked reference ones to be overridden again. */
BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true);
GHash *linkedref_to_old_override = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
@ -835,6 +845,12 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_
}
id->tag &= ~LIB_TAG_DOIT;
}
/* Also cleanup old overrides that went missing in new linked data. */
else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) {
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id));
id->tag |= LIB_TAG_DOIT;
id->tag &= ~LIB_TAG_MISSING;
}
}
FOREACH_MAIN_ID_END;
BKE_id_multi_tagged_delete(bmain);
@ -876,7 +892,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
id_root->tag |= LIB_TAG_DOIT;
/* Tag all library overrides in the chains of dependencies from the given root one. */
BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true);
BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {

View File

@ -26,10 +26,8 @@
#include "BLI_sys_types.h"
struct BMesh;
struct Depsgraph;
struct Mesh;
struct MultiresModifierData;
struct Object;
typedef struct MultiresUnsubdivideGrid {
/* For sanity checks. */

View File

@ -4737,7 +4737,7 @@ static void registerGeometryNodes(void)
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();
register_node_type_geo_object_info();
register_node_type_geo_random_attribute();
register_node_type_geo_attribute_randomize();
register_node_type_geo_attribute_math();
register_node_type_geo_join_geometry();
register_node_type_geo_attribute_mix();

View File

@ -220,13 +220,13 @@ class Array {
return MutableSpan<T>(data_, size_);
}
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator Span<U>() const
{
return Span<U>(data_, size_);
}
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator MutableSpan<U>()
{
return MutableSpan<U>(data_, size_);

View File

@ -73,21 +73,22 @@ class IndexRange {
int64_t size_ = 0;
public:
IndexRange() = default;
constexpr IndexRange() = default;
explicit IndexRange(int64_t size) : start_(0), size_(size)
constexpr explicit IndexRange(int64_t size) : start_(0), size_(size)
{
BLI_assert(size >= 0);
}
IndexRange(int64_t start, int64_t size) : start_(start), size_(size)
constexpr IndexRange(int64_t start, int64_t size) : start_(start), size_(size)
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
}
template<typename T>
IndexRange(const tbb::blocked_range<T> &range) : start_(range.begin()), size_(range.size())
constexpr IndexRange(const tbb::blocked_range<T> &range)
: start_(range.begin()), size_(range.size())
{
}
@ -96,33 +97,33 @@ class IndexRange {
int64_t current_;
public:
Iterator(int64_t current) : current_(current)
constexpr Iterator(int64_t current) : current_(current)
{
}
Iterator &operator++()
constexpr Iterator &operator++()
{
current_++;
return *this;
}
bool operator!=(const Iterator &iterator) const
constexpr bool operator!=(const Iterator &iterator) const
{
return current_ != iterator.current_;
}
int64_t operator*() const
constexpr int64_t operator*() const
{
return current_;
}
};
Iterator begin() const
constexpr Iterator begin() const
{
return Iterator(start_);
}
Iterator end() const
constexpr Iterator end() const
{
return Iterator(start_ + size_);
}
@ -130,7 +131,7 @@ class IndexRange {
/**
* Access an element in the range.
*/
int64_t operator[](int64_t index) const
constexpr int64_t operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
@ -140,7 +141,7 @@ class IndexRange {
/**
* Two ranges compare equal when they contain the same numbers.
*/
friend bool operator==(IndexRange a, IndexRange b)
constexpr friend bool operator==(IndexRange a, IndexRange b)
{
return (a.size_ == b.size_) && (a.start_ == b.start_ || a.size_ == 0);
}
@ -148,7 +149,7 @@ class IndexRange {
/**
* Get the amount of numbers in the range.
*/
int64_t size() const
constexpr int64_t size() const
{
return size_;
}
@ -156,7 +157,7 @@ class IndexRange {
/**
* Create a new range starting at the end of the current one.
*/
IndexRange after(int64_t n) const
constexpr IndexRange after(int64_t n) const
{
BLI_assert(n >= 0);
return IndexRange(start_ + size_, n);
@ -165,7 +166,7 @@ class IndexRange {
/**
* Create a new range that ends at the start of the current one.
*/
IndexRange before(int64_t n) const
constexpr IndexRange before(int64_t n) const
{
BLI_assert(n >= 0);
return IndexRange(start_ - n, n);
@ -175,7 +176,7 @@ class IndexRange {
* Get the first element in the range.
* Asserts when the range is empty.
*/
int64_t first() const
constexpr int64_t first() const
{
BLI_assert(this->size() > 0);
return start_;
@ -185,7 +186,7 @@ class IndexRange {
* Get the last element in the range.
* Asserts when the range is empty.
*/
int64_t last() const
constexpr int64_t last() const
{
BLI_assert(this->size() > 0);
return start_ + size_ - 1;
@ -194,7 +195,7 @@ class IndexRange {
/**
* Get the element one after the end. The returned value is undefined when the range is empty.
*/
int64_t one_after_last() const
constexpr int64_t one_after_last() const
{
return start_ + size_;
}
@ -202,7 +203,7 @@ class IndexRange {
/**
* Get the first element in the range. The returned value is undefined when the range is empty.
*/
int64_t start() const
constexpr int64_t start() const
{
return start_;
}
@ -210,7 +211,7 @@ class IndexRange {
/**
* Returns true when the range contains a certain number, otherwise false.
*/
bool contains(int64_t value) const
constexpr bool contains(int64_t value) const
{
return value >= start_ && value < start_ + size_;
}
@ -218,7 +219,7 @@ class IndexRange {
/**
* Returns a new range, that contains a sub-interval of the current one.
*/
IndexRange slice(int64_t start, int64_t size) const
constexpr IndexRange slice(int64_t start, int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
@ -226,7 +227,7 @@ class IndexRange {
BLI_assert(new_start + size <= start_ + size_ || size == 0);
return IndexRange(new_start, size);
}
IndexRange slice(IndexRange range) const
constexpr IndexRange slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}

View File

@ -0,0 +1,304 @@
/*
* 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.
*/
#pragma once
#include "BLI_array.hh"
#include "BLI_dot_export.hh"
namespace blender {
/**
* An InplacePriorityQueue adds priority queue functionality to an existing array. The underlying
* array is not changed. Instead, the priority queue maintains indices into the original array.
*
* The priority queue provides efficient access to the element in order of their priorities.
*
* When a priority changes, the priority queue has to be informed using one of the following
* methods: #priority_decreased, #priority_increased or #priority_changed.
*/
template<
/* Type of the elements in the underlying array. */
typename T,
/* Binary function that takes two `const T &` inputs and returns true, when the first input has
greater priority than the second. */
typename FirstHasHigherPriority = std::greater<T>>
class InplacePriorityQueue {
private:
/* Underlying array the priority queue is built upon. This is a span instead of a mutable span,
* because this data structure never changes the values itself. */
Span<T> data_;
/* Maps indices from the heap (binary tree in array format) to indices of the underlying/original
* array. */
Array<int64_t> heap_to_orig_;
/* This is the inversion of the above mapping. */
Array<int64_t> orig_to_heap_;
/* Number of elements that are currently in the priority queue. */
int64_t heap_size_ = 0;
/* Function that can be changed to customize how the priority of two elements is compared. */
FirstHasHigherPriority first_has_higher_priority_fn_;
public:
/**
* Construct the priority queue on top of the data in the given span.
*/
InplacePriorityQueue(Span<T> data)
: data_(data), heap_to_orig_(data_.size()), orig_to_heap_(data_.size())
{
for (const int64_t i : IndexRange(data_.size())) {
heap_to_orig_[i] = i;
orig_to_heap_[i] = i;
}
this->rebuild();
}
/**
* Rebuilds the priority queue from the array that has been passed to the constructor.
*/
void rebuild()
{
const int final_heap_size = data_.size();
if (final_heap_size > 1) {
for (int64_t i = this->get_parent(final_heap_size - 1); i >= 0; i--) {
this->heapify(i, final_heap_size);
}
}
heap_size_ = final_heap_size;
}
/**
* Returns the number of elements in the priority queue.
* This is less or equal than the size of the underlying array.
*/
int64_t size() const
{
return heap_size_;
}
/**
* Returns true, when the priority queue contains no elements. If this returns true, #peek and
* #pop must not be used.
*/
bool is_empty() const
{
return heap_size_ == 0;
}
/**
* Get the element with the highest priority in the priority queue.
* The returned reference is const, because the priority queue has read-only access to the
* underlying data. If you need a mutable reference, use #peek_index instead.
*/
const T &peek() const
{
return data_[this->peek_index()];
}
/**
* Get the element with the highest priority in the priority queue and remove it.
* The returned reference is const, because the priority queue has read-only access to the
* underlying data. If you need a mutable reference, use #pop_index instead.
*/
const T &pop()
{
return data_[this->pop_index()];
}
/**
* Get the index of the element with the highest priority in the priority queue.
*/
int64_t peek_index() const
{
BLI_assert(!this->is_empty());
return heap_to_orig_[0];
}
/**
* Get the index of the element with the highest priority in the priority queue and remove it.
*/
int64_t pop_index()
{
BLI_assert(!this->is_empty());
const int64_t top_index_orig = heap_to_orig_[0];
heap_size_--;
if (heap_size_ > 1) {
this->swap_indices(0, heap_size_);
this->heapify(0, heap_size_);
}
return top_index_orig;
}
/**
* Inform the priority queue that the priority of the element at the given index has been
* decreased.
*/
void priority_decreased(const int64_t index)
{
const int64_t heap_index = orig_to_heap_[index];
if (heap_index >= heap_size_) {
/* This element is not in the queue currently. */
return;
}
this->heapify(heap_index, heap_size_);
}
/**
* Inform the priority queue that the priority of the element at the given index has been
* increased.
*/
void priority_increased(const int64_t index)
{
int64_t current = orig_to_heap_[index];
if (current >= heap_size_) {
/* This element is not in the queue currently. */
return;
}
while (true) {
if (current == 0) {
break;
}
const int64_t parent = this->get_parent(current);
if (this->first_has_higher_priority(parent, current)) {
break;
}
this->swap_indices(current, parent);
current = parent;
}
}
/**
* Inform the priority queue that the priority of the element at the given index has been
* changed.
*/
void priority_changed(const int64_t index)
{
this->priority_increased(index);
this->priority_decreased(index);
}
/**
* Returns the indices of all elements that are in the priority queue.
* There are no guarantees about the order of indices.
*/
Span<int64_t> active_indices() const
{
return heap_to_orig_.as_span().take_front(heap_size_);
}
/**
* Returns the indices of all elements that are not in the priority queue.
* The indices are in reverse order of their removal from the queue.
* I.e. the index that has been removed last, comes first.
*/
Span<int64_t> inactive_indices() const
{
return heap_to_orig_.as_span().drop_front(heap_size_);
}
/**
* Returns the concatenation of the active and inactive indices.
*/
Span<int64_t> all_indices() const
{
return heap_to_orig_;
}
/**
* Return the heap used by the priority queue as dot graph string.
* This exists for debugging purposes.
*/
std::string to_dot() const
{
return this->partial_to_dot(heap_size_);
}
private:
bool first_has_higher_priority(const int64_t a, const int64_t b)
{
const T &value_a = data_[heap_to_orig_[a]];
const T &value_b = data_[heap_to_orig_[b]];
return first_has_higher_priority_fn_(value_a, value_b);
}
void swap_indices(const int64_t a, const int64_t b)
{
std::swap(heap_to_orig_[a], heap_to_orig_[b]);
orig_to_heap_[heap_to_orig_[a]] = a;
orig_to_heap_[heap_to_orig_[b]] = b;
}
void heapify(const int64_t parent, const int64_t heap_size)
{
int64_t max_index = parent;
const int left = this->get_left(parent);
const int right = this->get_right(parent);
if (left < heap_size && this->first_has_higher_priority(left, max_index)) {
max_index = left;
}
if (right < heap_size && this->first_has_higher_priority(right, max_index)) {
max_index = right;
}
if (max_index != parent) {
this->swap_indices(parent, max_index);
this->heapify(max_index, heap_size);
}
if (left < heap_size) {
BLI_assert(!this->first_has_higher_priority(left, parent));
}
if (right < heap_size) {
BLI_assert(!this->first_has_higher_priority(right, parent));
}
}
int64_t get_parent(const int64_t child) const
{
BLI_assert(child > 0);
return (child - 1) / 2;
}
int64_t get_left(const int64_t parent) const
{
return parent * 2 + 1;
}
int64_t get_right(const int64_t parent) const
{
return parent * 2 + 2;
}
std::string partial_to_dot(const int size) const
{
dot::DirectedGraph digraph;
Array<dot::Node *> dot_nodes(size);
for (const int i : IndexRange(size)) {
std::stringstream ss;
ss << data_[heap_to_orig_[i]];
const std::string name = ss.str();
dot::Node &node = digraph.new_node(name);
node.set_shape(dot::Attr_shape::Rectangle);
node.attributes.set("ordering", "out");
dot_nodes[i] = &node;
if (i > 0) {
const int64_t parent = this->get_parent(i);
digraph.new_edge(*dot_nodes[parent], node);
}
}
return digraph.to_dot_string();
}
};
} // namespace blender

View File

@ -427,6 +427,25 @@ template<typename From, typename To>
inline constexpr bool is_convertible_pointer_v =
std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>;
/**
* Helper variable that checks if a Span<From> can be converted to Span<To> safely, whereby From
* and To are pointers. Adding const and casting to a void pointer is allowed.
* Casting up and down a class hierarchy generally is not allowed, because this might change the
* pointer under some circumstances.
*/
template<typename From, typename To>
inline constexpr bool is_span_convertible_pointer_v =
/* Make sure we are working with pointers. */
std::is_pointer_v<From> &&std::is_pointer_v<To> &&
(/* No casting is necessary when both types are the same. */
std::is_same_v<From, To> ||
/* Allow adding const to the underlying type. */
std::is_same_v<const std::remove_pointer_t<From>, std::remove_pointer_t<To>> ||
/* Allow casting non-const pointers to void pointers. */
(!std::is_const_v<std::remove_pointer_t<From>> && std::is_same_v<To, void *>) ||
/* Allow casting any pointer to const void pointers. */
std::is_same_v<To, const void *>);
/**
* Inline buffers for small-object-optimization should be disable by default. Otherwise we might
* get large unexpected allocations on the stack.

View File

@ -93,15 +93,15 @@ template<typename T> class Span {
/**
* Create a reference to an empty array.
*/
Span() = default;
constexpr Span() = default;
Span(const T *start, int64_t size) : data_(start), size_(size)
constexpr Span(const T *start, int64_t size) : data_(start), size_(size)
{
BLI_assert(size >= 0);
}
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
constexpr Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
{
BLI_assert(size >= 0);
}
@ -117,16 +117,17 @@ template<typename T> class Span {
* Span<int> span = {1, 2, 3, 4};
* call_function_with_array(span);
*/
Span(const std::initializer_list<T> &list)
constexpr Span(const std::initializer_list<T> &list)
: Span(list.begin(), static_cast<int64_t>(list.size()))
{
}
Span(const std::vector<T> &vector) : Span(vector.data(), static_cast<int64_t>(vector.size()))
constexpr Span(const std::vector<T> &vector)
: Span(vector.data(), static_cast<int64_t>(vector.size()))
{
}
template<std::size_t N> Span(const std::array<T, N> &array) : Span(array.data(), N)
template<std::size_t N> constexpr Span(const std::array<T, N> &array) : Span(array.data(), N)
{
}
@ -134,8 +135,9 @@ template<typename T> class Span {
* Support implicit conversions like the ones below:
* Span<T *> -> Span<const T *>
*/
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
constexpr Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
{
}
@ -143,7 +145,7 @@ template<typename T> class Span {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice does
* not stay within the bounds of the array.
*/
Span slice(int64_t start, int64_t size) const
constexpr Span slice(int64_t start, int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
@ -151,7 +153,7 @@ template<typename T> class Span {
return Span(data_ + start, size);
}
Span slice(IndexRange range) const
constexpr Span slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}
@ -160,7 +162,7 @@ template<typename T> class Span {
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
Span drop_front(int64_t n) const
constexpr Span drop_front(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@ -171,7 +173,7 @@ template<typename T> class Span {
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
Span drop_back(int64_t n) const
constexpr Span drop_back(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@ -182,7 +184,7 @@ template<typename T> class Span {
* Returns a new Span that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
Span take_front(int64_t n) const
constexpr Span take_front(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@ -193,7 +195,7 @@ template<typename T> class Span {
* Returns a new Span that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
Span take_back(int64_t n) const
constexpr Span take_back(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@ -204,25 +206,25 @@ template<typename T> class Span {
* Returns the pointer to the beginning of the referenced array. This may be nullptr when the
* size is zero.
*/
const T *data() const
constexpr const T *data() const
{
return data_;
}
const T *begin() const
constexpr const T *begin() const
{
return data_;
}
const T *end() const
constexpr const T *end() const
{
return data_ + size_;
}
std::reverse_iterator<const T *> rbegin() const
constexpr std::reverse_iterator<const T *> rbegin() const
{
return std::reverse_iterator<const T *>(this->end());
}
std::reverse_iterator<const T *> rend() const
constexpr std::reverse_iterator<const T *> rend() const
{
return std::reverse_iterator<const T *>(this->begin());
}
@ -231,7 +233,7 @@ template<typename T> class Span {
* Access an element in the array. This invokes undefined behavior when the index is out of
* bounds.
*/
const T &operator[](int64_t index) const
constexpr const T &operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
@ -241,7 +243,7 @@ template<typename T> class Span {
/**
* Returns the number of elements in the referenced array.
*/
int64_t size() const
constexpr int64_t size() const
{
return size_;
}
@ -249,7 +251,7 @@ template<typename T> class Span {
/**
* Returns true if the size is zero.
*/
bool is_empty() const
constexpr bool is_empty() const
{
return size_ == 0;
}
@ -257,7 +259,7 @@ template<typename T> class Span {
/**
* Returns the number of bytes referenced by this Span.
*/
int64_t size_in_bytes() const
constexpr int64_t size_in_bytes() const
{
return sizeof(T) * size_;
}
@ -266,7 +268,7 @@ template<typename T> class Span {
* Does a linear search to see of the value is in the array.
* Returns true if it is, otherwise false.
*/
bool contains(const T &value) const
constexpr bool contains(const T &value) const
{
for (const T &element : *this) {
if (element == value) {
@ -280,7 +282,7 @@ template<typename T> class Span {
* Does a constant time check to see if the pointer points to a value in the referenced array.
* Return true if it is, otherwise false.
*/
bool contains_ptr(const T *ptr) const
constexpr bool contains_ptr(const T *ptr) const
{
return (this->begin() <= ptr) && (ptr < this->end());
}
@ -289,7 +291,7 @@ template<typename T> class Span {
* Does a linear search to count how often the value is in the array.
* Returns the number of occurrences.
*/
int64_t count(const T &value) const
constexpr int64_t count(const T &value) const
{
int64_t counter = 0;
for (const T &element : *this) {
@ -304,7 +306,7 @@ template<typename T> class Span {
* Return a reference to the first element in the array. This invokes undefined behavior when the
* array is empty.
*/
const T &first() const
constexpr const T &first() const
{
BLI_assert(size_ > 0);
return data_[0];
@ -314,7 +316,7 @@ template<typename T> class Span {
* Returns a reference to the last element in the array. This invokes undefined behavior when the
* array is empty.
*/
const T &last() const
constexpr const T &last() const
{
BLI_assert(size_ > 0);
return data_[size_ - 1];
@ -324,7 +326,7 @@ template<typename T> class Span {
* Returns the element at the given index. If the index is out of range, return the fallback
* value.
*/
T get(int64_t index, const T &fallback) const
constexpr T get(int64_t index, const T &fallback) const
{
if (index < size_ && index >= 0) {
return data_[index];
@ -336,7 +338,7 @@ template<typename T> class Span {
* Check if the array contains duplicates. Does a linear search for every element. So the total
* running time is O(n^2). Only use this for small arrays.
*/
bool has_duplicates__linear_search() const
constexpr bool has_duplicates__linear_search() const
{
/* The size should really be smaller than that. If it is not, the calling code should be
* changed. */
@ -358,7 +360,7 @@ template<typename T> class Span {
* called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of
* the arrays.
*/
bool intersects__linear_search(Span other) const
constexpr bool intersects__linear_search(Span other) const
{
/* The size should really be smaller than that. If it is not, the calling code should be
* changed. */
@ -377,7 +379,7 @@ template<typename T> class Span {
* Returns the index of the first occurrence of the given value. This invokes undefined behavior
* when the value is not in the array.
*/
int64_t first_index(const T &search_value) const
constexpr int64_t first_index(const T &search_value) const
{
const int64_t index = this->first_index_try(search_value);
BLI_assert(index >= 0);
@ -387,7 +389,7 @@ template<typename T> class Span {
/**
* Returns the index of the first occurrence of the given value or -1 if it does not exist.
*/
int64_t first_index_try(const T &search_value) const
constexpr int64_t first_index_try(const T &search_value) const
{
for (int64_t i = 0; i < size_; i++) {
if (data_[i] == search_value) {
@ -401,7 +403,7 @@ template<typename T> class Span {
* Utility to make it more convenient to iterate over all indices that can be used with this
* array.
*/
IndexRange index_range() const
constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@ -409,7 +411,7 @@ template<typename T> class Span {
/**
* Returns a new Span to the same underlying memory buffer. No conversions are done.
*/
template<typename NewT> Span<NewT> cast() const
template<typename NewT> Span<NewT> constexpr cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
@ -450,21 +452,22 @@ template<typename T> class MutableSpan {
int64_t size_;
public:
MutableSpan() = default;
constexpr MutableSpan() = default;
MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
constexpr MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
{
}
MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
constexpr MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
{
}
template<std::size_t N> MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
template<std::size_t N>
constexpr MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
{
}
operator Span<T>() const
constexpr operator Span<T>() const
{
return Span<T>(data_, size_);
}
@ -472,7 +475,7 @@ template<typename T> class MutableSpan {
/**
* Returns the number of elements in the array.
*/
int64_t size() const
constexpr int64_t size() const
{
return size_;
}
@ -480,7 +483,7 @@ template<typename T> class MutableSpan {
/**
* Replace all elements in the referenced array with the given value.
*/
void fill(const T &value)
constexpr void fill(const T &value)
{
initialized_fill_n(data_, size_, value);
}
@ -489,7 +492,7 @@ template<typename T> class MutableSpan {
* Replace a subset of all elements with the given value. This invokes undefined behavior when
* one of the indices is out of bounds.
*/
void fill_indices(Span<int64_t> indices, const T &value)
constexpr void fill_indices(Span<int64_t> indices, const T &value)
{
for (int64_t i : indices) {
BLI_assert(i < size_);
@ -501,30 +504,30 @@ template<typename T> class MutableSpan {
* Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size
* is zero.
*/
T *data() const
constexpr T *data() const
{
return data_;
}
T *begin() const
constexpr T *begin() const
{
return data_;
}
T *end() const
constexpr T *end() const
{
return data_ + size_;
}
std::reverse_iterator<T *> rbegin() const
constexpr std::reverse_iterator<T *> rbegin() const
{
return std::reverse_iterator<T *>(this->end());
}
std::reverse_iterator<T *> rend() const
constexpr std::reverse_iterator<T *> rend() const
{
return std::reverse_iterator<T *>(this->begin());
}
T &operator[](const int64_t index) const
constexpr T &operator[](const int64_t index) const
{
BLI_assert(index < this->size());
return data_[index];
@ -534,7 +537,7 @@ template<typename T> class MutableSpan {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice would
* go out of bounds.
*/
MutableSpan slice(const int64_t start, const int64_t length) const
constexpr MutableSpan slice(const int64_t start, const int64_t length) const
{
BLI_assert(start + length <= this->size());
return MutableSpan(data_ + start, length);
@ -544,7 +547,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when the array is too small.
*/
MutableSpan drop_front(const int64_t n) const
constexpr MutableSpan drop_front(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(n, this->size() - n);
@ -554,7 +557,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan with n elements removed from the end. This invokes undefined
* behavior when the array is too small.
*/
MutableSpan drop_back(const int64_t n) const
constexpr MutableSpan drop_back(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(0, this->size() - n);
@ -564,7 +567,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
MutableSpan take_front(const int64_t n) const
constexpr MutableSpan take_front(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(0, n);
@ -574,7 +577,7 @@ template<typename T> class MutableSpan {
* Return a new MutableSpan that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
MutableSpan take_back(const int64_t n) const
constexpr MutableSpan take_back(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(this->size() - n, n);
@ -584,7 +587,7 @@ template<typename T> class MutableSpan {
* Returns an (immutable) Span that references the same array. This is usually not needed,
* due to implicit conversions. However, sometimes automatic type deduction needs some help.
*/
Span<T> as_span() const
constexpr Span<T> as_span() const
{
return Span<T>(data_, size_);
}
@ -593,7 +596,7 @@ template<typename T> class MutableSpan {
* Utility to make it more convenient to iterate over all indices that can be used with this
* array.
*/
IndexRange index_range() const
constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@ -602,7 +605,7 @@ template<typename T> class MutableSpan {
* Returns a reference to the last element. This invokes undefined behavior when the array is
* empty.
*/
T &last() const
constexpr T &last() const
{
BLI_assert(size_ > 0);
return data_[size_ - 1];
@ -612,7 +615,7 @@ template<typename T> class MutableSpan {
* Does a linear search to count how often the value is in the array.
* Returns the number of occurrences.
*/
int64_t count(const T &value) const
constexpr int64_t count(const T &value) const
{
int64_t counter = 0;
for (const T &element : *this) {
@ -628,7 +631,7 @@ template<typename T> class MutableSpan {
* destination contains uninitialized data and T is not trivially copy constructible.
* The size of both spans is expected to be the same.
*/
void copy_from(Span<T> values)
constexpr void copy_from(Span<T> values)
{
BLI_assert(size_ == values.size());
initialized_copy_n(values.data(), size_, data_);
@ -637,7 +640,7 @@ template<typename T> class MutableSpan {
/**
* Returns a new span to the same underlying memory buffer. No conversions are done.
*/
template<typename NewT> MutableSpan<NewT> cast() const
template<typename NewT> constexpr MutableSpan<NewT> cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
@ -648,7 +651,7 @@ template<typename T> class MutableSpan {
/**
* Utilities to check that arrays have the same size in debug builds.
*/
template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2 &v2)
template<typename T1, typename T2> constexpr void assert_same_size(const T1 &v1, const T2 &v2)
{
UNUSED_VARS_NDEBUG(v1, v2);
#ifdef DEBUG
@ -659,7 +662,7 @@ template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2
}
template<typename T1, typename T2, typename T3>
void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
{
UNUSED_VARS_NDEBUG(v1, v2, v3);
#ifdef DEBUG

View File

@ -64,7 +64,7 @@ class StringRefBase {
const char *data_;
int64_t size_;
StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
{
}
@ -75,12 +75,12 @@ class StringRefBase {
/**
* Return the (byte-)length of the referenced string, without any null-terminator.
*/
int64_t size() const
constexpr int64_t size() const
{
return size_;
}
bool is_empty() const
constexpr bool is_empty() const
{
return size_ == 0;
}
@ -88,12 +88,12 @@ class StringRefBase {
/**
* Return a pointer to the start of the string.
*/
const char *data() const
constexpr const char *data() const
{
return data_;
}
operator Span<char>() const
constexpr operator Span<char>() const
{
return Span<char>(data_, size_);
}
@ -107,22 +107,22 @@ class StringRefBase {
return std::string(data_, static_cast<size_t>(size_));
}
operator std::string_view() const
constexpr operator std::string_view() const
{
return std::string_view(data_, static_cast<size_t>(size_));
}
const char *begin() const
constexpr const char *begin() const
{
return data_;
}
const char *end() const
constexpr const char *end() const
{
return data_ + size_;
}
IndexRange index_range() const
constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@ -165,19 +165,19 @@ class StringRefBase {
/**
* Returns true when the string begins with the given prefix. Otherwise false.
*/
bool startswith(StringRef prefix) const;
constexpr bool startswith(StringRef prefix) const;
/**
* Returns true when the string ends with the given suffix. Otherwise false.
*/
bool endswith(StringRef suffix) const;
constexpr bool endswith(StringRef suffix) const;
StringRef substr(int64_t start, const int64_t size) const;
constexpr StringRef substr(int64_t start, const int64_t size) const;
/**
* Get the first char in the string. This invokes undefined behavior when the string is empty.
*/
const char &front() const
constexpr const char &front() const
{
BLI_assert(size_ >= 1);
return data_[0];
@ -186,7 +186,7 @@ class StringRefBase {
/**
* Get the last char in the string. This invokes undefined behavior when the string is empty.
*/
const char &back() const
constexpr const char &back() const
{
BLI_assert(size_ >= 1);
return data_[size_ - 1];
@ -196,18 +196,18 @@ class StringRefBase {
* The behavior of those functions matches the standard library implementation of
* std::string_view.
*/
int64_t find(char c, int64_t pos = 0) const;
int64_t find(StringRef str, int64_t pos = 0) const;
int64_t rfind(char c, int64_t pos = INT64_MAX) const;
int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
int64_t find_first_of(char c, int64_t pos = 0) const;
int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
int64_t find_first_not_of(char c, int64_t pos = 0) const;
int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
constexpr int64_t find(char c, int64_t pos = 0) const;
constexpr int64_t find(StringRef str, int64_t pos = 0) const;
constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const;
constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
constexpr int64_t find_first_of(char c, int64_t pos = 0) const;
constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const;
constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
};
/**
@ -216,7 +216,7 @@ class StringRefBase {
class StringRefNull : public StringRefBase {
public:
StringRefNull() : StringRefBase("", 0)
constexpr StringRefNull() : StringRefBase("", 0)
{
}
@ -226,7 +226,7 @@ class StringRefNull : public StringRefBase {
*/
StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
{
BLI_assert(str != NULL);
BLI_assert(str != nullptr);
BLI_assert(data_[size_] == '\0');
}
@ -234,7 +234,7 @@ class StringRefNull : public StringRefBase {
* Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
* when the given size is not the correct size of the string.
*/
StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
{
BLI_assert(static_cast<int64_t>(strlen(str)) == size);
}
@ -250,7 +250,7 @@ class StringRefNull : public StringRefBase {
/**
* Get the char at the given index.
*/
char operator[](const int64_t index) const
constexpr char operator[](const int64_t index) const
{
BLI_assert(index >= 0);
/* Use '<=' instead of just '<', so that the null character can be accessed as well. */
@ -263,7 +263,7 @@ class StringRefNull : public StringRefBase {
*
* This is like ->data(), but can only be called on a StringRefNull.
*/
const char *c_str() const
constexpr const char *c_str() const
{
return data_;
}
@ -274,25 +274,26 @@ class StringRefNull : public StringRefBase {
*/
class StringRef : public StringRefBase {
public:
StringRef() : StringRefBase(nullptr, 0)
constexpr StringRef() : StringRefBase(nullptr, 0)
{
}
/**
* StringRefNull can be converted into StringRef, but not the other way around.
*/
StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
{
}
/**
* Create a StringRef from a null-terminated c-string.
*/
StringRef(const char *str) : StringRefBase(str, str ? static_cast<int64_t>(strlen(str)) : 0)
constexpr StringRef(const char *str)
: StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
{
}
StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
{
}
@ -300,7 +301,7 @@ class StringRef : public StringRefBase {
* Create a StringRef from a start and end pointer. This invokes undefined behavior when the
* second point points to a smaller address than the first one.
*/
StringRef(const char *begin, const char *one_after_end)
constexpr StringRef(const char *begin, const char *one_after_end)
: StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
{
BLI_assert(begin <= one_after_end);
@ -314,7 +315,8 @@ class StringRef : public StringRefBase {
{
}
StringRef(std::string_view view) : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
constexpr StringRef(std::string_view view)
: StringRefBase(view.data(), static_cast<int64_t>(view.size()))
{
}
@ -323,7 +325,7 @@ class StringRef : public StringRefBase {
*
* This is similar to std::string_view::remove_prefix.
*/
StringRef drop_prefix(const int64_t n) const
constexpr StringRef drop_prefix(const int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= size_);
@ -334,7 +336,7 @@ class StringRef : public StringRefBase {
* Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
* the string does not begin with the given prefix.
*/
StringRef drop_prefix(StringRef prefix) const
constexpr StringRef drop_prefix(StringRef prefix) const
{
BLI_assert(this->startswith(prefix));
return this->drop_prefix(prefix.size());
@ -345,7 +347,7 @@ class StringRef : public StringRefBase {
*
* This is similar to std::string_view::remove_suffix.
*/
StringRef drop_suffix(const int64_t n) const
constexpr StringRef drop_suffix(const int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= size_);
@ -355,7 +357,7 @@ class StringRef : public StringRefBase {
/**
* Get the char at the given index.
*/
char operator[](int64_t index) const
constexpr char operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
@ -391,7 +393,7 @@ inline std::string operator+(StringRef a, StringRef b)
* not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
* std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
* Ideally, we only use StringRef in our code to avoid this problem altogether. */
inline bool operator==(StringRef a, StringRef b)
constexpr inline bool operator==(StringRef a, StringRef b)
{
if (a.size() != b.size()) {
return false;
@ -399,27 +401,27 @@ inline bool operator==(StringRef a, StringRef b)
return STREQLEN(a.data(), b.data(), (size_t)a.size());
}
inline bool operator!=(StringRef a, StringRef b)
constexpr inline bool operator!=(StringRef a, StringRef b)
{
return !(a == b);
}
inline bool operator<(StringRef a, StringRef b)
constexpr inline bool operator<(StringRef a, StringRef b)
{
return std::string_view(a) < std::string_view(b);
}
inline bool operator>(StringRef a, StringRef b)
constexpr inline bool operator>(StringRef a, StringRef b)
{
return std::string_view(a) > std::string_view(b);
}
inline bool operator<=(StringRef a, StringRef b)
constexpr inline bool operator<=(StringRef a, StringRef b)
{
return std::string_view(a) <= std::string_view(b);
}
inline bool operator>=(StringRef a, StringRef b)
constexpr inline bool operator>=(StringRef a, StringRef b)
{
return std::string_view(a) >= std::string_view(b);
}
@ -427,7 +429,7 @@ inline bool operator>=(StringRef a, StringRef b)
/**
* Return true when the string starts with the given prefix.
*/
inline bool StringRefBase::startswith(StringRef prefix) const
constexpr inline bool StringRefBase::startswith(StringRef prefix) const
{
if (size_ < prefix.size_) {
return false;
@ -443,7 +445,7 @@ inline bool StringRefBase::startswith(StringRef prefix) const
/**
* Return true when the string ends with the given suffix.
*/
inline bool StringRefBase::endswith(StringRef suffix) const
constexpr inline bool StringRefBase::endswith(StringRef suffix) const
{
if (size_ < suffix.size_) {
return false;
@ -460,8 +462,8 @@ inline bool StringRefBase::endswith(StringRef suffix) const
/**
* Return a new #StringRef containing only a sub-string of the original string.
*/
inline StringRef StringRefBase::substr(const int64_t start,
const int64_t max_size = INT64_MAX) const
constexpr inline StringRef StringRefBase::substr(const int64_t start,
const int64_t max_size = INT64_MAX) const
{
BLI_assert(max_size >= 0);
BLI_assert(start >= 0);
@ -469,7 +471,7 @@ inline StringRef StringRefBase::substr(const int64_t start,
return StringRef(data_ + start, substr_size);
}
inline int64_t index_or_npos_to_int64(size_t index)
constexpr inline int64_t index_or_npos_to_int64(size_t index)
{
/* The compiler will probably optimize this check away. */
if (index == std::string_view::npos) {
@ -478,62 +480,62 @@ inline int64_t index_or_npos_to_int64(size_t index)
return static_cast<int64_t>(index);
}
inline int64_t StringRefBase::find(char c, int64_t pos) const
constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
}
inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
}
inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
}
inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
{
return this->find_first_of(StringRef(&c, 1), pos);
}
inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
}
inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
{
return this->find_last_of(StringRef(&c, 1), pos);
}
inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
}
inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
{
return this->find_first_not_of(StringRef(&c, 1), pos);
}
inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
}
inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
{
return this->find_last_not_of(StringRef(&c, 1), pos);
}

View File

@ -35,7 +35,6 @@ extern "C" {
#define BLENDER_MAX_THREADS 1024
struct ListBase;
struct TaskScheduler;
/* Threading API */

View File

@ -315,13 +315,13 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator Span<U>() const
{
return Span<U>(begin_, this->size());
}
template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator MutableSpan<U>()
{
return MutableSpan<U>(begin_, this->size());

View File

@ -203,6 +203,7 @@ set(SRC
BLI_heap_simple.h
BLI_index_mask.hh
BLI_index_range.hh
BLI_inplace_priority_queue.hh
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@ -390,6 +391,7 @@ if(WITH_GTESTS)
tests/BLI_heap_test.cc
tests/BLI_index_mask_test.cc
tests/BLI_index_range_test.cc
tests/BLI_inplace_priority_queue_test.cc
tests/BLI_kdopbvh_test.cc
tests/BLI_linear_allocator_test.cc
tests/BLI_linklist_lockfree_test.cc

View File

@ -140,4 +140,11 @@ TEST(index_range, AsSpan)
EXPECT_EQ(span[3], 7);
}
TEST(index_range, constexpr_)
{
constexpr IndexRange range = IndexRange(1, 1);
std::array<int, range[0]> compiles = {1};
BLI_STATIC_ASSERT(range.size() == 1, "");
EXPECT_EQ(compiles[0], 1);
}
} // namespace blender::tests

View File

@ -0,0 +1,113 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_inplace_priority_queue.hh"
#include "BLI_rand.hh"
namespace blender::tests {
TEST(inplace_priority_queue, BuildSmall)
{
Array<int> values = {1, 5, 2, 8, 5, 6, 5, 4, 3, 6, 7, 3};
InplacePriorityQueue<int> priority_queue{values};
EXPECT_EQ(priority_queue.peek(), 8);
EXPECT_EQ(priority_queue.pop(), 8);
EXPECT_EQ(priority_queue.peek(), 7);
EXPECT_EQ(priority_queue.pop(), 7);
EXPECT_EQ(priority_queue.pop(), 6);
EXPECT_EQ(priority_queue.pop(), 6);
EXPECT_EQ(priority_queue.pop(), 5);
}
TEST(inplace_priority_queue, DecreasePriority)
{
Array<int> values = {5, 2, 7, 4};
InplacePriorityQueue<int> priority_queue(values);
EXPECT_EQ(priority_queue.peek(), 7);
values[2] = 0;
EXPECT_EQ(priority_queue.peek(), 0);
priority_queue.priority_decreased(2);
EXPECT_EQ(priority_queue.peek(), 5);
}
TEST(inplace_priority_queue, IncreasePriority)
{
Array<int> values = {5, 2, 7, 4};
InplacePriorityQueue<int> priority_queue(values);
EXPECT_EQ(priority_queue.peek(), 7);
values[1] = 10;
EXPECT_EQ(priority_queue.peek(), 7);
priority_queue.priority_increased(1);
EXPECT_EQ(priority_queue.peek(), 10);
}
TEST(inplace_priority_queue, PopAll)
{
RandomNumberGenerator rng;
Vector<int> values;
const int amount = 1000;
for (int i = 0; i < amount; i++) {
values.append(rng.get_int32() % amount);
}
InplacePriorityQueue<int> priority_queue(values);
int last_value = amount;
while (!priority_queue.is_empty()) {
const int value = priority_queue.pop();
EXPECT_LE(value, last_value);
last_value = value;
}
}
TEST(inplace_priority_queue, ManyPriorityChanges)
{
RandomNumberGenerator rng;
Vector<int> values;
const int amount = 1000;
for (int i = 0; i < amount; i++) {
values.append(rng.get_int32() % amount);
}
InplacePriorityQueue<int> priority_queue(values);
for (int i = 0; i < amount; i++) {
const int index = rng.get_int32() % amount;
const int new_priority = rng.get_int32() % amount;
values[index] = new_priority;
priority_queue.priority_changed(index);
}
int last_value = amount;
while (!priority_queue.is_empty()) {
const int value = priority_queue.pop();
EXPECT_LE(value, last_value);
last_value = value;
}
}
TEST(inplace_priority_queue, IndicesAccess)
{
Array<int> values = {4, 6, 2, 4, 8, 1, 10, 2, 5};
InplacePriorityQueue<int> priority_queue(values);
EXPECT_EQ(priority_queue.active_indices().size(), 9);
EXPECT_EQ(priority_queue.inactive_indices().size(), 0);
EXPECT_EQ(priority_queue.all_indices().size(), 9);
EXPECT_EQ(priority_queue.pop(), 10);
EXPECT_EQ(priority_queue.active_indices().size(), 8);
EXPECT_EQ(priority_queue.inactive_indices().size(), 1);
EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 10);
EXPECT_EQ(priority_queue.all_indices().size(), 9);
EXPECT_EQ(priority_queue.pop(), 8);
EXPECT_EQ(priority_queue.inactive_indices().size(), 2);
EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 8);
EXPECT_EQ(values[priority_queue.inactive_indices()[1]], 10);
EXPECT_EQ(priority_queue.all_indices().size(), 9);
}
} // namespace blender::tests

View File

@ -158,4 +158,15 @@ static_assert(is_convertible_pointer_v<int **, int **const>);
static_assert(is_convertible_pointer_v<int **, int *const *>);
static_assert(is_convertible_pointer_v<int **, int const *const *>);
static_assert(is_span_convertible_pointer_v<int *, int *>);
static_assert(is_span_convertible_pointer_v<int *, const int *>);
static_assert(!is_span_convertible_pointer_v<const int *, int *>);
static_assert(is_span_convertible_pointer_v<const int *, const int *>);
static_assert(is_span_convertible_pointer_v<const int *, const void *>);
static_assert(!is_span_convertible_pointer_v<const int *, void *>);
static_assert(is_span_convertible_pointer_v<int *, void *>);
static_assert(is_span_convertible_pointer_v<int *, const void *>);
static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
} // namespace blender::tests

View File

@ -337,4 +337,19 @@ TEST(span, MutableReverseIterator)
EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4);
}
TEST(span, constexpr_)
{
static constexpr std::array<int, 3> src = {3, 2, 1};
constexpr Span<int> span(src);
BLI_STATIC_ASSERT(span[2] == 1, "");
BLI_STATIC_ASSERT(span.size() == 3, "");
BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, "");
BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, "");
std::integral_constant<bool, span.first_index(1) == 2> ic;
BLI_STATIC_ASSERT(ic.value, "");
EXPECT_EQ(span.slice(1, 2).size(), 2);
}
} // namespace blender::tests

View File

@ -298,4 +298,12 @@ TEST(string_ref, ToStringView)
EXPECT_EQ(view, "hello");
}
TEST(string_ref, constexpr_)
{
constexpr StringRef sref("World");
BLI_STATIC_ASSERT(sref[2] == 'r', "");
BLI_STATIC_ASSERT(sref.size() == 5, "");
std::array<int, static_cast<std::size_t>(sref.find_first_of('o'))> compiles = {1};
EXPECT_EQ(compiles[0], 1);
}
} // namespace blender::tests

View File

@ -34,16 +34,13 @@
#include "zlib.h"
struct BLOCacheStorage;
struct GSet;
struct IDNameLib_Map;
struct Key;
struct MemFile;
struct Object;
struct OldNewMap;
struct PartEff;
struct ReportList;
struct UserDef;
struct View3D;
typedef struct IDNameLib_Map IDNameLib_Map;

View File

@ -1234,18 +1234,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, 7)) {
/* Make all IDProperties used as interface of geometry node trees overridable. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
@ -1301,5 +1290,39 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
/* Overlay elements in the sequencer. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
sseq->flag |= (SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_SOURCE |
SEQ_SHOW_STRIP_DURATION);
}
}
}
}
}
/**
* 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. */
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (STREQ(node->idname, "GeometryNodeRandomAttribute")) {
STRNCPY(node->idname, "GeometryNodeAttributeRandomize");
}
}
}
}
}

View File

@ -182,7 +182,8 @@ static void blo_update_defaults_screen(bScreen *screen,
}
else if (area->spacetype == SPACE_SEQ) {
SpaceSeq *seq = area->spacedata.first;
seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT;
seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY |
SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_DURATION;
}
else if (area->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */

View File

@ -39,7 +39,6 @@ struct Main;
struct Object;
struct Scene;
struct Simulation;
struct ViewLayer;
struct bNodeTree;
#include "BLI_sys_types.h"

View File

@ -45,7 +45,6 @@
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
struct Base;
struct CacheFile;
struct Camera;
struct Collection;

View File

@ -25,8 +25,6 @@
#pragma once
struct Main;
namespace blender {
namespace deg {

View File

@ -24,14 +24,14 @@
#include "BLI_sys_types.h" /* for bool */
struct BlendDataReader;
struct BlendWriter;
struct EEVEE_Data;
struct EEVEE_ViewLayerData;
struct LightCache;
struct Scene;
struct SceneEEVEE;
struct ViewLayer;
struct BlendWriter;
struct BlendDataReader;
/* Light Bake */
struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,

View File

@ -39,10 +39,7 @@ extern DrawEngineType draw_engine_gpencil_type;
struct GPENCIL_Data;
struct GPENCIL_StorageList;
struct GPUBatch;
struct GPUVertBuf;
struct GPUVertFormat;
struct GpencilBatchCache;
struct MaterialGPencilStyle;
struct Object;
struct RenderEngine;
struct RenderLayer;

View File

@ -25,11 +25,9 @@ extern "C" {
#endif
/* Forward declarations */
struct GPUBatch;
struct GPUTexture;
struct ImBuf;
struct Image;
struct rcti;
/* *********** LISTS *********** */

View File

@ -64,7 +64,6 @@
#include "DEG_depsgraph.h"
struct GPUBatch;
struct GPUFrameBuffer;
struct GPUMaterial;
struct GPUShader;
struct GPUTexture;

View File

@ -22,10 +22,8 @@
#pragma once
struct DRWPass;
struct DRWShadingGroup;
struct FluidModifierData;
struct GPUMaterial;
struct ModifierData;
struct Object;
struct ParticleSystem;

View File

@ -2073,7 +2073,6 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
* for the image editor this is when showing UV's.*/
const bool do_populate_loop = (DST.draw_ctx.space_data->spacetype == SPACE_IMAGE);
const bool do_annotations = drw_draw_show_annotation();
const bool do_region_callbacks = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE);
const bool do_draw_gizmos = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE);
/* Get list of enabled engines */
@ -2125,7 +2124,7 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
/* Start Drawing */
DRW_state_reset();
if (do_region_callbacks && DST.draw_ctx.evil_C) {
if (DST.draw_ctx.evil_C) {
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_PRE_VIEW);
}
@ -2147,10 +2146,8 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
if (do_annotations) {
ED_annotation_draw_view2d(DST.draw_ctx.evil_C, true);
}
if (do_region_callbacks) {
GPU_depth_test(GPU_DEPTH_NONE);
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
}
GPU_depth_test(GPU_DEPTH_NONE);
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
GPU_matrix_pop_projection();
/* Callback can be nasty and do whatever they want with the state.
* Don't trust them! */

View File

@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
tgpil->gpl = gpl;
tgpil->prevFrame = gpl->actframe;
tgpil->nextFrame = gpl->actframe->next;
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
BLI_addtail(&tgpi->ilayers, tgpil);
@ -326,24 +326,25 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
valid = false;
}
/* create new stroke */
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
if (valid) {
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
new_stroke->points = MEM_recallocN(new_stroke->points,
sizeof(*new_stroke->points) * gps_to->totpoints);
if (new_stroke->dvert != NULL) {
new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
sizeof(*new_stroke->dvert) * gps_to->totpoints);
}
new_stroke->totpoints = gps_to->totpoints;
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
}
/* update points position */
if (gps_to->totpoints > gps_from->totpoints) {
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
}
/* Create new stroke. */
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* Update points position. */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
}
else {
/* Create new stroke. */
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* need an empty stroke to keep index correct for lookup, but resize to smallest size */
new_stroke->totpoints = 0;
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
@ -443,12 +444,16 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
/* finally, free memory used by temp data */
LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
BKE_gpencil_free_strokes(tgpil->prevFrame);
BKE_gpencil_free_strokes(tgpil->nextFrame);
BKE_gpencil_free_strokes(tgpil->interFrame);
MEM_freeN(tgpil->interFrame);
MEM_SAFE_FREE(tgpil->prevFrame);
MEM_SAFE_FREE(tgpil->nextFrame);
MEM_SAFE_FREE(tgpil->interFrame);
}
BLI_freelistN(&tgpi->ilayers);
MEM_freeN(tgpi);
MEM_SAFE_FREE(tgpi);
}
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@ -992,8 +997,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* store extremes */
prevFrame = gpl->actframe;
nextFrame = gpl->actframe->next;
prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
/* Loop over intermediary frames and create the interpolation */
for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) {
@ -1049,27 +1054,16 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
}
/* create new stroke */
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
/* free weights of removed points */
if (new_stroke->dvert != NULL) {
BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints,
gps_from->totpoints - gps_to->totpoints);
}
new_stroke->points = MEM_recallocN(new_stroke->points,
sizeof(*new_stroke->points) * gps_to->totpoints);
if (new_stroke->dvert != NULL) {
new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
sizeof(*new_stroke->dvert) * gps_to->totpoints);
}
new_stroke->totpoints = gps_to->totpoints;
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
}
if (gps_to->totpoints > gps_from->totpoints) {
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
}
/* create new stroke */
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* update points position */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
@ -1081,6 +1075,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
BLI_addtail(&interFrame->strokes, new_stroke);
}
}
BKE_gpencil_free_strokes(prevFrame);
BKE_gpencil_free_strokes(nextFrame);
MEM_SAFE_FREE(prevFrame);
MEM_SAFE_FREE(nextFrame);
}
/* notifiers */

View File

@ -31,7 +31,6 @@ struct Base;
struct Bone;
struct Depsgraph;
struct EditBone;
struct IDProperty;
struct ListBase;
struct Main;
struct Mesh;

View File

@ -28,8 +28,9 @@ extern "C" {
#endif
struct ARegion;
struct FileSelectParams;
struct FileAssetSelectParams;
struct FileSelectParams;
struct FileDirEntry;
struct Scene;
struct ScrArea;
struct SpaceFile;
@ -154,6 +155,7 @@ struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
int ED_path_extension_type(const char *path);
int ED_file_extension_icon(const char *path);
int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);

View File

@ -51,7 +51,6 @@ struct ScrArea;
struct SnapObjectContext;
struct ToolSettings;
struct View3D;
struct ViewLayer;
struct bContext;
struct Material;

View File

@ -34,12 +34,10 @@ struct ARegion;
struct ImBuf;
struct Image;
struct ImageUser;
struct LinkNodePair;
struct Main;
struct ReportList;
struct Scene;
struct SpaceImage;
struct ViewLayer;
struct bContext;
struct wmOperator;
struct wmWindowManager;

View File

@ -53,7 +53,6 @@ struct uiLayout;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
/* object_edit.c */
/* context.object */

View File

@ -239,6 +239,7 @@ void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
void ED_screen_full_restore(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_state_maximized_create(struct bContext *C);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,

View File

@ -32,7 +32,6 @@ extern "C" {
struct Object;
struct bContext;
struct wmKeyConfig;
struct wmMsgBus;
struct wmOperatorType;
void ED_keymap_transform(struct wmKeyConfig *keyconf);
@ -108,7 +107,6 @@ bool calculateTransformCenter(struct bContext *C,
struct Object;
struct Scene;
struct wmGizmoGroup;
struct wmGizmoGroupType;
/* UNUSED */

View File

@ -31,7 +31,6 @@ struct BMVert;
struct ARegion;
struct Depsgraph;
struct ListBase;
struct Main;
struct Object;
struct Scene;
struct View3D;

View File

@ -54,6 +54,7 @@ void ED_spacedata_id_remap(struct ScrArea *area,
void ED_OT_flush_edits(struct wmOperatorType *ot);
void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot);
void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot);
/* ************** XXX OLD CRUFT WARNING ************* */

View File

@ -31,7 +31,6 @@ extern "C" {
#endif
struct ARegion;
struct Main;
struct bContext;
struct wmEvent;
struct wmOperator;

Some files were not shown because too many files have changed in this diff Show More