Fix #105430: Curves pick select selects multiple objects #105495
|
@ -2,4 +2,4 @@ ${CommitTitle}
|
|||
|
||||
${CommitBody}
|
||||
|
||||
Pull Request #${PullRequestIndex}
|
||||
Pull Request: https://projects.blender.org/blender/blender/pulls/${PullRequestIndex}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
${PullRequestTitle}
|
||||
|
||||
Pull Request #${PullRequestIndex}
|
||||
Pull Request: https://projects.blender.org/blender/blender/pulls/${PullRequestIndex}
|
||||
|
|
|
@ -1673,7 +1673,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
driver_version = "470"
|
||||
col.label(text=iface_("Requires NVIDIA GPU with compute capability %s") % compute_capability,
|
||||
icon='BLANK1', translate=False)
|
||||
col.label(text="and NVIDIA driver version %s or newer" % driver_version,
|
||||
col.label(text=iface_("and NVIDIA driver version %s or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif device_type == 'HIP':
|
||||
import sys
|
||||
|
@ -1716,7 +1716,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
.replace('(TM)', unicodedata.lookup('TRADE MARK SIGN'))
|
||||
.replace('(tm)', unicodedata.lookup('TRADE MARK SIGN'))
|
||||
.replace('(R)', unicodedata.lookup('REGISTERED SIGN'))
|
||||
.replace('(C)', unicodedata.lookup('COPYRIGHT SIGN'))
|
||||
.replace('(C)', unicodedata.lookup('COPYRIGHT SIGN')),
|
||||
translate=False
|
||||
)
|
||||
|
||||
def draw_impl(self, layout, context):
|
||||
|
|
|
@ -161,25 +161,12 @@ ShaderCache::~ShaderCache()
|
|||
running = false;
|
||||
cond_var.notify_all();
|
||||
|
||||
int num_incomplete = int(incomplete_requests);
|
||||
if (num_incomplete) {
|
||||
/* Shutting down the app with incomplete shader compilation requests. Give 1 second's grace for
|
||||
* clean shutdown. */
|
||||
metal_printf("ShaderCache busy (incomplete_requests = %d)...\n", num_incomplete);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
num_incomplete = int(incomplete_requests);
|
||||
}
|
||||
|
||||
if (num_incomplete && !MetalDeviceKernels::is_benchmark_warmup()) {
|
||||
metal_printf("ShaderCache still busy (incomplete_requests = %d). Terminating...\n",
|
||||
num_incomplete);
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
metal_printf("ShaderCache idle. Shutting down.\n");
|
||||
metal_printf("Waiting for ShaderCache threads... (incomplete_requests = %d)\n",
|
||||
int(incomplete_requests));
|
||||
for (auto &thread : compile_threads) {
|
||||
thread.join();
|
||||
}
|
||||
metal_printf("ShaderCache shut down.\n");
|
||||
}
|
||||
|
||||
void ShaderCache::wait_for_all()
|
||||
|
@ -675,7 +662,9 @@ void MetalKernelPipeline::compile()
|
|||
}
|
||||
}
|
||||
|
||||
__block bool creating_new_archive = false;
|
||||
bool creating_new_archive = false;
|
||||
bool recreate_archive = false;
|
||||
|
||||
if (@available(macOS 11.0, *)) {
|
||||
if (use_binary_archive) {
|
||||
if (!archive) {
|
||||
|
@ -684,51 +673,101 @@ void MetalKernelPipeline::compile()
|
|||
archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
|
||||
creating_new_archive = true;
|
||||
}
|
||||
computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
|
||||
pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss;
|
||||
else {
|
||||
pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss;
|
||||
computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Lambda to do the actual pipeline compilation. */
|
||||
auto do_compilation = [&]() {
|
||||
__block bool compilation_finished = false;
|
||||
__block string error_str;
|
||||
|
||||
if (archive && path_exists(metalbin_path)) {
|
||||
/* Use the blocking variant of newComputePipelineStateWithDescriptor if an archive exists on
|
||||
* disk. It should load almost instantaneously, and will fail gracefully when loading a
|
||||
* corrupt archive (unlike the async variant). */
|
||||
NSError *error = nil;
|
||||
pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
|
||||
options:pipelineOptions
|
||||
reflection:nullptr
|
||||
error:&error];
|
||||
const char *err = error ? [[error localizedDescription] UTF8String] : nullptr;
|
||||
error_str = err ? err : "nil";
|
||||
}
|
||||
else {
|
||||
/* Use the async variant of newComputePipelineStateWithDescriptor if no archive exists on
|
||||
* disk. This allows us responds to app shutdown. */
|
||||
[mtlDevice
|
||||
newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
|
||||
options:pipelineOptions
|
||||
completionHandler:^(id<MTLComputePipelineState> computePipelineState,
|
||||
MTLComputePipelineReflection *reflection,
|
||||
NSError *error) {
|
||||
pipeline = computePipelineState;
|
||||
|
||||
/* Retain the pipeline so we can use it safely past the completion
|
||||
* handler. */
|
||||
if (pipeline) {
|
||||
[pipeline retain];
|
||||
}
|
||||
const char *err = error ?
|
||||
[[error localizedDescription] UTF8String] :
|
||||
nullptr;
|
||||
error_str = err ? err : "nil";
|
||||
|
||||
compilation_finished = true;
|
||||
}];
|
||||
|
||||
/* Immediately wait for either the compilation to finish or for app shutdown. */
|
||||
while (ShaderCache::running && !compilation_finished) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
}
|
||||
|
||||
if (creating_new_archive && pipeline && ShaderCache::running) {
|
||||
/* Add pipeline into the new archive. It should be instantaneous following
|
||||
* newComputePipelineStateWithDescriptor. */
|
||||
NSError *error;
|
||||
|
||||
computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
|
||||
if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
|
||||
error:&error]) {
|
||||
NSString *errStr = [error localizedDescription];
|
||||
metal_printf("Failed to add PSO to archive:\n%s\n", errStr ? [errStr UTF8String] : "nil");
|
||||
}
|
||||
}
|
||||
else if (!pipeline) {
|
||||
metal_printf(
|
||||
"newComputePipelineStateWithDescriptor failed for \"%s\"%s. "
|
||||
"Error:\n%s\n",
|
||||
device_kernel_as_string((DeviceKernel)device_kernel),
|
||||
(archive && !recreate_archive) ? " Archive may be incomplete or corrupt - attempting "
|
||||
"recreation.." :
|
||||
"",
|
||||
error_str.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
double starttime = time_dt();
|
||||
|
||||
/* Block on load to ensure we continue with a valid kernel function */
|
||||
if (creating_new_archive) {
|
||||
starttime = time_dt();
|
||||
NSError *error;
|
||||
if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
|
||||
error:&error]) {
|
||||
NSString *errStr = [error localizedDescription];
|
||||
metal_printf("Failed to add PSO to archive:\n%s\n", errStr ? [errStr UTF8String] : "nil");
|
||||
}
|
||||
}
|
||||
do_compilation();
|
||||
|
||||
pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
|
||||
options:pipelineOptions
|
||||
reflection:nullptr
|
||||
error:&error];
|
||||
|
||||
bool recreate_archive = false;
|
||||
/* An archive might have a corrupt entry and fail to materialize the pipeline. This shouldn't
|
||||
* happen, but if it does we recreate it. */
|
||||
if (pipeline == nil && archive) {
|
||||
NSString *errStr = [error localizedDescription];
|
||||
metal_printf(
|
||||
"Failed to create compute pipeline state \"%s\" from archive - attempting recreation... "
|
||||
"(error: %s)\n",
|
||||
device_kernel_as_string((DeviceKernel)device_kernel),
|
||||
errStr ? [errStr UTF8String] : "nil");
|
||||
pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
|
||||
options:MTLPipelineOptionNone
|
||||
reflection:nullptr
|
||||
error:&error];
|
||||
recreate_archive = true;
|
||||
pipelineOptions = MTLPipelineOptionNone;
|
||||
path_remove(metalbin_path);
|
||||
|
||||
do_compilation();
|
||||
}
|
||||
|
||||
double duration = time_dt() - starttime;
|
||||
|
||||
if (pipeline == nil) {
|
||||
NSString *errStr = [error localizedDescription];
|
||||
error_str = string_printf("Failed to create compute pipeline state \"%s\", error: \n",
|
||||
device_kernel_as_string((DeviceKernel)device_kernel));
|
||||
error_str += (errStr ? [errStr UTF8String] : "nil");
|
||||
metal_printf("%16s | %2d | %-55s | %7.2fs | FAILED!\n",
|
||||
kernel_type_as_string(pso_type),
|
||||
device_kernel,
|
||||
|
@ -748,7 +787,8 @@ void MetalKernelPipeline::compile()
|
|||
if (creating_new_archive || recreate_archive) {
|
||||
if (![archive serializeToURL:[NSURL fileURLWithPath:@(metalbin_path.c_str())]
|
||||
error:&error]) {
|
||||
metal_printf("Failed to save binary archive, error:\n%s\n",
|
||||
metal_printf("Failed to save binary archive to %s, error:\n%s\n",
|
||||
metalbin_path.c_str(),
|
||||
[[error localizedDescription] UTF8String]);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef __FFMPEG_COMPAT_H__
|
||||
#define __FFMPEG_COMPAT_H__
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
/* Check if our ffmpeg is new enough, avoids user complaints.
|
||||
|
|
|
@ -20,11 +20,13 @@ enum TransformType {
|
|||
TRANSFORM_SRGB_TO_LINEAR,
|
||||
TRANSFORM_SCALE,
|
||||
TRANSFORM_EXPONENT,
|
||||
TRANSFORM_NONE,
|
||||
TRANSFORM_UNKNOWN,
|
||||
};
|
||||
|
||||
#define COLORSPACE_LINEAR ((OCIO_ConstColorSpaceRcPtr *)1)
|
||||
#define COLORSPACE_SRGB ((OCIO_ConstColorSpaceRcPtr *)2)
|
||||
#define COLORSPACE_DATA ((OCIO_ConstColorSpaceRcPtr *)3)
|
||||
|
||||
typedef struct OCIO_PackedImageDescription {
|
||||
float *data;
|
||||
|
@ -165,6 +167,8 @@ OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcP
|
|||
return COLORSPACE_LINEAR;
|
||||
else if (strcmp(name, "sRGB") == 0)
|
||||
return COLORSPACE_SRGB;
|
||||
else if (strcmp(name, "data") == 0)
|
||||
return COLORSPACE_DATA;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -179,6 +183,9 @@ int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, con
|
|||
else if (cs == COLORSPACE_SRGB) {
|
||||
return 1;
|
||||
}
|
||||
else if (cs == COLORSPACE_DATA) {
|
||||
return 2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -314,7 +321,10 @@ OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstCo
|
|||
OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName);
|
||||
OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName);
|
||||
FallbackTransform transform;
|
||||
if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) {
|
||||
if (cs_src == COLORSPACE_DATA || cs_dst == COLORSPACE_DATA) {
|
||||
transform.type = TRANSFORM_NONE;
|
||||
}
|
||||
else if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) {
|
||||
transform.type = TRANSFORM_LINEAR_TO_SRGB;
|
||||
}
|
||||
else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) {
|
||||
|
@ -433,6 +443,9 @@ const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
|
|||
else if (cs == COLORSPACE_SRGB) {
|
||||
return "sRGB";
|
||||
}
|
||||
else if (cs == COLORSPACE_DATA) {
|
||||
return "data";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -692,6 +692,15 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
else:
|
||||
continue
|
||||
|
||||
# Skip function if it's marked as not translatable.
|
||||
do_translate = True
|
||||
for kw in node.keywords:
|
||||
if kw.arg == "translate" and not kw.value.value:
|
||||
do_translate = False
|
||||
break
|
||||
if not do_translate:
|
||||
continue
|
||||
|
||||
func_args = func_translate_args.get(func_id, {})
|
||||
|
||||
# First try to get i18n contexts, for every possible msgid id.
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
import bpy
|
||||
from bpy.types import Menu
|
||||
from bl_ui import node_add_menu
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
|
||||
|
||||
class NODE_MT_geometry_node_GEO_ATTRIBUTE(Menu):
|
||||
|
@ -238,6 +241,7 @@ class NODE_MT_geometry_node_GEO_INPUT(Menu):
|
|||
class NODE_MT_geometry_node_GEO_INPUT_CONSTANT(Menu):
|
||||
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_CONSTANT"
|
||||
bl_label = "Constant"
|
||||
bl_translation_context = i18n_contexts.id_nodetree
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -745,6 +745,8 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
|
|||
row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS')
|
||||
|
||||
layout.prop(asset_file_handle.asset_data, "description")
|
||||
layout.prop(asset_file_handle.asset_data, "license")
|
||||
layout.prop(asset_file_handle.asset_data, "copyright")
|
||||
layout.prop(asset_file_handle.asset_data, "author")
|
||||
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ class TEXT_HT_footer(Header):
|
|||
text=iface_("Text: External")
|
||||
if text.library
|
||||
else iface_("Text: Internal"),
|
||||
translate=False
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ AssetMetaData::~AssetMetaData()
|
|||
}
|
||||
MEM_SAFE_FREE(author);
|
||||
MEM_SAFE_FREE(description);
|
||||
MEM_SAFE_FREE(copyright);
|
||||
MEM_SAFE_FREE(license);
|
||||
BLI_freelistN(&tags);
|
||||
}
|
||||
|
||||
|
@ -161,13 +163,19 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
|
|||
if (asset_data->properties) {
|
||||
IDP_BlendWrite(writer, asset_data->properties);
|
||||
}
|
||||
|
||||
if (asset_data->author) {
|
||||
BLO_write_string(writer, asset_data->author);
|
||||
}
|
||||
if (asset_data->description) {
|
||||
BLO_write_string(writer, asset_data->description);
|
||||
}
|
||||
if (asset_data->copyright) {
|
||||
BLO_write_string(writer, asset_data->copyright);
|
||||
}
|
||||
if (asset_data->license) {
|
||||
BLO_write_string(writer, asset_data->license);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (AssetTag *, tag, &asset_data->tags) {
|
||||
BLO_write_struct(writer, AssetTag, tag);
|
||||
}
|
||||
|
@ -185,6 +193,8 @@ void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
|
|||
|
||||
BLO_read_data_address(reader, &asset_data->author);
|
||||
BLO_read_data_address(reader, &asset_data->description);
|
||||
BLO_read_data_address(reader, &asset_data->copyright);
|
||||
BLO_read_data_address(reader, &asset_data->license);
|
||||
BLO_read_list(reader, &asset_data->tags);
|
||||
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ static bool library_foreach_ID_link(Main *bmain,
|
|||
}
|
||||
|
||||
if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY) &&
|
||||
(flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) == 0 &&
|
||||
(flag & (IDWALK_DO_INTERNAL_RUNTIME_POINTERS | IDWALK_DO_LIBRARY_POINTER)) == 0 &&
|
||||
(((bmain->relations->flag & MAINIDRELATIONS_INCLUDE_UI) == 0) ==
|
||||
((data.flag & IDWALK_INCLUDE_UI) == 0))) {
|
||||
/* Note that this is minor optimization, even in worst cases (like id being an object with
|
||||
|
|
|
@ -342,7 +342,7 @@ MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
|
|||
BLI_strncpy(masklay->name, name, sizeof(masklay->name));
|
||||
}
|
||||
else {
|
||||
strcpy(masklay->name, "MaskLayer");
|
||||
strcpy(masklay->name, DATA_("MaskLayer"));
|
||||
}
|
||||
|
||||
BLI_addtail(&mask->masklayers, masklay);
|
||||
|
|
|
@ -130,6 +130,8 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
|
|||
#define BLT_I18NCONTEXT_VIRTUAL_REALITY "Virtual reality"
|
||||
#define BLT_I18NCONTEXT_CONSTRAINT "Constraint"
|
||||
#define BLT_I18NCONTEXT_COLOR "Color"
|
||||
#define BLT_I18NCONTEXT_AMOUNT "Amount"
|
||||
#define BLT_I18NCONTEXT_UNIT "Unit"
|
||||
|
||||
/* Helper for bpy.app.i18n object... */
|
||||
typedef struct {
|
||||
|
@ -198,6 +200,8 @@ typedef struct {
|
|||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_VIRTUAL_REALITY, "virtual_reality"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_CONSTRAINT, "constraint"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_COLOR, "color"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_AMOUNT, "amount"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UNIT, "unit"), \
|
||||
{ \
|
||||
NULL, NULL, NULL \
|
||||
} \
|
||||
|
|
|
@ -559,21 +559,21 @@ MeshRenderData *mesh_render_data_create(Object *object,
|
|||
mr->p_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
|
||||
|
||||
mr->material_indices = static_cast<const int *>(
|
||||
CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, "material_index"));
|
||||
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_INT32, "material_index"));
|
||||
|
||||
mr->hide_vert = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert"));
|
||||
CustomData_get_layer_named(&mr->me->vdata, CD_PROP_BOOL, ".hide_vert"));
|
||||
mr->hide_edge = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me->edata, CD_PROP_BOOL, ".hide_edge"));
|
||||
CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".hide_edge"));
|
||||
mr->hide_poly = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly"));
|
||||
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".hide_poly"));
|
||||
|
||||
mr->select_vert = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".select_vert"));
|
||||
CustomData_get_layer_named(&mr->me->vdata, CD_PROP_BOOL, ".select_vert"));
|
||||
mr->select_edge = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me->edata, CD_PROP_BOOL, ".select_edge"));
|
||||
CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".select_edge"));
|
||||
mr->select_poly = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".select_poly"));
|
||||
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".select_poly"));
|
||||
}
|
||||
else {
|
||||
/* #BMesh */
|
||||
|
@ -586,7 +586,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
|
|||
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
|
||||
}
|
||||
|
||||
retrieve_active_attribute_names(*mr, *object, *me);
|
||||
retrieve_active_attribute_names(*mr, *object, *mr->me);
|
||||
|
||||
return mr;
|
||||
}
|
||||
|
|
|
@ -56,13 +56,16 @@ using namespace blender::bke::idprop;
|
|||
* "catalog_name": "<catalog_name>",
|
||||
* "description": "<description>",
|
||||
* "author": "<author>",
|
||||
* "copyright": "<copyright>",
|
||||
* "license": "<license>",
|
||||
* "tags": ["<tag>"],
|
||||
* "properties": [..]
|
||||
* }]
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* NOTE: entries, author, description, tags and properties are optional attributes.
|
||||
* NOTE: entries, author, description, copyright, license, tags and properties are optional
|
||||
* attributes.
|
||||
*
|
||||
* NOTE: File browser uses name and idcode separate. Inside the index they are joined together like
|
||||
* #ID.name.
|
||||
|
@ -75,6 +78,8 @@ constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_ID("catalog_id");
|
|||
constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name");
|
||||
constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description");
|
||||
constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author");
|
||||
constexpr StringRef ATTRIBUTE_ENTRIES_COPYRIGHT("copyright");
|
||||
constexpr StringRef ATTRIBUTE_ENTRIES_LICENSE("license");
|
||||
constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags");
|
||||
constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties");
|
||||
|
||||
|
@ -178,6 +183,26 @@ struct AssetEntryReader {
|
|||
return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value();
|
||||
}
|
||||
|
||||
bool has_copyright() const
|
||||
{
|
||||
return lookup.contains(ATTRIBUTE_ENTRIES_COPYRIGHT);
|
||||
}
|
||||
|
||||
StringRefNull get_copyright() const
|
||||
{
|
||||
return lookup.lookup(ATTRIBUTE_ENTRIES_COPYRIGHT)->as_string_value()->value();
|
||||
}
|
||||
|
||||
bool has_license() const
|
||||
{
|
||||
return lookup.contains(ATTRIBUTE_ENTRIES_LICENSE);
|
||||
}
|
||||
|
||||
StringRefNull get_license() const
|
||||
{
|
||||
return lookup.lookup(ATTRIBUTE_ENTRIES_LICENSE)->as_string_value()->value();
|
||||
}
|
||||
|
||||
StringRefNull get_catalog_name() const
|
||||
{
|
||||
return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value();
|
||||
|
@ -267,6 +292,16 @@ struct AssetEntryWriter {
|
|||
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author)));
|
||||
}
|
||||
|
||||
void add_copyright(const StringRefNull copyright)
|
||||
{
|
||||
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_COPYRIGHT, new StringValue(copyright)));
|
||||
}
|
||||
|
||||
void add_license(const StringRefNull license)
|
||||
{
|
||||
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_LICENSE, new StringValue(license)));
|
||||
}
|
||||
|
||||
void add_tags(const ListBase /* AssetTag */ *asset_tags)
|
||||
{
|
||||
ArrayValue *tags = new ArrayValue();
|
||||
|
@ -305,6 +340,12 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
|
|||
if (asset_data.author != nullptr) {
|
||||
result.add_author(asset_data.author);
|
||||
}
|
||||
if (asset_data.copyright != nullptr) {
|
||||
result.add_copyright(asset_data.copyright);
|
||||
}
|
||||
if (asset_data.license != nullptr) {
|
||||
result.add_license(asset_data.license);
|
||||
}
|
||||
|
||||
if (!BLI_listbase_is_empty(&asset_data.tags)) {
|
||||
result.add_tags(&asset_data.tags);
|
||||
|
@ -372,6 +413,18 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
|
|||
BLI_strncpy(author_c_str, author.c_str(), author.size() + 1);
|
||||
asset_data->author = author_c_str;
|
||||
}
|
||||
if (entry.has_copyright()) {
|
||||
const StringRefNull copyright = entry.get_copyright();
|
||||
char *copyright_c_str = static_cast<char *>(MEM_mallocN(copyright.size() + 1, __func__));
|
||||
BLI_strncpy(copyright_c_str, copyright.c_str(), copyright.size() + 1);
|
||||
asset_data->copyright = copyright_c_str;
|
||||
}
|
||||
if (entry.has_license()) {
|
||||
const StringRefNull license = entry.get_license();
|
||||
char *license_c_str = static_cast<char *>(MEM_mallocN(license.size() + 1, __func__));
|
||||
BLI_strncpy(license_c_str, license.c_str(), license.size() + 1);
|
||||
asset_data->license = license_c_str;
|
||||
}
|
||||
|
||||
const StringRefNull catalog_name = entry.get_catalog_name();
|
||||
BLI_strncpy(asset_data->catalog_simple_name,
|
||||
|
|
|
@ -3877,7 +3877,7 @@ static void ui_but_update_ex(uiBut *but, const bool validate)
|
|||
case UI_BTYPE_KEY_EVENT: {
|
||||
const char *str;
|
||||
if (but->flag & UI_SELECT) {
|
||||
str = "Press a key";
|
||||
str = IFACE_("Press a key");
|
||||
}
|
||||
else {
|
||||
UI_GET_BUT_VALUE_INIT(but, value);
|
||||
|
@ -3910,7 +3910,7 @@ static void ui_but_update_ex(uiBut *but, const bool validate)
|
|||
(void)str; /* UNUSED */
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(but->drawstr, "Press a key", UI_MAX_DRAW_STR);
|
||||
BLI_strncpy(but->drawstr, IFACE_("Press a key"), UI_MAX_DRAW_STR);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -5912,7 +5912,8 @@ static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *p
|
|||
LISTBASE_FOREACH (uiItem *, subitem, &layout->items) {
|
||||
if (subitem->type == ITEM_BUTTON) {
|
||||
uiButtonItem *bitem = (uiButtonItem *)subitem;
|
||||
if (!(bitem->but->flag & UI_HIDDEN) && STREQ(bitem->but->str, pt->label)) {
|
||||
if (!(bitem->but->flag & UI_HIDDEN) &&
|
||||
STREQ(bitem->but->str, CTX_IFACE_(pt->translation_context, pt->label))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2810,8 +2810,10 @@ void TEXT_OT_scroll(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_INTERNAL;
|
||||
|
||||
/* properties */
|
||||
RNA_def_int(
|
||||
PropertyRNA *prop;
|
||||
prop = RNA_def_int(
|
||||
ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -2915,8 +2917,10 @@ void TEXT_OT_scroll_bar(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
|
||||
|
||||
/* properties */
|
||||
RNA_def_int(
|
||||
PropertyRNA *prop;
|
||||
prop = RNA_def_int(
|
||||
ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -3059,6 +3059,7 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi
|
|||
}
|
||||
|
||||
if (!closest.curves_id) {
|
||||
MEM_freeN(bases_ptr);
|
||||
HooglyBoogly marked this conversation as resolved
|
||||
return deselected;
|
||||
}
|
||||
|
||||
|
|
|
@ -146,12 +146,21 @@ void solve_length_and_collision_constraints(const OffsetIndices<int> points_by_c
|
|||
float slide_direction_length_cu;
|
||||
const float3 normalized_slide_direction_cu = math::normalize_and_get_length(
|
||||
slide_direction_cu, slide_direction_length_cu);
|
||||
const float slide_normal_length_sq_cu = math::length_squared(slide_normal_cu);
|
||||
|
||||
/* Use pythagorian theorem to determine how far to slide. */
|
||||
const float slide_distance_cu = std::sqrt(pow2f(goal_segment_length_cu) -
|
||||
math::length_squared(slide_normal_cu)) -
|
||||
slide_direction_length_cu;
|
||||
positions_cu[point_i] = plane_pos_cu + normalized_slide_direction_cu * slide_distance_cu;
|
||||
if (pow2f(goal_segment_length_cu) > slide_normal_length_sq_cu) {
|
||||
/* Use pythagorian theorem to determine how far to slide. */
|
||||
const float slide_distance_cu = std::sqrt(pow2f(goal_segment_length_cu) -
|
||||
slide_normal_length_sq_cu) -
|
||||
slide_direction_length_cu;
|
||||
positions_cu[point_i] = plane_pos_cu +
|
||||
normalized_slide_direction_cu * slide_distance_cu;
|
||||
}
|
||||
else {
|
||||
/* Minimum distance is larger than allowed segment length.
|
||||
* The unilateral collision constraint is satisfied by just clamping segment length. */
|
||||
positions_cu[point_i] = prev_pos_cu + math::normalize(old_pos_su - prev_pos_cu) * goal_segment_length_cu;
|
||||
}
|
||||
}
|
||||
if (used_iterations == max_collisions) {
|
||||
revert_curve = true;
|
||||
|
|
|
@ -62,11 +62,24 @@ template<> uint denormalize<uint>(float val)
|
|||
return uint(float(DEPTH_SCALE_FACTOR) * val);
|
||||
}
|
||||
|
||||
/* Float to other type case. */
|
||||
template<typename T> T convert_type(float type)
|
||||
{
|
||||
return T(type);
|
||||
}
|
||||
|
||||
/* Uint to other types. */
|
||||
template<typename T> T convert_type(uint type)
|
||||
{
|
||||
return T(type);
|
||||
}
|
||||
|
||||
/* Int to other types. */
|
||||
template<typename T> T convert_type(int type)
|
||||
{
|
||||
return T(type);
|
||||
}
|
||||
|
||||
template<> uchar convert_type<uchar>(float val)
|
||||
{
|
||||
return uchar(val * float(0xFF));
|
||||
|
@ -141,8 +154,8 @@ kernel void compute_texture_read(constant TextureReadParams ¶ms [[buffer(0)]
|
|||
uint xx = position[0];
|
||||
uint yy = position[1];
|
||||
uint zz = position[2];
|
||||
int index = (zz * (params.extent[0] * params.extent[1]) + yy * params.extnt[0] + xx) *
|
||||
COMPONENT_COUNT_INPUT;
|
||||
int index = (zz * (params.extent[0] * params.extent[1]) + yy * params.extent[0] + xx) *
|
||||
COMPONENT_COUNT_OUTPUT;
|
||||
read_colour = read_tex.read(uint3(params.offset[0], params.offset[1], params.offset[2]) +
|
||||
uint3(xx, yy, zz));
|
||||
|
||||
|
@ -163,7 +176,7 @@ kernel void compute_texture_read(constant TextureReadParams ¶ms [[buffer(0)]
|
|||
uint yy = position[1];
|
||||
uint layer = position[2];
|
||||
int index = (layer * (params.extent[0] * params.extent[1]) + yy * params.extent[0] + xx) *
|
||||
COMPONENT_COUNT_INPUT;
|
||||
COMPONENT_COUNT_OUTPUT;
|
||||
|
||||
/* Read data */
|
||||
# if IS_DEPTH_FORMAT == 1
|
||||
|
|
|
@ -606,17 +606,6 @@ void MTLFrameBuffer::update_attachments(bool update_viewport)
|
|||
if (!dirty_attachments_) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cache viewport and scissor (If we have existing attachments). */
|
||||
int t_viewport[4], t_scissor[4];
|
||||
update_viewport = update_viewport &&
|
||||
(this->get_attachment_count() > 0 && this->has_depth_attachment() &&
|
||||
this->has_stencil_attachment());
|
||||
if (update_viewport) {
|
||||
this->viewport_get(t_viewport);
|
||||
this->scissor_get(t_scissor);
|
||||
}
|
||||
|
||||
/* Clear current attachments state. */
|
||||
this->remove_all_attachments();
|
||||
|
||||
|
@ -738,22 +727,25 @@ void MTLFrameBuffer::update_attachments(bool update_viewport)
|
|||
}
|
||||
}
|
||||
|
||||
/* Check whether the first attachment is SRGB. */
|
||||
/* Extract attachment size and determine if framebuffer is SRGB. */
|
||||
if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
|
||||
srgb_ = (first_attachment_mtl.texture->format_get() == GPU_SRGB8_A8);
|
||||
}
|
||||
|
||||
/* Reset viewport and Scissor (If viewport is smaller or equal to the framebuffer size). */
|
||||
if (update_viewport && t_viewport[2] <= width_ && t_viewport[3] <= height_) {
|
||||
|
||||
this->viewport_set(t_viewport);
|
||||
this->scissor_set(t_viewport);
|
||||
/* Ensure size is correctly assigned. */
|
||||
GPUAttachment &attach = attachments_[first_attachment];
|
||||
int size[3];
|
||||
GPU_texture_get_mipmap_size(attach.tex, attach.mip, size);
|
||||
this->size_set(size[0], size[1]);
|
||||
srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8);
|
||||
}
|
||||
else {
|
||||
this->viewport_reset();
|
||||
this->scissor_reset();
|
||||
/* Empty frame-buffer. */
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
}
|
||||
|
||||
/* Reset viewport and Scissor. */
|
||||
this->viewport_reset();
|
||||
this->scissor_reset();
|
||||
|
||||
/* We have now updated our internal structures. */
|
||||
dirty_attachments_ = false;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,12 @@ typedef struct AssetMetaData {
|
|||
/** Optional description of this asset for display in the UI. Dynamic length. */
|
||||
char *description;
|
||||
|
||||
/** Optional copyright of this asset for display in the UI. Dynamic length. */
|
||||
char *copyright;
|
||||
|
||||
/** Optional license of this asset for display in the UI. Dynamic length. */
|
||||
char *license;
|
||||
|
||||
/** User defined tags for this asset. The asset manager uses these for filtering, but how they
|
||||
* function exactly (e.g. how they are registered to provide a list of searchable available tags)
|
||||
* is up to the asset-engine. */
|
||||
|
|
|
@ -205,6 +205,74 @@ static void rna_AssetMetaData_description_set(PointerRNA *ptr, const char *value
|
|||
}
|
||||
}
|
||||
|
||||
static void rna_AssetMetaData_copyright_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
AssetMetaData *asset_data = ptr->data;
|
||||
|
||||
if (asset_data->copyright) {
|
||||
strcpy(value, asset_data->copyright);
|
||||
}
|
||||
else {
|
||||
value[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_AssetMetaData_copyright_length(PointerRNA *ptr)
|
||||
{
|
||||
AssetMetaData *asset_data = ptr->data;
|
||||
return asset_data->copyright ? strlen(asset_data->copyright) : 0;
|
||||
}
|
||||
|
||||
static void rna_AssetMetaData_copyright_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
AssetMetaData *asset_data = ptr->data;
|
||||
|
||||
if (asset_data->copyright) {
|
||||
MEM_freeN(asset_data->copyright);
|
||||
}
|
||||
|
||||
if (value[0]) {
|
||||
asset_data->copyright = BLI_strdup(value);
|
||||
}
|
||||
else {
|
||||
asset_data->copyright = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_AssetMetaData_license_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
AssetMetaData *asset_data = ptr->data;
|
||||
|
||||
if (asset_data->license) {
|
||||
strcpy(value, asset_data->license);
|
||||
}
|
||||
else {
|
||||
value[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_AssetMetaData_license_length(PointerRNA *ptr)
|
||||
{
|
||||
AssetMetaData *asset_data = ptr->data;
|
||||
return asset_data->license ? strlen(asset_data->license) : 0;
|
||||
}
|
||||
|
||||
static void rna_AssetMetaData_license_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
AssetMetaData *asset_data = ptr->data;
|
||||
|
||||
if (asset_data->license) {
|
||||
MEM_freeN(asset_data->license);
|
||||
}
|
||||
|
||||
if (value[0]) {
|
||||
asset_data->license = BLI_strdup(value);
|
||||
}
|
||||
else {
|
||||
asset_data->license = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_AssetMetaData_active_tag_range(
|
||||
PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
|
||||
{
|
||||
|
@ -397,6 +465,30 @@ static void rna_def_asset_data(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(
|
||||
prop, "Description", "A description of the asset to be displayed for the user");
|
||||
|
||||
prop = RNA_def_property(srna, "copyright", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_AssetMetaData_copyright_get",
|
||||
"rna_AssetMetaData_copyright_length",
|
||||
"rna_AssetMetaData_copyright_set");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Copyright",
|
||||
"Copyright notice for this asset. An empty copyright notice does not necessarily indicate "
|
||||
"that this is copyright-free. Contact the author if any clarification is needed");
|
||||
|
||||
prop = RNA_def_property(srna, "license", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_AssetMetaData_license_get",
|
||||
"rna_AssetMetaData_license_length",
|
||||
"rna_AssetMetaData_license_set");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"License",
|
||||
"The type of license this asset is distributed under. An empty license "
|
||||
"name does not necessarily indicate that this is free of licensing "
|
||||
"terms. Contact the author if any clarification is needed");
|
||||
|
||||
prop = RNA_def_property(srna, "tags", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "AssetTag");
|
||||
RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");
|
||||
|
|
|
@ -2556,6 +2556,8 @@ static void rna_def_brush(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, brush_curve_preset_items);
|
||||
RNA_def_property_ui_text(prop, "Curve Preset", "");
|
||||
RNA_def_property_translation_context(prop,
|
||||
BLT_I18NCONTEXT_ID_CURVES); /* Abusing id_curves :/ */
|
||||
RNA_def_property_update(prop, 0, "rna_Brush_update");
|
||||
|
||||
prop = RNA_def_property(srna, "deform_target", PROP_ENUM, PROP_NONE);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
@ -364,6 +366,7 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
|||
"Velocity Unit",
|
||||
"Define how the velocity vectors are interpreted with regard to time, 'frame' means "
|
||||
"the delta time is 1 frame, 'second' means the delta time is 1 / FPS");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UNIT);
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
|
|
|
@ -1821,6 +1821,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
|
|||
RNA_def_property_range(prop, 1, 5);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Number", "Particle number factor (higher value results in more particles)");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_AMOUNT);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "particle_min", PROP_INT, PROP_NONE);
|
||||
|
|
|
@ -2948,6 +2948,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
|||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_range(prop, 0, 1000000, 1, -1);
|
||||
RNA_def_property_ui_text(prop, "Number", "Total number of particles");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_AMOUNT);
|
||||
RNA_def_property_update(prop, 0, "rna_Particle_reset");
|
||||
|
||||
prop = RNA_def_property(
|
||||
|
|
|
@ -6440,6 +6440,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "hair_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, hair_shape_type_items);
|
||||
RNA_def_property_ui_text(prop, "Curves Shape Type", "Curves shape type");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVES);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update");
|
||||
|
||||
prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE);
|
||||
|
|
|
@ -237,6 +237,7 @@ static void rna_def_text(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "lines", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "TextLine");
|
||||
RNA_def_property_ui_text(prop, "Lines", "Lines of text");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
|
||||
|
||||
prop = RNA_def_property(srna, "current_line", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
|
|
|
@ -664,6 +664,7 @@ static void rna_def_volume(BlenderRNA *brna)
|
|||
"Velocity Unit",
|
||||
"Define how the velocity vectors are interpreted with regard to time, 'frame' means "
|
||||
"the delta time is 1 frame, 'second' means the delta time is 1 / FPS");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UNIT);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "velocity_scale", PROP_FLOAT, PROP_NONE);
|
||||
|
|
Loading…
Reference in New Issue
Needs a
MEM_freeN(bases_ptr)
.